OpenCL.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #include <cstdlib>
  2. #include "OpenCL.h"
  3. OpenCL::OpenCL(int displayOutput)
  4. {
  5. VERBOSE = displayOutput;
  6. }
  7. OpenCL::~OpenCL()
  8. {
  9. // Flush and kill the command queue...
  10. clFlush(command_queue);
  11. clFinish(command_queue);
  12. // Release each kernel in the map kernelArray
  13. map<string, cl_kernel>::iterator it;
  14. for ( it=kernelArray.begin() ; it != kernelArray.end(); it++ )
  15. clReleaseKernel( (*it).second );
  16. // Now the program...
  17. clReleaseProgram(program);
  18. // ...and finally, the queue and context.
  19. clReleaseCommandQueue(command_queue);
  20. clReleaseContext(context);
  21. }
  22. size_t OpenCL::localSize()
  23. {
  24. return this->lwsize;
  25. }
  26. cl_command_queue OpenCL::q()
  27. {
  28. return this->command_queue;
  29. }
  30. void OpenCL::launch(string toLaunch)
  31. {
  32. // Launch the kernel (or at least enqueue it).
  33. ret = clEnqueueNDRangeKernel(command_queue,
  34. kernelArray[toLaunch],
  35. 1,
  36. NULL,
  37. &gwsize,
  38. &lwsize,
  39. 0,
  40. NULL,
  41. NULL);
  42. if (ret != CL_SUCCESS)
  43. {
  44. printf("\nError attempting to launch %s. Error in clCreateProgramWithSource with error code %i\n\n", toLaunch.c_str(), ret);
  45. exit(1);
  46. }
  47. }
  48. void OpenCL::gwSize(size_t theSize)
  49. {
  50. this->gwsize = theSize;
  51. }
  52. cl_context OpenCL::ctxt()
  53. {
  54. return this->context;
  55. }
  56. cl_kernel OpenCL::kernel(string kernelName)
  57. {
  58. return this->kernelArray[kernelName];
  59. }
  60. void OpenCL::createKernel(string kernelName)
  61. {
  62. cl_kernel kernel = clCreateKernel(this->program, kernelName.c_str(), NULL);
  63. kernelArray[kernelName] = kernel;
  64. // Get the kernel work group size.
  65. clGetKernelWorkGroupInfo(kernelArray[kernelName], device_id[0], CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &lwsize, NULL);
  66. if (lwsize == 0)
  67. {
  68. cout << "Error: clGetKernelWorkGroupInfo() returned a max work group size of zero!" << endl;
  69. exit(1);
  70. }
  71. // Local work size must divide evenly into global work size.
  72. size_t howManyThreads = lwsize;
  73. if (lwsize > gwsize)
  74. {
  75. lwsize = gwsize;
  76. printf("Using %zu for local work size. \n", lwsize);
  77. }
  78. else
  79. {
  80. while (gwsize % howManyThreads != 0)
  81. {
  82. howManyThreads--;
  83. }
  84. if (VERBOSE)
  85. printf("Max local threads is %zu. Using %zu for local work size. \n", lwsize, howManyThreads);
  86. this->lwsize = howManyThreads;
  87. }
  88. }
  89. void OpenCL::buildKernel()
  90. {
  91. /* Load the source code for all of the kernels into the array source_str */
  92. FILE* theFile;
  93. char* source_str;
  94. size_t source_size;
  95. theFile = fopen("kernels.cl", "r");
  96. if (!theFile)
  97. {
  98. fprintf(stderr, "Failed to load kernel file.\n");
  99. exit(1);
  100. }
  101. // Obtain length of source file.
  102. fseek(theFile, 0, SEEK_END);
  103. source_size = ftell(theFile);
  104. rewind(theFile);
  105. // Read in the file.
  106. source_str = (char*) malloc(sizeof(char) * (source_size + 1));
  107. fread(source_str, 1, source_size, theFile);
  108. fclose(theFile);
  109. source_str[source_size] = '\0';
  110. // Create a program from the kernel source.
  111. program = clCreateProgramWithSource(context,
  112. 1,
  113. (const char **) &source_str,
  114. NULL, // Number of chars in kernel src. NULL means src is null-terminated.
  115. &ret); // Return status message in the ret variable.
  116. if (ret != CL_SUCCESS)
  117. {
  118. printf("\nError at clCreateProgramWithSource! Error code %i\n\n", ret);
  119. exit(1);
  120. }
  121. // Memory cleanup for the variable used to hold the kernel source.
  122. free(source_str);
  123. // Build (compile) the program.
  124. ret = clBuildProgram(program, NULL, NULL, NULL, NULL, NULL);
  125. if (ret != CL_SUCCESS)
  126. {
  127. printf("\nError at clBuildProgram! Error code %i\n\n", ret);
  128. cout << "\n*************************************************" << endl;
  129. cout << "*** OUTPUT FROM COMPILING THE KERNEL FILE ***" << endl;
  130. cout << "*************************************************" << endl;
  131. // Shows the log
  132. char* build_log;
  133. size_t log_size;
  134. // First call to know the proper size
  135. clGetProgramBuildInfo(program, device_id[0], CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size);
  136. build_log = new char[log_size + 1];
  137. // Second call to get the log
  138. clGetProgramBuildInfo(program, device_id[0], CL_PROGRAM_BUILD_LOG, log_size, build_log, NULL);
  139. build_log[log_size] = '\0';
  140. cout << build_log << endl;
  141. delete[] build_log;
  142. cout << "\n*************************************************" << endl;
  143. cout << "*** END OUTPUT FROM COMPILING THE KERNEL FILE ***" << endl;
  144. cout << "*************************************************\n\n" << endl;
  145. exit(1);
  146. }
  147. /* Show error info from building the program. */
  148. if (VERBOSE)
  149. {
  150. cout << "\n*************************************************" << endl;
  151. cout << "*** OUTPUT FROM COMPILING THE KERNEL FILE ***" << endl;
  152. cout << "*************************************************" << endl;
  153. // Shows the log
  154. char* build_log;
  155. size_t log_size;
  156. // First call to know the proper size
  157. clGetProgramBuildInfo(program, device_id[0], CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size);
  158. build_log = new char[log_size + 1];
  159. // Second call to get the log
  160. clGetProgramBuildInfo(program, device_id[0], CL_PROGRAM_BUILD_LOG, log_size, build_log, NULL);
  161. build_log[log_size] = '\0';
  162. cout << build_log << endl;
  163. delete[] build_log;
  164. cout << "\n*************************************************" << endl;
  165. cout << "*** END OUTPUT FROM COMPILING THE KERNEL FILE ***" << endl;
  166. cout << "*************************************************\n\n" << endl;
  167. }
  168. }
  169. void OpenCL::getDevices(cl_device_type deviceType)
  170. {
  171. cl_uint platforms_n = 0;
  172. cl_uint devices_n = 0;
  173. /* The following code queries the number of platforms and devices, and
  174. * lists the information about both.
  175. */
  176. clGetPlatformIDs(100, platform_id, &platforms_n);
  177. if (VERBOSE)
  178. {
  179. printf("\n=== %d OpenCL platform(s) found: ===\n", platforms_n);
  180. for (int i = 0; i < platforms_n; i++)
  181. {
  182. char buffer[10240];
  183. printf(" -- %d --\n", i);
  184. clGetPlatformInfo(platform_id[i], CL_PLATFORM_PROFILE, 10240, buffer,
  185. NULL);
  186. printf(" PROFILE = %s\n", buffer);
  187. clGetPlatformInfo(platform_id[i], CL_PLATFORM_VERSION, 10240, buffer,
  188. NULL);
  189. printf(" VERSION = %s\n", buffer);
  190. clGetPlatformInfo(platform_id[i], CL_PLATFORM_NAME, 10240, buffer, NULL);
  191. printf(" NAME = %s\n", buffer);
  192. clGetPlatformInfo(platform_id[i], CL_PLATFORM_VENDOR, 10240, buffer, NULL);
  193. printf(" VENDOR = %s\n", buffer);
  194. clGetPlatformInfo(platform_id[i], CL_PLATFORM_EXTENSIONS, 10240, buffer,
  195. NULL);
  196. printf(" EXTENSIONS = %s\n", buffer);
  197. }
  198. }
  199. clGetDeviceIDs(platform_id[1], deviceType, 100, device_id, &devices_n);
  200. if (VERBOSE)
  201. {
  202. printf("Using the default platform (platform 0)...\n\n");
  203. printf("=== %d OpenCL device(s) found on platform:\n", devices_n);
  204. for (int i = 0; i < devices_n; i++)
  205. {
  206. char buffer[10240];
  207. cl_uint buf_uint;
  208. cl_ulong buf_ulong;
  209. printf(" -- %d --\n", i);
  210. clGetDeviceInfo(device_id[i], CL_DEVICE_NAME, sizeof(buffer), buffer,
  211. NULL);
  212. printf(" DEVICE_NAME = %s\n", buffer);
  213. clGetDeviceInfo(device_id[i], CL_DEVICE_VENDOR, sizeof(buffer), buffer,
  214. NULL);
  215. printf(" DEVICE_VENDOR = %s\n", buffer);
  216. clGetDeviceInfo(device_id[i], CL_DEVICE_VERSION, sizeof(buffer), buffer,
  217. NULL);
  218. printf(" DEVICE_VERSION = %s\n", buffer);
  219. clGetDeviceInfo(device_id[i], CL_DRIVER_VERSION, sizeof(buffer), buffer,
  220. NULL);
  221. printf(" DRIVER_VERSION = %s\n", buffer);
  222. clGetDeviceInfo(device_id[i], CL_DEVICE_MAX_COMPUTE_UNITS,
  223. sizeof(buf_uint), &buf_uint, NULL);
  224. printf(" DEVICE_MAX_COMPUTE_UNITS = %u\n", (unsigned int) buf_uint);
  225. clGetDeviceInfo(device_id[i], CL_DEVICE_MAX_CLOCK_FREQUENCY,
  226. sizeof(buf_uint), &buf_uint, NULL);
  227. printf(" DEVICE_MAX_CLOCK_FREQUENCY = %u\n", (unsigned int) buf_uint);
  228. clGetDeviceInfo(device_id[i], CL_DEVICE_GLOBAL_MEM_SIZE,
  229. sizeof(buf_ulong), &buf_ulong, NULL);
  230. printf(" DEVICE_GLOBAL_MEM_SIZE = %llu\n",
  231. (unsigned long long) buf_ulong);
  232. clGetDeviceInfo(device_id[i], CL_DEVICE_LOCAL_MEM_SIZE,
  233. sizeof(buf_ulong), &buf_ulong, NULL);
  234. printf(" CL_DEVICE_LOCAL_MEM_SIZE = %llu\n",
  235. (unsigned long long) buf_ulong);
  236. }
  237. printf("\n");
  238. }
  239. // Create an OpenCL context.
  240. context = clCreateContext(NULL, devices_n, device_id, NULL, NULL, &ret);
  241. if (ret != CL_SUCCESS)
  242. {
  243. printf("\nError at clCreateContext! Error code %i\n\n", ret);
  244. exit(1);
  245. }
  246. // Create a command queue.
  247. command_queue = clCreateCommandQueue(context, device_id[0], 0, &ret);
  248. if (ret != CL_SUCCESS)
  249. {
  250. printf("\nError at clCreateCommandQueue! Error code %i\n\n", ret);
  251. exit(1);
  252. }
  253. }
  254. void OpenCL::init(int isGPU)
  255. {
  256. if (isGPU)
  257. getDevices(CL_DEVICE_TYPE_GPU);
  258. else
  259. getDevices(CL_DEVICE_TYPE_CPU);
  260. buildKernel();
  261. }