ホストコードadd.cが無駄に長い・・・
あとコンパイルするときに
cl add.c OpenCL.lib
みたいな感じでOpenCL.libをコマンドライン引数に追加するとうまくいった。
add.cl
__kernel void add(__global float *result, __global float *ope1, __global float *ope2){
int id = get_global_id(0);
result[id] = ope1[id] + ope2[id];
}
add.c
#include<stdio.h>
#include<stdlib.h>
#ifdef __APPLE__
#include<OpenCL/opencl.h>
#else
#include<CL/cl.h>
#endif#define MAX_SOURCE_SIZE (0x100000)#define ARRAY_SIZE (4)
int main(){
float *result=NULL, *ope1=NULL, *ope2=NULL;
int i;
cl_platform_id platform_id = NULL;
cl_uint ret_num_platforms;
cl_device_id device_id = NULL;
cl_uint ret_num_devices;
cl_context context = NULL;
cl_command_queue command_queue = NULL; cl_mem resmem = NULL;
cl_mem ope1mem = NULL;
cl_mem ope2mem = NULL;
cl_program program = NULL;
cl_kernel kernel = NULL;
size_t global_item_size = 4;
size_t local_item_size = 1;
cl_int ret;
FILE *fp;
char fileName[] = "./add.cl";
char *source_str;
size_t source_size;
fp = fopen(fileName, "r");
if (!fp){
fprintf(stderr, "Failed to load kernel.\n");
exit(1);
}
source_str = (char*)malloc(MAX_SOURCE_SIZE);
source_size = fread(source_str, 1, MAX_SOURCE_SIZE, fp);
fclose(fp); result = (float *)malloc(ARRAY_SIZE*sizeof(float));
ope1 = (float *)malloc(ARRAY_SIZE*sizeof(float));
ope2 = (float *)malloc(ARRAY_SIZE*sizeof(float));
if((result==NULL) || (ope1==NULL) || (ope2==NULL)){
printf("Memory alloc failed.\n");
exit(EXIT_FAILURE);
}
for(i=0;i<ARRAY_SIZE;i++){
ope1[i] = i;
ope2[i] = i+ARRAY_SIZE;
}
ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);
ret = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, &ret_num_devices);
context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &ret);
command_queue = clCreateCommandQueue(context, device_id, 0, &ret); resmem = clCreateBuffer(context, CL_MEM_READ_WRITE, ARRAY_SIZE*sizeof(float), NULL, &ret);
ope1mem = clCreateBuffer(context, CL_MEM_READ_WRITE, ARRAY_SIZE*sizeof(float), NULL, &ret);
ope2mem = clCreateBuffer(context, CL_MEM_READ_WRITE, ARRAY_SIZE*sizeof(float), NULL, &ret);
ret = clEnqueueWriteBuffer(command_queue, ope1mem, CL_TRUE, 0, ARRAY_SIZE*sizeof(float), ope1, 0, NULL, NULL);
ret = clEnqueueWriteBuffer(command_queue, ope2mem, CL_TRUE, 0, ARRAY_SIZE*sizeof(float), ope2, 0, NULL, NULL);
program = clCreateProgramWithSource(context, 1, (const char **)&source_str, (const size_t *)&source_size, &ret);
ret = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL);
kernel = clCreateKernel(program, "add", &ret); ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *) &resmem);
ret = clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *) &ope1mem);
ret = clSetKernelArg(kernel, 2, sizeof(cl_mem), (void *) &ope2mem);
ret = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, &global_item_size, &local_item_size, 0, NULL, NULL); ret = clEnqueueReadBuffer(command_queue, resmem, CL_TRUE, 0, ARRAY_SIZE*sizeof(float), result, 0, NULL, NULL);
for(i=0;i<ARRAY_SIZE;i++){
printf("result[%d]:%5.2f = ope1[%d]:%5.2f + ope2[%d]:%5.2f\n", i, result[i], i, ope1[i], i, ope2[i]);
}
ret = clFlush(command_queue);
ret = clFinish(command_queue);
ret = clReleaseKernel(kernel);
ret = clReleaseProgram(program);
ret = clReleaseMemObject(resmem);
ret = clReleaseMemObject(ope1mem);
ret = clReleaseMemObject(ope2mem);
ret = clReleaseCommandQueue(command_queue);
ret = clReleaseContext(context); free(source_str); free(result);
free(ope1);
free(ope2);
return 0;
}
実行結果
result[0]: 4.00 = ope1[0]: 0.00 + ope2[0]: 4.00
result[1]: 6.00 = ope1[1]: 1.00 + ope2[1]: 5.00
result[2]: 8.00 = ope1[2]: 2.00 + ope2[2]: 6.00
result[3]:10.00 = ope1[3]: 3.00 + ope2[3]: 7.00
青文字を適当にコピペして赤文字の部分をちょっと書き換えることに
なるのかな?他は普通に書く方が早そうな?理解が進めば青いところでも
引数をちょこっと書き換える必要あるかも。とにかく無駄に長い。
カーネルコードadd.clがエラーを吐かないうえに実行までできてしまう件
引数が__global float *ope1ではなく__ global float *ope1と余計なスペースが
入っていてもresult[0]~result[3]が0.00とか謎の数値とかになるだけだった。
エラーを吐かせる方法も調べないと・・・orz
3/14追記
switch(get_id()){
case 0:
信号処理
break;
case 1:
情報処理
break;
case 2:
データ処理
break;
case 3:
信号処理
break;
}
というような並列処理は調査が足りないのでよく分かりません。
グラフィックカードの場合は分岐予測やアウトオブオーダーが苦手
(グラフィックカード上では複雑な機構を実装するのが困難
)
なので避けた方が無難だと思いますが、マルチコアCPUの場合
などは十分な有用性があると思います。
※上のような処理はCUDAだと
ウォープダイバージェントが起こる※OpenCLではswitch文ではなく実際にはタスク並列で処理を記述します
PR