Примечание. Если сообщение кажется длинным, можно сразу перейти к разделу, начинающемуся с «Мне было интересно..» в конце, на случай, если вы захотите пропустить сборку/контекст.
Сборка/контекст:
Для кода, упомянутого в сообщении, это — это функция __nv_cudaEntityRegisterCallback, внедренная компилятором nvcc, которая регистрирует имя/символ ядра на стороне хоста ((void (*)(double*, double*, double*, int))vecAdd) с помощью символ
на устройстве для разрешения графическим процессором с помощью некоторой таблицы поиска во время вызова API cudaLaunchKernel (чтобы получить указатель устройства), как указано здесь.
Аналогично, для определения указателя функции __device__, чтобы получить указатель устройства ядра vecAdd as:
// vecAdd.cu
#include
#include
// CUDA kernel that adds two vectors, each thread handles one element of c
__global__ void vecAdd(double *a, double *b, double *c, int n) {
int id = blockIdx.x * blockDim.x + threadIdx.x;
if (id < n) {
c[id] = a[id] + b[id];
}
}
./a.out vecAdd: 0x56400fc49640
Iteration 0: Time vecAdd: 6.092896 ms
...
Iteration 9: Time vecAdd: 6.029056 ms
Final sum = 100000000.000000; sum/n = 1.000000 (should be ~1)
В приведенном выше коде я загружаю кубин кода ядра vecAdd в файл main.cu, а затем получаю хост боковая заглушка (как видно из адреса 0x56400fc49640) ядра vecAdd с использованием cuModuleGetFunction, передавая только имя символа функции ядра в виде строки (как в _Z6vecAddPdS_S_i) (хотя в этой конкретной ситуации имя в стиле управляемого cpp содержит информацию о сигнатуре функции, но это может быть не всегда), с помощью которого я могу запустить ядро с помощью cuLaunchKernel.
содержит запись функции регистрации для _Z6vecAddPdS_S_i. Итак, я думаю, cuModuleLoad и cuModuleGetFunction устанавливают это в основной исполняемый файл.
Мне интересно
Мне интересно
Мне интересно
Strong>,
Есть ли способ, с помощью которого, используя только строку _Z6vecAddPdS_S_i, я мог бы получить указатель на стороне устройства ядра vecAdd< /код>. Точно так же, как при использовании cuModuleGetFunction, мы получаем указатель хоста ядра vecAdd.
Или, если vecAdd.cu был скомпилирован как vecAdd.o с помощью nvcc -c vecAdd.cu -o vecAdd.o -rdc=true и main скомпилировать как nvcc main.cu vecAdd.o, чтобы определить
Примечание. Если сообщение кажется длинным, можно сразу перейти к разделу, начинающемуся с «Мне было интересно..» в конце, на случай, если вы захотите пропустить сборку/контекст.
[b]Сборка/контекст:[/b] Для кода, упомянутого в сообщении, это — это функция __nv_cudaEntityRegisterCallback, внедренная компилятором nvcc, которая регистрирует имя/символ ядра на стороне хоста ((void (*)(double*, double*, double*, int))vecAdd) с помощью символ[code]_Z6vecAddPdS_S_i[/code] на устройстве для разрешения графическим процессором с помощью некоторой таблицы поиска во время вызова API cudaLaunchKernel (чтобы получить указатель устройства), как указано здесь. Аналогично, для определения указателя функции __device__, чтобы получить указатель устройства ядра vecAdd as: [code]typedef void (*fp)(double *, double *, double *, int); __device__ fp kernelPtrvecAdd = vecAdd; [/code] даже обрабатывается функцией __nv_cudaEntityRegisterCallback. [code]static void __nv_cudaEntityRegisterCallback(void **__T23) { // Save the fat binary handle for managed runtime __nv_save_fatbinhandle_for_managed_rt(__T23); ... ... // Register the vecAdd function __cudaRegisterFunction( __T23, (const char*)((void (*)(double*, double*, double*, int))vecAdd), "_Z6vecAddPdS_S_i", "_Z6vecAddPdS_S_i", -1, (uint3*)0, (uint3*)0, (dim3*)0, (dim3*)0, (int*)0 );
// Register the kernelPtrvecAdd variable __cudaRegisterVar( __T23, (char*)&::kernelPtrvecAdd, "kernelPtrvecAdd", "kernelPtrvecAdd", 0, 8UL, 0, 0 ); ... ... } [/code] Приведенный выше фрагмент кода можно получить, скомпилировав файл post.cu следующим образом: [code]$ nvcc -cuda post.cu -o post.cu.cpp.ii [/code]
Но рассмотрим ситуацию в примере, приведенном ниже: Где у меня есть следующая настройка: vecAdd.cu [code]// vecAdd.cu #include #include
// CUDA kernel that adds two vectors, each thread handles one element of c __global__ void vecAdd(double *a, double *b, double *c, int n) { int id = blockIdx.x * blockDim.x + threadIdx.x; if (id < n) { c[id] = a[id] + b[id]; } } [/code] Скомпилировано как [code]$ nvcc -cubin -arch=sm_75 vecAdd.cu -o vecAdd.cubin [/code] main.cu [code]#include #include #include #include #include
#define CUDA_SAFECALL(call) \ { \ call; \ cudaError err = cudaGetLastError(); \ if (cudaSuccess != err) { \ fprintf( \ stderr, \ "Cuda error in function '%s' file '%s' in line %i : %s.\n", \ #call, __FILE__, __LINE__, cudaGetErrorString(err)); \ fflush(stderr); \ exit(EXIT_FAILURE); \ } \ }
#define SAFECALL_DRV(call) \ { \ CUresult err = call; \ if (err != CUDA_SUCCESS) { \ const char *errStr; \ cuGetErrorString(err, &errStr); \ fprintf( \ stderr, \ "CUDA Driver API error in function '%s' file '%s' in line %i : %s.\n", \ #call, __FILE__, __LINE__, errStr); \ fflush(stderr); \ exit(EXIT_FAILURE); \ } \ }
int main(int argc, char *argv[]) { int n = 100000000; // Size of the vectors if (argc > 1) n = atoi(argv[1]);
// Initialize CUDA Driver API cuInit(0);
// Get a CUDA device and create a context CUdevice device; CUcontext context; cuDeviceGet(&device, 0); cuCtxCreate(&context, 0, device); cuDevicePrimaryCtxRetain(&context, device); // Load the module from vecAdd.o CUmodule module; SAFECALL_DRV(cuModuleLoad(&module, "vecAdd.cubin"));
// Create a CUDA stream for asynchronous execution cudaStream_t stream; cudaStreamCreate(&stream);
// Host and device vectors double *h_a, *h_b, *h_c; double *d_a, *d_b, *d_c; size_t bytes = n * sizeof(double);
// Synchronize the stream to ensure everything is done cudaStreamSynchronize(stream);
// Sum up vector c and print result divided by n, this should equal 1 within error double sum = 0; for (int i = 0; i < n; i++) sum += h_c[i]; printf("Final sum = %f; sum/n = %f (should be ~1)\n", sum, sum / n);
// Destroy the CUDA context cuCtxDestroy(context);
return 0; } [/code] [code]$ nvcc main.cu -lcuda [/code] [code]./a.out vecAdd: 0x56400fc49640 Iteration 0: Time vecAdd: 6.092896 ms ... Iteration 9: Time vecAdd: 6.029056 ms Final sum = 100000000.000000; sum/n = 1.000000 (should be ~1) [/code] В приведенном выше коде я загружаю кубин кода ядра vecAdd в файл main.cu, а затем получаю хост боковая заглушка (как видно из адреса 0x56400fc49640) ядра vecAdd с использованием cuModuleGetFunction, передавая только имя символа функции ядра в виде строки (как в _Z6vecAddPdS_S_i) (хотя в этой конкретной ситуации имя в стиле управляемого cpp содержит информацию о сигнатуре функции, но это может быть не всегда), с помощью которого я могу запустить ядро с помощью cuLaunchKernel. [code]nvcc -cuda main.cu main.cu.cpp.ii[/code] выходной файл (main.cu.cpp.ii) не содержит ни одной строки функции регистрации в __nv_cudaEntityRegisterCallback, но [code]nvcc -cuda vecAdd.cu vecAdd.cu.cpp.ii[/code] содержит запись функции регистрации для _Z6vecAddPdS_S_i. Итак, я думаю, cuModuleLoad и cuModuleGetFunction устанавливают это в основной исполняемый файл.
Мне интересно
Мне интересно
Мне интересно
Strong>, [list] [*]Есть ли способ, с помощью которого, используя только строку _Z6vecAddPdS_S_i, я мог бы получить указатель на стороне устройства ядра vecAdd< /код>. Точно так же, как при использовании cuModuleGetFunction, мы получаем указатель хоста ядра vecAdd. [*]Или, если vecAdd.cu был скомпилирован как vecAdd.o с помощью nvcc -c vecAdd.cu -o vecAdd.o -rdc=true и main скомпилировать как nvcc main.cu vecAdd.o, чтобы определить[code]__device__[/code] указатель функции требует, чтобы мы знали подпись vecAdd (для внешней связи) в main.cu: [/list] < pre class="lang-cuda beautifulprint-override">[code]typedef void (*fp)(double *, double *, double *, int); extern __global__ void vecAdd(double *a, double *b, double *c, int n); __device__ fp kernelPtr = vecAdd; [/code] Есть ли выход, при котором я могу получить указатель функции устройства vecAdd без знания его сигнатуры (по линии динамического параллелизма cuda)?
Для кода, упомянутого в сообщении, это функция __nv_cudaEntityRegisterCallback, внедренная компилятором nvcc, которая регистрирует имя/символ ядра на стороне хоста ((void (*)(double*, double*, double* , int))vecAdd) с символом _Z6vecAddPdS_S_i на...
Примечание. Если сообщение кажется длинным, можно сразу перейти к разделу, начинающемуся с «Мне было интересно..» в конце, на случай, если вы захотите пропустить сборку/контекст.
Сборка/контекст:
Для кода, упомянутого в сообщении, это — это...
](
sstatic.net/H3JmrldO.png
)
Для отладки рассмотрите возможность передачи CUDA_LAUNCH_BLOCKING=1
Скомпилируйте с TORCH_USE_CUDA_DSA, чтобы включить утверждения на стороне устройства.
Я тренирую YOLOv8 определять атрибуты одежды. Изображения...
Я обучаю две модели в одной и той же среде, и одна из них работает нормально с одной и той же конфигурацией, но другая выдает ошибки без какой-либо дополнительной причины. Я также добавил CUDA_LAUNCH_BLOCKING=1, но проблема осталась прежней....
Я обучаю две модели в одной и той же среде, и одна из них работает нормально с одной и той же конфигурацией, но другая выдает ошибки без какой-либо дополнительной причины. Я также добавил CUDA_LAUNCH_BLOCKING=1, но проблема осталась прежней....