OpenCL.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  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, int device_idx)
  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[device_idx], 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(int device_idx)
  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[device_idx], 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[device_idx], 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[device_idx], 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[device_idx], 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(int platform_idx, int device_idx, cl_device_type deviceType)
  170. {
  171. cl_uint platforms_n = 0;
  172. cl_uint devices_n = 0;
  173. // create OpenCL context
  174. clGetPlatformIDs(0, NULL, &platforms_n);
  175. cl_platform_id *platforms_ids;
  176. platforms_ids = (cl_platform_id*) malloc(sizeof(cl_platform_id) * platforms_n);
  177. /* The following code queries the number of platforms and devices, and
  178. * lists the information about both.
  179. */
  180. clGetPlatformIDs(platforms_n, platforms_ids, NULL);
  181. if (VERBOSE)
  182. {
  183. printf("\n=== %d OpenCL platform(s) found: ===\n", platforms_n);
  184. for (int i = 0; i < platforms_n; i++)
  185. {
  186. char buffer[10240];
  187. printf(" -- %d --\n", i);
  188. clGetPlatformInfo(platforms_ids[i], CL_PLATFORM_PROFILE, 10240, buffer,
  189. NULL);
  190. printf(" PROFILE = %s\n", buffer);
  191. clGetPlatformInfo(platforms_ids[i], CL_PLATFORM_VERSION, 10240, buffer,
  192. NULL);
  193. printf(" VERSION = %s\n", buffer);
  194. clGetPlatformInfo(platforms_ids[i], CL_PLATFORM_NAME, 10240, buffer, NULL);
  195. printf(" NAME = %s\n", buffer);
  196. clGetPlatformInfo(platforms_ids[i], CL_PLATFORM_VENDOR, 10240, buffer, NULL);
  197. printf(" VENDOR = %s\n", buffer);
  198. clGetPlatformInfo(platforms_ids[i], CL_PLATFORM_EXTENSIONS, 10240, buffer,
  199. NULL);
  200. printf(" EXTENSIONS = %s\n", buffer);
  201. }
  202. }
  203. printf("DEBUG %d \n", platform_idx);
  204. clGetDeviceIDs(platforms_ids[platform_idx], deviceType, 100, device_id, &devices_n);
  205. if (VERBOSE)
  206. {
  207. printf("=== %d OpenCL device(s) found on platform:\n", devices_n);
  208. for (int i = 0; i < devices_n; i++)
  209. {
  210. char buffer[10240];
  211. cl_uint buf_uint;
  212. cl_ulong buf_ulong;
  213. printf(" -- %d --\n", i);
  214. clGetDeviceInfo(device_id[i], CL_DEVICE_NAME, sizeof(buffer), buffer,
  215. NULL);
  216. printf(" DEVICE_NAME = %s\n", buffer);
  217. clGetDeviceInfo(device_id[i], CL_DEVICE_VENDOR, sizeof(buffer), buffer,
  218. NULL);
  219. printf(" DEVICE_VENDOR = %s\n", buffer);
  220. clGetDeviceInfo(device_id[i], CL_DEVICE_VERSION, sizeof(buffer), buffer,
  221. NULL);
  222. printf(" DEVICE_VERSION = %s\n", buffer);
  223. clGetDeviceInfo(device_id[i], CL_DRIVER_VERSION, sizeof(buffer), buffer,
  224. NULL);
  225. printf(" DRIVER_VERSION = %s\n", buffer);
  226. clGetDeviceInfo(device_id[i], CL_DEVICE_MAX_COMPUTE_UNITS,
  227. sizeof(buf_uint), &buf_uint, NULL);
  228. printf(" DEVICE_MAX_COMPUTE_UNITS = %u\n", (unsigned int) buf_uint);
  229. clGetDeviceInfo(device_id[i], CL_DEVICE_MAX_CLOCK_FREQUENCY,
  230. sizeof(buf_uint), &buf_uint, NULL);
  231. printf(" DEVICE_MAX_CLOCK_FREQUENCY = %u\n", (unsigned int) buf_uint);
  232. clGetDeviceInfo(device_id[i], CL_DEVICE_GLOBAL_MEM_SIZE,
  233. sizeof(buf_ulong), &buf_ulong, NULL);
  234. printf(" DEVICE_GLOBAL_MEM_SIZE = %llu\n",
  235. (unsigned long long) buf_ulong);
  236. clGetDeviceInfo(device_id[i], CL_DEVICE_LOCAL_MEM_SIZE,
  237. sizeof(buf_ulong), &buf_ulong, NULL);
  238. printf(" CL_DEVICE_LOCAL_MEM_SIZE = %llu\n",
  239. (unsigned long long) buf_ulong);
  240. }
  241. printf("\n");
  242. }
  243. cl_context_properties ctxprop[] = {CL_CONTEXT_PLATFORM, (cl_context_properties) platforms_ids[platform_idx], 0};
  244. context = clCreateContextFromType(ctxprop, deviceType, NULL, NULL, NULL);
  245. if (!context) {
  246. printf("ERROR: clCreateContextFromType failed\n");
  247. exit(1);
  248. }
  249. // Create a command queue.
  250. command_queue = clCreateCommandQueue(context, device_id[device_idx], 0, &ret);
  251. if (ret != CL_SUCCESS)
  252. {
  253. printf("\nError at clCreateCommandQueue! Error code %i\n\n", ret);
  254. exit(1);
  255. }
  256. }
  257. void OpenCL::init(int platform_idx, int device_idx, int use_gpu)
  258. {
  259. if (use_gpu)
  260. getDevices(platform_idx, device_idx, CL_DEVICE_TYPE_GPU);
  261. else
  262. getDevices(platform_idx, device_idx, CL_DEVICE_TYPE_CPU);
  263. buildKernel(device_idx);
  264. }