Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEA] CUTLASS should ensure all its symbols are hidden from shared object libraries #1027

Open
jrhemstad opened this issue Aug 4, 2023 · 3 comments
Labels
feature request New feature or request inactive-30d
Milestone

Comments

@jrhemstad
Copy link
Contributor

Is your feature request related to a problem? Please describe.

As a user of CUTLASS, I would like to build a shared object library, libA.so, that internally uses CUTLASS function templates, including __global__ function templates.

Today, CUTLASS does nothing to hide the visibility of its __global__ function templates or any other host template functions, and by default these symbols have weak visibility. In short, this means if I link two dynamic libraries A.so and B.so into my application that both contain identical instantiations of a CUTLASS template, then the linker will discard one of the two instantiations and use only one of them. This can lead to disastrous and insidious issues like spurious silent failures.

This issue is true of any header-only, C++ template library, but is particularly bad for CUDA C++ libraries that ship __global__ function templates. Consider this trivial example of one of many ways things can go wrong

The following code has two TUs:

  • volta.cu​ compiled with sm_70​
  • pascal.cu​ compiled with sm_60​

Each TU has a single function ( volta()​ or pascal()​ respectively) and this function queries and prints the ptxVersion​ of a kernel<void>​ using cudaFuncGetAttributes​.

These TUs are linked into a program that determines the compute capability of device 0 and invokes volta()​ or pascal​() accordingly.

One would expect that invoking volta​() would always print 70​ and invoking pascal()​ would print 60​.

However, this is not the case. As described above, the kernel​ template has weak linkage, and so when linking the volta.o​ and pascal.o​ TUs together, the linker selects one of the instantiations of kernel<void>​ and discards the other.

The end result is that the program will randomly print 60 or 70 depending on which instantiation the linker picked.

// kernel.cuh
template <typename T>
__global__ void kernel(){}

// volta.cu
#include "kernel.cuh"
void volta(){
   cudaFuncAttributes attrs;
   cudaFuncGetAttributes(&attrs, (void *)(kernel<void>));
   printf("%d\n, attrs.ptxVersion*10);
}

// pascal.cu
#include "kernel.cuh"
void pascal(){

   cudaFuncAttributes attrs;
   cudaFuncGetAttributes(&attrs, (void *)(kernel<void>));
   printf("%d\n, attrs.ptxVersion*10);

}

// main.cpp
void volta();
void pascal();
int main(){
   int compute_capability;
   cudaDeviceGetAttribute(&compute_capability, cudaDevAttrComputeCapabilityMajor, 0);
   if(compute_capability >= 70)
      volta();
   else
      pascal();
}

nvcc -c -arch=sm_70 volta.cu
nvcc -c -arch=sm_60 pascal.cu
nvcc -c main.cpp
nvcc -o test volta.o pascal.o main.o
./test

TL;DR:

  • Given a __global__​ function, kernel​, with weak linkage (like a template)
  • Instantiate kernel​ in separate TUs compiled with different PTX architectures
  • Link the separate TUs into a single program
  • The linker will see the two instantiations of kernel​ as identical and discard one
  • Invoking kernel()​ results in potentially executing code you did not expect

Describe the solution you'd like

Luckily the solution is quite simple. Every host template function (including __global__ functions) in CUTLAS should be annotated with __attribute__((visibility("hidden"))).

This makes the symbol hidden in any resulting dynamic library.

Additional Context

We've been bitten by this in Thrust/CUB several times over the years.

Like CUTLASS, Thrust/CUB also have the ability to allow users to customize the namespace in order to differentiate the symbols and avoid this problem. However, this solution is not robust. First of all, it requires every user to remember to customize the namespace. Secondly, it's possible for users to properly customize the namespace and still run afoul of the issues that can result.

See:

@github-actions
Copy link

github-actions bot commented Sep 7, 2023

This issue has been labeled inactive-30d due to no recent activity in the past 30 days. Please close this issue if no further response or action is needed. Otherwise, please respond with a comment indicating any updates or changes to the original issue and/or confirm this issue still needs to be addressed. This issue will be labeled inactive-90d if there is no activity in the next 60 days.

@mnicely mnicely added this to the CUTLASS 3.3 milestone Sep 8, 2023
@mnicely mnicely modified the milestones: CUTLASS 3.3, CUTLASS 3.4 Dec 5, 2023
Copy link

github-actions bot commented Mar 4, 2024

This issue has been labeled inactive-90d due to no recent activity in the past 90 days. Please close this issue if no further response or action is needed. Otherwise, please respond with a comment indicating any updates or changes to the original issue and/or confirm this issue still needs to be addressed.

@leofang
Copy link
Member

leofang commented Sep 16, 2024

I think this is still relevant?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request New feature or request inactive-30d
Projects
None yet
Development

No branches or pull requests

3 participants