Cublas не работает в ядре после компиляции в cubin с использованием флага -G с nvcc
У меня есть ядро CUDA, которое выглядит следующим образом:
#include <cublas_v2.h>
#include <math_constants.h>
#include <stdio.h>
extern "C" {
__device__ float ONE = 1.0f;
__device__ float M_ONE = -1.0f;
__device__ float ZERO = 0.0f;
__global__ void kernel(float *W, float *input, int i, float *output, int o) {
int idx = blockIdx.x*blockDim.x+threadIdx.x;
cublasHandle_t cnpHandle;
if(idx == 0) {
cublasCreate(&cnpHandle);
cublasStatus_t s = cublasSgemv(cnpHandle, CUBLAS_OP_N, o, i, &ONE, W, o, input, 1, &ZERO, output, 1);
printf("status %d\n", s);
cudaError_t e = cudaDeviceSynchronize();
printf("sync %d\n", e);
}
}
}
Код хоста:
#include <iostream>
#include <numeric>
#include <stdlib.h>
#include <cstring>
#include <cuda_runtime.h>
#include <cuda.h>
#include <cublas_v2.h>
extern "C" {
__global__ void kernel(float *W, float *input, int i, float *output, int o);
}
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort=true)
{
if (code != cudaSuccess)
{
fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
if (abort) exit(code);
}
}
int main(int argc, char* argv[])
{
cuInit(0);
CUcontext pctx;
CUdevice dev;
cuDeviceGet(&dev, 0);
cuCtxCreate(&pctx, 0, dev);
CUmodule module;
CUresult t = cuModuleLoad(&module, "pathto/src/minimalKernel.cubin");
CUfunction function;
CUresult r = cuModuleGetFunction(&function, module, "kernel");
float *W = new float[2];
W[0] = 0.1f;
W[1] = 0.1f;
float *input = new float[2];
input[0] = 0.1f;
input[1] = 0.1f;
float *out = new float[1];
out[0] = 0.0f;
int i = 2;
int o = 1;
float *d_W;
float *d_input;
float *d_out;
cudaMalloc((void**)&d_W, 2*sizeof(float));
cudaMalloc((void**)&d_input, 2*sizeof(float));
cudaMalloc((void**)&d_out, sizeof(float));
cudaMemcpy(d_W, W, 2*sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy(d_input, input, 2*sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy(d_out, out, sizeof(float), cudaMemcpyHostToDevice);
//kernel<<<1, 2>>>(d_W, d_input, i, d_out, o);
//cudaMemcpy(out, d_out, sizeof(float), cudaMemcpyDeviceToHost);
//std::cout<<"out:"<<out[0]<<std::endl;
void * kernelParams[] { &d_W, &d_input, &i, &d_out, &o };
CUresult k = cuLaunchKernel(function, 1, 1, 1, 2, 1, 1, 0, 0, (void**)kernelParams, 0);
gpuErrchk( cudaPeekAtLastError() );
gpuErrchk( cudaDeviceSynchronize() );
cudaMemcpy(out, d_out, sizeof(float), cudaMemcpyDeviceToHost);
std::cout<<"out:"<<out[0]<<std::endl;
}
Когда это ядро работает inline kernel<<<1,2>>>()
встроенное и связанное (в eclipse Nsight) ядро работает полностью и out
возвращается 0.02
как и ожидалось.
Если я скомпилирую ядро в.cubin, используя -G
(генерировать символы отладки устройства), функция cublas никогда не запускается, и out
всегда 0.0
Я могу поставить точки останова, когда работает.cubin, и я вижу, что данные правильно поступают в функцию cublas, но похоже, что функция cublas вообще никогда не запускается. Функция cublas также всегда возвращает 0 CUDA_SUCCESS
, Важно, что это происходит ТОЛЬКО при запуске этого из.cubin
Для компиляции в кубин я использую с -G
:
nvcc -G -cubin -arch=sm_52 --device-c kernel.cu -o kernel.cubin -dlink -lcudadevrt -lcublas_device
который не возвращает ошибок.
Почему функции cublas в.cubin перестают работать, если -G
опция добавлена?
CUDA 7.0 linux 14.04 x64 980GTX
1 ответ
FWIW, ваш код не работает правильно для меня с или без -G
переключатель. Вы можете запустить свой код с cuda-memcheck
чтобы помочь выявить ошибки. (Похоже, вы не выполняете надлежащую проверку ошибок CUDA ни в коде своего хоста, ни в коде своего устройства. С динамическим параллелизмом вы можете использовать аналогичную методологию в коде устройства. А API-интерфейс CUBLAS вызывает возврат кодов ошибок, которые вы не ' кажется, проверяет.)
Это не верно:
if(idx == 0) {
cublasCreate(&cnpHandle);
}
Это локальная переменная потока:
cublasHandle_t cnpHandle;
Так как вы запускаете ядро с двумя потоками:
CUresult k = cuLaunchKernel(function, 1, 1, 1, 2, 1, 1, 0, 0, (void**)kernelParams, 0);
Один из ваших потоков (0) передает действительный дескриптор cublasSgemv
вызов, а другой поток (1) нет.
Когда я исправляю эту ошибку, твой код "работает" для меня. Обратите внимание, что у вас все еще есть ситуация, когда вы передаете точно такие же параметры cublasSgemv
призыв к каждой из двух ваших тем. Поэтому каждый вызов записывает в одно и то же местоположение вывода. Так как порядок выполнения / поведения потока в этом случае не определен, возможно, вы могли бы видеть довольно переменное поведение: похоже, чтобы получить корректный вывод (так как один поток записал правильное значение в результате успешного вызова cublas), даже если другой cublas звонок не удался. Возможно, я полагаю, что -G
Переключатель может повлиять на этот порядок, или как-то повлиять на это поведение.
$ cat t889_kern.cu
#include <cublas_v2.h>
#include <math_constants.h>
#include <stdio.h>
extern "C" {
__device__ float ONE = 1.0f;
__device__ float M_ONE = -1.0f;
__device__ float ZERO = 0.0f;
__global__ void kernel(float *W, float *input, int i, float *output, int o) {
// int idx = blockIdx.x*blockDim.x+threadIdx.x;
cublasHandle_t cnpHandle;
cublasCreate(&cnpHandle);
cublasSgemv(cnpHandle, CUBLAS_OP_N, o, i, &ONE, W, o, input, 1, &ZERO, output, 1);
cudaDeviceSynchronize();
}
}
$ cat t889.cpp
#include <iostream>
#include <numeric>
#include <stdlib.h>
#include <cstring>
#include <cuda_runtime.h>
#include <cuda.h>
#include <cublas_v2.h>
extern "C" {
__global__ void kernel(float *W, float *input, int i, float *output, int o);
}
int main(int argc, char* argv[])
{
cuInit(0);
CUcontext pctx;
CUdevice dev;
cuDeviceGet(&dev, 0);
cuCtxCreate(&pctx, 0, dev);
CUmodule module;
CUresult t = cuModuleLoad(&module, "kernel.cubin");
CUfunction function;
CUresult r = cuModuleGetFunction(&function, module, "kernel");
float *W = new float[2];
W[0] = 0.1f;
W[1] = 0.1f;
float *input = new float[2];
input[0] = 0.1f;
input[1] = 0.1f;
float *out = new float[1];
out[0] = 0.0f;
int i = 2;
int o = 1;
float *d_W;
float *d_input;
float *d_out;
cudaMalloc((void**)&d_W, 2*sizeof(float));
cudaMalloc((void**)&d_input, 2*sizeof(float));
cudaMalloc((void**)&d_out, sizeof(float));
cudaMemcpy(d_W, W, 2*sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy(d_input, input, 2*sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy(d_out, out, sizeof(float), cudaMemcpyHostToDevice);
//kernel<<<1, 2>>>(d_W, d_input, i, d_out, o);
//cudaMemcpy(out, d_out, sizeof(float), cudaMemcpyDeviceToHost);
//std::cout<<"out:"<<out[0]<<std::endl;
void * kernelParams[] { &d_W, &d_input, &i, &d_out, &o };
CUresult k = cuLaunchKernel(function, 1, 1, 1, 2, 1, 1, 0, 0, (void**)kernelParams, 0);
cudaMemcpy(out, d_out, sizeof(float), cudaMemcpyDeviceToHost);
std::cout<<"out:"<<out[0]<<std::endl;
}
$ nvcc -cubin -arch=sm_35 --device-c t889_kern.cu -o kernel.cubin -dlink -lcudadevrt -lcublas_device
ptxas info : 'device-function-maxrregcount' is a BETA feature
$ g++ -std=c++11 -I/usr/local/cuda/include t889.cpp -o t889 -L/usr/local/cuda/lib64 -lcuda -lcudart
$ CUDA_VISIBLE_DEVICES="1" cuda-memcheck ./t889
========= CUDA-MEMCHECK
out:0.02
========= ERROR SUMMARY: 0 errors
$