我正在尝试执行OpenCL,但它给了我一个CL_OUT_OF_RESOURCES。情况如下:
我正在测试100个工作项,所以我将global_sizes和local_sizes设置为100。 我创建了一个100 * 128的只写缓冲区,用于处理工作项的128个值。 我执行内核,当我要读取生成的缓冲区时,我得到了错误。
内核代码如下:
__kernel void k2(__global int* debug) {
uint idx = 128 * get_global_id(0);
uint i, k;
for (i = 0; i < 128000; ++i) {
for (k = 0; k < 128; ++k) {
debug[idx+k] = 23;
}
}
}
我在变量 idx 中获取每个工作项的索引。然后,我循环128000次子循环(我知道这是一个愚蠢的事情,但它仅用于测试目的!),并将值23赋予缓冲区的每个值。
启动代码如下:
cl_int status;
cl_uint num_platforms;
cl_platform_id* platforms;
cl_uint* num_devices;
cl_device_id** devices;
cl_platform_id platform;
cl_device_id device;
cl_context context;
cl_command_queue queue;
cl_kernel kernel;
cl_program program;
cl_ulong max_mem_size;
cl_ulong max_work_group_size;
size_t max_work_item_size[3];
// Discover and populate the platforms
status = clGetPlatformIDs(0, NULL, &num_platforms);
chk_err(status, "Getting platform IDs", true);
if (num_platforms <= 0) {
// If no platforms are available, we shouldn't continue
fprintf(stderr, "No OpenCL platforms found!\n");
exit(-1);
}
// Get all the platforms
platforms = new cl_platform_id[num_platforms];
status = clGetPlatformIDs(num_platforms, platforms, NULL);
chk_err(status, "Getting platform IDs", true);
// Allocate space for the device lists and lengths
num_devices = new cl_uint[num_platforms];
devices = new cl_device_id*[num_platforms];
// Traverse the platforms array printing information and
// populating devices
for (cl_uint i = 0; i < num_platforms; ++i) {
// Print some platform info
char* name = get_platform_info(platforms[i], CL_PLATFORM_NAME,
"Getting platform name");
char* vendor = get_platform_info(platforms[i], CL_PLATFORM_VENDOR,
"Getting platform vendor");
//printf("Platform: %s\nVendor: %s\n", name, vendor);
delete[] name;
delete[] vendor;
// Retrieve the devices
status = clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_GPU, 0, NULL, &num_devices[i]);
if (chk_err(status, "Getting device IDs")) {
printf("This is a known NVIDIA bug (if platform == AMD then die)\n");
printf("Setting number of devices to 0 and continuing\n");
num_devices[i] = 0;
}
//printf("Devices: %d\n", num_devices[i]);
// Populate OpenCL devices if any exist
if (num_devices[i] != 0) {
// Allocate an array of devices of size "numDevices"
devices[i] = new cl_device_id[num_devices[i]];
// Populate Array with devices
status = clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_GPU, num_devices[i],
devices[i], NULL);
chk_err(status, "Getting device IDs", true);
}
}
cl_uint chosen_platform = 0;
cl_uint chosen_device = 0;
// Do a sanity check of platform/device selection
if (chosen_platform >= num_platforms ||
chosen_device >= num_devices[chosen_platform]) {
fprintf(stderr, "Invalid platform/device combination\n");
exit(-1);
}
// Set the selected platform and device
platform = platforms[chosen_platform];
device = devices[chosen_platform][chosen_device];
// Get some device info
char* name = get_device_name(device);
char* vendor = get_device_vendor(device);
max_mem_size = get_device_max_mem_size(device);
max_work_group_size = get_device_max_work_group_size(device);
get_device_max_work_item_size(device, max_work_item_size);
printf("Device: %s\n", name);
printf("Vendor: %s\n", vendor);
printf("Max mem size: %llu Mb\n", max_mem_size / 1024);
printf("Max work group size: %llu\n", max_work_group_size);
printf("Max work item size: %llu, %llu, %llu\n",
max_work_item_size[0], max_work_item_size[1], max_work_item_size[2]);
delete[] name;
delete[] vendor;
// Create the context
cl_context_properties cps[3] = {CL_CONTEXT_PLATFORM,
(cl_context_properties)(platform), 0};
context = clCreateContext(cps, 1, &device, NULL, NULL, &status);
chk_err(status, "Creating context", true);
// Create the command queue
queue = clCreateCommandQueue(context, device, 0, &status);
chk_err(status, "creating command queue", true);
// Load kernel source
char* source = load_kernel_source("vpm2.cl");
size_t source_size[] = { strlen(source) };
// Create the program object
program = clCreateProgramWithSource(context, 1, (const char**)&source,
source_size, &status);
chk_err(status, "Creating program", true);
delete[] source;
// Try to compile the program
const char options[] = "-D ENABLE_DOUBLE -Werror -cl-nv-verbose";
status = clBuildProgram(program, 1, &device, options, NULL, NULL);
if (chk_err(status, "Building program")) {
cl_build_status build_status;
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_STATUS,
sizeof(cl_build_status), &build_status, NULL);
size_t size;
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0,
NULL, &size);
char* build_log = new char[size+1];
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG,
size+1, build_log, NULL);
build_log[size] = '\0';
printf("Build log:\n%s\nEnd log\n", build_log);
chk_err(build_status, "Getting build info", true);
}
// Create the kernel
kernel = clCreateKernel(program, "k2", &status);
chk_err(status, "Creating kernel", true);
// Create the buffer
uint num_workitems = 100;
uint buf_size = num_workitems * 128;
cl_mem mem = clCreateBuffer(context, CL_MEM_WRITE_ONLY, buf_size * sizeof(int), NULL, &status);
chk_err(status, "Error creating const mem buffer", true);
// Add arguments
status = clSetKernelArg(kernel, 0, sizeof(mem), &mem);
chk_err(status, "Setting kernel arg", true);
// Execute kernel
size_t global_sizes[1] = {num_workitems};
size_t local_sizes[1] = {num_workitems};
status = clEnqueueNDRangeKernel(queue, kernel, 1, NULL,
global_sizes, local_sizes, 0, NULL, NULL);
chk_err(status, "Executing kernel", true);
// Read the results
int* res = new int[buf_size];
status = clEnqueueReadBuffer(queue, mem, CL_TRUE, 0,
buf_size * sizeof(int), (void*)res, 0, NULL, NULL);
chk_err(status, "Reading buffer", true);
// Release objects
status = clReleaseProgram(program);
chk_err(status, "Releasing program");
status = clReleaseKernel(kernel);
chk_err(status, "Releasing kernel");
status = clReleaseMemObject(mem);
chk_err(status, "Releasing mem object");
clReleaseCommandQueue(queue);
clReleaseContext(context);
for (cl_uint i = 0; i < num_platforms; ++i) {
delete[] devices[i];
}
delete[] devices;
delete[] num_devices;
delete[] platforms;
delete res;
起初我虽然在 idx + k 索引中的范围已经不在了,但事实并非如此。
该错误确实很奇怪,因为如果我为 idx + 127 更改 idx + k ,例如,它可以正常工作。如果我还为较小的一个更改数字128000,例如56000,它也可以工作(!),这样就可以丢弃内核创建/执行中的错误。太棒了,不是吗?我开始认为本地内存管理存在问题或类似的问题。有什么想法??
顺便说一句......我正在运行NVIDIA Quadro 2000中的代码。
非常感谢!
答案 0 :(得分:2)
最可能的情况是你在内核中是SEG_FAULTing并且正在给你CL_OUT_OF_RESOURCES,这是nVIDIA平台中内核SEG_FAULTS时的一般错误。但是,由于clEnqueueNDRangeKernel在排队内核时无法检测到错误,因此在SEG_FAULTED的缓冲区读取时返回它。
原因可能是:
PD:如果您只运行100个工作项,我原来的假设是错误的。
您的错误的替代选项是您正在向120kB区域和仅1个工作组写入6GB的数据,这导致了一个巨大的瓶颈,使得内核花费了大量时间来运行被驱动程序杀死。返回CL_OUT_OF_RESOURCES。
减少循环量解决它,并将k设置为固定值将消除编译器优化阶段的循环(因此,也解决了问题)。 您可以尝试使用更多工作组来解决它。
你有2秒的屏幕冻结吗?那肯定是问题所在。