starpu_mpi.c 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  1. /* StarPU --- Runtime system for heterogeneous multicore architectures.
  2. *
  3. * Copyright (C) 2009, 2010-2012 Université de Bordeaux 1
  4. * Copyright (C) 2010, 2011, 2012, 2013 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 <stdlib.h>
  18. #include <starpu_mpi.h>
  19. #include <starpu_mpi_datatype.h>
  20. //#define STARPU_MPI_VERBOSE 1
  21. #include <starpu_mpi_private.h>
  22. #include <starpu_profiling.h>
  23. #include <starpu_mpi_stats.h>
  24. #include <starpu_mpi_insert_task.h>
  25. #ifdef STARPU_DEVEL
  26. # warning TODO find a better way to select the polling method (perhaps during the configuration)
  27. #endif
  28. //#define USE_STARPU_ACTIVITY 1
  29. static void _starpu_mpi_submit_new_mpi_request(void *arg);
  30. static void _starpu_mpi_handle_request_termination(struct _starpu_mpi_req *req);
  31. #ifdef STARPU_MPI_VERBOSE
  32. static char *_starpu_mpi_request_type(enum _starpu_mpi_request_type request_type);
  33. #endif
  34. static struct _starpu_mpi_req *_starpu_mpi_isend_common(starpu_data_handle_t data_handle,
  35. int dest, int mpi_tag, MPI_Comm comm,
  36. unsigned detached, void (*callback)(void *), void *arg);
  37. static struct _starpu_mpi_req *_starpu_mpi_irecv_common(starpu_data_handle_t data_handle, int source, int mpi_tag, MPI_Comm comm, unsigned detached, void (*callback)(void *), void *arg);
  38. static void _starpu_mpi_handle_detached_request(struct _starpu_mpi_req *req);
  39. /* The list of requests that have been newly submitted by the application */
  40. static struct _starpu_mpi_req_list *new_requests;
  41. /* The list of detached requests that have already been submitted to MPI */
  42. static struct _starpu_mpi_req_list *detached_requests;
  43. static _starpu_pthread_mutex_t detached_requests_mutex;
  44. /* Condition to wake up progression thread */
  45. static _starpu_pthread_cond_t cond_progression;
  46. /* Condition to wake up waiting for all current MPI requests to finish */
  47. static _starpu_pthread_cond_t cond_finished;
  48. static _starpu_pthread_mutex_t mutex;
  49. static pthread_t progress_thread;
  50. static int running = 0;
  51. /* Count requests posted by the application and not yet submitted to MPI, i.e pushed into the new_requests list */
  52. static _starpu_pthread_mutex_t mutex_posted_requests;
  53. static int posted_requests = 0, newer_requests, barrier_running = 0;
  54. #define _STARPU_MPI_INC_POSTED_REQUESTS(value) { _STARPU_PTHREAD_MUTEX_LOCK(&mutex_posted_requests); posted_requests += value; _STARPU_PTHREAD_MUTEX_UNLOCK(&mutex_posted_requests); }
  55. /********************************************************/
  56. /* */
  57. /* Send/Receive functionalities */
  58. /* */
  59. /********************************************************/
  60. static struct _starpu_mpi_req *_starpu_mpi_isend_irecv_common(starpu_data_handle_t data_handle,
  61. size_t size,
  62. int srcdst, int mpi_tag, MPI_Comm comm,
  63. unsigned detached, void (*callback)(void *), void *arg,
  64. enum _starpu_mpi_request_type request_type, void (*func)(struct _starpu_mpi_req *),
  65. enum starpu_access_mode mode)
  66. {
  67. _STARPU_MPI_LOG_IN();
  68. struct _starpu_mpi_req *req = calloc(1, sizeof(struct _starpu_mpi_req));
  69. STARPU_ASSERT(req);
  70. _STARPU_MPI_INC_POSTED_REQUESTS(1);
  71. /* Initialize the request structure */
  72. req->submitted = 0;
  73. req->completed = 0;
  74. _STARPU_PTHREAD_MUTEX_INIT(&req->req_mutex, NULL);
  75. _STARPU_PTHREAD_COND_INIT(&req->req_cond, NULL);
  76. req->request_type = request_type;
  77. req->data_handle = data_handle;
  78. req->count = size;
  79. req->srcdst = srcdst;
  80. req->mpi_tag = mpi_tag;
  81. req->comm = comm;
  82. req->detached = detached;
  83. req->callback = callback;
  84. req->callback_arg = arg;
  85. req->func = func;
  86. /* Asynchronously request StarPU to fetch the data in main memory: when
  87. * it is available in main memory, _starpu_mpi_submit_new_mpi_request(req) is called and
  88. * the request is actually submitted */
  89. starpu_data_acquire_cb(data_handle, mode, _starpu_mpi_submit_new_mpi_request, (void *)req);
  90. _STARPU_MPI_LOG_OUT();
  91. return req;
  92. }
  93. /********************************************************/
  94. /* */
  95. /* Send functionalities */
  96. /* */
  97. /********************************************************/
  98. static void _starpu_mpi_isend_data_func(struct _starpu_mpi_req *req)
  99. {
  100. _STARPU_MPI_LOG_IN();
  101. STARPU_ASSERT(req->ptr);
  102. _STARPU_MPI_DEBUG("post MPI isend tag %d dst %d ptr %p datatype %p count %d req %p\n", req->mpi_tag, req->srcdst, req->ptr, req->datatype, (int)req->count, &req->request);
  103. _starpu_mpi_comm_amounts_inc(req->comm, req->srcdst, req->datatype, req->count);
  104. req->ret = MPI_Isend(req->ptr, req->count, req->datatype, req->srcdst, req->mpi_tag, req->comm, &req->request);
  105. STARPU_ASSERT(req->ret == MPI_SUCCESS);
  106. TRACE_MPI_ISEND(req->srcdst, req->mpi_tag, 0);
  107. /* somebody is perhaps waiting for the MPI request to be posted */
  108. _STARPU_PTHREAD_MUTEX_LOCK(&req->req_mutex);
  109. req->submitted = 1;
  110. _STARPU_PTHREAD_COND_BROADCAST(&req->req_cond);
  111. _STARPU_PTHREAD_MUTEX_UNLOCK(&req->req_mutex);
  112. _starpu_mpi_handle_detached_request(req);
  113. _STARPU_MPI_LOG_OUT();
  114. }
  115. static void _starpu_mpi_isend_pack_func(struct _starpu_mpi_req *req)
  116. {
  117. _starpu_mpi_handle_allocate_datatype(req->data_handle, &req->datatype, &req->user_datatype);
  118. if (req->user_datatype == 0)
  119. {
  120. req->count = 1;
  121. req->ptr = starpu_handle_get_local_ptr(req->data_handle);
  122. _starpu_mpi_isend_data_func(req);
  123. }
  124. else
  125. {
  126. starpu_handle_pack_data(req->data_handle, &req->ptr, &req->count);
  127. _starpu_mpi_isend_data_func(req);
  128. }
  129. }
  130. static struct _starpu_mpi_req *_starpu_mpi_isend_common(starpu_data_handle_t data_handle,
  131. int dest, int mpi_tag, MPI_Comm comm,
  132. unsigned detached, void (*callback)(void *), void *arg)
  133. {
  134. enum starpu_data_interface_id id = starpu_handle_get_interface_id(data_handle);
  135. size_t size;
  136. size = starpu_handle_get_size(data_handle);
  137. if (id >= STARPU_MAX_INTERFACE_ID)
  138. {
  139. starpu_data_handle_t size_handle;
  140. starpu_variable_data_register(&size_handle, 0, (uintptr_t)&(size), sizeof(size));
  141. starpu_mpi_send(size_handle, dest, mpi_tag, comm);
  142. }
  143. return _starpu_mpi_isend_irecv_common(data_handle, size, dest, mpi_tag, comm, detached, callback, arg, SEND_REQ, _starpu_mpi_isend_pack_func, STARPU_R);
  144. }
  145. int starpu_mpi_isend(starpu_data_handle_t data_handle, starpu_mpi_req *public_req, int dest, int mpi_tag, MPI_Comm comm)
  146. {
  147. _STARPU_MPI_LOG_IN();
  148. STARPU_ASSERT(public_req);
  149. struct _starpu_mpi_req *req;
  150. req = _starpu_mpi_isend_common(data_handle, dest, mpi_tag, comm, 0, NULL, NULL);
  151. STARPU_ASSERT(req);
  152. *public_req = req;
  153. _STARPU_MPI_LOG_OUT();
  154. return 0;
  155. }
  156. int starpu_mpi_isend_detached(starpu_data_handle_t data_handle,
  157. int dest, int mpi_tag, MPI_Comm comm, void (*callback)(void *), void *arg)
  158. {
  159. _STARPU_MPI_LOG_IN();
  160. _starpu_mpi_isend_common(data_handle, dest, mpi_tag, comm, 1, callback, arg);
  161. _STARPU_MPI_LOG_OUT();
  162. return 0;
  163. }
  164. int starpu_mpi_send(starpu_data_handle_t data_handle, int dest, int mpi_tag, MPI_Comm comm)
  165. {
  166. starpu_mpi_req req;
  167. MPI_Status status;
  168. _STARPU_MPI_LOG_IN();
  169. memset(&status, 0, sizeof(MPI_Status));
  170. starpu_mpi_isend(data_handle, &req, dest, mpi_tag, comm);
  171. starpu_mpi_wait(&req, &status);
  172. _STARPU_MPI_LOG_OUT();
  173. return 0;
  174. }
  175. /********************************************************/
  176. /* */
  177. /* Receive functionalities */
  178. /* */
  179. /********************************************************/
  180. static void _starpu_mpi_irecv_data_func(struct _starpu_mpi_req *req)
  181. {
  182. _STARPU_MPI_LOG_IN();
  183. STARPU_ASSERT(req->ptr);
  184. _STARPU_MPI_DEBUG("post MPI irecv tag %d src %d data %p ptr %p datatype %p count %d req %p \n", req->mpi_tag, req->srcdst, req->data_handle, req->ptr, req->datatype, (int)req->count, &req->request);
  185. req->ret = MPI_Irecv(req->ptr, req->count, req->datatype, req->srcdst, req->mpi_tag, req->comm, &req->request);
  186. STARPU_ASSERT(req->ret == MPI_SUCCESS);
  187. /* somebody is perhaps waiting for the MPI request to be posted */
  188. _STARPU_PTHREAD_MUTEX_LOCK(&req->req_mutex);
  189. req->submitted = 1;
  190. _STARPU_PTHREAD_COND_BROADCAST(&req->req_cond);
  191. _STARPU_PTHREAD_MUTEX_UNLOCK(&req->req_mutex);
  192. _starpu_mpi_handle_detached_request(req);
  193. _STARPU_MPI_LOG_OUT();
  194. }
  195. static void _starpu_mpi_irecv_pack_func(struct _starpu_mpi_req *req)
  196. {
  197. _STARPU_MPI_LOG_IN();
  198. _starpu_mpi_handle_allocate_datatype(req->data_handle, &req->datatype, &req->user_datatype);
  199. if (req->user_datatype == 0)
  200. {
  201. req->count = 1;
  202. req->ptr = starpu_handle_get_local_ptr(req->data_handle);
  203. _starpu_mpi_irecv_data_func(req);
  204. }
  205. else
  206. {
  207. req->ptr = malloc(req->count);
  208. _starpu_mpi_irecv_data_func(req);
  209. }
  210. }
  211. static struct _starpu_mpi_req *_starpu_mpi_irecv_common(starpu_data_handle_t data_handle, int source, int mpi_tag, MPI_Comm comm, unsigned detached, void (*callback)(void *), void *arg)
  212. {
  213. enum starpu_data_interface_id id = starpu_handle_get_interface_id(data_handle);
  214. size_t size=0;
  215. if (id >= STARPU_MAX_INTERFACE_ID)
  216. {
  217. starpu_data_handle_t size_handle;
  218. MPI_Status status;
  219. starpu_variable_data_register(&size_handle, 0, (uintptr_t)&(size), sizeof(size));
  220. starpu_mpi_recv(size_handle, source, mpi_tag, comm, &status);
  221. starpu_data_unregister(size_handle);
  222. }
  223. return _starpu_mpi_isend_irecv_common(data_handle, size, source, mpi_tag, comm, detached, callback, arg, RECV_REQ, _starpu_mpi_irecv_pack_func, STARPU_W);
  224. }
  225. int starpu_mpi_irecv(starpu_data_handle_t data_handle, starpu_mpi_req *public_req, int source, int mpi_tag, MPI_Comm comm)
  226. {
  227. _STARPU_MPI_LOG_IN();
  228. STARPU_ASSERT(public_req);
  229. struct _starpu_mpi_req *req;
  230. req = _starpu_mpi_irecv_common(data_handle, source, mpi_tag, comm, 0, NULL, NULL);
  231. STARPU_ASSERT(req);
  232. *public_req = req;
  233. _STARPU_MPI_LOG_OUT();
  234. return 0;
  235. }
  236. int starpu_mpi_irecv_detached(starpu_data_handle_t data_handle, int source, int mpi_tag, MPI_Comm comm, void (*callback)(void *), void *arg)
  237. {
  238. _STARPU_MPI_LOG_IN();
  239. _starpu_mpi_irecv_common(data_handle, source, mpi_tag, comm, 1, callback, arg);
  240. _STARPU_MPI_LOG_OUT();
  241. return 0;
  242. }
  243. int starpu_mpi_recv(starpu_data_handle_t data_handle, int source, int mpi_tag, MPI_Comm comm, MPI_Status *status)
  244. {
  245. starpu_mpi_req req;
  246. _STARPU_MPI_LOG_IN();
  247. starpu_mpi_irecv(data_handle, &req, source, mpi_tag, comm);
  248. starpu_mpi_wait(&req, status);
  249. _STARPU_MPI_LOG_OUT();
  250. return 0;
  251. }
  252. static void _starpu_mpi_probe_func(struct _starpu_mpi_req *req)
  253. {
  254. _STARPU_MPI_LOG_IN();
  255. _starpu_mpi_handle_allocate_datatype(req->data_handle, &req->datatype, &req->user_datatype);
  256. #ifdef STARPU_DEVEL
  257. #warning TODO: release that assert
  258. #endif
  259. assert(req->user_datatype == 0);
  260. req->count = 1;
  261. req->ptr = starpu_handle_get_local_ptr(req->data_handle);
  262. _STARPU_MPI_DEBUG("MPI probe tag %d dst %d ptr %p datatype %p count %d req %p\n", req->mpi_tag, req->srcdst, req->ptr, req->datatype, (int)req->count, req);
  263. /* somebody is perhaps waiting for the MPI request to be posted */
  264. _STARPU_PTHREAD_MUTEX_LOCK(&req->req_mutex);
  265. req->submitted = 1;
  266. _STARPU_PTHREAD_COND_BROADCAST(&req->req_cond);
  267. _STARPU_PTHREAD_MUTEX_UNLOCK(&req->req_mutex);
  268. _starpu_mpi_handle_detached_request(req);
  269. _STARPU_MPI_LOG_OUT();
  270. }
  271. int starpu_mpi_irecv_probe_detached(starpu_data_handle_t data_handle, int source, int mpi_tag, MPI_Comm comm, void (*callback)(void *), void *arg)
  272. {
  273. size_t size;
  274. _STARPU_MPI_LOG_IN();
  275. size = starpu_handle_get_size(data_handle);
  276. _starpu_mpi_isend_irecv_common(data_handle, size, source, mpi_tag, comm, 1, callback, arg, PROBE_REQ, _starpu_mpi_probe_func, STARPU_W);
  277. _STARPU_MPI_LOG_OUT();
  278. return 0;
  279. }
  280. /********************************************************/
  281. /* */
  282. /* Wait functionalities */
  283. /* */
  284. /********************************************************/
  285. static void _starpu_mpi_wait_func(struct _starpu_mpi_req *waiting_req)
  286. {
  287. _STARPU_MPI_LOG_IN();
  288. /* Which is the mpi request we are waiting for ? */
  289. struct _starpu_mpi_req *req = waiting_req->other_request;
  290. req->ret = MPI_Wait(&req->request, waiting_req->status);
  291. STARPU_ASSERT(req->ret == MPI_SUCCESS);
  292. _starpu_mpi_handle_request_termination(req);
  293. _STARPU_MPI_LOG_OUT();
  294. }
  295. int starpu_mpi_wait(starpu_mpi_req *public_req, MPI_Status *status)
  296. {
  297. _STARPU_MPI_LOG_IN();
  298. int ret;
  299. struct _starpu_mpi_req *waiting_req = calloc(1, sizeof(struct _starpu_mpi_req));
  300. STARPU_ASSERT(waiting_req);
  301. struct _starpu_mpi_req *req = *public_req;
  302. _STARPU_MPI_INC_POSTED_REQUESTS(1);
  303. /* We cannot try to complete a MPI request that was not actually posted
  304. * to MPI yet. */
  305. _STARPU_PTHREAD_MUTEX_LOCK(&(req->req_mutex));
  306. while (!(req->submitted))
  307. _STARPU_PTHREAD_COND_WAIT(&(req->req_cond), &(req->req_mutex));
  308. _STARPU_PTHREAD_MUTEX_UNLOCK(&(req->req_mutex));
  309. /* Initialize the request structure */
  310. _STARPU_PTHREAD_MUTEX_INIT(&(waiting_req->req_mutex), NULL);
  311. _STARPU_PTHREAD_COND_INIT(&(waiting_req->req_cond), NULL);
  312. waiting_req->status = status;
  313. waiting_req->other_request = req;
  314. waiting_req->func = _starpu_mpi_wait_func;
  315. waiting_req->request_type = WAIT_REQ;
  316. _starpu_mpi_submit_new_mpi_request(waiting_req);
  317. /* We wait for the MPI request to finish */
  318. _STARPU_PTHREAD_MUTEX_LOCK(&req->req_mutex);
  319. while (!req->completed)
  320. _STARPU_PTHREAD_COND_WAIT(&req->req_cond, &req->req_mutex);
  321. _STARPU_PTHREAD_MUTEX_UNLOCK(&req->req_mutex);
  322. ret = req->ret;
  323. /* The internal request structure was automatically allocated */
  324. *public_req = NULL;
  325. free(req);
  326. free(waiting_req);
  327. _STARPU_MPI_LOG_OUT();
  328. return ret;
  329. }
  330. /********************************************************/
  331. /* */
  332. /* Test functionalities */
  333. /* */
  334. /********************************************************/
  335. static void _starpu_mpi_test_func(struct _starpu_mpi_req *testing_req)
  336. {
  337. _STARPU_MPI_LOG_IN();
  338. /* Which is the mpi request we are testing for ? */
  339. struct _starpu_mpi_req *req = testing_req->other_request;
  340. _STARPU_MPI_DEBUG("Test request %p - mpitag %d - TYPE %s %d\n", &req->request, req->mpi_tag, _starpu_mpi_request_type(req->request_type), req->srcdst);
  341. req->ret = MPI_Test(&req->request, testing_req->flag, testing_req->status);
  342. STARPU_ASSERT(req->ret == MPI_SUCCESS);
  343. if (*testing_req->flag)
  344. {
  345. testing_req->ret = req->ret;
  346. _starpu_mpi_handle_request_termination(req);
  347. }
  348. _STARPU_PTHREAD_MUTEX_LOCK(&testing_req->req_mutex);
  349. testing_req->completed = 1;
  350. _STARPU_PTHREAD_COND_SIGNAL(&testing_req->req_cond);
  351. _STARPU_PTHREAD_MUTEX_UNLOCK(&testing_req->req_mutex);
  352. _STARPU_MPI_LOG_OUT();
  353. }
  354. int starpu_mpi_test(starpu_mpi_req *public_req, int *flag, MPI_Status *status)
  355. {
  356. _STARPU_MPI_LOG_IN();
  357. int ret = 0;
  358. STARPU_ASSERT(public_req);
  359. struct _starpu_mpi_req *req = *public_req;
  360. STARPU_ASSERT(!req->detached);
  361. _STARPU_PTHREAD_MUTEX_LOCK(&req->req_mutex);
  362. unsigned submitted = req->submitted;
  363. _STARPU_PTHREAD_MUTEX_UNLOCK(&req->req_mutex);
  364. if (submitted)
  365. {
  366. struct _starpu_mpi_req *testing_req = calloc(1, sizeof(struct _starpu_mpi_req));
  367. STARPU_ASSERT(testing_req);
  368. // memset(testing_req, 0, sizeof(struct _starpu_mpi_req));
  369. /* Initialize the request structure */
  370. _STARPU_PTHREAD_MUTEX_INIT(&(testing_req->req_mutex), NULL);
  371. _STARPU_PTHREAD_COND_INIT(&(testing_req->req_cond), NULL);
  372. testing_req->flag = flag;
  373. testing_req->status = status;
  374. testing_req->other_request = req;
  375. testing_req->func = _starpu_mpi_test_func;
  376. testing_req->completed = 0;
  377. testing_req->request_type = TEST_REQ;
  378. _STARPU_MPI_INC_POSTED_REQUESTS(1);
  379. _starpu_mpi_submit_new_mpi_request(testing_req);
  380. /* We wait for the test request to finish */
  381. _STARPU_PTHREAD_MUTEX_LOCK(&(testing_req->req_mutex));
  382. while (!(testing_req->completed))
  383. _STARPU_PTHREAD_COND_WAIT(&(testing_req->req_cond), &(testing_req->req_mutex));
  384. _STARPU_PTHREAD_MUTEX_UNLOCK(&(testing_req->req_mutex));
  385. ret = testing_req->ret;
  386. if (*(testing_req->flag))
  387. {
  388. /* The request was completed so we free the internal
  389. * request structure which was automatically allocated
  390. * */
  391. *public_req = NULL;
  392. free(req);
  393. }
  394. free(testing_req);
  395. }
  396. else
  397. {
  398. *flag = 0;
  399. }
  400. _STARPU_MPI_LOG_OUT();
  401. return ret;
  402. }
  403. /********************************************************/
  404. /* */
  405. /* Barrier functionalities */
  406. /* */
  407. /********************************************************/
  408. static void _starpu_mpi_barrier_func(struct _starpu_mpi_req *barrier_req)
  409. {
  410. _STARPU_MPI_LOG_IN();
  411. barrier_req->ret = MPI_Barrier(barrier_req->comm);
  412. STARPU_ASSERT(barrier_req->ret == MPI_SUCCESS);
  413. _starpu_mpi_handle_request_termination(barrier_req);
  414. _STARPU_MPI_LOG_OUT();
  415. }
  416. int starpu_mpi_barrier(MPI_Comm comm)
  417. {
  418. _STARPU_MPI_LOG_IN();
  419. int ret;
  420. struct _starpu_mpi_req *barrier_req = calloc(1, sizeof(struct _starpu_mpi_req));
  421. STARPU_ASSERT(barrier_req);
  422. /* First wait for *both* all tasks and MPI requests to finish, in case
  423. * some tasks generate MPI requests, MPI requests generate tasks, etc.
  424. */
  425. _STARPU_PTHREAD_MUTEX_LOCK(&mutex);
  426. STARPU_ASSERT_MSG(!barrier_running, "Concurrent starpu_mpi_barrier is not implemented, even on different communicators");
  427. barrier_running = 1;
  428. do
  429. {
  430. while (posted_requests)
  431. /* Wait for all current MPI requests to finish */
  432. _STARPU_PTHREAD_COND_WAIT(&cond_finished, &mutex);
  433. /* No current request, clear flag */
  434. newer_requests = 0;
  435. _STARPU_PTHREAD_MUTEX_UNLOCK(&mutex);
  436. /* Now wait for all tasks */
  437. starpu_task_wait_for_all();
  438. _STARPU_PTHREAD_MUTEX_LOCK(&mutex);
  439. /* Check newer_requests again, in case some MPI requests
  440. * triggered by tasks completed and triggered tasks between
  441. * wait_for_all finished and we take the lock */
  442. } while (posted_requests || newer_requests);
  443. barrier_running = 0;
  444. _STARPU_PTHREAD_MUTEX_UNLOCK(&mutex);
  445. /* Initialize the request structure */
  446. _STARPU_PTHREAD_MUTEX_INIT(&(barrier_req->req_mutex), NULL);
  447. _STARPU_PTHREAD_COND_INIT(&(barrier_req->req_cond), NULL);
  448. barrier_req->func = _starpu_mpi_barrier_func;
  449. barrier_req->request_type = BARRIER_REQ;
  450. barrier_req->comm = comm;
  451. _STARPU_MPI_INC_POSTED_REQUESTS(1);
  452. _starpu_mpi_submit_new_mpi_request(barrier_req);
  453. /* We wait for the MPI request to finish */
  454. _STARPU_PTHREAD_MUTEX_LOCK(&barrier_req->req_mutex);
  455. while (!barrier_req->completed)
  456. _STARPU_PTHREAD_COND_WAIT(&barrier_req->req_cond, &barrier_req->req_mutex);
  457. _STARPU_PTHREAD_MUTEX_UNLOCK(&barrier_req->req_mutex);
  458. ret = barrier_req->ret;
  459. //free(waiting_req);
  460. _STARPU_MPI_LOG_OUT();
  461. return ret;
  462. }
  463. /********************************************************/
  464. /* */
  465. /* Progression */
  466. /* */
  467. /********************************************************/
  468. #ifdef STARPU_MPI_VERBOSE
  469. static char *_starpu_mpi_request_type(enum _starpu_mpi_request_type request_type)
  470. {
  471. switch (request_type)
  472. {
  473. case SEND_REQ: return "SEND_REQ";
  474. case RECV_REQ: return "RECV_REQ";
  475. case WAIT_REQ: return "WAIT_REQ";
  476. case TEST_REQ: return "TEST_REQ";
  477. case BARRIER_REQ: return "BARRIER_REQ";
  478. case PROBE_REQ: return "PROBE_REQ";
  479. default: return "unknown request type";
  480. }
  481. }
  482. #endif
  483. static void _starpu_mpi_handle_request_termination(struct _starpu_mpi_req *req)
  484. {
  485. _STARPU_MPI_LOG_IN();
  486. _STARPU_MPI_DEBUG("complete MPI req %p (%s) srcdst %d - data %p - tag %d - user datatype %d\n", req, _starpu_mpi_request_type(req->request_type), req->srcdst, req->data_handle, req->mpi_tag, req->user_datatype);
  487. if (req->request_type == PROBE_REQ)
  488. {
  489. #ifdef STARPU_DEVEL
  490. #warning TODO: instead of calling MPI_Recv, we should post a starpu mpi recv request
  491. #endif
  492. MPI_Status status;
  493. memset(&status, 0, sizeof(MPI_Status));
  494. req->ret = MPI_Recv(req->ptr, req->count, req->datatype, req->srcdst, req->mpi_tag, req->comm, &status);
  495. }
  496. if (req->request_type == RECV_REQ || req->request_type == SEND_REQ || req->request_type == PROBE_REQ)
  497. {
  498. if (req->user_datatype == 1)
  499. {
  500. if (req->request_type == RECV_REQ)
  501. // req->ptr is freed by starpu_handle_unpack_data
  502. starpu_handle_unpack_data(req->data_handle, req->ptr, req->count);
  503. else
  504. free(req->ptr);
  505. }
  506. else
  507. {
  508. _starpu_mpi_handle_free_datatype(req->data_handle, &req->datatype);
  509. }
  510. starpu_data_release(req->data_handle);
  511. }
  512. if (req->request_type == RECV_REQ || req->request_type == PROBE_REQ)
  513. {
  514. TRACE_MPI_IRECV_END(req->srcdst, req->mpi_tag);
  515. }
  516. /* Execute the specified callback, if any */
  517. if (req->callback)
  518. req->callback(req->callback_arg);
  519. /* tell anyone potentially waiting on the request that it is
  520. * terminated now */
  521. _STARPU_PTHREAD_MUTEX_LOCK(&req->req_mutex);
  522. req->completed = 1;
  523. _STARPU_PTHREAD_COND_BROADCAST(&req->req_cond);
  524. _STARPU_PTHREAD_MUTEX_UNLOCK(&req->req_mutex);
  525. _STARPU_MPI_LOG_OUT();
  526. }
  527. static void _starpu_mpi_submit_new_mpi_request(void *arg)
  528. {
  529. _STARPU_MPI_LOG_IN();
  530. struct _starpu_mpi_req *req = arg;
  531. _STARPU_MPI_INC_POSTED_REQUESTS(-1);
  532. _STARPU_PTHREAD_MUTEX_LOCK(&mutex);
  533. _starpu_mpi_req_list_push_front(new_requests, req);
  534. newer_requests = 1;
  535. _STARPU_MPI_DEBUG("Pushing new request type %p (%s)\n", req, _starpu_mpi_request_type(req->request_type));
  536. _STARPU_PTHREAD_COND_BROADCAST(&cond_progression);
  537. _STARPU_PTHREAD_MUTEX_UNLOCK(&mutex);
  538. _STARPU_MPI_LOG_OUT();
  539. }
  540. #ifdef USE_STARPU_ACTIVITY
  541. static unsigned _starpu_mpi_progression_hook_func(void *arg __attribute__((unused)))
  542. {
  543. unsigned may_block = 1;
  544. _STARPU_PTHREAD_MUTEX_LOCK(&mutex);
  545. if (!_starpu_mpi_req_list_empty(detached_requests))
  546. {
  547. _STARPU_PTHREAD_COND_SIGNAL(&cond_progression);
  548. may_block = 0;
  549. }
  550. _STARPU_PTHREAD_MUTEX_UNLOCK(&mutex);
  551. return may_block;
  552. }
  553. #endif
  554. static void _starpu_mpi_test_detached_requests(void)
  555. {
  556. _STARPU_MPI_LOG_IN();
  557. int flag;
  558. MPI_Status status;
  559. struct _starpu_mpi_req *req, *next_req;
  560. _STARPU_PTHREAD_MUTEX_LOCK(&detached_requests_mutex);
  561. for (req = _starpu_mpi_req_list_begin(detached_requests);
  562. req != _starpu_mpi_req_list_end(detached_requests);
  563. req = next_req)
  564. {
  565. next_req = _starpu_mpi_req_list_next(req);
  566. _STARPU_PTHREAD_MUTEX_UNLOCK(&detached_requests_mutex);
  567. //_STARPU_MPI_DEBUG("Test detached request %p - mpitag %d - TYPE %s %d\n", &req->request, req->mpi_tag, _starpu_mpi_request_type(req->request_type), req->srcdst);
  568. if (req->request_type == PROBE_REQ)
  569. {
  570. req->ret = MPI_Iprobe(req->srcdst, req->mpi_tag, req->comm, &flag, &status);
  571. }
  572. else
  573. {
  574. req->ret = MPI_Test(&req->request, &flag, &status);
  575. }
  576. STARPU_ASSERT(req->ret == MPI_SUCCESS);
  577. if (flag)
  578. {
  579. _starpu_mpi_handle_request_termination(req);
  580. }
  581. _STARPU_PTHREAD_MUTEX_LOCK(&detached_requests_mutex);
  582. if (flag)
  583. {
  584. _starpu_mpi_req_list_erase(detached_requests, req);
  585. free(req);
  586. }
  587. }
  588. _STARPU_PTHREAD_MUTEX_UNLOCK(&detached_requests_mutex);
  589. _STARPU_MPI_LOG_OUT();
  590. }
  591. static void _starpu_mpi_handle_detached_request(struct _starpu_mpi_req *req)
  592. {
  593. if (req->detached)
  594. {
  595. _STARPU_PTHREAD_MUTEX_LOCK(&mutex);
  596. _starpu_mpi_req_list_push_front(detached_requests, req);
  597. _STARPU_PTHREAD_MUTEX_UNLOCK(&mutex);
  598. starpu_wake_all_blocked_workers();
  599. /* put the submitted request into the list of pending requests
  600. * so that it can be handled by the progression mechanisms */
  601. _STARPU_PTHREAD_MUTEX_LOCK(&mutex);
  602. _STARPU_PTHREAD_COND_SIGNAL(&cond_progression);
  603. _STARPU_PTHREAD_MUTEX_UNLOCK(&mutex);
  604. }
  605. }
  606. static void _starpu_mpi_handle_new_request(struct _starpu_mpi_req *req)
  607. {
  608. _STARPU_MPI_LOG_IN();
  609. STARPU_ASSERT(req);
  610. /* submit the request to MPI */
  611. _STARPU_MPI_DEBUG("Handling new request type %p (%s)\n", req, _starpu_mpi_request_type(req->request_type));
  612. req->func(req);
  613. _STARPU_MPI_LOG_OUT();
  614. }
  615. struct _starpu_mpi_argc_argv
  616. {
  617. int initialize_mpi;
  618. int *argc;
  619. char ***argv;
  620. };
  621. static void _starpu_mpi_print_thread_level_support(int thread_level, char *msg)
  622. {
  623. switch (thread_level)
  624. {
  625. case MPI_THREAD_SERIALIZED:
  626. {
  627. _STARPU_DISP("MPI%s MPI_THREAD_SERIALIZED; Multiple threads may make MPI calls, but only one at a time.\n", msg);
  628. break;
  629. }
  630. case MPI_THREAD_FUNNELED:
  631. {
  632. _STARPU_DISP("MPI%s MPI_THREAD_FUNNELED; The application can safely make calls to StarPU-MPI functions, but should not call directly MPI communication functions.\n", msg);
  633. break;
  634. }
  635. case MPI_THREAD_SINGLE:
  636. {
  637. _STARPU_DISP("MPI%s MPI_THREAD_SINGLE; MPI does not have multi-thread support, this might cause problems. The application can make calls to StarPU-MPI functions, but not call directly MPI Communication functions.\n", msg);
  638. break;
  639. }
  640. }
  641. }
  642. static void *_starpu_mpi_progress_thread_func(void *arg)
  643. {
  644. struct _starpu_mpi_argc_argv *argc_argv = (struct _starpu_mpi_argc_argv *) arg;
  645. if (argc_argv->initialize_mpi)
  646. {
  647. int thread_support;
  648. _STARPU_DEBUG("Calling MPI_Init_thread\n");
  649. if (MPI_Init_thread(argc_argv->argc, argc_argv->argv, MPI_THREAD_SERIALIZED, &thread_support) != MPI_SUCCESS)
  650. {
  651. _STARPU_ERROR("MPI_Init_thread failed\n");
  652. }
  653. _starpu_mpi_print_thread_level_support(thread_support, "_Init_thread level =");
  654. }
  655. else
  656. {
  657. int provided;
  658. MPI_Query_thread(&provided);
  659. _starpu_mpi_print_thread_level_support(provided, " has been initialized with");
  660. }
  661. /* notify the main thread that the progression thread is ready */
  662. _STARPU_PTHREAD_MUTEX_LOCK(&mutex);
  663. running = 1;
  664. _STARPU_PTHREAD_COND_SIGNAL(&cond_progression);
  665. _STARPU_PTHREAD_MUTEX_UNLOCK(&mutex);
  666. _STARPU_PTHREAD_MUTEX_LOCK(&mutex);
  667. while (running || posted_requests || !(_starpu_mpi_req_list_empty(new_requests)) || !(_starpu_mpi_req_list_empty(detached_requests)))
  668. {
  669. /* shall we block ? */
  670. unsigned block = _starpu_mpi_req_list_empty(new_requests);
  671. #ifndef USE_STARPU_ACTIVITY
  672. block = block && _starpu_mpi_req_list_empty(detached_requests);
  673. #endif
  674. if (block)
  675. {
  676. _STARPU_MPI_DEBUG("NO MORE REQUESTS TO HANDLE\n");
  677. if (barrier_running)
  678. /* Tell mpi_barrier */
  679. _STARPU_PTHREAD_COND_SIGNAL(&cond_finished);
  680. _STARPU_PTHREAD_COND_WAIT(&cond_progression, &mutex);
  681. }
  682. /* test whether there are some terminated "detached request" */
  683. _STARPU_PTHREAD_MUTEX_UNLOCK(&mutex);
  684. _starpu_mpi_test_detached_requests();
  685. _STARPU_PTHREAD_MUTEX_LOCK(&mutex);
  686. /* get one request */
  687. struct _starpu_mpi_req *req;
  688. while (!_starpu_mpi_req_list_empty(new_requests))
  689. {
  690. req = _starpu_mpi_req_list_pop_back(new_requests);
  691. /* handling a request is likely to block for a while
  692. * (on a sync_data_with_mem call), we want to let the
  693. * application submit requests in the meantime, so we
  694. * release the lock. */
  695. _STARPU_PTHREAD_MUTEX_UNLOCK(&mutex);
  696. _starpu_mpi_handle_new_request(req);
  697. _STARPU_PTHREAD_MUTEX_LOCK(&mutex);
  698. }
  699. }
  700. STARPU_ASSERT(_starpu_mpi_req_list_empty(detached_requests));
  701. STARPU_ASSERT(_starpu_mpi_req_list_empty(new_requests));
  702. STARPU_ASSERT(posted_requests == 0);
  703. if (argc_argv->initialize_mpi)
  704. {
  705. _STARPU_MPI_DEBUG("Calling MPI_Finalize()\n");
  706. MPI_Finalize();
  707. }
  708. _STARPU_PTHREAD_MUTEX_UNLOCK(&mutex);
  709. free(argc_argv);
  710. return NULL;
  711. }
  712. /********************************************************/
  713. /* */
  714. /* (De)Initialization methods */
  715. /* */
  716. /********************************************************/
  717. #ifdef USE_STARPU_ACTIVITY
  718. static int hookid = - 1;
  719. #endif
  720. static void _starpu_mpi_add_sync_point_in_fxt(void)
  721. {
  722. #ifdef STARPU_USE_FXT
  723. int rank;
  724. int worldsize;
  725. MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  726. MPI_Comm_size(MPI_COMM_WORLD, &worldsize);
  727. int barrier_ret = MPI_Barrier(MPI_COMM_WORLD);
  728. STARPU_ASSERT(barrier_ret == MPI_SUCCESS);
  729. /* We generate a "unique" key so that we can make sure that different
  730. * FxT traces come from the same MPI run. */
  731. int random_number;
  732. /* XXX perhaps we don't want to generate a new seed if the application
  733. * specified some reproductible behaviour ? */
  734. if (rank == 0)
  735. {
  736. srand(time(NULL));
  737. random_number = rand();
  738. }
  739. MPI_Bcast(&random_number, 1, MPI_INT, 0, MPI_COMM_WORLD);
  740. TRACE_MPI_BARRIER(rank, worldsize, random_number);
  741. _STARPU_MPI_DEBUG("unique key %x\n", random_number);
  742. #endif
  743. }
  744. static
  745. int _starpu_mpi_initialize(int *argc, char ***argv, int initialize_mpi)
  746. {
  747. _STARPU_PTHREAD_MUTEX_INIT(&mutex, NULL);
  748. _STARPU_PTHREAD_COND_INIT(&cond_progression, NULL);
  749. _STARPU_PTHREAD_COND_INIT(&cond_finished, NULL);
  750. new_requests = _starpu_mpi_req_list_new();
  751. _STARPU_PTHREAD_MUTEX_INIT(&detached_requests_mutex, NULL);
  752. detached_requests = _starpu_mpi_req_list_new();
  753. _STARPU_PTHREAD_MUTEX_INIT(&mutex_posted_requests, NULL);
  754. struct _starpu_mpi_argc_argv *argc_argv = malloc(sizeof(struct _starpu_mpi_argc_argv));
  755. argc_argv->initialize_mpi = initialize_mpi;
  756. argc_argv->argc = argc;
  757. argc_argv->argv = argv;
  758. _STARPU_PTHREAD_CREATE("MPI progress", &progress_thread, NULL, _starpu_mpi_progress_thread_func, argc_argv);
  759. _STARPU_PTHREAD_MUTEX_LOCK(&mutex);
  760. while (!running)
  761. _STARPU_PTHREAD_COND_WAIT(&cond_progression, &mutex);
  762. _STARPU_PTHREAD_MUTEX_UNLOCK(&mutex);
  763. #ifdef STARPU_USE_FXT
  764. int prank;
  765. MPI_Comm_rank(MPI_COMM_WORLD, &prank);
  766. starpu_set_profiling_id(prank);
  767. #endif //STARPU_USE_FXT
  768. #ifdef USE_STARPU_ACTIVITY
  769. hookid = starpu_progression_hook_register(progression_hook_func, NULL);
  770. STARPU_ASSERT(hookid >= 0);
  771. #endif
  772. _starpu_mpi_add_sync_point_in_fxt();
  773. _starpu_mpi_comm_amounts_init(MPI_COMM_WORLD);
  774. _starpu_mpi_cache_init(MPI_COMM_WORLD);
  775. return 0;
  776. }
  777. int starpu_mpi_init(int *argc, char ***argv, int initialize_mpi)
  778. {
  779. return _starpu_mpi_initialize(argc, argv, initialize_mpi);
  780. }
  781. int starpu_mpi_initialize(void)
  782. {
  783. return _starpu_mpi_initialize(NULL, NULL, 0);
  784. }
  785. int starpu_mpi_initialize_extended(int *rank, int *world_size)
  786. {
  787. int ret;
  788. ret = _starpu_mpi_initialize(NULL, NULL, 1);
  789. if (ret == 0)
  790. {
  791. _STARPU_DEBUG("Calling MPI_Comm_rank\n");
  792. MPI_Comm_rank(MPI_COMM_WORLD, rank);
  793. MPI_Comm_size(MPI_COMM_WORLD, world_size);
  794. }
  795. return ret;
  796. }
  797. int starpu_mpi_shutdown(void)
  798. {
  799. void *value;
  800. int rank, world_size;
  801. /* We need to get the rank before calling MPI_Finalize to pass to _starpu_mpi_comm_amounts_display() */
  802. MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  803. MPI_Comm_size(MPI_COMM_WORLD, &world_size);
  804. /* kill the progression thread */
  805. _STARPU_PTHREAD_MUTEX_LOCK(&mutex);
  806. running = 0;
  807. _STARPU_PTHREAD_COND_BROADCAST(&cond_progression);
  808. _STARPU_PTHREAD_MUTEX_UNLOCK(&mutex);
  809. pthread_join(progress_thread, &value);
  810. #ifdef USE_STARPU_ACTIVITY
  811. starpu_progression_hook_deregister(hookid);
  812. #endif
  813. /* free the request queues */
  814. _starpu_mpi_req_list_delete(detached_requests);
  815. _starpu_mpi_req_list_delete(new_requests);
  816. _starpu_mpi_comm_amounts_display(rank);
  817. _starpu_mpi_comm_amounts_free();
  818. _starpu_mpi_cache_free(world_size);
  819. return 0;
  820. }