Created
January 7, 2018 12:50
-
-
Save oss-dev-somewhere/7a0b0e9a302881f499181cf0019cff98 to your computer and use it in GitHub Desktop.
OpenCL NDRange kernel call
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#ifdef __APPLE__ | |
#include <OpenCL/opencl.h> | |
#else | |
#include <CL/cl.h> | |
#endif | |
#define KERNEL_FILE "add.cl" | |
#define KERNEL_NAME "add" | |
#define ARRAY_SIZE (128) | |
float array_a[ARRAY_SIZE] = {0, 1, 2}; | |
float array_b[ARRAY_SIZE] = {0, 1, 2}; | |
float array_c[ARRAY_SIZE]; | |
static void read_kernel(void); | |
static void check_status(cl_int err, const char *api); | |
int main() | |
{ | |
/* .clファイルを読み込む */ | |
FILE *fp = fopen(KERNEL_FILE, "r"); | |
if (fp == NULL) { | |
fprintf(stderr, "Could not open file %s.\n", KERNEL_FILE); | |
exit(1); | |
} | |
fseek(fp, 0, SEEK_END); | |
long file_size = ftell(fp); | |
char *source = malloc(file_size); | |
if (source == NULL) { | |
fprintf(stderr, "Could not allocate memory.\n"); | |
exit(1); | |
} | |
fseek(fp, 0, SEEK_SET); | |
if (fread(source, file_size, 1, fp) != 1) { | |
fprintf(stderr, "Could not read file %s.\n", KERNEL_FILE); | |
exit(1); | |
} | |
fclose(fp); | |
/* 1つめのプラットフォームを取得する */ | |
cl_int status; | |
cl_platform_id platform_id; | |
cl_uint num_platforms; | |
status = clGetPlatformIDs(1, &platform_id, &num_platforms); | |
check_status(status, "clGetPlatformIDs"); | |
/* 1つめのプラットフォームの1つめのデバイスを取得する */ | |
cl_device_id device_id; | |
cl_uint num_devices; | |
status = clGetDeviceIDs(platform_id, | |
CL_DEVICE_TYPE_DEFAULT, | |
1, | |
&device_id, | |
&num_devices); | |
check_status(status, "clGetDeviceIDs"); | |
/* OpenCLコンテキストを作成する */ | |
cl_context context = clCreateContext(NULL, | |
1, | |
&device_id, | |
NULL, | |
NULL, | |
&status); | |
check_status(status, "clCreateContext"); | |
/* コマンドキューを作成する */ | |
cl_command_queue command_queue = clCreateCommandQueue(context, | |
device_id, | |
0, | |
&status); | |
check_status(status, "clCreateCommandQueue"); | |
/* プログラムを作成する */ | |
size_t source_size = strlen(source); | |
cl_program program = clCreateProgramWithSource(context, | |
1, | |
(const char **)&source, | |
(size_t *)&source_size, | |
&status); | |
check_status(status, "clCreateProgramWithSource"); | |
/* プログラムをビルドする */ | |
status = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL); | |
if (status == CL_BUILD_PROGRAM_FAILURE) { | |
/* ログのサイズを取得する */ | |
size_t log_size; | |
clGetProgramBuildInfo(program, | |
device_id, | |
CL_PROGRAM_BUILD_LOG, | |
0, | |
NULL, | |
&log_size); | |
/* ログのメモリを確保する */ | |
char *log = malloc(log_size); | |
if (log == NULL) { | |
fprintf(stderr, "Could not allocate memory.\n"); | |
exit(1); | |
} | |
/* ログを取得する */ | |
clGetProgramBuildInfo(program, | |
device_id, | |
CL_PROGRAM_BUILD_LOG, | |
log_size, | |
log, | |
NULL); | |
/* ログを表示する */ | |
printf("%s\n", log); | |
free(log); | |
exit(1); | |
} | |
check_status(status, "clBuildProgram"); | |
/* カーネルを作成する */ | |
cl_kernel kernel = clCreateKernel(program, KERNEL_NAME, &status); | |
check_status(status, "clCreateKernel"); | |
/* バッファを作成する */ | |
cl_mem mem_a = clCreateBuffer(context, | |
CL_MEM_COPY_HOST_PTR | CL_MEM_READ_ONLY, | |
ARRAY_SIZE * sizeof(cl_float), | |
array_a, | |
&status); | |
check_status(status, "clCreateBuffer a"); | |
cl_mem mem_b = clCreateBuffer(context, | |
CL_MEM_COPY_HOST_PTR | CL_MEM_READ_ONLY, | |
ARRAY_SIZE * sizeof(cl_float), | |
array_b, | |
&status); | |
check_status(status, "clCreateBuffer b"); | |
cl_mem mem_c = clCreateBuffer(context, | |
CL_MEM_WRITE_ONLY, | |
ARRAY_SIZE * sizeof(cl_float), | |
NULL, | |
&status); | |
check_status(status, "clCreateBuffer c"); | |
/* カーネルの引数をセットする */ | |
status = clSetKernelArg(kernel, 0, sizeof(cl_mem), &mem_a); | |
check_status(status, "clSetKernelArg"); | |
status = clSetKernelArg(kernel, 1, sizeof(cl_mem), &mem_b); | |
check_status(status, "clSetKernelArg"); | |
status = clSetKernelArg(kernel, 2, sizeof(cl_mem), &mem_c); | |
check_status(status, "clSetKernelArg"); | |
/* カーネルを実行する */ | |
size_t global_work_size[1] = {ARRAY_SIZE}; | |
size_t local_work_size[1] = {1}; | |
status = clEnqueueNDRangeKernel(command_queue, | |
kernel, | |
1, | |
NULL, | |
global_work_size, | |
local_work_size, | |
0, | |
NULL, | |
NULL); | |
check_status(status, "clEnqueueNDRangeKernel"); | |
status = clFlush(command_queue); | |
check_status(status, "clFlush"); | |
status = clFinish(command_queue); | |
check_status(status, "clFinish"); | |
/* バッファから結果を取得する */ | |
status = clEnqueueReadBuffer(command_queue, | |
mem_c, | |
CL_TRUE, | |
0, | |
ARRAY_SIZE * sizeof(cl_float), | |
array_c, | |
0, | |
NULL, | |
NULL); | |
check_status(status, "clEnqueueReadBuffer"); | |
/* 結果を表示する */ | |
printf("%f %f %f\n", array_c[0], array_c[1], array_c[2]); | |
/* 終了処理を行う */ | |
status = clReleaseKernel(kernel); | |
check_status(status, "clReleaseKernel"); | |
status = clReleaseProgram(program); | |
check_status(status, "clReleaseProgram"); | |
status = clReleaseMemObject(mem_c); | |
check_status(status, "clReleaseMemObject"); | |
status = clReleaseMemObject(mem_b); | |
check_status(status, "clReleaseMemObject"); | |
status = clReleaseMemObject(mem_a); | |
check_status(status, "clReleaseMemObject"); | |
status = clReleaseCommandQueue(command_queue); | |
check_status(status, "clReleaseCommandQueue"); | |
status = clReleaseContext(context); | |
check_status(status, "clReleaseContext"); | |
free(source); | |
return 0; | |
} | |
/* | |
* APIエラーを確認する | |
*/ | |
static void check_status(cl_int err, const char *api) | |
{ | |
if (err == CL_SUCCESS) | |
return; | |
fprintf(stderr, "API %s error: %d\n", api, err); | |
exit(1); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment