Я новичок в OpenCL и узнал об этом из «OpenCL в действии» Мэтью Скарпино . Я рассмотрел пример умножения матрицы на вектор (стр. 11-13). По какой-то причине пример не работал на моем компьютере. Ядро не вернуло значения. Я начал искать простые примеры вывода данных из ядра.
Я нашел в youtube-канале Уэсли Шиллингфорда пример вывода строки символов «Hello world!» из ядра. На моем домашнем компьютере пример работал. Однако «кухня» OpenCL оставалась закрытой, поскольку представленный пример был написан на C ++. Краткость кода затемняла представление о том, что происходит. Поэтому я начал искать примеры в коде C.
Среди ответов на Stackoverflow я нашел пример минимальной программы OpenCL , которая увеличивает значение в ядре. Я взял этот код за основу для написания своей программы, потому что он прост и удобен для новичка. Как я позже узнал, пример содержал ошибку.
Другой отличный пример убедил меня использовать указатели для возврата данных из ядра. Использование массивов для хранения выходных значений ядра приводит к тому, что значения целевого массива не меняются, а данные из ядра исчезают во время вывода. Я понял, что нам нужно использовать указатели для вывода данных из ядра. Однако мне это не помогло. Проблема передачи данных из ядра в хост-программу остается. Пожалуйста, поправьте меня, если я в чем-то ошибаюсь. Суть топи c: Ядро не возвращает символьные данные в хост-программу. В чем может быть проблема?
#include <CL/cl.h>
#include <stdio.h>
#include <stdlib.h>
int main(){
cl_platform_id *platforms =NULL;
cl_device_id *devices=NULL;
cl_context context;
cl_command_queue cmdQueue;
cl_program program;
cl_kernel kernel = NULL;
char *cpOutputData;
int output_size = 8;
cl_mem output_buff;
cl_int status; // to check the output of each API call
const char *source =
"__kernel void Hello( __global char* ch) {\n"
" ch[0]='P';"
" ch[1]='r';"
" ch[2]='i';"
" ch[3]='v';"
" ch[4]='e';"
" ch[5]='t';"
" ch[6]='!';"
" ch[7]='\0';"
"}\0";
printf("GetPlatformIDs... ");
cl_uint numPlatforms = 0;
//STEP 1: Discover and initialize platforms
// Use clGetPlatformIDs to retreive the number of platforms
status = clGetPlatformIDs(0,
NULL,
&numPlatforms);
// Allocate enough space for each platform
platforms = (cl_platform_id*)malloc(numPlatforms*sizeof(cl_platform_id));
// Fill in platforms with clGetPlatformIDs()
status=clGetPlatformIDs(numPlatforms,
platforms,
NULL);
printf("\nNumber of discovered platforms is %d. ", numPlatforms);
// STEP 2: Discover and initialize devices
printf("OK.\nGetDeviceIDs... ");
cl_uint numDevices = 0;
// Use clGetDeviceIDs() to retrieve the number of devices present
status = clGetDeviceIDs(platforms[0],
CL_DEVICE_TYPE_CPU,
0,
NULL,
&numDevices);
// Allocate enough space for each device
devices = (cl_device_id*)malloc(numDevices*sizeof(cl_device_id));
// Fill in devices with clGetDeviceIDs()
clGetDeviceIDs(platforms[0],
CL_DEVICE_TYPE_CPU,
numDevices,
devices,
NULL);
printf("\nNumber of discovered devices is %d. ", numDevices);
// STEP 3: Create a context
printf("OK.\nCreating context... ");
// Create context using clCreateContext() and associate it with the devices
context = clCreateContext(NULL,
numDevices,
devices,
NULL,
NULL,
&status);
// STEP 4: Create a command queue
printf("OK.\nQueue creating... ");
cmdQueue = clCreateCommandQueue(context,
devices[0],
CL_QUEUE_PROFILING_ENABLE,
&status);
// STEP 5: Create device buffers
printf("OK.\nOutput buffer creating... ");
output_buff = clCreateBuffer(context,
CL_MEM_WRITE_ONLY,
sizeof(char)*output_size,
NULL,
&status);
// STEP 6: Create and compile program
printf("OK.\nBuilding program... ");
// Create a program using clCreateProgramWithSource()
program = clCreateProgramWithSource(context,
1,
(const char**)&source,
NULL,
&status);
// Build (compile) the program for the devices with clBuildProgram()
status=clBuildProgram(program,
numDevices,
devices,
NULL,
NULL,
NULL);
// STEP 7: Create a kernel
printf("OK.\nCreating kernel... ");
kernel = clCreateKernel(program,
"Hello",
&status);
// STEP 8: Set kernel arguments
// Associate ouput buffer with the kernel
printf("OK.\nSetting kernel arguments... ");
status = clSetKernelArg(kernel,
0,
sizeof(cl_mem),
&output_buff);
// STEP 9: Configure the work-item structure
// Define an index space (global work size) of work itmes for execution.
// A workgroup size (local work size) is not required, but can be used.
size_t globalWorkSize[1];
// There are 'elements' work-items
globalWorkSize[0] = output_size;
// STEP 10: Enqueue the kernel for execution
printf("OK.\nExecuting kernel... ");
//Execute the kernel by using clEnqueueNDRangeKernel().
// 'globalWorkSize' is the 1D dimension of the work-items
clEnqueueNDRangeKernel(cmdQueue,
kernel,
1,
NULL,
globalWorkSize,
NULL,
0,
NULL,
NULL);
clFinish(cmdQueue);
// STEP 11: Read the ouput buffer back to the host
printf("OK.\nReading buffer... ");
// Allocate space for the data to be read
cpOutputData = (char*)malloc(output_size*sizeof(char));
// Use clEnqueueReadBuffer() to read the OpenCL ouput buffer to the host ouput array
clEnqueueReadBuffer(cmdQueue,
output_buff,
CL_TRUE,
0,
output_size,
cpOutputData,
0,
NULL,
NULL);
printf("\nPrinting output data: \n");
printf(cpOutputData);
// STEP 12: Releasing resources
printf("\n...Releasing OpenCL resources... ");
clReleaseKernel(kernel);
clReleaseProgram(program);
clReleaseCommandQueue(cmdQueue);
clReleaseMemObject(output_buff);
clReleaseContext(context);
printf("OK.\n...Releasing host resources... ");
free(cpOutputData);
free(platforms);
free(devices);
printf("OK.\nEnd of program. Bey!\n");
system("PAUSE");
return 0;
}
Результат выполнения моей программы здесь .