parallel_eager.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. /* StarPU --- Runtime system for heterogeneous multicore architectures.
  2. *
  3. * Copyright (C) 2011-2013,2015,2017,2018 Inria
  4. * Copyright (C) 2011-2014,2016-2018 CNRS
  5. * Copyright (C) 2011-2016,2018 Université de Bordeaux
  6. * Copyright (C) 2013 Thibaut Lambert
  7. * Copyright (C) 2011 Télécom-SudParis
  8. *
  9. * StarPU is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU Lesser General Public License as published by
  11. * the Free Software Foundation; either version 2.1 of the License, or (at
  12. * your option) any later version.
  13. *
  14. * StarPU is distributed in the hope that it will be useful, but
  15. * WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. *
  18. * See the GNU Lesser General Public License in COPYING.LGPL for more details.
  19. */
  20. #include <sched_policies/fifo_queues.h>
  21. #include <core/detect_combined_workers.h>
  22. #include <starpu_scheduler.h>
  23. #include <core/workers.h>
  24. struct _starpu_peager_common_data
  25. {
  26. int possible_combinations_cnt[STARPU_NMAXWORKERS];
  27. int *possible_combinations[STARPU_NMAXWORKERS];
  28. int *possible_combinations_size[STARPU_NMAXWORKERS];
  29. int max_combination_size[STARPU_NMAXWORKERS];
  30. int no_combined_workers;
  31. int ref_count;
  32. };
  33. struct _starpu_peager_common_data *_peager_common_data = NULL;
  34. struct _starpu_peager_data
  35. {
  36. starpu_pthread_mutex_t policy_mutex;
  37. struct _starpu_fifo_taskq *fifo;
  38. struct _starpu_fifo_taskq *local_fifo[STARPU_NMAXWORKERS];
  39. };
  40. static void initialize_peager_common(void)
  41. {
  42. if (_peager_common_data == NULL)
  43. {
  44. struct _starpu_peager_common_data *common_data = NULL;
  45. _STARPU_CALLOC(common_data, 1, sizeof(struct _starpu_peager_common_data));
  46. common_data->ref_count = 1;
  47. _peager_common_data = common_data;
  48. const unsigned nbasic_workers = starpu_worker_get_count();
  49. int basic_workerids[nbasic_workers];
  50. unsigned i;
  51. for(i = 0; i < nbasic_workers; i++)
  52. {
  53. basic_workerids[i] = i;
  54. }
  55. _starpu_sched_find_worker_combinations(basic_workerids, nbasic_workers);
  56. const unsigned ncombined_workers = starpu_combined_worker_get_count();
  57. common_data->no_combined_workers = ncombined_workers == 0;
  58. for(i = 0; i < nbasic_workers; i++)
  59. {
  60. common_data->possible_combinations_cnt[i] = 0;
  61. int cnt = common_data->possible_combinations_cnt[i]++;
  62. /* Allocate ncombined_workers + 1 for the singleton worker itself */
  63. _STARPU_CALLOC(common_data->possible_combinations[i], 1+ncombined_workers, sizeof(int));
  64. _STARPU_CALLOC(common_data->possible_combinations_size[i], 1+ncombined_workers, sizeof(int));
  65. common_data->possible_combinations[i][cnt] = i;
  66. common_data->possible_combinations_size[i][cnt] = 1;
  67. common_data->max_combination_size[i] = 1;
  68. }
  69. for (i = 0; i < ncombined_workers; i++)
  70. {
  71. unsigned combined_workerid = nbasic_workers + i;
  72. int *workers;
  73. int size;
  74. starpu_combined_worker_get_description(combined_workerid, &size, &workers);
  75. int master = workers[0];
  76. if (size > common_data->max_combination_size[master])
  77. {
  78. common_data->max_combination_size[master] = size;
  79. }
  80. int cnt = common_data->possible_combinations_cnt[master]++;
  81. common_data->possible_combinations[master][cnt] = combined_workerid;
  82. common_data->possible_combinations_size[master][cnt] = size;
  83. }
  84. }
  85. else
  86. {
  87. _peager_common_data->ref_count++;
  88. }
  89. }
  90. static void deinitialize_peager_common(void)
  91. {
  92. STARPU_ASSERT(_peager_common_data != NULL);
  93. _peager_common_data->ref_count--;
  94. if (_peager_common_data->ref_count == 0)
  95. {
  96. const unsigned nbasic_workers = starpu_worker_get_count();
  97. unsigned i;
  98. for(i = 0; i < nbasic_workers; i++)
  99. {
  100. free(_peager_common_data->possible_combinations[i]);
  101. _peager_common_data->possible_combinations[i] = NULL;
  102. free(_peager_common_data->possible_combinations_size[i]);
  103. _peager_common_data->possible_combinations_size[i] = NULL;
  104. }
  105. free(_peager_common_data);
  106. _peager_common_data = NULL;
  107. }
  108. }
  109. static void peager_add_workers(unsigned sched_ctx_id, int *workerids, unsigned nworkers)
  110. {
  111. if (sched_ctx_id == 0)
  112. {
  113. /* FIXME Fix scheduling contexts initialization or combined
  114. * worker management, to make the initialize_peager_common()
  115. * call to work right from initialize_peager_policy. For now,
  116. * this fails because it causes combined workers to be generated
  117. * too early. */
  118. initialize_peager_common();
  119. }
  120. struct _starpu_peager_data *data = (struct _starpu_peager_data*)starpu_sched_ctx_get_policy_data(sched_ctx_id);
  121. unsigned i;
  122. for(i = 0; i < nworkers; i++)
  123. {
  124. unsigned workerid = workerids[i];
  125. if(starpu_worker_is_combined_worker(workerid))
  126. {
  127. continue;
  128. }
  129. starpu_sched_ctx_worker_shares_tasks_lists(workerid, sched_ctx_id);
  130. /* slaves pick up tasks from their local queue, their master
  131. * will put tasks directly in that local list when a parallel
  132. * tasks comes. */
  133. data->local_fifo[workerid] = _starpu_create_fifo();
  134. }
  135. }
  136. static void peager_remove_workers(unsigned sched_ctx_id, int *workerids, unsigned nworkers)
  137. {
  138. struct _starpu_peager_data *data = (struct _starpu_peager_data*)starpu_sched_ctx_get_policy_data(sched_ctx_id);
  139. unsigned i;
  140. for(i = 0; i < nworkers; i++)
  141. {
  142. int workerid = workerids[i];
  143. if(!starpu_worker_is_combined_worker(workerid))
  144. {
  145. _starpu_destroy_fifo(data->local_fifo[workerid]);
  146. }
  147. }
  148. if (sched_ctx_id == 0)
  149. {
  150. deinitialize_peager_common();
  151. }
  152. }
  153. static void initialize_peager_policy(unsigned sched_ctx_id)
  154. {
  155. struct _starpu_peager_data *data;
  156. _STARPU_CALLOC(data, 1, sizeof(struct _starpu_peager_data));
  157. /* masters pick tasks from that queue */
  158. data->fifo = _starpu_create_fifo();
  159. starpu_sched_ctx_set_policy_data(sched_ctx_id, (void*)data);
  160. STARPU_PTHREAD_MUTEX_INIT(&data->policy_mutex, NULL);
  161. }
  162. static void deinitialize_peager_policy(unsigned sched_ctx_id)
  163. {
  164. /* TODO check that there is no task left in the queue */
  165. struct _starpu_peager_data *data = (struct _starpu_peager_data*)starpu_sched_ctx_get_policy_data(sched_ctx_id);
  166. /* deallocate the job queue */
  167. _starpu_destroy_fifo(data->fifo);
  168. STARPU_PTHREAD_MUTEX_DESTROY(&data->policy_mutex);
  169. free(data);
  170. }
  171. static int push_task_peager_policy(struct starpu_task *task)
  172. {
  173. unsigned sched_ctx_id = task->sched_ctx;
  174. int ret_val;
  175. struct _starpu_peager_data *data = (struct _starpu_peager_data*)starpu_sched_ctx_get_policy_data(sched_ctx_id);
  176. STARPU_PTHREAD_MUTEX_LOCK(&data->policy_mutex);
  177. ret_val = _starpu_fifo_push_task(data->fifo, task);
  178. #ifndef STARPU_NON_BLOCKING_DRIVERS
  179. int is_parallel_task = task->cl && task->cl->max_parallelism > 1;
  180. #endif
  181. starpu_push_task_end(task);
  182. STARPU_PTHREAD_MUTEX_UNLOCK(&data->policy_mutex);
  183. #ifndef STARPU_NON_BLOCKING_DRIVERS
  184. struct _starpu_peager_common_data *common_data = _peager_common_data;
  185. /* if there are no tasks block */
  186. /* wake people waiting for a task */
  187. struct starpu_worker_collection *workers = starpu_sched_ctx_get_worker_collection(sched_ctx_id);
  188. struct starpu_sched_ctx_iterator it;
  189. workers->init_iterator(workers, &it);
  190. while(workers->has_next(workers, &it))
  191. {
  192. int workerid = workers->get_next(workers, &it);
  193. /* If this is not a CPU or a MIC, then the workerid simply grabs tasks from the fifo */
  194. if (starpu_worker_is_combined_worker(workerid))
  195. {
  196. continue;
  197. }
  198. if (starpu_worker_get_type(workerid) != STARPU_MIC_WORKER
  199. && starpu_worker_get_type(workerid) != STARPU_CPU_WORKER)
  200. {
  201. starpu_wake_worker_relax_light(workerid);
  202. continue;
  203. }
  204. if ((!is_parallel_task) /* This is not a parallel task, can wake any workerid */
  205. || (common_data->no_combined_workers) /* There is no combined workerid */
  206. || (common_data->max_combination_size[workerid] > 1) /* This is a combined workerid master and the task is parallel */
  207. )
  208. {
  209. starpu_wake_worker_relax_light(workerid);
  210. }
  211. }
  212. #endif
  213. return ret_val;
  214. }
  215. static struct starpu_task *pop_task_peager_policy(unsigned sched_ctx_id)
  216. {
  217. struct _starpu_peager_common_data *common_data = _peager_common_data;
  218. struct _starpu_peager_data *data = (struct _starpu_peager_data*)starpu_sched_ctx_get_policy_data(sched_ctx_id);
  219. int workerid = starpu_worker_get_id_check();
  220. /* If this is not a CPU or a MIC, then the worker simply grabs tasks from the fifo */
  221. if (starpu_worker_get_type(workerid) != STARPU_CPU_WORKER && starpu_worker_get_type(workerid) != STARPU_MIC_WORKER)
  222. {
  223. struct starpu_task *task = NULL;
  224. _starpu_worker_relax_on();
  225. STARPU_PTHREAD_MUTEX_LOCK(&data->policy_mutex);
  226. _starpu_worker_relax_off();
  227. task = _starpu_fifo_pop_task(data->fifo, workerid);
  228. STARPU_PTHREAD_MUTEX_UNLOCK(&data->policy_mutex);
  229. return task;
  230. }
  231. struct starpu_task *task = NULL;
  232. int slave_task = 0;
  233. _starpu_worker_relax_on();
  234. STARPU_PTHREAD_MUTEX_LOCK(&data->policy_mutex);
  235. _starpu_worker_relax_off();
  236. /* check if a slave task is available in the local queue */
  237. task = _starpu_fifo_pop_task(data->local_fifo[workerid], workerid);
  238. if (!task)
  239. {
  240. /* no slave task, try to pop a task as master */
  241. task = _starpu_fifo_pop_task(data->fifo, workerid);
  242. if (task)
  243. {
  244. _STARPU_DEBUG("poping master task %p\n", task);
  245. }
  246. #if 1
  247. /* Optional heuristic to filter out purely slave workers for parallel tasks */
  248. if (task && task->cl && task->cl->max_parallelism > 1 && common_data->max_combination_size[workerid] == 1 && !common_data->no_combined_workers)
  249. {
  250. /* task is potentially parallel, leave it for a combined worker master */
  251. _STARPU_DEBUG("pushing back master task %p\n", task);
  252. _starpu_fifo_push_back_task(data->fifo, task);
  253. task = NULL;
  254. }
  255. #endif
  256. }
  257. else
  258. {
  259. slave_task = 1;
  260. _STARPU_DEBUG("poping slave task %p\n", task);
  261. }
  262. if (!task || slave_task)
  263. {
  264. STARPU_PTHREAD_MUTEX_UNLOCK(&data->policy_mutex);
  265. goto ret;
  266. }
  267. /* Find the largest compatible worker combination */
  268. int best_size = -1;
  269. int best_workerid = -1;
  270. int i;
  271. for (i = 0; i < common_data->possible_combinations_cnt[workerid]; i++)
  272. {
  273. if (common_data->possible_combinations_size[workerid][i] > best_size)
  274. {
  275. int combined_worker = common_data->possible_combinations[workerid][i];
  276. if (starpu_combined_worker_can_execute_task(combined_worker, task, 0))
  277. {
  278. best_size = common_data->possible_combinations_size[workerid][i];
  279. best_workerid = combined_worker;
  280. }
  281. }
  282. }
  283. _STARPU_DEBUG("task %p, best_workerid=%d, best_size=%d\n", task, best_workerid, best_size);
  284. /* In case nobody can execute this task, we let the master
  285. * worker take it anyway, so that it can discard it afterward.
  286. * */
  287. if (best_workerid == -1)
  288. {
  289. STARPU_PTHREAD_MUTEX_UNLOCK(&data->policy_mutex);
  290. goto ret;
  291. }
  292. /* Is this a basic worker or a combined worker ? */
  293. if (best_workerid < (int) starpu_worker_get_count())
  294. {
  295. STARPU_PTHREAD_MUTEX_UNLOCK(&data->policy_mutex);
  296. /* The master is alone */
  297. goto ret;
  298. }
  299. starpu_parallel_task_barrier_init(task, best_workerid);
  300. int worker_size = 0;
  301. int *combined_workerid;
  302. starpu_combined_worker_get_description(best_workerid, &worker_size, &combined_workerid);
  303. _STARPU_DEBUG("dispatching task %p on combined worker %d of size %d\n", task, best_workerid, worker_size);
  304. /* Dispatch task aliases to the different slaves */
  305. for (i = 1; i < worker_size; i++)
  306. {
  307. struct starpu_task *alias = starpu_task_dup(task);
  308. int local_worker = combined_workerid[i];
  309. alias->destroy = 1;
  310. _STARPU_TRACE_JOB_PUSH(alias, alias->priority > 0);
  311. _starpu_fifo_push_task(data->local_fifo[local_worker], alias);
  312. }
  313. /* The master also manipulated an alias */
  314. struct starpu_task *master_alias = starpu_task_dup(task);
  315. master_alias->destroy = 1;
  316. task = master_alias;
  317. STARPU_PTHREAD_MUTEX_UNLOCK(&data->policy_mutex);
  318. _STARPU_TRACE_JOB_PUSH(master_alias, master_alias->priority > 0);
  319. for (i = 1; i < worker_size; i++)
  320. {
  321. int local_worker = combined_workerid[i];
  322. _starpu_worker_lock(local_worker);
  323. #if !defined(STARPU_NON_BLOCKING_DRIVERS) || defined(STARPU_SIMGRID)
  324. starpu_wake_worker_locked(local_worker);
  325. #endif
  326. _starpu_worker_unlock(local_worker);
  327. }
  328. ret:
  329. return task;
  330. }
  331. struct starpu_sched_policy _starpu_sched_peager_policy =
  332. {
  333. .init_sched = initialize_peager_policy,
  334. .deinit_sched = deinitialize_peager_policy,
  335. .add_workers = peager_add_workers,
  336. .remove_workers = peager_remove_workers,
  337. .push_task = push_task_peager_policy,
  338. .pop_task = pop_task_peager_policy,
  339. .pre_exec_hook = NULL,
  340. .post_exec_hook = NULL,
  341. .pop_every_task = NULL,
  342. .policy_name = "peager",
  343. .policy_description = "parallel eager policy",
  344. .worker_type = STARPU_WORKER_LIST,
  345. };