vector_interface.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. /* StarPU --- Runtime system for heterogeneous multicore architectures.
  2. *
  3. * Copyright (C) 2009, 2010 Université de Bordeaux 1
  4. * Copyright (C) 2010, 2011 Centre National de la Recherche Scientifique
  5. *
  6. * StarPU is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as published by
  8. * the Free Software Foundation; either version 2.1 of the License, or (at
  9. * your option) any later version.
  10. *
  11. * StarPU is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. *
  15. * See the GNU Lesser General Public License in COPYING.LGPL for more details.
  16. */
  17. #include <starpu.h>
  18. #include <common/config.h>
  19. #include <datawizard/coherency.h>
  20. #include <datawizard/copy_driver.h>
  21. #include <datawizard/filters.h>
  22. #include <common/hash.h>
  23. #include <starpu_cuda.h>
  24. #include <starpu_opencl.h>
  25. #include <drivers/opencl/driver_opencl.h>
  26. static int copy_ram_to_ram(void *src_interface, unsigned src_node __attribute__((unused)), void *dst_interface, unsigned dst_node);
  27. #ifdef STARPU_USE_CUDA
  28. static int copy_ram_to_cuda(void *src_interface, unsigned src_node __attribute__((unused)), void *dst_interface, unsigned dst_node);
  29. static int copy_cuda_to_ram(void *src_interface, unsigned src_node __attribute__((unused)), void *dst_interface, unsigned dst_node);
  30. static int copy_ram_to_cuda_async(void *src_interface, unsigned src_node __attribute__((unused)), void *dst_interface, unsigned dst_node, cudaStream_t stream);
  31. static int copy_cuda_to_ram_async(void *src_interface, unsigned src_node __attribute__((unused)), void *dst_interface, unsigned dst_node, cudaStream_t stream);
  32. static int copy_cuda_to_cuda(void *src_interface, unsigned src_node __attribute__((unused)), void *dst_interface, unsigned dst_node __attribute__((unused)));
  33. #endif
  34. #ifdef STARPU_USE_OPENCL
  35. static int copy_ram_to_opencl(void *src_interface, unsigned src_node __attribute__((unused)), void *dst_interface, unsigned dst_node);
  36. static int copy_opencl_to_ram(void *src_interface, unsigned src_node __attribute__((unused)), void *dst_interface, unsigned dst_node);
  37. static int copy_opencl_to_opencl(void *src_interface, unsigned src_node __attribute__((unused)), void *dst_interface, unsigned dst_node);
  38. static int copy_ram_to_opencl_async(void *src_interface, unsigned src_node __attribute__((unused)), void *dst_interface, unsigned dst_node, void *_event);
  39. static int copy_opencl_to_ram_async(void *src_interface, unsigned src_node __attribute__((unused)), void *dst_interface, unsigned dst_node, void *_event);
  40. #endif
  41. static const struct starpu_data_copy_methods vector_copy_data_methods_s = {
  42. .ram_to_ram = copy_ram_to_ram,
  43. .ram_to_spu = NULL,
  44. #ifdef STARPU_USE_CUDA
  45. .ram_to_cuda = copy_ram_to_cuda,
  46. .cuda_to_ram = copy_cuda_to_ram,
  47. .ram_to_cuda_async = copy_ram_to_cuda_async,
  48. .cuda_to_ram_async = copy_cuda_to_ram_async,
  49. .cuda_to_cuda = copy_cuda_to_cuda,
  50. #endif
  51. #ifdef STARPU_USE_OPENCL
  52. .ram_to_opencl = copy_ram_to_opencl,
  53. .opencl_to_ram = copy_opencl_to_ram,
  54. .opencl_to_opencl = copy_opencl_to_opencl,
  55. .ram_to_opencl_async = copy_ram_to_opencl_async,
  56. .opencl_to_ram_async = copy_opencl_to_ram_async,
  57. #endif
  58. .cuda_to_spu = NULL,
  59. .spu_to_ram = NULL,
  60. .spu_to_cuda = NULL,
  61. .spu_to_spu = NULL
  62. };
  63. static void register_vector_handle(starpu_data_handle handle, uint32_t home_node, void *data_interface);
  64. static ssize_t allocate_vector_buffer_on_node(void *data_interface_, uint32_t dst_node);
  65. static void free_vector_buffer_on_node(void *data_interface, uint32_t node);
  66. static size_t vector_interface_get_size(starpu_data_handle handle);
  67. static uint32_t footprint_vector_interface_crc32(starpu_data_handle handle);
  68. static int vector_compare(void *data_interface_a, void *data_interface_b);
  69. static void display_vector_interface(starpu_data_handle handle, FILE *f);
  70. #ifdef STARPU_USE_GORDON
  71. static int convert_vector_to_gordon(void *data_interface, uint64_t *ptr, gordon_strideSize_t *ss);
  72. #endif
  73. static struct starpu_data_interface_ops_t interface_vector_ops = {
  74. .register_data_handle = register_vector_handle,
  75. .allocate_data_on_node = allocate_vector_buffer_on_node,
  76. .free_data_on_node = free_vector_buffer_on_node,
  77. .copy_methods = &vector_copy_data_methods_s,
  78. .get_size = vector_interface_get_size,
  79. .footprint = footprint_vector_interface_crc32,
  80. .compare = vector_compare,
  81. #ifdef STARPU_USE_GORDON
  82. .convert_to_gordon = convert_vector_to_gordon,
  83. #endif
  84. .interfaceid = STARPU_VECTOR_INTERFACE_ID,
  85. .interface_size = sizeof(starpu_vector_interface_t),
  86. .display = display_vector_interface
  87. };
  88. static void register_vector_handle(starpu_data_handle handle, uint32_t home_node, void *data_interface)
  89. {
  90. starpu_vector_interface_t *vector_interface = data_interface;
  91. unsigned node;
  92. for (node = 0; node < STARPU_MAXNODES; node++)
  93. {
  94. starpu_vector_interface_t *local_interface =
  95. starpu_data_get_interface_on_node(handle, node);
  96. if (node == home_node) {
  97. local_interface->ptr = vector_interface->ptr;
  98. local_interface->dev_handle = vector_interface->dev_handle;
  99. local_interface->offset = vector_interface->offset;
  100. }
  101. else {
  102. local_interface->ptr = 0;
  103. local_interface->dev_handle = 0;
  104. local_interface->offset = 0;
  105. }
  106. local_interface->nx = vector_interface->nx;
  107. local_interface->elemsize = vector_interface->elemsize;
  108. }
  109. }
  110. #ifdef STARPU_USE_GORDON
  111. int convert_vector_to_gordon(void *data_interface, uint64_t *ptr, gordon_strideSize_t *ss)
  112. {
  113. starpu_vector_interface_t *vector_interface = interface;
  114. *ptr = vector_interface->ptr;
  115. (*ss).size = vector_interface->nx * vector_interface->elemsize;
  116. return 0;
  117. }
  118. #endif
  119. /* declare a new data with the vector interface */
  120. void starpu_vector_data_register(starpu_data_handle *handleptr, uint32_t home_node,
  121. uintptr_t ptr, uint32_t nx, size_t elemsize)
  122. {
  123. starpu_vector_interface_t vector = {
  124. .ptr = ptr,
  125. .nx = nx,
  126. .elemsize = elemsize,
  127. .dev_handle = ptr,
  128. .offset = 0
  129. };
  130. starpu_data_register(handleptr, home_node, &vector, &interface_vector_ops);
  131. }
  132. static uint32_t footprint_vector_interface_crc32(starpu_data_handle handle)
  133. {
  134. return _starpu_crc32_be(starpu_vector_get_nx(handle), 0);
  135. }
  136. static int vector_compare(void *data_interface_a, void *data_interface_b)
  137. {
  138. starpu_vector_interface_t *vector_a = data_interface_a;
  139. starpu_vector_interface_t *vector_b = data_interface_b;
  140. /* Two vectors are considered compatible if they have the same size */
  141. return ((vector_a->nx == vector_b->nx)
  142. && (vector_a->elemsize == vector_b->elemsize));
  143. }
  144. static void display_vector_interface(starpu_data_handle handle, FILE *f)
  145. {
  146. starpu_vector_interface_t *vector_interface =
  147. starpu_data_get_interface_on_node(handle, 0);
  148. fprintf(f, "%u\t", vector_interface->nx);
  149. }
  150. static size_t vector_interface_get_size(starpu_data_handle handle)
  151. {
  152. size_t size;
  153. starpu_vector_interface_t *vector_interface =
  154. starpu_data_get_interface_on_node(handle, 0);
  155. size = vector_interface->nx*vector_interface->elemsize;
  156. return size;
  157. }
  158. /* offer an access to the data parameters */
  159. uint32_t starpu_vector_get_nx(starpu_data_handle handle)
  160. {
  161. starpu_vector_interface_t *vector_interface =
  162. starpu_data_get_interface_on_node(handle, 0);
  163. return vector_interface->nx;
  164. }
  165. uintptr_t starpu_vector_get_local_ptr(starpu_data_handle handle)
  166. {
  167. unsigned node;
  168. node = _starpu_get_local_memory_node();
  169. STARPU_ASSERT(starpu_data_test_if_allocated_on_node(handle, node));
  170. starpu_vector_interface_t *vector_interface =
  171. starpu_data_get_interface_on_node(handle, node);
  172. return vector_interface->ptr;
  173. }
  174. size_t starpu_vector_get_elemsize(starpu_data_handle handle)
  175. {
  176. starpu_vector_interface_t *vector_interface =
  177. starpu_data_get_interface_on_node(handle, 0);
  178. return vector_interface->elemsize;
  179. }
  180. /* memory allocation/deallocation primitives for the vector interface */
  181. /* returns the size of the allocated area */
  182. static ssize_t allocate_vector_buffer_on_node(void *data_interface_, uint32_t dst_node)
  183. {
  184. starpu_vector_interface_t *vector_interface = data_interface_;
  185. unsigned fail = 0;
  186. uintptr_t addr = 0;
  187. ssize_t allocated_memory;
  188. uint32_t nx = vector_interface->nx;
  189. size_t elemsize = vector_interface->elemsize;
  190. starpu_node_kind kind = _starpu_get_node_kind(dst_node);
  191. #ifdef STARPU_USE_CUDA
  192. cudaError_t status;
  193. #endif
  194. switch(kind) {
  195. case STARPU_CPU_RAM:
  196. addr = (uintptr_t)malloc(nx*elemsize);
  197. if (!addr)
  198. fail = 1;
  199. break;
  200. #ifdef STARPU_USE_CUDA
  201. case STARPU_CUDA_RAM:
  202. status = cudaMalloc((void **)&addr, nx*elemsize);
  203. if (!addr || (status != cudaSuccess))
  204. {
  205. if (STARPU_UNLIKELY(status != cudaErrorMemoryAllocation))
  206. STARPU_CUDA_REPORT_ERROR(status);
  207. fail = 1;
  208. }
  209. break;
  210. #endif
  211. #ifdef STARPU_USE_OPENCL
  212. case STARPU_OPENCL_RAM:
  213. {
  214. int ret;
  215. void *ptr;
  216. ret = _starpu_opencl_allocate_memory(&ptr, nx*elemsize, CL_MEM_READ_WRITE);
  217. addr = (uintptr_t)ptr;
  218. if (ret) {
  219. fail = 1;
  220. }
  221. break;
  222. }
  223. #endif
  224. default:
  225. assert(0);
  226. }
  227. if (fail)
  228. return -ENOMEM;
  229. /* allocation succeeded */
  230. allocated_memory = nx*elemsize;
  231. /* update the data properly in consequence */
  232. vector_interface->ptr = addr;
  233. vector_interface->dev_handle = addr;
  234. vector_interface->offset = 0;
  235. return allocated_memory;
  236. }
  237. static void free_vector_buffer_on_node(void *data_interface, uint32_t node)
  238. {
  239. starpu_vector_interface_t *vector_interface = data_interface;
  240. starpu_node_kind kind = _starpu_get_node_kind(node);
  241. switch(kind) {
  242. case STARPU_CPU_RAM:
  243. free((void*)vector_interface->ptr);
  244. break;
  245. #ifdef STARPU_USE_CUDA
  246. case STARPU_CUDA_RAM:
  247. cudaFree((void*)vector_interface->ptr);
  248. break;
  249. #endif
  250. #ifdef STARPU_USE_OPENCL
  251. case STARPU_OPENCL_RAM:
  252. clReleaseMemObject((void *)vector_interface->ptr);
  253. break;
  254. #endif
  255. default:
  256. assert(0);
  257. }
  258. }
  259. #ifdef STARPU_USE_CUDA
  260. static int copy_cuda_common(void *src_interface, unsigned src_node __attribute__((unused)),
  261. void *dst_interface, unsigned dst_node __attribute__((unused)), enum cudaMemcpyKind kind)
  262. {
  263. starpu_vector_interface_t *src_vector = src_interface;
  264. starpu_vector_interface_t *dst_vector = dst_interface;
  265. cudaError_t cures;
  266. cures = cudaMemcpy((char *)dst_vector->ptr, (char *)src_vector->ptr, src_vector->nx*src_vector->elemsize, kind);
  267. if (STARPU_UNLIKELY(cures))
  268. STARPU_CUDA_REPORT_ERROR(cures);
  269. STARPU_TRACE_DATA_COPY(src_node, dst_node, src_vector->nx*src_vector->elemsize);
  270. return 0;
  271. }
  272. static int copy_cuda_to_ram(void *src_interface, unsigned src_node __attribute__((unused)),
  273. void *dst_interface, unsigned dst_node __attribute__((unused)))
  274. {
  275. return copy_cuda_common(src_interface, src_node, dst_interface, dst_node, cudaMemcpyDeviceToHost);
  276. }
  277. static int copy_ram_to_cuda(void *src_interface, unsigned src_node __attribute__((unused)),
  278. void *dst_interface, unsigned dst_node __attribute__((unused)))
  279. {
  280. return copy_cuda_common(src_interface, src_node, dst_interface, dst_node, cudaMemcpyHostToDevice);
  281. }
  282. static int copy_cuda_to_cuda(void *src_interface, unsigned src_node __attribute__((unused)),
  283. void *dst_interface, unsigned dst_node __attribute__((unused)))
  284. {
  285. return copy_cuda_common(src_interface, src_node, dst_interface, dst_node, cudaMemcpyDeviceToDevice);
  286. }
  287. static int copy_cuda_async_common(void *src_interface, unsigned src_node __attribute__((unused)),
  288. void *dst_interface, unsigned dst_node __attribute__((unused)),
  289. cudaStream_t stream, enum cudaMemcpyKind kind)
  290. {
  291. starpu_vector_interface_t *src_vector = src_interface;
  292. starpu_vector_interface_t *dst_vector = dst_interface;
  293. cudaError_t cures;
  294. cures = cudaMemcpyAsync((char *)dst_vector->ptr, (char *)src_vector->ptr, src_vector->nx*src_vector->elemsize, kind, stream);
  295. if (cures)
  296. {
  297. /* do it in a synchronous fashion */
  298. cures = cudaMemcpy((char *)dst_vector->ptr, (char *)src_vector->ptr, src_vector->nx*src_vector->elemsize, kind);
  299. if (STARPU_UNLIKELY(cures))
  300. STARPU_CUDA_REPORT_ERROR(cures);
  301. return 0;
  302. }
  303. STARPU_TRACE_DATA_COPY(src_node, dst_node, src_vector->nx*src_vector->elemsize);
  304. return -EAGAIN;
  305. }
  306. static int copy_cuda_to_ram_async(void *src_interface, unsigned src_node __attribute__((unused)),
  307. void *dst_interface, unsigned dst_node __attribute__((unused)), cudaStream_t stream)
  308. {
  309. return copy_cuda_async_common(src_interface, src_node, dst_interface, dst_node, stream, cudaMemcpyDeviceToHost);
  310. }
  311. static int copy_ram_to_cuda_async(void *src_interface, unsigned src_node __attribute__((unused)),
  312. void *dst_interface, unsigned dst_node __attribute__((unused)), cudaStream_t stream)
  313. {
  314. return copy_cuda_async_common(src_interface, src_node, dst_interface, dst_node, stream, cudaMemcpyHostToDevice);
  315. }
  316. #endif // STARPU_USE_CUDA
  317. #ifdef STARPU_USE_OPENCL
  318. static int copy_ram_to_opencl_async(void *src_interface, unsigned src_node __attribute__((unused)),
  319. void *dst_interface, unsigned dst_node __attribute__((unused)), void *_event)
  320. {
  321. starpu_vector_interface_t *src_vector = src_interface;
  322. starpu_vector_interface_t *dst_vector = dst_interface;
  323. int err, ret;
  324. err = _starpu_opencl_copy_ram_to_opencl_async_sync((void*)src_vector->ptr, (cl_mem)dst_vector->dev_handle,
  325. src_vector->nx*src_vector->elemsize,
  326. dst_vector->offset, (cl_event*)_event, &ret);
  327. if (STARPU_UNLIKELY(err))
  328. STARPU_OPENCL_REPORT_ERROR(err);
  329. STARPU_TRACE_DATA_COPY(src_node, dst_node, src_vector->nx*src_vector->elemsize);
  330. return ret;
  331. }
  332. static int copy_opencl_to_ram_async(void *src_interface, unsigned src_node __attribute__((unused)),
  333. void *dst_interface, unsigned dst_node __attribute__((unused)), void *_event)
  334. {
  335. starpu_vector_interface_t *src_vector = src_interface;
  336. starpu_vector_interface_t *dst_vector = dst_interface;
  337. int err, ret;
  338. err = _starpu_opencl_copy_opencl_to_ram_async_sync((cl_mem)src_vector->dev_handle, (void*)dst_vector->ptr, src_vector->nx*src_vector->elemsize,
  339. src_vector->offset, (cl_event *)_event, &ret);
  340. if (STARPU_UNLIKELY(err))
  341. STARPU_OPENCL_REPORT_ERROR(err);
  342. STARPU_TRACE_DATA_COPY(src_node, dst_node, src_vector->nx*src_vector->elemsize);
  343. return ret;
  344. }
  345. static int copy_ram_to_opencl(void *src_interface, unsigned src_node __attribute__((unused)),
  346. void *dst_interface, unsigned dst_node __attribute__((unused)))
  347. {
  348. return copy_ram_to_opencl_async(src_interface, src_node, dst_interface, dst_node, NULL);
  349. }
  350. static int copy_opencl_to_ram(void *src_interface, unsigned src_node __attribute__((unused)),
  351. void *dst_interface, unsigned dst_node __attribute__((unused)))
  352. {
  353. return copy_opencl_to_ram_async(src_interface, src_node, dst_interface, dst_node, NULL);
  354. }
  355. static int copy_opencl_to_opencl(void *src_interface, unsigned src_node __attribute__((unused)),
  356. void *dst_interface, unsigned dst_node __attribute__((unused)))
  357. {
  358. int err;
  359. starpu_vector_interface_t *src_vector = src_interface;
  360. starpu_vector_interface_t *dst_vector = dst_interface;
  361. cl_command_queue cq;
  362. starpu_opencl_get_current_queue(&cq);
  363. size_t size = src_vector->nx*src_vector->elemsize;
  364. err = clEnqueueCopyBuffer(cq, (cl_mem)src_vector->dev_handle, (cl_mem)dst_vector->dev_handle, src_vector->offset, dst_vector->offset, size, 0, NULL, NULL);
  365. if (STARPU_UNLIKELY(err))
  366. STARPU_OPENCL_REPORT_ERROR(err);
  367. STARPU_TRACE_DATA_COPY(src_node, dst_node, src_vector->nx*src_vector->elemsize);
  368. return 0;
  369. }
  370. #endif // STARPU_USE_OPENCL
  371. static int copy_ram_to_ram(void *src_interface, unsigned src_node __attribute__((unused)),
  372. void *dst_interface, unsigned dst_node __attribute__((unused)))
  373. {
  374. starpu_vector_interface_t *src_vector = src_interface;
  375. starpu_vector_interface_t *dst_vector = dst_interface;
  376. uint32_t nx = dst_vector->nx;
  377. size_t elemsize = dst_vector->elemsize;
  378. uintptr_t ptr_src = src_vector->ptr;
  379. uintptr_t ptr_dst = dst_vector->ptr;
  380. memcpy((void *)ptr_dst, (void *)ptr_src, nx*elemsize);
  381. STARPU_TRACE_DATA_COPY(src_node, dst_node, nx*elemsize);
  382. return 0;
  383. }