У меня проблема в том, что разрабатываемое мной ядро случайно зависает. Это означает, что он падает каждый 10-й пробег. Я думаю, что мое ядро может быть слишком сложным, но уменьшение сложности не очень помогло.
При сбое clEnqueueNDRangeKernel
не возвращает ошибки, но следующее clFinish
возвращает -36
(CL_INVALID_COMMAND_QUEUE
), а следующие clEnqueueReadBuffer
возвращают ошибку -5
(CL_OUT_OF_RESOURCES
).
Итак, мои вопросы:
- В чем может быть причина сообщений об ошибках и сбоев?
- Мое ядро уже слишком сложное? Каков ваш опыт?
- Есть ли способ узнать, насколько сложным может быть ядро, не ожидая сбоя?
Если отсутствует информация, которая, по вашему мнению, будет полезна, оставьте комментарий.
Я попытался свести свое ядро к минимальному примеру, который все еще показывает ошибку. Это выглядит так:
" __kernel void myKernel1(",
" __local float* x,",
" __local float* y,",
" __global float* z,",
" __global float* b1,",
" __global float* data,",
" __global float* classes,",
" int nsamples,",
" int nfeatures,",
" int sizeb,",
" int nclasses,",
" int groupsize,",
" )",
" {",
" int local_id = get_local_id(0); ",
" int j = get_global_id(0); ",
" int cls = classes[j];",
" for(int k = 0; k<nfeatures; k++) x[k] = data[j*nfeatures+k];",
" float target[20];",
" for(int k = 0; k<nclasses; k++) target[k] = 0;",
" z[1]=z[1]+(float)get_local_id(0);",
" b1[2]=b1[2]+(float)local_id+get_group_id(0)*groupsize;",
" target[cls] =1;",
" int l1 = 0;",
" for(int l1 = 0; l1<sizeb ; l1++) {",
" y[l1+local_id*groupsize]=b1[l1];",
" for(int l2 = 0; l2<nfeatures; l2++){",
" }",
" }",
Буферы:
cl_mem z_cl = clCreateBuffer(GPUContext, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, niters * nclasses * sizeof(*z), z, &_err);
cl_mem b1_cl = clCreateBuffer(GPUContext, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, sizeb*sizeof(*b1), b1, &_err);
cl_mem gpu_data_cl = clCreateBuffer(GPUContext, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, nsamples * nfeatures * sizeof(*gpu_data), gpu_data, &_err);
cl_mem gpu_classes_cl = clCreateBuffer(GPUContext, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, nsamples * sizeof(*gpu_classes), gpu_classes, &_err);
_err = clSetKernelArg(myKernel1, ArgCounter++, sizeof(float)*nfeatures, NULL);
_err = clSetKernelArg(myKernel1, ArgCounter++, sizeof(float)*nhidden*groupsize,NULL);
_err = clSetKernelArg(myKernel1, ArgCounter++, sizeof(cl_mem),(void*)&z_cl);
_err = clSetKernelArg(myKernel1, ArgCounter++, sizeof(cl_mem),(void*)&b1_cl);
_err = clSetKernelArg(myKernel1, ArgCounter++, sizeof(cl_mem),(void*)&gpu_data_cl);
_err = clSetKernelArg(myKernel1, ArgCounter++, sizeof(cl_mem),(void*)&gpu_classes_cl);
_err = clSetKernelArg(myKernel1, ArgCounter++, sizeof(int), (void *) &nsamples);
_err = clSetKernelArg(myKernel1, ArgCounter++, sizeof(int), (void *) &nfeatures);
_err = clSetKernelArg(myKernel1, ArgCounter++, sizeof(int), (void *) &sizeb);
_err = clSetKernelArg(myKernel1, ArgCounter++, sizeof(int), (void *) &nclasses);
_err = clSetKernelArg(myKernel1, ArgCounter++, sizeof(int), (void *) &groupsize);
С:
- нитры ~ = 10000
- nclasses ~ = 10
- sizeb ~ = 80
- nsamples ~ = 50000
- nfeatures ~ = 10
Я использую Quadro FX 580 с версией драйвера 260.19.21 под Ubuntu 10.10 64Bit.
Спасибо, что уделили мне время на чтение !!!
[обновление]
Примеры SDK, такие как oclBandwidthTest, работают, и я проверяю ошибки после каждой команды cl, сравниваю создание и запуск своей очереди команд:
cl_device_id* init_opencl(cl_context *GPUContext,cl_command_queue *GPUCommandQueue, cl_kernel* cl_myKernel1,cl_program *OpenCLProgram){
cl_int _err=0;
cl_platform_id cpPlatform; // OpenCL platform
cl_device_id cdDevice; // OpenCL device
//Get an OpenCL platform
_err = clGetPlatformIDs(1, &cpPlatform, NULL);
if(_err || VERBOSE)printf("clGetPlatformIDs:%i\n",_err);
//Get the devices
_err = clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, 1, &cdDevice, NULL);
if(_err || VERBOSE)printf("clGetDeviceIDs:%i\n",_err);
// Create a context to run OpenCL on our CUDA-enabled NVIDIA GPU
*GPUContext = clCreateContext(0, 1, &cdDevice, NULL, NULL, &_err);
if(_err || VERBOSE)printf("clCreateContextFromType:%i\n",_err);
// Get the list of GPU devices associated with this context
size_t ParmDataBytes;
_err = clGetContextInfo(*GPUContext, CL_CONTEXT_DEVICES, 0, NULL, &ParmDataBytes);
if(_err || VERBOSE)printf("clGetContextInfo:%i\n",_err);
cl_device_id* GPUDevices;
GPUDevices = (cl_device_id*)malloc(ParmDataBytes);
_err = clGetContextInfo(*GPUContext, CL_CONTEXT_DEVICES, ParmDataBytes, GPUDevices, NULL);
if(_err || VERBOSE)printf("clGetContextInfo:%i\n",_err);
// Create a command-queue on the first GPU device
*GPUCommandQueue = clCreateCommandQueue(*GPUContext, GPUDevices[0], 0, &_err);
if(_err || VERBOSE)printf("clCreateCommandQueue:%i\n",_err);
// Create OpenCL program with source code
*OpenCLProgram = clCreateProgramWithSource(*GPUContext, sizeof(OpenCLSource)/sizeof(char *), OpenCLSource, NULL, &_err);
if(_err || VERBOSE)printf("CreateProgramWithSource:%i\n",_err);
//build OpenCl program
char * buildoptions= "-Werror";
_err= clBuildProgram(*(OpenCLProgram), 0, NULL, buildoptions, NULL, NULL);
if(_err != CL_SUCCESS){
if(_err || VERBOSE)printf("clBuildProgram:%i\n",_err);
cl_build_status build_status;
_err = clGetProgramBuildInfo(*(OpenCLProgram), GPUDevices[0], CL_PROGRAM_BUILD_STATUS, sizeof(cl_build_status), &build_status, NULL);
char *build_log;
size_t ret_val_size;
_err = clGetProgramBuildInfo(*(OpenCLProgram), GPUDevices[0], CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
build_log = (char*)malloc(ret_val_size+1);
_err = clGetProgramBuildInfo(*(OpenCLProgram), GPUDevices[0], CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL);
build_log[ret_val_size] = '\0';
printf("BUILD LOG: \n %s", build_log);
}
//create Kernel
*cl_myKernel1 = clCreateKernel(*(OpenCLProgram), "myKernel1", &_err);
if(_err || VERBOSE)printf("clCreateKernel:%i\n",_err);
//output system info
if (VERBOSE){
size_t workgroupsize;
cl_uint devicedata;
size_t maxitems[3];
clGetKernelWorkGroupInfo(*cl_myKernel1,GPUDevices[0], CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &workgroupsize, NULL);
printf("CL_KERNEL_WORK_GROUP_SIZE:%i (recommended workgroupsize for the used kernel)\n",workgroupsize);
clGetDeviceInfo(GPUDevices[0], CL_DEVICE_ADDRESS_BITS, sizeof(cl_uint), &devicedata, NULL);
printf("CL_DEVICE_ADDRESS_BITS:%i\n",devicedata);
clGetDeviceInfo(GPUDevices[0], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(cl_uint), &devicedata, NULL);
printf("CL_DEVICE_MAX_COMPUTE_UNITS:%i\n",devicedata);
_err= clGetDeviceInfo(GPUDevices[0], CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof( maxitems), &maxitems, NULL);
printf("CL_DEVICE_MAX_WORK_ITEM_SIZES:%i,%i,%i error=%i\n",maxitems[0],maxitems[1],maxitems[2],_err);
_err= clGetDeviceInfo(GPUDevices[0], CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof( maxitems), &maxitems, NULL);
printf("CL_DEVICE_MAX_WORK_GROUP_SIZE:%i,%i,%i error=%i\n",maxitems[0],maxitems[1],maxitems[2],_err);
printf("Lines of CL code: %i\n",sizeof(OpenCLSource)/sizeof(char*));
getchar();
}
return GPUDevices;
}
Запуск:
clEnqueueNDRangeKernel(GPUCommandQueue, cl_myKernel1, 1, NULL, globalWorkSize, localWorkSize, 0, NULL, NULL);
if(_err!=CL_SUCCESS)printf("\nclEnqueueNDRangeKernel:%i\n",_err);
_err = clFinish(GPUCommandQueue);
if(_err!=CL_SUCCESS)printf("\nclFinish GPUCommandQueue:%i\n",_err);