driver_opencl.c 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042
  1. /* StarPU --- Runtime system for heterogeneous multicore architectures.
  2. *
  3. * Copyright (C) 2010-2015 Université de Bordeaux
  4. * Copyright (C) 2010 Mehdi Juhoor <mjuhoor@gmail.com>
  5. * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015 CNRS
  6. * Copyright (C) 2011 Télécom-SudParis
  7. *
  8. * StarPU is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU Lesser General Public License as published by
  10. * the Free Software Foundation; either version 2.1 of the License, or (at
  11. * your option) any later version.
  12. *
  13. * StarPU is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  16. *
  17. * See the GNU Lesser General Public License in COPYING.LGPL for more details.
  18. */
  19. #include <math.h>
  20. #include <starpu.h>
  21. #include <starpu_profiling.h>
  22. #include <common/config.h>
  23. #include <common/utils.h>
  24. #include <core/debug.h>
  25. #include <starpu_opencl.h>
  26. #include <drivers/driver_common/driver_common.h>
  27. #include "driver_opencl.h"
  28. #include "driver_opencl_utils.h"
  29. #include <common/utils.h>
  30. #include <datawizard/memory_manager.h>
  31. #include <datawizard/memory_nodes.h>
  32. #include <datawizard/malloc.h>
  33. #ifdef STARPU_SIMGRID
  34. #include <core/simgrid.h>
  35. #endif
  36. static int nb_devices = -1;
  37. static int init_done = 0;
  38. static starpu_pthread_mutex_t big_lock = STARPU_PTHREAD_MUTEX_INITIALIZER;
  39. static size_t global_mem[STARPU_MAXOPENCLDEVS];
  40. #ifdef STARPU_USE_OPENCL
  41. static cl_context contexts[STARPU_MAXOPENCLDEVS];
  42. static cl_device_id devices[STARPU_MAXOPENCLDEVS];
  43. static cl_command_queue queues[STARPU_MAXOPENCLDEVS];
  44. static cl_command_queue in_transfer_queues[STARPU_MAXOPENCLDEVS];
  45. static cl_command_queue out_transfer_queues[STARPU_MAXOPENCLDEVS];
  46. static cl_command_queue peer_transfer_queues[STARPU_MAXOPENCLDEVS];
  47. #ifndef STARPU_SIMGRID
  48. static cl_command_queue alloc_queues[STARPU_MAXOPENCLDEVS];
  49. static cl_event task_events[STARPU_MAXOPENCLDEVS][STARPU_MAX_PIPELINE];
  50. #endif /* !STARPU_SIMGRID */
  51. #endif
  52. #ifdef STARPU_SIMGRID
  53. static unsigned task_finished[STARPU_MAXOPENCLDEVS][STARPU_MAX_PIPELINE];
  54. static starpu_pthread_mutex_t task_mutex[STARPU_MAXOPENCLDEVS][STARPU_MAX_PIPELINE];
  55. static starpu_pthread_cond_t task_cond[STARPU_MAXOPENCLDEVS][STARPU_MAX_PIPELINE];
  56. #endif /* STARPU_SIMGRID */
  57. void
  58. _starpu_opencl_discover_devices(struct _starpu_machine_config *config)
  59. {
  60. /* Discover the number of OpenCL devices. Fill the result in CONFIG. */
  61. /* As OpenCL must have been initialized before calling this function,
  62. * `nb_device' is ensured to be correctly set. */
  63. STARPU_ASSERT(init_done == 1);
  64. config->topology.nhwopenclgpus = nb_devices;
  65. }
  66. static void _starpu_opencl_limit_gpu_mem_if_needed(unsigned devid)
  67. {
  68. starpu_ssize_t limit;
  69. size_t STARPU_ATTRIBUTE_UNUSED totalGlobalMem = 0;
  70. size_t STARPU_ATTRIBUTE_UNUSED to_waste = 0;
  71. char name[30];
  72. #ifdef STARPU_SIMGRID
  73. totalGlobalMem = _starpu_simgrid_get_memsize("OpenCL", devid);
  74. #elif defined(STARPU_USE_OPENCL)
  75. /* Request the size of the current device's memory */
  76. cl_int err;
  77. cl_ulong size;
  78. err = clGetDeviceInfo(devices[devid], CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(size), &size, NULL);
  79. if (STARPU_UNLIKELY(err != CL_SUCCESS))
  80. STARPU_OPENCL_REPORT_ERROR(err);
  81. totalGlobalMem = size;
  82. #endif
  83. limit = starpu_get_env_number("STARPU_LIMIT_OPENCL_MEM");
  84. if (limit == -1)
  85. {
  86. sprintf(name, "STARPU_LIMIT_OPENCL_%u_MEM", devid);
  87. limit = starpu_get_env_number(name);
  88. }
  89. #if defined(STARPU_USE_OPENCL) || defined(STARPU_SIMGRID)
  90. if (limit == -1)
  91. {
  92. /* Use 90% of the available memory by default. */
  93. limit = totalGlobalMem / (1024*1024) * 0.9;
  94. }
  95. #endif
  96. global_mem[devid] = limit * 1024*1024;
  97. #ifdef STARPU_USE_OPENCL
  98. /* How much memory to waste ? */
  99. to_waste = totalGlobalMem - global_mem[devid];
  100. #endif
  101. _STARPU_DEBUG("OpenCL device %d: Wasting %ld MB / Limit %ld MB / Total %ld MB / Remains %ld MB\n",
  102. devid, (long)to_waste/(1024*1024), (long) limit, (long)totalGlobalMem/(1024*1024),
  103. (long)(totalGlobalMem - to_waste)/(1024*1024));
  104. }
  105. #ifdef STARPU_USE_OPENCL
  106. void starpu_opencl_get_context(int devid, cl_context *context)
  107. {
  108. *context = contexts[devid];
  109. }
  110. void starpu_opencl_get_device(int devid, cl_device_id *device)
  111. {
  112. *device = devices[devid];
  113. }
  114. void starpu_opencl_get_queue(int devid, cl_command_queue *queue)
  115. {
  116. *queue = queues[devid];
  117. }
  118. void starpu_opencl_get_current_queue(cl_command_queue *queue)
  119. {
  120. struct _starpu_worker *worker = _starpu_get_local_worker_key();
  121. STARPU_ASSERT(queue);
  122. *queue = queues[worker->devid];
  123. }
  124. void starpu_opencl_get_current_context(cl_context *context)
  125. {
  126. struct _starpu_worker *worker = _starpu_get_local_worker_key();
  127. STARPU_ASSERT(context);
  128. *context = contexts[worker->devid];
  129. }
  130. #endif /* STARPU_USE_OPENCL */
  131. int _starpu_opencl_init_context(int devid)
  132. {
  133. #ifdef STARPU_SIMGRID
  134. int j;
  135. for (j = 0; j < STARPU_MAX_PIPELINE; j++)
  136. {
  137. task_finished[devid][j] = 0;
  138. STARPU_PTHREAD_MUTEX_INIT(&task_mutex[devid][j], NULL);
  139. STARPU_PTHREAD_COND_INIT(&task_cond[devid][j], NULL);
  140. }
  141. #else /* !STARPU_SIMGRID */
  142. cl_int err;
  143. cl_uint uint;
  144. STARPU_PTHREAD_MUTEX_LOCK(&big_lock);
  145. _STARPU_DEBUG("Initialising context for dev %d\n", devid);
  146. // Create a compute context
  147. err = 0;
  148. contexts[devid] = clCreateContext(NULL, 1, &devices[devid], NULL, NULL, &err);
  149. if (STARPU_UNLIKELY(err != CL_SUCCESS)) STARPU_OPENCL_REPORT_ERROR(err);
  150. err = clGetDeviceInfo(devices[devid], CL_DEVICE_MEM_BASE_ADDR_ALIGN, sizeof(uint), &uint, NULL);
  151. if (STARPU_UNLIKELY(err != CL_SUCCESS))
  152. STARPU_OPENCL_REPORT_ERROR(err);
  153. starpu_malloc_set_align(uint/8);
  154. // Create execution queue for the given device
  155. queues[devid] = clCreateCommandQueue(contexts[devid], devices[devid], 0, &err);
  156. if (STARPU_UNLIKELY(err != CL_SUCCESS)) STARPU_OPENCL_REPORT_ERROR(err);
  157. // Create transfer queue for the given device
  158. cl_command_queue_properties props;
  159. err = clGetDeviceInfo(devices[devid], CL_DEVICE_QUEUE_PROPERTIES, sizeof(props), &props, NULL);
  160. if (STARPU_UNLIKELY(err != CL_SUCCESS))
  161. STARPU_OPENCL_REPORT_ERROR(err);
  162. props &= ~CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE;
  163. in_transfer_queues[devid] = clCreateCommandQueue(contexts[devid], devices[devid], props, &err);
  164. if (STARPU_UNLIKELY(err != CL_SUCCESS)) STARPU_OPENCL_REPORT_ERROR(err);
  165. out_transfer_queues[devid] = clCreateCommandQueue(contexts[devid], devices[devid], props, &err);
  166. if (STARPU_UNLIKELY(err != CL_SUCCESS)) STARPU_OPENCL_REPORT_ERROR(err);
  167. peer_transfer_queues[devid] = clCreateCommandQueue(contexts[devid], devices[devid], props, &err);
  168. if (STARPU_UNLIKELY(err != CL_SUCCESS)) STARPU_OPENCL_REPORT_ERROR(err);
  169. alloc_queues[devid] = clCreateCommandQueue(contexts[devid], devices[devid], 0, &err);
  170. if (STARPU_UNLIKELY(err != CL_SUCCESS)) STARPU_OPENCL_REPORT_ERROR(err);
  171. STARPU_PTHREAD_MUTEX_UNLOCK(&big_lock);
  172. #endif /* !STARPU_SIMGRID */
  173. return 0;
  174. }
  175. int _starpu_opencl_deinit_context(int devid)
  176. {
  177. #ifdef STARPU_SIMGRID
  178. int j;
  179. for (j = 0; j < STARPU_MAX_PIPELINE; j++)
  180. {
  181. task_finished[devid][j] = 0;
  182. STARPU_PTHREAD_MUTEX_DESTROY(&task_mutex[devid][j]);
  183. STARPU_PTHREAD_COND_DESTROY(&task_cond[devid][j]);
  184. }
  185. #else /* !STARPU_SIMGRID */
  186. cl_int err;
  187. STARPU_PTHREAD_MUTEX_LOCK(&big_lock);
  188. _STARPU_DEBUG("De-initialising context for dev %d\n", devid);
  189. err = clReleaseContext(contexts[devid]);
  190. if (STARPU_UNLIKELY(err != CL_SUCCESS)) STARPU_OPENCL_REPORT_ERROR(err);
  191. err = clReleaseCommandQueue(queues[devid]);
  192. if (STARPU_UNLIKELY(err != CL_SUCCESS)) STARPU_OPENCL_REPORT_ERROR(err);
  193. err = clReleaseCommandQueue(in_transfer_queues[devid]);
  194. if (STARPU_UNLIKELY(err != CL_SUCCESS)) STARPU_OPENCL_REPORT_ERROR(err);
  195. err = clReleaseCommandQueue(out_transfer_queues[devid]);
  196. if (STARPU_UNLIKELY(err != CL_SUCCESS)) STARPU_OPENCL_REPORT_ERROR(err);
  197. err = clReleaseCommandQueue(peer_transfer_queues[devid]);
  198. if (STARPU_UNLIKELY(err != CL_SUCCESS)) STARPU_OPENCL_REPORT_ERROR(err);
  199. err = clReleaseCommandQueue(alloc_queues[devid]);
  200. if (STARPU_UNLIKELY(err != CL_SUCCESS)) STARPU_OPENCL_REPORT_ERROR(err);
  201. contexts[devid] = NULL;
  202. STARPU_PTHREAD_MUTEX_UNLOCK(&big_lock);
  203. #endif
  204. return 0;
  205. }
  206. #ifdef STARPU_USE_OPENCL
  207. cl_int starpu_opencl_allocate_memory(int devid STARPU_ATTRIBUTE_UNUSED, cl_mem *mem STARPU_ATTRIBUTE_UNUSED, size_t size STARPU_ATTRIBUTE_UNUSED, cl_mem_flags flags STARPU_ATTRIBUTE_UNUSED)
  208. {
  209. #ifdef STARPU_SIMGRID
  210. STARPU_ABORT();
  211. #else
  212. cl_int err;
  213. cl_mem memory;
  214. memory = clCreateBuffer(contexts[devid], flags, size, NULL, &err);
  215. if (err == CL_OUT_OF_HOST_MEMORY) return err;
  216. if (err != CL_SUCCESS) STARPU_OPENCL_REPORT_ERROR(err);
  217. /*
  218. * OpenCL uses lazy memory allocation: we will only know if the
  219. * allocation failed when trying to copy data onto the device. But we
  220. * want to know this __now__, so we just perform a dummy copy.
  221. */
  222. char dummy = 0;
  223. cl_event ev;
  224. err = clEnqueueWriteBuffer(alloc_queues[devid], memory, CL_TRUE,
  225. 0, sizeof(dummy), &dummy,
  226. 0, NULL, &ev);
  227. if (err == CL_MEM_OBJECT_ALLOCATION_FAILURE)
  228. return err;
  229. if (err == CL_OUT_OF_RESOURCES)
  230. return err;
  231. if (err != CL_SUCCESS)
  232. STARPU_OPENCL_REPORT_ERROR(err);
  233. clWaitForEvents(1, &ev);
  234. clReleaseEvent(ev);
  235. *mem = memory;
  236. return CL_SUCCESS;
  237. #endif
  238. }
  239. cl_int starpu_opencl_copy_ram_to_opencl(void *ptr, unsigned src_node STARPU_ATTRIBUTE_UNUSED, cl_mem buffer, unsigned dst_node STARPU_ATTRIBUTE_UNUSED, size_t size, size_t offset, cl_event *event, int *ret)
  240. {
  241. cl_int err;
  242. struct _starpu_worker *worker = _starpu_get_local_worker_key();
  243. if (event)
  244. _STARPU_TRACE_START_DRIVER_COPY_ASYNC(src_node, dst_node);
  245. cl_event ev;
  246. err = clEnqueueWriteBuffer(in_transfer_queues[worker->devid], buffer, CL_FALSE, offset, size, ptr, 0, NULL, &ev);
  247. if (event)
  248. _STARPU_TRACE_END_DRIVER_COPY_ASYNC(src_node, dst_node);
  249. if (STARPU_LIKELY(err == CL_SUCCESS))
  250. {
  251. if (event == NULL)
  252. {
  253. /* We want a synchronous copy, let's synchronise the queue */
  254. err = clWaitForEvents(1, &ev);
  255. if (STARPU_UNLIKELY(err))
  256. STARPU_OPENCL_REPORT_ERROR(err);
  257. err = clReleaseEvent(ev);
  258. if (STARPU_UNLIKELY(err))
  259. STARPU_OPENCL_REPORT_ERROR(err);
  260. }
  261. else
  262. {
  263. *event = ev;
  264. }
  265. if (ret)
  266. {
  267. *ret = (event == NULL) ? 0 : -EAGAIN;
  268. }
  269. }
  270. return err;
  271. }
  272. cl_int starpu_opencl_copy_opencl_to_ram(cl_mem buffer, unsigned src_node STARPU_ATTRIBUTE_UNUSED, void *ptr, unsigned dst_node STARPU_ATTRIBUTE_UNUSED, size_t size, size_t offset, cl_event *event, int *ret)
  273. {
  274. cl_int err;
  275. struct _starpu_worker *worker = _starpu_get_local_worker_key();
  276. if (event)
  277. _STARPU_TRACE_START_DRIVER_COPY_ASYNC(src_node, dst_node);
  278. cl_event ev;
  279. err = clEnqueueReadBuffer(out_transfer_queues[worker->devid], buffer, CL_FALSE, offset, size, ptr, 0, NULL, &ev);
  280. if (event)
  281. _STARPU_TRACE_END_DRIVER_COPY_ASYNC(src_node, dst_node);
  282. if (STARPU_LIKELY(err == CL_SUCCESS))
  283. {
  284. if (event == NULL)
  285. {
  286. /* We want a synchronous copy, let's synchronise the queue */
  287. err = clWaitForEvents(1, &ev);
  288. if (STARPU_UNLIKELY(err))
  289. STARPU_OPENCL_REPORT_ERROR(err);
  290. err = clReleaseEvent(ev);
  291. if (STARPU_UNLIKELY(err))
  292. STARPU_OPENCL_REPORT_ERROR(err);
  293. }
  294. else
  295. {
  296. *event = ev;
  297. }
  298. if (ret)
  299. {
  300. *ret = (event == NULL) ? 0 : -EAGAIN;
  301. }
  302. }
  303. return err;
  304. }
  305. cl_int starpu_opencl_copy_opencl_to_opencl(cl_mem src, unsigned src_node STARPU_ATTRIBUTE_UNUSED, size_t src_offset, cl_mem dst, unsigned dst_node STARPU_ATTRIBUTE_UNUSED, size_t dst_offset, size_t size, cl_event *event, int *ret)
  306. {
  307. cl_int err;
  308. struct _starpu_worker *worker = _starpu_get_local_worker_key();
  309. if (event)
  310. _STARPU_TRACE_START_DRIVER_COPY_ASYNC(src_node, dst_node);
  311. cl_event ev;
  312. err = clEnqueueCopyBuffer(peer_transfer_queues[worker->devid], src, dst, src_offset, dst_offset, size, 0, NULL, &ev);
  313. if (event)
  314. _STARPU_TRACE_END_DRIVER_COPY_ASYNC(src_node, dst_node);
  315. if (STARPU_LIKELY(err == CL_SUCCESS))
  316. {
  317. if (event == NULL)
  318. {
  319. /* We want a synchronous copy, let's synchronise the queue */
  320. err = clWaitForEvents(1, &ev);
  321. if (STARPU_UNLIKELY(err))
  322. STARPU_OPENCL_REPORT_ERROR(err);
  323. err = clReleaseEvent(ev);
  324. if (STARPU_UNLIKELY(err))
  325. STARPU_OPENCL_REPORT_ERROR(err);
  326. }
  327. else
  328. {
  329. *event = ev;
  330. }
  331. if (ret)
  332. {
  333. *ret = (event == NULL) ? 0 : -EAGAIN;
  334. }
  335. }
  336. return err;
  337. }
  338. cl_int starpu_opencl_copy_async_sync(uintptr_t src, size_t src_offset, unsigned src_node, uintptr_t dst, size_t dst_offset, unsigned dst_node, size_t size, cl_event *event)
  339. {
  340. enum starpu_node_kind src_kind = starpu_node_get_kind(src_node);
  341. enum starpu_node_kind dst_kind = starpu_node_get_kind(dst_node);
  342. cl_int err;
  343. int ret;
  344. switch (_STARPU_MEMORY_NODE_TUPLE(src_kind,dst_kind))
  345. {
  346. case _STARPU_MEMORY_NODE_TUPLE(STARPU_OPENCL_RAM,STARPU_CPU_RAM):
  347. err = starpu_opencl_copy_opencl_to_ram(
  348. (cl_mem) src, src_node,
  349. (void*) (dst + dst_offset), dst_node,
  350. size, src_offset, event, &ret);
  351. if (STARPU_UNLIKELY(err))
  352. STARPU_OPENCL_REPORT_ERROR(err);
  353. return ret;
  354. case _STARPU_MEMORY_NODE_TUPLE(STARPU_CPU_RAM,STARPU_OPENCL_RAM):
  355. err = starpu_opencl_copy_ram_to_opencl(
  356. (void*) (src + src_offset), src_node,
  357. (cl_mem) dst, dst_node,
  358. size, dst_offset, event, &ret);
  359. if (STARPU_UNLIKELY(err))
  360. STARPU_OPENCL_REPORT_ERROR(err);
  361. return ret;
  362. case _STARPU_MEMORY_NODE_TUPLE(STARPU_OPENCL_RAM,STARPU_OPENCL_RAM):
  363. err = starpu_opencl_copy_opencl_to_opencl(
  364. (cl_mem) src, src_node, src_offset,
  365. (cl_mem) dst, dst_node, dst_offset,
  366. size, event, &ret);
  367. if (STARPU_UNLIKELY(err))
  368. STARPU_OPENCL_REPORT_ERROR(err);
  369. return ret;
  370. default:
  371. STARPU_ABORT();
  372. break;
  373. }
  374. }
  375. #if 0
  376. cl_int _starpu_opencl_copy_rect_opencl_to_ram(cl_mem buffer, unsigned src_node STARPU_ATTRIBUTE_UNUSED, void *ptr, unsigned dst_node STARPU_ATTRIBUTE_UNUSED, const size_t buffer_origin[3], const size_t host_origin[3],
  377. const size_t region[3], size_t buffer_row_pitch, size_t buffer_slice_pitch,
  378. size_t host_row_pitch, size_t host_slice_pitch, cl_event *event)
  379. {
  380. cl_int err;
  381. struct _starpu_worker *worker = _starpu_get_local_worker_key();
  382. cl_bool blocking;
  383. blocking = (event == NULL) ? CL_TRUE : CL_FALSE;
  384. if (event)
  385. _STARPU_TRACE_START_DRIVER_COPY_ASYNC(src_node, dst_node);
  386. err = clEnqueueReadBufferRect(out_transfer_queues[worker->devid], buffer, blocking, buffer_origin, host_origin, region, buffer_row_pitch,
  387. buffer_slice_pitch, host_row_pitch, host_slice_pitch, ptr, 0, NULL, event);
  388. if (event)
  389. _STARPU_TRACE_END_DRIVER_COPY_ASYNC(src_node, dst_node);
  390. if (err != CL_SUCCESS) STARPU_OPENCL_REPORT_ERROR(err);
  391. return CL_SUCCESS;
  392. }
  393. cl_int _starpu_opencl_copy_rect_ram_to_opencl(void *ptr, unsigned src_node STARPU_ATTRIBUTE_UNUSED, cl_mem buffer, unsigned dst_node STARPU_ATTRIBUTE_UNUSED, const size_t buffer_origin[3], const size_t host_origin[3],
  394. const size_t region[3], size_t buffer_row_pitch, size_t buffer_slice_pitch,
  395. size_t host_row_pitch, size_t host_slice_pitch, cl_event *event)
  396. {
  397. cl_int err;
  398. struct _starpu_worker *worker = _starpu_get_local_worker_key();
  399. cl_bool blocking;
  400. blocking = (event == NULL) ? CL_TRUE : CL_FALSE;
  401. if (event)
  402. _STARPU_TRACE_START_DRIVER_COPY_ASYNC(src_node, dst_node);
  403. err = clEnqueueWriteBufferRect(in_transfer_queues[worker->devid], buffer, blocking, buffer_origin, host_origin, region, buffer_row_pitch,
  404. buffer_slice_pitch, host_row_pitch, host_slice_pitch, ptr, 0, NULL, event);
  405. if (event)
  406. _STARPU_TRACE_END_DRIVER_COPY_ASYNC(src_node, dst_node);
  407. if (err != CL_SUCCESS) STARPU_OPENCL_REPORT_ERROR(err);
  408. return CL_SUCCESS;
  409. }
  410. #endif
  411. #endif /* STARPU_USE_OPENCL */
  412. static size_t _starpu_opencl_get_global_mem_size(int devid)
  413. {
  414. return global_mem[devid];
  415. }
  416. void _starpu_opencl_init(void)
  417. {
  418. STARPU_PTHREAD_MUTEX_LOCK(&big_lock);
  419. if (!init_done)
  420. {
  421. #ifdef STARPU_SIMGRID
  422. nb_devices = _starpu_simgrid_get_nbhosts("OpenCL");
  423. #else /* STARPU_USE_OPENCL */
  424. cl_platform_id platform_id[_STARPU_OPENCL_PLATFORM_MAX];
  425. cl_uint nb_platforms;
  426. cl_int err;
  427. int i;
  428. cl_device_type device_type = CL_DEVICE_TYPE_GPU|CL_DEVICE_TYPE_ACCELERATOR;
  429. _STARPU_DEBUG("Initialising OpenCL\n");
  430. // Get Platforms
  431. if (starpu_get_env_number("STARPU_OPENCL_ON_CPUS") > 0)
  432. device_type |= CL_DEVICE_TYPE_CPU;
  433. if (starpu_get_env_number("STARPU_OPENCL_ONLY_ON_CPUS") > 0)
  434. device_type = CL_DEVICE_TYPE_CPU;
  435. err = clGetPlatformIDs(_STARPU_OPENCL_PLATFORM_MAX, platform_id, &nb_platforms);
  436. if (STARPU_UNLIKELY(err != CL_SUCCESS)) nb_platforms=0;
  437. _STARPU_DEBUG("Platforms detected: %u\n", nb_platforms);
  438. _STARPU_DEBUG("CPU device type: %s\n", device_type&CL_DEVICE_TYPE_CPU?"requested":"not requested");
  439. _STARPU_DEBUG("GPU device type: %s\n", device_type&CL_DEVICE_TYPE_GPU?"requested":"not requested");
  440. _STARPU_DEBUG("Accelerator device type: %s\n", device_type&CL_DEVICE_TYPE_ACCELERATOR?"requested":"not requested");
  441. // Get devices
  442. nb_devices = 0;
  443. {
  444. unsigned j;
  445. for (j=0; j<nb_platforms; j++)
  446. {
  447. cl_uint num;
  448. int platform_valid = 1;
  449. char name[1024], vendor[1024];
  450. err = clGetPlatformInfo(platform_id[j], CL_PLATFORM_NAME, 1024, name, NULL);
  451. if (err != CL_SUCCESS)
  452. {
  453. STARPU_OPENCL_REPORT_ERROR_WITH_MSG("clGetPlatformInfo NAME", err);
  454. platform_valid = 0;
  455. }
  456. else
  457. {
  458. err = clGetPlatformInfo(platform_id[j], CL_PLATFORM_VENDOR, 1024, vendor, NULL);
  459. if (STARPU_UNLIKELY(err != CL_SUCCESS))
  460. {
  461. STARPU_OPENCL_REPORT_ERROR_WITH_MSG("clGetPlatformInfo VENDOR", err);
  462. platform_valid = 0;
  463. }
  464. }
  465. if(strcmp(name, "SOCL Platform") == 0)
  466. {
  467. platform_valid = 0;
  468. _STARPU_DEBUG("Skipping SOCL Platform\n");
  469. }
  470. #ifdef STARPU_VERBOSE
  471. if (platform_valid)
  472. _STARPU_DEBUG("Platform: %s - %s\n", name, vendor);
  473. else
  474. _STARPU_DEBUG("Platform invalid\n");
  475. #endif
  476. if (platform_valid && nb_devices <= STARPU_MAXOPENCLDEVS)
  477. {
  478. err = clGetDeviceIDs(platform_id[j], device_type, STARPU_MAXOPENCLDEVS-nb_devices, STARPU_MAXOPENCLDEVS == nb_devices ? NULL : &devices[nb_devices], &num);
  479. if (err == CL_DEVICE_NOT_FOUND)
  480. {
  481. const cl_device_type all_device_types = CL_DEVICE_TYPE_CPU|CL_DEVICE_TYPE_GPU|CL_DEVICE_TYPE_ACCELERATOR;
  482. if (device_type != all_device_types)
  483. {
  484. _STARPU_DEBUG(" No devices of the requested type(s) subset detected on this platform\n");
  485. }
  486. else
  487. {
  488. _STARPU_DEBUG(" No devices detected on this platform\n");
  489. }
  490. }
  491. else
  492. {
  493. if (STARPU_UNLIKELY(err != CL_SUCCESS)) STARPU_OPENCL_REPORT_ERROR(err);
  494. _STARPU_DEBUG(" %u devices detected\n", num);
  495. nb_devices += num;
  496. }
  497. }
  498. }
  499. }
  500. // Get location of OpenCl kernel source files
  501. _starpu_opencl_program_dir = starpu_getenv("STARPU_OPENCL_PROGRAM_DIR");
  502. if (nb_devices > STARPU_MAXOPENCLDEVS)
  503. {
  504. _STARPU_DISP("# Warning: %u OpenCL devices available. Only %d enabled. Use configure option --enable-maxopencldev=xxx to update the maximum value of supported OpenCL devices?\n", nb_devices, STARPU_MAXOPENCLDEVS);
  505. nb_devices = STARPU_MAXOPENCLDEVS;
  506. }
  507. // initialise internal structures
  508. for(i=0 ; i<nb_devices ; i++)
  509. {
  510. contexts[i] = NULL;
  511. queues[i] = NULL;
  512. in_transfer_queues[i] = NULL;
  513. out_transfer_queues[i] = NULL;
  514. peer_transfer_queues[i] = NULL;
  515. alloc_queues[i] = NULL;
  516. }
  517. #endif /* STARPU_USE_OPENCL */
  518. init_done=1;
  519. }
  520. STARPU_PTHREAD_MUTEX_UNLOCK(&big_lock);
  521. }
  522. #ifndef STARPU_SIMGRID
  523. static unsigned _starpu_opencl_get_device_name(int dev, char *name, int lname);
  524. #endif
  525. static int _starpu_opencl_start_job(struct _starpu_job *j, struct _starpu_worker *worker, unsigned char pipeline_idx);
  526. static void _starpu_opencl_stop_job(struct _starpu_job *j, struct _starpu_worker *worker);
  527. static void _starpu_opencl_execute_job(struct starpu_task *task, struct _starpu_worker *worker);
  528. int _starpu_opencl_driver_init(struct _starpu_worker *worker)
  529. {
  530. int devid = worker->devid;
  531. _starpu_driver_start(worker, _STARPU_FUT_OPENCL_KEY, 0);
  532. _starpu_opencl_init_context(devid);
  533. /* one more time to avoid hacks from third party lib :) */
  534. _starpu_bind_thread_on_cpu(worker->config, worker->bindid);
  535. _starpu_opencl_limit_gpu_mem_if_needed(devid);
  536. _starpu_memory_manager_set_global_memory_size(worker->memory_node, _starpu_opencl_get_global_mem_size(devid));
  537. _starpu_malloc_init(worker->memory_node);
  538. float size = (float) global_mem[devid] / (1<<30);
  539. #ifdef STARPU_SIMGRID
  540. const char *devname = "Simgrid";
  541. #else
  542. /* get the device's name */
  543. char devname[128];
  544. _starpu_opencl_get_device_name(devid, devname, 128);
  545. #endif
  546. snprintf(worker->name, sizeof(worker->name), "OpenCL %u (%s %.1f GiB)", devid, devname, size);
  547. snprintf(worker->short_name, sizeof(worker->short_name), "OpenCL %u", devid);
  548. worker->pipeline_length = starpu_get_env_number_default("STARPU_OPENCL_PIPELINE", 2);
  549. if (worker->pipeline_length > STARPU_MAX_PIPELINE)
  550. {
  551. _STARPU_DISP("Warning: STARPU_OPENCL_PIPELINE is %u, but STARPU_MAX_PIPELINE is only %u", worker->pipeline_length, STARPU_MAX_PIPELINE);
  552. worker->pipeline_length = STARPU_MAX_PIPELINE;
  553. }
  554. #if defined(STARPU_SIMGRID) && defined(STARPU_NON_BLOCKING_DRIVERS)
  555. if (worker->pipeline_length >= 1)
  556. {
  557. /* We need blocking drivers, otherwise idle drivers
  558. * would keep consuming real CPU time while just
  559. * polling for task termination */
  560. _STARPU_DISP("Warning: reducing STARPU_OPENCL_PIPELINE to 0 because simgrid is enabled and blocking drivers are not enabled\n");
  561. worker->pipeline_length = 0;
  562. }
  563. #endif
  564. #if !defined(STARPU_SIMGRID) && !defined(STARPU_NON_BLOCKING_DRIVERS)
  565. if (worker->pipeline_length >= 1)
  566. {
  567. /* We need non-blocking drivers, to poll for OPENCL task
  568. * termination */
  569. _STARPU_DISP("Warning: reducing STARPU_OPENCL_PIPELINE to 0 because blocking drivers are enabled (and simgrid is not enabled)\n");
  570. worker->pipeline_length = 0;
  571. }
  572. #endif
  573. _STARPU_DEBUG("OpenCL (%s) dev id %d thread is ready to run on CPU %d !\n", devname, devid, worker->bindid);
  574. _STARPU_TRACE_WORKER_INIT_END(worker->workerid);
  575. /* tell the main thread that this one is ready */
  576. STARPU_PTHREAD_MUTEX_LOCK(&worker->mutex);
  577. worker->status = STATUS_UNKNOWN;
  578. worker->worker_is_initialized = 1;
  579. STARPU_PTHREAD_COND_SIGNAL(&worker->ready_cond);
  580. STARPU_PTHREAD_MUTEX_UNLOCK(&worker->mutex);
  581. return 0;
  582. }
  583. int _starpu_opencl_driver_run_once(struct _starpu_worker *worker)
  584. {
  585. int workerid = worker->workerid;
  586. unsigned memnode = worker->memory_node;
  587. struct _starpu_job *j;
  588. struct starpu_task *task;
  589. if (worker->ntasks)
  590. {
  591. #ifndef STARPU_SIMGRID
  592. size_t size;
  593. int err;
  594. #endif
  595. /* On-going asynchronous task, check for its termination first */
  596. task = worker->current_tasks[worker->first_task];
  597. #ifdef STARPU_SIMGRID
  598. if (task_finished[worker->devid][worker->first_task])
  599. #else /* !STARPU_SIMGRID */
  600. cl_int status;
  601. err = clGetEventInfo(task_events[worker->devid][worker->first_task], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(cl_int), &status, &size);
  602. STARPU_ASSERT(size == sizeof(cl_int));
  603. if (STARPU_UNLIKELY(err != CL_SUCCESS)) STARPU_OPENCL_REPORT_ERROR(err);
  604. if (status != CL_COMPLETE)
  605. #endif /* !STARPU_SIMGRID */
  606. {
  607. _STARPU_TRACE_START_EXECUTING();
  608. /* Not ready yet, no better thing to do than waiting */
  609. __starpu_datawizard_progress(memnode, 1, 0);
  610. __starpu_datawizard_progress(STARPU_MAIN_RAM, 1, 0);
  611. return 0;
  612. }
  613. else
  614. {
  615. #ifndef STARPU_SIMGRID
  616. task_events[worker->devid][worker->first_task] = 0;
  617. #endif
  618. /* Asynchronous task completed! */
  619. _starpu_opencl_stop_job(_starpu_get_job_associated_to_task(task), worker);
  620. /* See next task if any */
  621. if (worker->ntasks)
  622. {
  623. task = worker->current_tasks[worker->first_task];
  624. j = _starpu_get_job_associated_to_task(task);
  625. if (task->cl->opencl_flags[j->nimpl] & STARPU_OPENCL_ASYNC)
  626. {
  627. /* An asynchronous task, it was already queued,
  628. * it's now running, record its start time. */
  629. _starpu_driver_start_job(worker, j, &worker->perf_arch, &j->cl_start, 0, starpu_profiling_status_get());
  630. }
  631. else
  632. {
  633. /* A synchronous task, we have finished flushing the pipeline, we can now at last execute it. */
  634. _STARPU_TRACE_END_PROGRESS(memnode);
  635. _STARPU_TRACE_EVENT("sync_task");
  636. _starpu_opencl_execute_job(task, worker);
  637. _STARPU_TRACE_EVENT("end_sync_task");
  638. _STARPU_TRACE_START_PROGRESS(memnode);
  639. worker->pipeline_stuck = 0;
  640. }
  641. }
  642. _STARPU_TRACE_END_EXECUTING();
  643. }
  644. }
  645. __starpu_datawizard_progress(memnode, 1, 1);
  646. __starpu_datawizard_progress(STARPU_MAIN_RAM, 1, 1);
  647. task = _starpu_get_worker_task(worker, workerid, memnode);
  648. if (task == NULL)
  649. return 0;
  650. j = _starpu_get_job_associated_to_task(task);
  651. /* can OpenCL do that task ? */
  652. if (!_STARPU_OPENCL_MAY_PERFORM(j))
  653. {
  654. /* this is not a OpenCL task */
  655. _starpu_push_task_to_workers(task);
  656. return 0;
  657. }
  658. worker->current_tasks[(worker->first_task + worker->ntasks)%STARPU_MAX_PIPELINE] = task;
  659. worker->ntasks++;
  660. if (worker->ntasks > 1 && !(task->cl->opencl_flags[j->nimpl] & STARPU_OPENCL_ASYNC))
  661. {
  662. /* We have to execute a non-asynchronous task but we
  663. * still have tasks in the pipeline... Record it to
  664. * prevent more tasks from coming, and do it later */
  665. worker->pipeline_stuck = 1;
  666. return 0;
  667. }
  668. _STARPU_TRACE_END_PROGRESS(memnode);
  669. _starpu_opencl_execute_job(task, worker);
  670. _STARPU_TRACE_START_PROGRESS(memnode);
  671. return 0;
  672. }
  673. int _starpu_opencl_driver_deinit(struct _starpu_worker *worker)
  674. {
  675. _STARPU_TRACE_WORKER_DEINIT_START;
  676. unsigned memnode = worker->memory_node;
  677. _starpu_handle_all_pending_node_data_requests(memnode);
  678. /* In case there remains some memory that was automatically
  679. * allocated by StarPU, we release it now. Note that data
  680. * coherency is not maintained anymore at that point ! */
  681. _starpu_free_all_automatically_allocated_buffers(memnode);
  682. _starpu_malloc_shutdown(memnode);
  683. unsigned devid = worker->devid;
  684. _starpu_opencl_deinit_context(devid);
  685. worker->worker_is_initialized = 0;
  686. _STARPU_TRACE_WORKER_DEINIT_END(_STARPU_FUT_OPENCL_KEY);
  687. return 0;
  688. }
  689. void *_starpu_opencl_worker(void *_arg)
  690. {
  691. struct _starpu_worker* worker = _arg;
  692. _starpu_opencl_driver_init(worker);
  693. _STARPU_TRACE_START_PROGRESS(memnode);
  694. while (_starpu_machine_is_running())
  695. {
  696. _starpu_may_pause();
  697. _starpu_opencl_driver_run_once(worker);
  698. }
  699. _starpu_opencl_driver_deinit(worker);
  700. _STARPU_TRACE_END_PROGRESS(memnode);
  701. return NULL;
  702. }
  703. #ifdef STARPU_USE_OPENCL
  704. #ifndef STARPU_SIMGRID
  705. static unsigned _starpu_opencl_get_device_name(int dev, char *name, int lname)
  706. {
  707. int err;
  708. if (!init_done)
  709. {
  710. _starpu_opencl_init();
  711. }
  712. // Get device name
  713. err = clGetDeviceInfo(devices[dev], CL_DEVICE_NAME, lname, name, NULL);
  714. if (STARPU_UNLIKELY(err != CL_SUCCESS)) STARPU_OPENCL_REPORT_ERROR(err);
  715. _STARPU_DEBUG("Device %d : [%s]\n", dev, name);
  716. return EXIT_SUCCESS;
  717. }
  718. #endif
  719. #endif
  720. unsigned _starpu_opencl_get_device_count(void)
  721. {
  722. if (!init_done)
  723. {
  724. _starpu_opencl_init();
  725. }
  726. return nb_devices;
  727. }
  728. #ifdef STARPU_USE_OPENCL
  729. cl_device_type _starpu_opencl_get_device_type(int devid)
  730. {
  731. int err;
  732. cl_device_type type;
  733. if (!init_done)
  734. _starpu_opencl_init();
  735. err = clGetDeviceInfo(devices[devid], CL_DEVICE_TYPE, sizeof(cl_device_type), &type, NULL);
  736. if (STARPU_UNLIKELY(err != CL_SUCCESS))
  737. STARPU_OPENCL_REPORT_ERROR(err);
  738. return type;
  739. }
  740. #endif /* STARPU_USE_OPENCL */
  741. static int _starpu_opencl_start_job(struct _starpu_job *j, struct _starpu_worker *worker, unsigned char pipeline_idx STARPU_ATTRIBUTE_UNUSED)
  742. {
  743. int ret;
  744. STARPU_ASSERT(j);
  745. struct starpu_task *task = j->task;
  746. int profiling = starpu_profiling_status_get();
  747. STARPU_ASSERT(task);
  748. struct starpu_codelet *cl = task->cl;
  749. STARPU_ASSERT(cl);
  750. _starpu_set_current_task(j->task);
  751. ret = _starpu_fetch_task_input(j);
  752. if (ret != 0)
  753. {
  754. /* there was not enough memory, so the input of
  755. * the codelet cannot be fetched ... put the
  756. * codelet back, and try it later */
  757. return -EAGAIN;
  758. }
  759. if (worker->ntasks == 1)
  760. {
  761. /* We are alone in the pipeline, the kernel will start now, record it */
  762. _starpu_driver_start_job(worker, j, &worker->perf_arch, &j->cl_start, 0, profiling);
  763. }
  764. starpu_opencl_func_t func = _starpu_task_get_opencl_nth_implementation(cl, j->nimpl);
  765. STARPU_ASSERT_MSG(func, "when STARPU_OPENCL is defined in 'where', opencl_func or opencl_funcs has to be defined");
  766. if (_starpu_get_disable_kernels() <= 0)
  767. {
  768. _STARPU_TRACE_START_EXECUTING();
  769. #ifdef STARPU_SIMGRID
  770. double length = NAN;
  771. #ifdef STARPU_OPENCL_SIMULATOR
  772. func(_STARPU_TASK_GET_INTERFACES(task), task->cl_arg);
  773. #ifndef CL_PROFILING_CLOCK_CYCLE_COUNT
  774. #ifdef CL_PROFILING_COMMAND_SHAVE_CYCLE_COUNT
  775. #define CL_PROFILING_CLOCK_CYCLE_COUNT CL_PROFILING_COMMAND_SHAVE_CYCLE_COUNT
  776. #else
  777. #error The OpenCL simulator must provide CL_PROFILING_CLOCK_CYCLE_COUNT
  778. #endif
  779. #endif
  780. struct starpu_profiling_task_info *profiling_info = task->profiling_info;
  781. STARPU_ASSERT_MSG(profiling_info->used_cycles, "Application kernel must call starpu_opencl_collect_stats to collect simulated time");
  782. length = ((double) profiling_info->used_cycles)/MSG_get_host_speed(MSG_host_self());
  783. #endif
  784. int async = task->cl->opencl_flags[j->nimpl] & STARPU_OPENCL_ASYNC;
  785. _starpu_simgrid_submit_job(worker->workerid, j, &worker->perf_arch, length,
  786. async ? &task_finished[worker->devid][pipeline_idx] : NULL,
  787. async ? &task_mutex[worker->devid][pipeline_idx] : NULL,
  788. async ? &task_cond[worker->devid][pipeline_idx] : NULL);
  789. #else
  790. func(_STARPU_TASK_GET_INTERFACES(task), task->cl_arg);
  791. #endif
  792. _STARPU_TRACE_END_EXECUTING();
  793. }
  794. return 0;
  795. }
  796. static void _starpu_opencl_stop_job(struct _starpu_job *j, struct _starpu_worker *worker)
  797. {
  798. struct timespec codelet_end;
  799. int profiling = starpu_profiling_status_get();
  800. _starpu_set_current_task(NULL);
  801. if (worker->pipeline_length)
  802. worker->current_tasks[worker->first_task] = NULL;
  803. else
  804. worker->current_task = NULL;
  805. worker->first_task = (worker->first_task + 1) % STARPU_MAX_PIPELINE;
  806. worker->ntasks--;
  807. _starpu_driver_end_job(worker, j, &worker->perf_arch, &codelet_end, 0, profiling);
  808. struct _starpu_sched_ctx *sched_ctx = _starpu_sched_ctx_get_sched_ctx_for_worker_and_job(worker, j);
  809. STARPU_ASSERT_MSG(sched_ctx != NULL, "there should be a worker %d in the ctx of this job \n", worker->workerid);
  810. if(!sched_ctx->sched_policy)
  811. _starpu_driver_update_job_feedback(j, worker, &sched_ctx->perf_arch, &j->cl_start, &codelet_end, profiling);
  812. else
  813. _starpu_driver_update_job_feedback(j, worker, &worker->perf_arch, &j->cl_start, &codelet_end, profiling);
  814. _starpu_push_task_output(j);
  815. _starpu_handle_job_termination(j);
  816. }
  817. static void _starpu_opencl_execute_job(struct starpu_task *task, struct _starpu_worker *worker)
  818. {
  819. int res;
  820. struct _starpu_job *j = _starpu_get_job_associated_to_task(task);
  821. unsigned char pipeline_idx = (worker->first_task + worker->ntasks - 1)%STARPU_MAX_PIPELINE;
  822. res = _starpu_opencl_start_job(j, worker, pipeline_idx);
  823. if (res)
  824. {
  825. switch (res)
  826. {
  827. case -EAGAIN:
  828. _STARPU_DISP("ouch, OpenCL could not actually run task %p, putting it back...\n", task);
  829. _starpu_push_task_to_workers(task);
  830. STARPU_ABORT();
  831. default:
  832. STARPU_ABORT();
  833. }
  834. }
  835. if (task->cl->opencl_flags[j->nimpl] & STARPU_OPENCL_ASYNC)
  836. {
  837. /* Record event to synchronize with task termination later */
  838. #ifndef STARPU_SIMGRID
  839. cl_command_queue queue;
  840. starpu_opencl_get_queue(worker->devid, &queue);
  841. #endif
  842. if (worker->pipeline_length == 0)
  843. {
  844. #ifdef STARPU_SIMGRID
  845. _starpu_simgrid_wait_tasks(worker->workerid);
  846. #else
  847. starpu_opencl_get_queue(worker->devid, &queue);
  848. clFinish(queue);
  849. #endif
  850. _starpu_opencl_stop_job(j, worker);
  851. }
  852. else
  853. {
  854. #ifndef STARPU_SIMGRID
  855. int err;
  856. /* the function clEnqueueMarker is deprecated from
  857. * OpenCL version 1.2. We would like to use the new
  858. * function clEnqueueMarkerWithWaitList. We could do
  859. * it by checking its availability through our own
  860. * configure macro HAVE_CLENQUEUEMARKERWITHWAITLIST
  861. * and the OpenCL macro CL_VERSION_1_2. However these
  862. * 2 macros detect the function availability in the
  863. * ICD and not in the device implementation.
  864. */
  865. err = clEnqueueMarker(queue, &task_events[worker->devid][pipeline_idx]);
  866. if (STARPU_UNLIKELY(err != CL_SUCCESS)) STARPU_OPENCL_REPORT_ERROR(err);
  867. #endif
  868. _STARPU_TRACE_START_EXECUTING();
  869. }
  870. }
  871. else
  872. /* Synchronous execution */
  873. {
  874. _starpu_opencl_stop_job(j, worker);
  875. }
  876. }
  877. #ifdef STARPU_USE_OPENCL
  878. int _starpu_run_opencl(struct _starpu_worker *workerarg)
  879. {
  880. _STARPU_DEBUG("Running OpenCL %u from the application\n", workerarg->devid);
  881. workerarg->set = NULL;
  882. workerarg->worker_is_initialized = 0;
  883. /* Let's go ! */
  884. _starpu_opencl_worker(workerarg);
  885. return 0;
  886. }
  887. #endif /* STARPU_USE_OPENCL */