ããŒãã¹ã¿ãŒã
ã¿ãªããããã«ã¡ã¯ïŒ å°ãåã«ãCïŒã§OpenCLããããŒããæãå§ããŸããã ããããCïŒã®äžã ãã§ãªããäžè¬ã«ãã®ãããã¯ã«é¢ããè³æãã»ãšãã©ãªããšããäºå®ã«é¢é£ããå°é£ã«ééããŸããã OpenCLã®ããã€ãã®å ¥åã¯ã ããã«ãããŸã ã åæ§ã«ã·ã³ãã«ã§ãããåäœããOpenCLã®èµ·åã«ã€ããŠèª¬æããŸã ã èè ã«1ã€ã®ã€ãªã¿ãæããããã¯ãããŸãããããã·ã¢èªã§èŠã€ãããã¹ãŠã®èšäºïŒHabréãå«ãïŒã¯ãåãåé¡ã«èŠããã§ããŸãã ããã¥ã¡ã³ããŒã·ã§ã³ããããããã¯ãããããããè¯ãããã¥ã¡ã³ããŒã·ã§ã³ã®ããã«åãå ¥ããããŠããã®ã§ãèªãã®ã¯é£ããã§ãã ç§ã®èšäºïŒãããŠãã¹ãŠãããŸãããã°ãäžé£ã®èšäºïŒã§ããã®é åãæåããæãå§ãã人ã®èŠ³ç¹ããããã詳ãã説æããããšããŸãã ãã®ã¢ãããŒãã¯ãçç£æ§ã®é«ãã³ã³ãã¥ãŒãã£ã³ã°ãããã«å§ããã人ã«åœ¹ç«ã€ãšæããŸãã
æåã¯ãOpenCLã®ãããã¥ãŒããªã¢ã«èšäºãæžãããããäœã§ããããã©ã®ããã«æ©èœããããã³ãŒããæžãæ¹æ³ãããã³ç§ã®çµéšã«åºã¥ããããã€ãã®æšå¥šäºé ã«é¢ããæ å ±ãæžããããšæããŸããã ãããããã®éçšã§ãç§ã¯ç°¡åã«èšã£ãŠããèšäºã®éçã«æ²¡é ããããšã«æ°ä»ããŸããã ãªããªããç§èŠã§ã¯ãèšäºã¯ãã®ããªã¥ãŒã ãåžåããã®ãé£ãããªããããªããªã¥ãŒã ã§ããã¹ãã ããã§ãã ãããã£ãŠããã®èšäºïŒæåã®èšäºïŒã§ã¯ãOpenCLã§éå§ããæ¹æ³ã説æãããã¹ãŠãããŒã«ã«ã§æ£ããæ§æãããŠããããšã確èªããç°¡åãªããã°ã©ã ãäœæããŸãã ã¡ã¢ãªããã€ã¹ãã¢ãŒããã¯ãã£ãªã©ã«é¢ãã質åã«ã€ããŠã¯ã次ã®èšäºã§èª¬æããŸãã
å人ãã¡ãOpenCLã§ã®ç§ã®çµéšã¯ãæ®å¿µãªãããã°ã«/ãšãŒãã®ã¬ãã«ãšã¯çšé ããã®ã§ãããšããã«èšãããã®ã§ãããã§ããéãã®è³ªåã«çããããšããŸãã ãããŠãäœãããããªãå Žåã¯ããªãœãŒã¹ãšãããå®éã«ã©ã®ããã«æ©èœãããã«ã€ããŠã®ããžã§ã³ãå ±æããŸãã
ãªã«ã ã©ãã æ¹æ³ã
OpenCLã¯ãããŸããŸãªã¿ã€ãã®ã°ã©ãã£ãã¯ã¹ããã³äžå€®åŠçè£ çœ®ã§ã®äžŠåã³ã³ãã¥ãŒã¿ãŒã³ã³ãã¥ãŒãã£ã³ã°ã«é¢é£ããæè¡ã§ãã GPUã§ã®äžŠåã³ã³ãã¥ãŒãã£ã³ã°ã®ãããã¯ã¯ãæè¿ãCUDAãã¯ãããžãŒãšãšãã«åºã宣äŒãããŠããŸãã ãã®ããã¢ãŒã·ã§ã³ã¯äž»ã«Nvidiaã®åªåã«ãã£ãŠæšé²ãããŸããã OpenGLãšCUDAã®éãã¯ãã§ã«åºãè°è«ãããŠããŸã ã
OpenLã䜿çšãããšãCPUãšGPUã®äž¡æ¹ã§äœæ¥ã§ããŸãããGPUã§ã®äœæ¥ã«éäžããæ¹ãèå³æ·±ããšæããŸãã ãã®æè¡ã䜿çšããã«ã¯ãããå°ãææ°ã®ã°ã©ãã£ãã¯ã«ãŒããå¿ èŠã§ãã äž»ãªããšã¯ãããã€ã¹ãé©åã«æ©èœããŠããããšã確èªããããšã§ãã 念ã®ãããããã¯ããã€ã¹ãããŒãžã£ãŒã§å®è¡ã§ããããšãæãåºãããŠãã ããã
ãã®ãŠã£ã³ããŠã«å€±æãŸãã¯å€±æã衚瀺ãããå Žåããããªã«ãŒãã®è£œé å ã®Webãµã€ãã«çŽæ¥ã¢ã¯ã»ã¹ã§ããŸãã æ°ãããã©ã€ããŒã¯ãããŒããŠã§ã¢ã®æ©èœã«é¢ããåé¡ã解決ãããã®çµæãOpenCLã®ãã¯ãŒãå©çšã§ããããã«ããå¿ èŠããããŸãã
ç§ã¯ããšããšCïŒã§OpenCLã䜿çšããäºå®ã§ããã ããããClooãOpenCLNetãªã©ã®æ¢åã®ãã¬ãŒã ã¯ãŒã¯ã¯ãã¹ãŠèªå·±èšè¿°åã§ãããKhronosã¯ããããšã¯äœã®é¢ä¿ããªããããå®å®ããåäœãä¿èšŒããªããšããåé¡ã«ééããŸããã ãŸããç§ãã¡ã¯çãäž»ãªåé¡ãèŠããŠããŸã- éåžžã«å°æ°ã®äŸ ããã«åºã¥ããŠãæåã«C ++ã§èšè¿°ãããäŸãæ瀺ããOpenCLãæåŸ ã©ããã«åäœãããšãã確èªãåãåã£ãŠããããããã·ãCïŒãã¬ãŒã ã¯ãŒã¯ã®åœ¢åŒã§ãã蟌ã¿ãŸãã
ãã®ãããC ++ã§OpenCLã䜿çšããã«ã¯ããã®APIãèŠã€ããå¿ èŠããããŸãã ãããè¡ãã«ã¯ãç°å¢å€æ°ãéããããã§æãããååã®å€æ°ãæ¢ãããã®ååããããªã«ãŒãã®è£œé å ã«ãã³ããäžããŸãã ãAMDAPPSDKROOTããšåŒã°ãããã®å€æ°ããããŸãã ãã®åŸãæå®ãããã¹ã«ãããã®ã確èªã§ããŸãã ã€ã³ã¯ã«ãŒã\ CLãããæ¢ããŸãã
ã¡ãªã¿ã«ãéåžžã¯ã€ã³ã¯ã«ãŒããã©ã«ããŒã®CLãã©ã«ããŒã®é£ã«GLãã©ã«ããŒããããæåãªã°ã©ãã£ãã¯ã©ã€ãã©ãªãžã®ã¢ã¯ã»ã¹ãæäŸããŸãã
Visual Studioã§ãããžã§ã¯ããäœæãããããžã§ã¯ãããããã£ã®includeãã©ã«ããŒïŒç§ã®å Žåã¯$ïŒAMDAPPSDKROOTïŒ\ include \ïŒãæ¥ç¶ããããã«ã«è¡ããŸãïŒ
ã€ã³ãã©
APIãä»ããŠã§ã¯ãªããAPIãä»ããŠOpenCLãæäœããããšãèŠããŠããå¿ èŠããããŸã ã ãããã®2ã€ã®ãã¬ãŒãºã¯ã»ãšãã©åãããã«èŠããŸãããããã§ã¯ãããŸããã ããšãã°ãOpenGLãæãåºããŠãã ããã ããã§ã®äœæ¥ã¯ã©ã®ããã«è¡ãããŸããïŒç°¡ç¥çïŒ-æåã«ããã€ãã®äžè¬çãªãã©ã¡ãŒã¿ãŒãæ§æãã次ã«ã³ãŒãããçŽæ¥ãçãæããããå æºã®ãã©ã¡ãŒã¿ãŒãå€æŽããããªã©ã®ã¡ãœãããåŒã³åºããŸãã
OpenCLã§ã¯ãã¹ã¯ãªãããç°ãªããŸãã
- APIã䜿çšããŠãOpenCLããµããŒãããããã€ã¹ã«ã¢ã¯ã»ã¹ã§ããŸãã ã¢ããªã±ãŒã·ã§ã³ã®ãã®éšåã¯ãéåžžãã¹ããšåŒã°ããŸã ã
- ããã€ã¹ã§å®è¡ãããã³ãŒããèšè¿°ããŸãã ãã®ã³ãŒãã¯kernelãšåŒã°ããŸã ã ãã®ãã¹ãã³ãŒãã¯ãŸã£ããäœãç¥ããŸããã ã©ã®ãã¹ãã§ããã«ã§ããŸã
- APIã䜿çšããŠãã«ãŒãã«ã³ãŒããããŒãããéžæããããã€ã¹ã§å®è¡ãå®è¡ããŸãã
ã芧ã®ãšããããã®ã¢ããªã±ãŒã·ã§ã³ã«ã¯å æ¬çãªã€ã³ãã©ã¹ãã©ã¯ãã£ããããŸãã ã»ããã¢ããããŸãããïŒ
åã®ã¹ãããã§include ãã©ã«ããŒãæ éã«æ¥ç¶ããããã cl.hããããŒãã¡ã€ã«ã«ãªã³ã¯ãè¿œå ããã ãã§APIã«ã¢ã¯ã»ã¹ã§ããããã«ãªããŸãã cl.hãè¿œå ããå Žåããã©ãããã©ãŒã éžæãã§ãã¯ãè¿œå ãã䟡å€ããããŸãã
#ifdef __APPLE__ #include <OpenCL/opencl.h> #else #include <CL/cl.h> #endif
ããã§ãã³ãŒããæ©èœããããã€ã¹ãéžæããå€æ°ãååšããã³ã³ããã¹ããäœæããå¿ èŠããããŸãã ãããè¡ãæ¹æ³ã以äžã«ç€ºããŸãã
/* */ 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);
å€æ°retã«æ³šç®ããŸãã ããã¯ããã®é¢æ°ãŸãã¯ãã®é¢æ°ãè¿ãæ°å€ãå«ãå€æ°ã§ãã ret == 0ã®å Žåãé¢æ°ã¯æ£ããå®è¡ãããããã§ãªãå Žåã¯ãšã©ãŒãçºçããŸããã
CL_DEVICE_TYPE_DEFAULTå®æ°ã«ã泚æãå¿ èŠã§ããããã©ã«ãã§OpenCLã®èšç®ã«äœ¿çšãããããã€ã¹ãèŠæ±ããŸãã ãã®å®æ°ã®ä»£ããã«ãä»ã®å®æ°ã䜿çšã§ããŸãã äŸïŒ
- CL_DEVICE_TYPE_CPU-æ¢åã®CPUãèŠæ±ããŸãã
- CL_DEVICE_TYPE_GPU-æ¢åã®GPUããªã¯ãšã¹ãããŸãã
ã«ãŒãã«
çŽ æŽãããã ã€ã³ãã©ã¹ãã©ã¯ãã£ãã»ããã¢ããããŸãã ããã§ã¯ãã«ãŒãã«ã«åãæãããŸãããã ã«ãŒãã«ã¯ãåã«__kernelããŒã¯ãŒãã§å§ãŸãã¢ããŠã³ã¹ã¡ã³ãé¢æ°ã§ãã OpenCLããã°ã©ãã³ã°èšèªã®æ§æã¯C99æšæºã«åºã¥ããŠããŸãããããã€ãã®å ·äœçãã€éåžžã«éèŠãªå€æŽããããŸãã ããã¯å¥ã®èšäºã«ãªããŸãïŒæ¬åœã«é¡ã£ãŠããŸãïŒã ãããŸã§ã®åºæ¬æ å ±ïŒ
- å®è¡ã®ããã«ãã¹ãéšåããã²ãã€ã¥ãã³ãŒãã¯ãããŒã¯ãŒã__kernelã§å§ãŸãå¿ èŠããããŸãã
- __kernelããŒã¯ãŒããæã€é¢æ°ã¯åžžã«voidãè¿ããŸã ã
- ã¡ã¢ãªã¿ã€ãã®ä¿®é£ŸåããããŸãïŒ __global ã __local ã __constant ã __privateã¯ãå€æ°ãã©ã®ã¡ã¢ãªã«æ ŒçŽããããã決å®ããŸãã å€æ°ã®åã«ä¿®é£Ÿåããªãå Žåãããã¯__privateã§ãã
- ãã¹ããšã«ãŒãã«éã®ãéä¿¡ãã¯ãã«ãŒãã«ãã©ã¡ãŒã¿ãŒãä»ããŠè¡ãããŸãã ã«ãŒãã«ããã©ã¡ãŒã¿ãŒãä»ããŠãã¹ãã«äœããæž¡ãã«ã¯ããã©ã¡ãŒã¿ãŒã«__global修食åãä»ããå¿ èŠããããŸãïŒããã§ã¯ã__ globalã®ã¿ã䜿çšããŸãïŒã
- ã«ãŒãã«ã³ãŒãã¯éåžžãæ¡åŒµåãclã®ãã¡ã€ã«ã«ä¿åãããŸãã ãããå®éã«ã¯ãåæ§ã®ã³ãŒãããã®å Žã§çæã§ããŸãã ããã«ãããããã€ãã®å¶éãåé¿ãããŸãã ãããããã®å¥ã®æéã«ã€ããŠã®è©³çŽ°:)
æãç°¡åãªã«ãŒãã«ã®äŸã次ã«ç€ºããŸãã
__kernel void test(__global int* message) { // id. int gid = get_global_id(0); message[gid] += gid; }
ãã®ã³ãŒãã¯äœãããŸããã 1ã€ç®ã¯ãçŸåšå®è¡ãããŠããã°ããŒãã«ID ã¯ãŒã¯ã¢ã€ãã ãååŸããããšã§ãã äœæ¥é ç®ã¯ãã«ãŒãã«ãè¡ãããšã§ãã 䞊åèšç®ãæ±ã£ãŠãããããåäœæ¥é ç®ã«å¯ŸããŠãä»ã®ããšã«ã€ããŠäœãç¥ããªãç¬èªã®ã«ãŒãã«ãäœæãããŸãã ãããŠã誰ããã¹ãŠã®äœæ¥é ç®ãã©ã®é åºã§æ©èœããããä¿èšŒã§ããŸããã ããããããã«ã€ããŠã¯å¥ã®èšäºã§èª¬æããŸãïŒãã§ã«ãããç¹°ãè¿ãã®ã«ããããããŠããŸãïŒã ãã®äŸã§ã¯ãé åã®åèŠçŽ ãåå¥ã®ã¯ãŒã¯ã¢ã€ãã ã§åŠçãããããããã¯åºæ¬çã«é åå ã®èŠçŽ ã®ã€ã³ããã¯ã¹ã§ãã ã«ãŒãã«ã®è¡ã®2è¡ç®ã¯ã³ã¡ã³ãããå¿ èŠããªããšæããŸã:)
ã«ãŒãã«ã圢æãã
次ã®ã¹ãããã¯ã* .clãã¡ã€ã«ã«ãããã®ãã³ã³ãã€ã«ããããšã§ãã ããã¯æ¬¡ã®ããã«è¡ãããŸãã
cl_program program = NULL; cl_kernel kernel = NULL; FILE *fp; const char fileName[] = "../forTest.cl"; size_t source_size; char *source_str; int i; try { 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); } catch (int a) { printf("%f", a); } /* */ 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, "test", &ret);
ã¿ã€ãcl_programããã³cl_kernelã¯cl.hã§å®çŸ©ãããŠããŸãã ã¹ã¯ãªããèªäœã¯éåžžã«åçŽã§ãããã¡ã€ã«ãããŒããããã€ããªïŒclCreateProgramWithSourceïŒãäœæããŠã³ã³ãã€ã«ããŸãã retå€æ°ã«ãŸã 0ãå«ãŸããŠããå Žåããã¹ãŠãæ£ããè¡ããŸããã ãããŠãã«ãŒãã«èªäœãäœæããã ãã§ãã clCreateKernelã³ãã³ãã«æž¡ãããååãclãã¡ã€ã«å ã®ã«ãŒãã«åãšäžèŽããããšãéèŠã§ãã ç§ãã¡ã®å Žåãããã¯ããã¹ããã§ãã
ãã©ã¡ãŒã¿
ã«ãŒãã«ã¯ãã«ãŒãã«ã«æž¡ããããã©ã¡ãŒã¿ãŒãžã®æžã蟌ã¿/èªã¿åãã«ãã£ãŠãã¹ããšéä¿¡ããããšãæ¢ã«è¿°ã¹ãŸããã ç§ãã¡ã®å Žåãããã¯ã¡ãã»ãŒãžãã©ã¡ãŒã¿ã§ãã ãã®ããã«ãã¹ããã«ãŒãã«ãšéä¿¡ã§ããããã«ãããã©ã¡ãŒã¿ãŒã¯ã ãããã¡ãŒãšåŒã°ããŸã ã ãã¹ãåŽã§ãã®ãããªãããã¡ãäœæããAPIçµç±ã§ã«ãŒãã«ã«æž¡ããŸãããã
cl_mem memobj = NULL; int memLenth = 10; cl_int* mem = (cl_int *)malloc(sizeof(cl_int) * memLenth); /* */ memobj = clCreateBuffer(context, CL_MEM_READ_WRITE, memLenth * sizeof(cl_int), NULL, &ret); /* */ ret = clEnqueueWriteBuffer(command_queue, memobj, CL_TRUE, 0, memLenth * sizeof(cl_int), mem, 0, NULL, NULL); /* */ ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&memobj);
å®æ°CL_MEM_READ_WRITEã«æ³šæããããšãéèŠã§ããããã¯ãã«ãŒãã«åŽã§èªã¿åãããã³æžã蟌ã¿çšã®ãããã¡ãŒã«å¯Ÿããæš©éãããããšãæå³ããŸãã CL_MEM_WRITE_ONLY ã CL_MEM_READ_ONLYãªã©ã®å®æ°ã䜿çšã§ããŸãclSetKernelArgã¡ãœããã§ãã2çªç®ã®åŒæ°ã¯éèŠã§ããã©ã¡ãŒã¿ã®ã€ã³ããã¯ã¹ãå«ãŸããŠããŸãã ãã®å Žåã0ã¯ãã¡ãã»ãŒãžãã©ã¡ãŒã¿ãŒãã«ãŒãã«ã·ã°ããã£ã®æåã«æ¥ãããã§ãã 圌ã2çªç®ã«è¡ã£ãå Žåã次ã®ããã«èšè¿°ããŸãã
/* */ ret = clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&memobj);
clEnqueueWriteBufferã¯ãmemé åããmemobjãããã¡ãŒã«ããŒã¿ãæžã蟌ã¿ãŸãã
ãŸããäžè¬çã«ããã¹ãŠãæºåãã§ããŠããŸãã ã«ãŒãã«ãå®è¡ããããã ãã«æ®ããŸãã
ã«ãŒãã«ãå®è¡ãã
å®è¡ã³ãŒããéä¿¡ããŸãã
size_t global_work_size[1] = { 10 }; /* */ ret = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, global_work_size, NULL, 0, NULL, NULL); /* */ ret = clEnqueueReadBuffer(command_queue, memobj, CL_TRUE, 0, memLenth * sizeof(float), mem, 0, NULL, NULL);
global_work_sizeã«ã¯ãäœæããäœæ¥é ç®ã®æ°ãå«ãŸããŸãã é åã®åèŠçŽ ãåŠçããããã®ç¬èªã®äœæ¥é ç®ããããšæ¢ã«è¿°ã¹ãŸããã é åã«ã¯10åã®èŠçŽ ããããããwork-itemã«ã¯10ãå«ãŸããŸããclEnqueueNDRangeKernelã¯ç¹å¥ãªåé¡ãåŒãèµ·ããããšã¯ãããŸãã-æå®ãããã«ãŒãã«ãæå®ãããåæ°ã ãèµ·åããŸãã clEnqueueReadBufferã¯ãmemobjãšããååã®ãããã¡ãŒããããŒã¿ãèªã¿åãããã®ããŒã¿ãmemé åã«å ¥ããŸãã memã®ããŒã¿ã¯çµæã§ãïŒ
ãŸãšããšçµè«
å人ãããã¯ç§ãåå¿è ã®ããã«OpenCLããå§ããããšãæ³åããæ¹æ³ã§ãã å°æ¥çã«æŽæ°ã§ããããã«ãã³ã¡ã³ãã«å»ºèšçãªã³ã¡ã³ãããé¡ãããŸãã çãããããšããŸããããããã§ãé³éã¯å°ãããããŸããã§ããã ã§ãããã2ã3æ¬ã®èšäºã®è³æããŸã èŠã€ããããšãã§ããŸãã
æåŸãŸã§èªãã§ãã ãã£ãçãããããããšãããããŸããïŒ