ocl.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /*
  2. * This file is part of oclkit.
  3. *
  4. * oclkit is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * oclkit is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <assert.h>
  21. #include <getopt.h>
  22. #include "ocl.h"
  23. struct OclPlatform {
  24. cl_platform_id platform;
  25. cl_context context;
  26. cl_uint num_devices;
  27. cl_device_id *devices;
  28. cl_command_queue *cmd_queues;
  29. int own_queues;
  30. };
  31. static const char* opencl_error_msgs[] = {
  32. "CL_SUCCESS",
  33. "CL_DEVICE_NOT_FOUND",
  34. "CL_DEVICE_NOT_AVAILABLE",
  35. "CL_COMPILER_NOT_AVAILABLE",
  36. "CL_MEM_OBJECT_ALLOCATION_FAILURE",
  37. "CL_OUT_OF_RESOURCES",
  38. "CL_OUT_OF_HOST_MEMORY",
  39. "CL_PROFILING_INFO_NOT_AVAILABLE",
  40. "CL_MEM_COPY_OVERLAP",
  41. "CL_IMAGE_FORMAT_MISMATCH",
  42. "CL_IMAGE_FORMAT_NOT_SUPPORTED",
  43. "CL_BUILD_PROGRAM_FAILURE",
  44. "CL_MAP_FAILURE",
  45. "CL_MISALIGNED_SUB_BUFFER_OFFSET",
  46. "CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST",
  47. /* next IDs start at 30! */
  48. "CL_INVALID_VALUE",
  49. "CL_INVALID_DEVICE_TYPE",
  50. "CL_INVALID_PLATFORM",
  51. "CL_INVALID_DEVICE",
  52. "CL_INVALID_CONTEXT",
  53. "CL_INVALID_QUEUE_PROPERTIES",
  54. "CL_INVALID_COMMAND_QUEUE",
  55. "CL_INVALID_HOST_PTR",
  56. "CL_INVALID_MEM_OBJECT",
  57. "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR",
  58. "CL_INVALID_IMAGE_SIZE",
  59. "CL_INVALID_SAMPLER",
  60. "CL_INVALID_BINARY",
  61. "CL_INVALID_BUILD_OPTIONS",
  62. "CL_INVALID_PROGRAM",
  63. "CL_INVALID_PROGRAM_EXECUTABLE",
  64. "CL_INVALID_KERNEL_NAME",
  65. "CL_INVALID_KERNEL_DEFINITION",
  66. "CL_INVALID_KERNEL",
  67. "CL_INVALID_ARG_INDEX",
  68. "CL_INVALID_ARG_VALUE",
  69. "CL_INVALID_ARG_SIZE",
  70. "CL_INVALID_KERNEL_ARGS",
  71. "CL_INVALID_WORK_DIMENSION",
  72. "CL_INVALID_WORK_GROUP_SIZE",
  73. "CL_INVALID_WORK_ITEM_SIZE",
  74. "CL_INVALID_GLOBAL_OFFSET",
  75. "CL_INVALID_EVENT_WAIT_LIST",
  76. "CL_INVALID_EVENT",
  77. "CL_INVALID_OPERATION",
  78. "CL_INVALID_GL_OBJECT",
  79. "CL_INVALID_BUFFER_SIZE",
  80. "CL_INVALID_MIP_LEVEL",
  81. "CL_INVALID_GLOBAL_WORK_SIZE"
  82. };
  83. const char*
  84. ocl_strerr (int error)
  85. {
  86. int index = 0;
  87. if (error >= -14)
  88. index = -error;
  89. else if (error <= -30 && error >= -64)
  90. index = -error-15;
  91. return opencl_error_msgs[index];
  92. }
  93. static void
  94. transfer_error (cl_int src, cl_int *dst)
  95. {
  96. if (dst != NULL)
  97. *dst = src;
  98. }
  99. char *
  100. ocl_read_program (const char *filename)
  101. {
  102. FILE *fp;
  103. char *buffer;
  104. size_t length;
  105. size_t buffer_length;
  106. if ((fp = fopen(filename, "r")) == NULL)
  107. return NULL;
  108. fseek (fp, 0, SEEK_END);
  109. length = ftell (fp);
  110. rewind (fp);
  111. buffer = malloc (length + 1);
  112. buffer[length] = '\0';
  113. if (buffer == NULL) {
  114. fclose(fp);
  115. return NULL;
  116. }
  117. buffer_length = fread (buffer, 1, length, fp);
  118. fclose(fp);
  119. if (buffer_length != length) {
  120. free (buffer);
  121. buffer = NULL;
  122. }
  123. return buffer;
  124. }
  125. OclPlatform *
  126. ocl_new (unsigned platform,
  127. cl_device_type type)
  128. {
  129. OclPlatform *ocl;
  130. cl_int errcode;
  131. cl_uint num_platforms;
  132. cl_platform_id *platforms;
  133. ocl = malloc (sizeof(OclPlatform));
  134. OCL_CHECK_ERROR (clGetPlatformIDs (0, NULL, &num_platforms));
  135. platforms = malloc (sizeof (cl_platform_id) * num_platforms);
  136. if (platform >= num_platforms) {
  137. fprintf (stderr, "invalid platform %i out of %i platforms\n", platform, num_platforms);
  138. goto ocl_new_cleanup;
  139. }
  140. OCL_CHECK_ERROR (clGetPlatformIDs (num_platforms, platforms, NULL));
  141. ocl->platform = platforms[platform];
  142. OCL_CHECK_ERROR (clGetDeviceIDs (ocl->platform, type, 0, NULL, &ocl->num_devices));
  143. ocl->devices = malloc (ocl->num_devices * sizeof(cl_device_id));
  144. OCL_CHECK_ERROR (clGetDeviceIDs (ocl->platform, type, ocl->num_devices, ocl->devices, NULL));
  145. ocl->context = clCreateContext (NULL, ocl->num_devices, ocl->devices, NULL, NULL, &errcode);
  146. OCL_CHECK_ERROR (errcode);
  147. ocl->own_queues = 0;
  148. free (platforms);
  149. return ocl;
  150. ocl_new_cleanup:
  151. free (ocl);
  152. free (platforms);
  153. return NULL;
  154. }
  155. OclPlatform *
  156. ocl_new_with_queues (unsigned platform,
  157. cl_device_type type,
  158. cl_command_queue_properties queue_properties)
  159. {
  160. OclPlatform *ocl;
  161. cl_int errcode;
  162. ocl = ocl_new (platform, type);
  163. if (ocl == NULL)
  164. return NULL;
  165. ocl->own_queues = 1;
  166. ocl->cmd_queues = malloc (ocl->num_devices * sizeof(cl_command_queue));
  167. for (cl_uint i = 0; i < ocl->num_devices; i++) {
  168. ocl->cmd_queues[i] = clCreateCommandQueue (ocl->context, ocl->devices[i],
  169. queue_properties, &errcode);
  170. OCL_CHECK_ERROR (errcode);
  171. }
  172. return ocl;
  173. }
  174. void
  175. ocl_print_usage (void)
  176. {
  177. printf ("oclkit options\n"
  178. " --ocl-platform\tIndex of platform, starting with 0, to use\n"
  179. " --ocl-type\tDevice type: gpu, cpu or accelerator\n");
  180. }
  181. int
  182. ocl_read_args (int argc,
  183. const char **argv,
  184. unsigned int *platform,
  185. cl_device_type *type)
  186. {
  187. int c;
  188. static struct option options[] = {
  189. { "ocl-platform", required_argument, NULL, 'p' },
  190. { "ocl-type", required_argument, NULL, 't' },
  191. { "help", no_argument, NULL, 'h' },
  192. { NULL, 0, NULL, 0 }
  193. };
  194. while (1) {
  195. int index = 0;
  196. c = getopt_long (argc, (char **) argv, "p:d:t:h", options, &index);
  197. if (c == -1)
  198. break;
  199. switch (c) {
  200. case 'h':
  201. ocl_print_usage ();
  202. return -1;
  203. case 'p':
  204. *platform = atoi (optarg);
  205. break;
  206. case 't':
  207. {
  208. int n = strlen (optarg);
  209. n = n > 10 ? 10 : n; /* for accelerator */
  210. if (!strncmp (optarg, "gpu", n))
  211. *type = CL_DEVICE_TYPE_GPU;
  212. else if (!strncmp (optarg, "cpu", n))
  213. *type = CL_DEVICE_TYPE_CPU;
  214. else if (!strncmp (optarg, "accelerator", n))
  215. *type = CL_DEVICE_TYPE_ACCELERATOR;
  216. }
  217. break;
  218. default:
  219. abort ();
  220. }
  221. }
  222. return 0;
  223. }
  224. OclPlatform *
  225. ocl_new_from_args (int argc,
  226. const char **argv,
  227. cl_command_queue_properties queue_properties)
  228. {
  229. unsigned platform = 0;
  230. cl_device_type type = CL_DEVICE_TYPE_GPU;
  231. if (ocl_read_args (argc, argv, &platform, &type))
  232. return NULL;
  233. return ocl_new_with_queues (platform, type, queue_properties);
  234. }
  235. void
  236. ocl_free (OclPlatform *ocl)
  237. {
  238. if (ocl == NULL)
  239. return;
  240. if (ocl->own_queues) {
  241. for (cl_uint i = 0; i < ocl->num_devices; i++)
  242. OCL_CHECK_ERROR (clReleaseCommandQueue (ocl->cmd_queues[i]));
  243. free (ocl->cmd_queues);
  244. }
  245. OCL_CHECK_ERROR (clReleaseContext (ocl->context));
  246. free (ocl->devices);
  247. free (ocl);
  248. }
  249. char *
  250. ocl_get_platform_info (OclPlatform *ocl,
  251. cl_platform_info param)
  252. {
  253. size_t size;
  254. char *result;
  255. OCL_CHECK_ERROR (clGetPlatformInfo (ocl->platform, param, 0, NULL, &size));
  256. result = malloc (size);
  257. OCL_CHECK_ERROR (clGetPlatformInfo (ocl->platform, param, size, result, NULL));
  258. return result;
  259. }
  260. cl_program
  261. ocl_create_program_from_source (OclPlatform *ocl,
  262. const char *source,
  263. const char *options,
  264. cl_int *errcode)
  265. {
  266. cl_int tmp_err;
  267. cl_program program;
  268. program = clCreateProgramWithSource (ocl->context, 1, (const char **) &source, NULL, &tmp_err);
  269. if (tmp_err != CL_SUCCESS) {
  270. transfer_error (tmp_err, errcode);
  271. return NULL;
  272. }
  273. tmp_err = clBuildProgram (program, ocl->num_devices, ocl->devices, options, NULL, NULL);
  274. if (tmp_err != CL_SUCCESS) {
  275. size_t log_size;
  276. char* log;
  277. transfer_error (tmp_err, errcode);
  278. OCL_CHECK_ERROR (clGetProgramBuildInfo (program, ocl->devices[0], CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size));
  279. log = malloc (log_size * sizeof(char));
  280. OCL_CHECK_ERROR (clGetProgramBuildInfo (program, ocl->devices[0], CL_PROGRAM_BUILD_LOG, log_size, log, NULL));
  281. fprintf (stderr, "\n** Error building program. Build log:\n%s\n", log);
  282. free (log);
  283. return NULL;
  284. }
  285. *errcode = CL_SUCCESS;
  286. return program;
  287. }
  288. cl_program
  289. ocl_create_program_from_file (OclPlatform *ocl,
  290. const char *filename,
  291. const char *options,
  292. cl_int *errcode)
  293. {
  294. char *source;
  295. cl_program program;
  296. source = ocl_read_program (filename);
  297. if (source == NULL)
  298. return NULL;
  299. program = ocl_create_program_from_source (ocl, source, options, errcode);
  300. free(source);
  301. return program;
  302. }
  303. cl_context
  304. ocl_get_context (OclPlatform *ocl)
  305. {
  306. assert (ocl != NULL);
  307. return ocl->context;
  308. }
  309. int
  310. ocl_get_num_devices (OclPlatform *ocl)
  311. {
  312. assert (ocl != NULL);
  313. return ocl->num_devices;
  314. }
  315. cl_device_id *
  316. ocl_get_devices (OclPlatform *ocl)
  317. {
  318. assert (ocl != NULL);
  319. return ocl->devices;
  320. }
  321. cl_command_queue *
  322. ocl_get_cmd_queues (OclPlatform *ocl)
  323. {
  324. assert (ocl != NULL);
  325. return ocl->cmd_queues;
  326. }
  327. void
  328. ocl_get_event_times (cl_event event,
  329. cl_ulong *start,
  330. cl_ulong *end,
  331. cl_ulong *queued,
  332. cl_ulong *submitted)
  333. {
  334. if (queued != NULL)
  335. OCL_CHECK_ERROR (clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_QUEUED, sizeof (cl_ulong), queued, NULL));
  336. if (submitted != NULL)
  337. OCL_CHECK_ERROR (clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_SUBMIT, sizeof (cl_ulong), submitted, NULL));
  338. if (start != NULL)
  339. OCL_CHECK_ERROR (clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_START, sizeof (cl_ulong), start, NULL));
  340. if (end != NULL)
  341. OCL_CHECK_ERROR (clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_END, sizeof (cl_ulong), end, NULL));
  342. }