component_sched.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. /* StarPU --- Runtime system for heterogeneous multicore architectures.
  2. *
  3. * Copyright (C) 2013,2014,2017 Inria
  4. * Copyright (C) 2014-2017 CNRS
  5. * Copyright (C) 2014-2019 Université de Bordeaux
  6. * Copyright (C) 2013 Simon Archipoff
  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 <core/jobs.h>
  20. #include <core/workers.h>
  21. #include <starpu_sched_component.h>
  22. #include <starpu_thread_util.h>
  23. #include <float.h>
  24. #include "sched_component.h"
  25. /******************************************************************************
  26. * Generic Scheduling Components' helper functions *
  27. ******************************************************************************/
  28. /* this function find the best implementation or an implementation that need to be calibrated for a worker available
  29. * and set prediction in *length. nan if a implementation need to be calibrated, 0.0 if no perf model are available
  30. * return false if no worker on the component can execute that task
  31. */
  32. int starpu_sched_component_execute_preds(struct starpu_sched_component * component, struct starpu_task * task, double * length)
  33. {
  34. STARPU_ASSERT(component && task);
  35. int can_execute = 0;
  36. starpu_task_bundle_t bundle = task->bundle;
  37. double len = DBL_MAX;
  38. int workerid;
  39. for(workerid = starpu_bitmap_first(component->workers_in_ctx);
  40. workerid != -1;
  41. workerid = starpu_bitmap_next(component->workers_in_ctx, workerid))
  42. {
  43. struct starpu_perfmodel_arch* archtype = starpu_worker_get_perf_archtype(workerid, component->tree->sched_ctx_id);
  44. int nimpl;
  45. for(nimpl = 0; nimpl < STARPU_MAXIMPLEMENTATIONS; nimpl++)
  46. {
  47. if(starpu_worker_can_execute_task(workerid,task,nimpl)
  48. || starpu_combined_worker_can_execute_task(workerid, task, nimpl))
  49. {
  50. double d;
  51. can_execute = 1;
  52. if(bundle)
  53. d = starpu_task_bundle_expected_length(bundle, archtype, nimpl);
  54. else
  55. d = starpu_task_expected_length(task, archtype, nimpl);
  56. if(isnan(d))
  57. {
  58. *length = d;
  59. return can_execute;
  60. }
  61. if(_STARPU_IS_ZERO(d))
  62. {
  63. continue;
  64. }
  65. STARPU_ASSERT_MSG(d >= 0, "workerid=%d, nimpl=%d, bundle=%p, d=%lf\n", workerid, nimpl, bundle, d);
  66. if(d < len)
  67. {
  68. len = d;
  69. }
  70. }
  71. }
  72. if(STARPU_SCHED_COMPONENT_IS_HOMOGENEOUS(component))
  73. break;
  74. }
  75. if(len == DBL_MAX) /* we dont have perf model */
  76. len = 0.0;
  77. if(length)
  78. *length = len;
  79. return can_execute;
  80. }
  81. /* very similar function that dont compute prediction */
  82. int starpu_sched_component_can_execute_task(struct starpu_sched_component * component, struct starpu_task * task)
  83. {
  84. STARPU_ASSERT(task);
  85. STARPU_ASSERT(component);
  86. unsigned nimpl;
  87. int worker;
  88. for (nimpl = 0; nimpl < STARPU_MAXIMPLEMENTATIONS; nimpl++)
  89. for(worker = starpu_bitmap_first(component->workers_in_ctx);
  90. -1 != worker;
  91. worker = starpu_bitmap_next(component->workers_in_ctx, worker))
  92. if (starpu_worker_can_execute_task(worker, task, nimpl)
  93. || starpu_combined_worker_can_execute_task(worker, task, nimpl))
  94. return 1;
  95. return 0;
  96. }
  97. /* compute the average of transfer length for tasks on all workers
  98. * maybe this should be optimised if all workers are under the same numa component
  99. */
  100. double starpu_sched_component_transfer_length(struct starpu_sched_component * component, struct starpu_task * task)
  101. {
  102. STARPU_ASSERT(component && task);
  103. int nworkers = starpu_bitmap_cardinal(component->workers_in_ctx);
  104. double sum = 0.0;
  105. int worker;
  106. if(STARPU_SCHED_COMPONENT_IS_SINGLE_MEMORY_NODE(component))
  107. {
  108. unsigned memory_node = starpu_worker_get_memory_node(starpu_bitmap_first(component->workers_in_ctx));
  109. if(task->bundle)
  110. return starpu_task_bundle_expected_data_transfer_time(task->bundle,memory_node);
  111. else
  112. return starpu_task_expected_data_transfer_time(memory_node, task);
  113. }
  114. for(worker = starpu_bitmap_first(component->workers_in_ctx);
  115. worker != -1;
  116. worker = starpu_bitmap_next(component->workers_in_ctx, worker))
  117. {
  118. unsigned memory_node = starpu_worker_get_memory_node(worker);
  119. if(task->bundle)
  120. {
  121. sum += starpu_task_bundle_expected_data_transfer_time(task->bundle,memory_node);
  122. }
  123. else
  124. {
  125. sum += starpu_task_expected_data_transfer_time(memory_node, task);
  126. /* sum += starpu_task_expected_conversion_time(task, starpu_worker_get_perf_archtype(worker, component->tree->sched_ctx_id), impl ?)
  127. * I dont know what to do as we dont know what implementation would be used here...
  128. */
  129. }
  130. }
  131. return sum / nworkers;
  132. }
  133. /* This function can be called by components when they think that a prefetching request can be submitted.
  134. * For example, it is currently used by the MCT component to begin the prefetching on accelerators
  135. * on which it pushed tasks as soon as possible.
  136. */
  137. void starpu_sched_component_prefetch_on_node(struct starpu_sched_component * component, struct starpu_task * task)
  138. {
  139. if (starpu_get_prefetch_flag() && (!task->prefetched)
  140. && (component->properties & STARPU_SCHED_COMPONENT_SINGLE_MEMORY_NODE))
  141. {
  142. int worker = starpu_bitmap_first(component->workers_in_ctx);
  143. unsigned memory_node = starpu_worker_get_memory_node(worker);
  144. starpu_prefetch_task_input_on_node(task, memory_node);
  145. task->prefetched = 1;
  146. }
  147. }
  148. /* remove all child
  149. * for all child of component, if child->parents[x] == component, set child->parents[x] to null
  150. * call component->deinit_data
  151. */
  152. void starpu_sched_component_destroy(struct starpu_sched_component *component)
  153. {
  154. STARPU_ASSERT(component);
  155. unsigned i,j;
  156. for(i = 0; i < component->nchildren; i++)
  157. {
  158. struct starpu_sched_component * child = component->children[i];
  159. for(j = 0; j < child->nparents; j++)
  160. if(child->parents[j] == component)
  161. child->remove_parent(child,component);
  162. }
  163. while(component->nchildren != 0)
  164. component->remove_child(component, component->children[0]);
  165. for(i = 0; i < component->nparents; i++)
  166. {
  167. struct starpu_sched_component * parent = component->parents[i];
  168. for(j = 0; j < parent->nchildren; j++)
  169. if(parent->children[j] == component)
  170. parent->remove_child(parent,component);
  171. }
  172. while(component->nparents != 0)
  173. component->remove_parent(component, component->parents[0]);
  174. component->deinit_data(component);
  175. free(component->children);
  176. free(component->parents);
  177. free(component->name);
  178. starpu_bitmap_destroy(component->workers);
  179. starpu_bitmap_destroy(component->workers_in_ctx);
  180. free(component);
  181. }
  182. void starpu_sched_component_destroy_rec(struct starpu_sched_component * component)
  183. {
  184. if(component == NULL)
  185. return;
  186. unsigned i = 0;
  187. while(i < component->nchildren)
  188. {
  189. if (starpu_sched_component_is_worker(component->children[i]))
  190. i++;
  191. else
  192. starpu_sched_component_destroy_rec(component->children[i]);
  193. }
  194. if (!starpu_sched_component_is_worker(component))
  195. starpu_sched_component_destroy(component);
  196. }
  197. void set_properties(struct starpu_sched_component * component)
  198. {
  199. STARPU_ASSERT(component);
  200. component->properties = 0;
  201. int worker = starpu_bitmap_first(component->workers_in_ctx);
  202. if (worker == -1)
  203. return;
  204. if (starpu_worker_is_combined_worker(worker))
  205. return;
  206. #ifdef STARPU_DEVEL
  207. #warning FIXME: Not all CUDA devices have the same speed
  208. #endif
  209. uint32_t first_worker = _starpu_get_worker_struct(worker)->worker_mask;
  210. unsigned first_memory_node = _starpu_get_worker_struct(worker)->memory_node;
  211. int is_homogeneous = 1;
  212. int is_all_same_component = 1;
  213. for(;
  214. worker != -1;
  215. worker = starpu_bitmap_next(component->workers_in_ctx, worker))
  216. {
  217. if(starpu_worker_is_combined_worker(worker))
  218. continue;
  219. if(first_worker != _starpu_get_worker_struct(worker)->worker_mask)
  220. is_homogeneous = 0;
  221. if(first_memory_node != _starpu_get_worker_struct(worker)->memory_node)
  222. is_all_same_component = 0;
  223. }
  224. if(is_homogeneous)
  225. component->properties |= STARPU_SCHED_COMPONENT_HOMOGENEOUS;
  226. if(is_all_same_component)
  227. component->properties |= STARPU_SCHED_COMPONENT_SINGLE_MEMORY_NODE;
  228. }
  229. /* recursively set the component->workers member of component's subtree
  230. */
  231. void _starpu_sched_component_update_workers(struct starpu_sched_component * component)
  232. {
  233. STARPU_ASSERT(component);
  234. if(starpu_sched_component_is_worker(component))
  235. return;
  236. starpu_bitmap_unset_all(component->workers);
  237. unsigned i;
  238. for(i = 0; i < component->nchildren; i++)
  239. {
  240. _starpu_sched_component_update_workers(component->children[i]);
  241. starpu_bitmap_or(component->workers, component->children[i]->workers);
  242. }
  243. component->notify_change_workers(component);
  244. }
  245. /* recursively set the component->workers_in_ctx in component's subtree
  246. */
  247. void _starpu_sched_component_update_workers_in_ctx(struct starpu_sched_component * component, unsigned sched_ctx_id)
  248. {
  249. STARPU_ASSERT(component);
  250. /* worker components are shared among sched_ctxs, thus we do not apply the sched_ctx worker mask to them.
  251. * per-ctx filtering is performed higher in the tree */
  252. if(starpu_sched_component_is_worker(component))
  253. return;
  254. struct starpu_bitmap * workers_in_ctx = _starpu_get_worker_mask(sched_ctx_id);
  255. starpu_bitmap_unset_and(component->workers_in_ctx,component->workers, workers_in_ctx);
  256. unsigned i,j;
  257. for(i = starpu_worker_get_count(); i < starpu_worker_get_count() + starpu_combined_worker_get_count(); i++) {
  258. if (starpu_bitmap_get(component->workers, i)) {
  259. /* Component has this combined worker, check whether the
  260. * context has all the corresponding workers */
  261. int worker_size;
  262. int *combined_workerid;
  263. starpu_combined_worker_get_description(i, &worker_size, &combined_workerid);
  264. for (j = 0; j < (unsigned) worker_size; j++)
  265. if (!starpu_bitmap_get(workers_in_ctx, combined_workerid[j]))
  266. goto nocombined;
  267. /* We have all workers, add it */
  268. starpu_bitmap_set(component->workers_in_ctx, i);
  269. }
  270. nocombined:
  271. (void)0;
  272. }
  273. for(i = 0; i < component->nchildren; i++)
  274. {
  275. struct starpu_sched_component * child = component->children[i];
  276. _starpu_sched_component_update_workers_in_ctx(child, sched_ctx_id);
  277. }
  278. set_properties(component);
  279. component->notify_change_workers(component);
  280. }
  281. /******************************************************************************
  282. * Scheduling Trees' helper functions *
  283. ******************************************************************************/
  284. struct starpu_bitmap * _starpu_get_worker_mask(unsigned sched_ctx_id)
  285. {
  286. STARPU_ASSERT(sched_ctx_id < STARPU_NMAX_SCHED_CTXS);
  287. struct starpu_sched_tree * t = starpu_sched_ctx_get_policy_data(sched_ctx_id);
  288. STARPU_ASSERT(t);
  289. return t->workers;
  290. }
  291. void starpu_sched_tree_update_workers_in_ctx(struct starpu_sched_tree * t)
  292. {
  293. STARPU_ASSERT(t);
  294. if (t->root)
  295. _starpu_sched_component_update_workers_in_ctx(t->root, t->sched_ctx_id);
  296. }
  297. void starpu_sched_tree_update_workers(struct starpu_sched_tree * t)
  298. {
  299. STARPU_ASSERT(t);
  300. if (t->root)
  301. _starpu_sched_component_update_workers(t->root);
  302. }
  303. /******************************************************************************
  304. * Scheduling Trees' Functions *
  305. * Most of them are used to define the starpu_sched_policy interface *
  306. ******************************************************************************/
  307. void starpu_sched_component_connect(struct starpu_sched_component *parent, struct starpu_sched_component *child)
  308. {
  309. parent->add_child(parent, child);
  310. child->add_parent(child, parent);
  311. _STARPU_TRACE_SCHED_COMPONENT_CONNECT(parent,child);
  312. }
  313. int starpu_sched_tree_push_task(struct starpu_task * task)
  314. {
  315. STARPU_ASSERT(task);
  316. unsigned sched_ctx_id = task->sched_ctx;
  317. struct starpu_sched_tree *tree = starpu_sched_ctx_get_policy_data(sched_ctx_id);
  318. int ret_val = starpu_sched_component_push_task(NULL, tree->root,task);
  319. /* Modular schedulers are not supposed to refuse tasks */
  320. STARPU_ASSERT(!ret_val);
  321. return 0;
  322. }
  323. int starpu_sched_component_push_task(struct starpu_sched_component *from STARPU_ATTRIBUTE_UNUSED, struct starpu_sched_component *to, struct starpu_task *task)
  324. {
  325. int pushback;
  326. pushback = to->push_task(to, task);
  327. if (!pushback)
  328. _STARPU_TRACE_SCHED_COMPONENT_PUSH(from, to, task);
  329. return pushback;
  330. }
  331. struct starpu_task * starpu_sched_tree_pop_task(unsigned sched_ctx)
  332. {
  333. unsigned workerid = starpu_worker_get_id_check();
  334. struct starpu_sched_component * component = starpu_sched_component_worker_get(sched_ctx, workerid);
  335. /* _starpu_sched_component_lock_worker(workerid) is called by component->pull_task()
  336. */
  337. struct starpu_task * task = starpu_sched_component_pull_task(component,NULL);
  338. return task;
  339. }
  340. struct starpu_task * starpu_sched_component_pull_task(struct starpu_sched_component *from, struct starpu_sched_component *to)
  341. {
  342. struct starpu_task *task = from->pull_task(from, to);
  343. if (task)
  344. _STARPU_TRACE_SCHED_COMPONENT_PULL(from, to, task);
  345. return task;
  346. }
  347. /* Pump mechanic to get the task flow rolling. Takes tasks from component and send them to the child.
  348. To be used by components with only one child */
  349. struct starpu_task* starpu_sched_component_pump_to(struct starpu_sched_component *component, struct starpu_sched_component *child, int* success)
  350. {
  351. int ret = 0;
  352. struct starpu_task * task;
  353. while (1)
  354. {
  355. task = component->pull_task(component,child);
  356. if (!task)
  357. break;
  358. ret = starpu_sched_component_push_task(component,child,task);
  359. if (ret)
  360. break;
  361. if(success)
  362. * success = 1;
  363. }
  364. if(task && ret)
  365. /* Return the task which couldn't actually be pushed */
  366. return task;
  367. return NULL;
  368. }
  369. struct starpu_task* starpu_sched_component_pump_downstream(struct starpu_sched_component *component, int* success)
  370. {
  371. STARPU_ASSERT(component->nchildren == 1);
  372. return starpu_sched_component_pump_to(component, component->children[0], success);
  373. }
  374. void starpu_sched_tree_add_workers(unsigned sched_ctx_id, int *workerids, unsigned nworkers)
  375. {
  376. STARPU_ASSERT(sched_ctx_id < STARPU_NMAX_SCHED_CTXS);
  377. STARPU_ASSERT(workerids);
  378. struct starpu_sched_tree * t = starpu_sched_ctx_get_policy_data(sched_ctx_id);
  379. STARPU_COMPONENT_MUTEX_LOCK(&t->lock);
  380. _starpu_sched_component_lock_all_workers();
  381. unsigned i;
  382. for(i = 0; i < nworkers; i++)
  383. starpu_bitmap_set(t->workers, workerids[i]);
  384. starpu_sched_tree_update_workers_in_ctx(t);
  385. _starpu_sched_component_unlock_all_workers();
  386. STARPU_COMPONENT_MUTEX_UNLOCK(&t->lock);
  387. }
  388. void starpu_sched_tree_remove_workers(unsigned sched_ctx_id, int *workerids, unsigned nworkers)
  389. {
  390. STARPU_ASSERT(sched_ctx_id < STARPU_NMAX_SCHED_CTXS);
  391. STARPU_ASSERT(workerids);
  392. struct starpu_sched_tree * t = starpu_sched_ctx_get_policy_data(sched_ctx_id);
  393. STARPU_COMPONENT_MUTEX_LOCK(&t->lock);
  394. _starpu_sched_component_lock_all_workers();
  395. unsigned i;
  396. for(i = 0; i < nworkers; i++)
  397. starpu_bitmap_unset(t->workers, workerids[i]);
  398. starpu_sched_tree_update_workers_in_ctx(t);
  399. _starpu_sched_component_unlock_all_workers();
  400. STARPU_COMPONENT_MUTEX_UNLOCK(&t->lock);
  401. }
  402. static struct starpu_sched_tree *trees[STARPU_NMAX_SCHED_CTXS];
  403. struct starpu_sched_tree * starpu_sched_tree_create(unsigned sched_ctx_id)
  404. {
  405. STARPU_ASSERT(sched_ctx_id < STARPU_NMAX_SCHED_CTXS);
  406. STARPU_ASSERT(!trees[sched_ctx_id]);
  407. struct starpu_sched_tree *t;
  408. _STARPU_CALLOC(t, 1, sizeof(*t));
  409. t->sched_ctx_id = sched_ctx_id;
  410. t->workers = starpu_bitmap_create();
  411. STARPU_PTHREAD_MUTEX_INIT(&t->lock,NULL);
  412. trees[sched_ctx_id] = t;
  413. return t;
  414. }
  415. void starpu_sched_tree_destroy(struct starpu_sched_tree * tree)
  416. {
  417. STARPU_ASSERT(tree);
  418. STARPU_ASSERT(trees[tree->sched_ctx_id] == tree);
  419. trees[tree->sched_ctx_id] = NULL;
  420. if(tree->root)
  421. starpu_sched_component_destroy_rec(tree->root);
  422. starpu_bitmap_destroy(tree->workers);
  423. STARPU_PTHREAD_MUTEX_DESTROY(&tree->lock);
  424. free(tree);
  425. }
  426. struct starpu_sched_tree * starpu_sched_tree_get(unsigned sched_ctx_id)
  427. {
  428. return trees[sched_ctx_id];
  429. }
  430. /******************************************************************************
  431. * Interface Functions for Generic Scheduling Components *
  432. ******************************************************************************/
  433. void starpu_sched_component_add_child(struct starpu_sched_component* component, struct starpu_sched_component * child)
  434. {
  435. STARPU_ASSERT(component && child);
  436. STARPU_ASSERT(!starpu_sched_component_is_simple_worker(component));
  437. unsigned i;
  438. for(i = 0; i < component->nchildren; i++)
  439. {
  440. STARPU_ASSERT(component->children[i] != component);
  441. STARPU_ASSERT(component->children[i] != NULL);
  442. }
  443. _STARPU_REALLOC(component->children, sizeof(struct starpu_sched_component *) * (component->nchildren + 1));
  444. component->children[component->nchildren] = child;
  445. component->nchildren++;
  446. }
  447. static void starpu_sched_component_remove_child(struct starpu_sched_component * component, struct starpu_sched_component * child)
  448. {
  449. STARPU_ASSERT(component && child);
  450. STARPU_ASSERT(!starpu_sched_component_is_simple_worker(component));
  451. unsigned pos;
  452. for(pos = 0; pos < component->nchildren; pos++)
  453. if(component->children[pos] == child)
  454. break;
  455. STARPU_ASSERT(pos != component->nchildren);
  456. component->children[pos] = component->children[--component->nchildren];
  457. }
  458. static void starpu_sched_component_add_parent(struct starpu_sched_component* component, struct starpu_sched_component * parent)
  459. {
  460. STARPU_ASSERT(component && parent);
  461. unsigned i;
  462. for(i = 0; i < component->nparents; i++)
  463. {
  464. STARPU_ASSERT(component->parents[i] != component);
  465. STARPU_ASSERT(component->parents[i] != NULL);
  466. }
  467. _STARPU_REALLOC(component->parents, sizeof(struct starpu_sched_component *) * (component->nparents + 1));
  468. component->parents[component->nparents] = parent;
  469. component->nparents++;
  470. }
  471. static void starpu_sched_component_remove_parent(struct starpu_sched_component * component, struct starpu_sched_component * parent)
  472. {
  473. STARPU_ASSERT(component && parent);
  474. unsigned pos;
  475. for(pos = 0; pos < component->nparents; pos++)
  476. if(component->parents[pos] == parent)
  477. break;
  478. STARPU_ASSERT(pos != component->nparents);
  479. component->parents[pos] = component->parents[--component->nparents];
  480. }
  481. /* default implementation for component->pull_task()
  482. * just perform a recursive call on parent
  483. */
  484. struct starpu_task * starpu_sched_component_parents_pull_task(struct starpu_sched_component * component, struct starpu_sched_component * to STARPU_ATTRIBUTE_UNUSED)
  485. {
  486. STARPU_ASSERT(component);
  487. struct starpu_task * task = NULL;
  488. unsigned i;
  489. for(i=0; i < component->nparents; i++)
  490. {
  491. if(component->parents[i] == NULL)
  492. continue;
  493. else
  494. {
  495. task = starpu_sched_component_pull_task(component->parents[i], component);
  496. if(task)
  497. break;
  498. }
  499. }
  500. return task;
  501. }
  502. /* The default implementation of the can_push function is a recursive call to its parents.
  503. * A personally-made can_push in a component (like in prio components) is necessary to catch
  504. * this recursive call somewhere, if the user wants to exploit it.
  505. */
  506. int starpu_sched_component_can_push(struct starpu_sched_component * component, struct starpu_sched_component * to STARPU_ATTRIBUTE_UNUSED)
  507. {
  508. STARPU_ASSERT(component);
  509. int ret = 0;
  510. if(component->nparents > 0)
  511. {
  512. unsigned i;
  513. for(i=0; i < component->nparents; i++)
  514. {
  515. struct starpu_sched_component * parent = component->parents[i];
  516. if(parent != NULL)
  517. ret = parent->can_push(parent, component);
  518. if(ret)
  519. break;
  520. }
  521. }
  522. return ret;
  523. }
  524. /* A can_pull call will try to wake up one worker associated to the childs of the
  525. * component. It is currenly called by components which holds a queue (like fifo and prio
  526. * components) to signify its childs that a task has been pushed on its local queue.
  527. */
  528. int starpu_sched_component_can_pull(struct starpu_sched_component * component)
  529. {
  530. STARPU_ASSERT(component);
  531. STARPU_ASSERT(!starpu_sched_component_is_worker(component));
  532. unsigned i;
  533. for(i = 0; i < component->nchildren; i++)
  534. {
  535. if (component->children[i]->can_pull(component->children[i]))
  536. return 1;
  537. }
  538. return 0;
  539. }
  540. /* A can_pull call will try to wake up one worker associated to the childs of the
  541. * component. It is currenly called by components which holds a queue (like fifo and prio
  542. * components) to signify its childs that a task has been pushed on its local queue.
  543. */
  544. int starpu_sched_component_can_pull_all(struct starpu_sched_component * component)
  545. {
  546. STARPU_ASSERT(component);
  547. STARPU_ASSERT(!starpu_sched_component_is_worker(component));
  548. unsigned i;
  549. for(i = 0; i < component->nchildren; i++)
  550. component->children[i]->can_pull(component->children[i]);
  551. return 0;
  552. }
  553. /* Alternative can_pull which says that this component does not want
  554. to pull but prefers that you push. It can be used by decision
  555. components, in which decisions are usually taken in their push()
  556. functions */
  557. int starpu_sched_component_send_can_push_to_parents(struct starpu_sched_component * component)
  558. {
  559. STARPU_ASSERT(component);
  560. STARPU_ASSERT(!starpu_sched_component_is_worker(component));
  561. unsigned i;
  562. int ret = 0;
  563. for(i=0; i < component->nparents; i++)
  564. {
  565. if(component->parents[i] == NULL)
  566. continue;
  567. else
  568. {
  569. ret = component->parents[i]->can_push(component->parents[i], component);
  570. if(ret)
  571. break;
  572. }
  573. }
  574. return ret != 0;
  575. }
  576. double starpu_sched_component_estimated_load(struct starpu_sched_component * component)
  577. {
  578. double sum = 0.0;
  579. unsigned i;
  580. for( i = 0; i < component->nchildren; i++)
  581. {
  582. struct starpu_sched_component * c = component->children[i];
  583. sum += c->estimated_load(c);
  584. }
  585. return sum;
  586. }
  587. double starpu_sched_component_estimated_end_min_add(struct starpu_sched_component * component, double exp_len)
  588. {
  589. STARPU_ASSERT(component);
  590. double min = DBL_MAX;
  591. unsigned i;
  592. for(i = 0; i < component->nchildren; i++)
  593. {
  594. double tmp = component->children[i]->estimated_end(component->children[i]);
  595. if(tmp < min)
  596. min = tmp;
  597. }
  598. if (exp_len > 0)
  599. {
  600. /* We don't know which workers will do this, assume it will be
  601. * evenly distributed to existing work */
  602. int card = starpu_bitmap_cardinal(component->workers_in_ctx);
  603. if (card == 0)
  604. /* Oops, no resources to compute our tasks. Let's just hope that
  605. * we will be given one at some point */
  606. card = 1;
  607. for(i = 0; i < component->nchildren; i++)
  608. {
  609. double tmp = component->children[i]->estimated_end(component->children[i]);
  610. exp_len += tmp - min;
  611. }
  612. min += exp_len / card;
  613. }
  614. return min;
  615. }
  616. double starpu_sched_component_estimated_end_min(struct starpu_sched_component * component)
  617. {
  618. return starpu_sched_component_estimated_end_min_add(component, 0.);
  619. }
  620. double starpu_sched_component_estimated_end_average(struct starpu_sched_component * component)
  621. {
  622. STARPU_ASSERT(component);
  623. double sum = 0.0;
  624. unsigned i;
  625. for(i = 0; i < component->nchildren; i++)
  626. sum += component->children[i]->estimated_end(component->children[i]);
  627. return sum / component->nchildren;
  628. }
  629. static void take_component_and_does_nothing(struct starpu_sched_component * component STARPU_ATTRIBUTE_UNUSED)
  630. {
  631. }
  632. struct starpu_sched_component * starpu_sched_component_create(struct starpu_sched_tree *tree, const char *name)
  633. {
  634. struct starpu_sched_component *component;
  635. _STARPU_CALLOC(component, 1, sizeof(*component));
  636. component->tree = tree;
  637. component->workers = starpu_bitmap_create();
  638. component->workers_in_ctx = starpu_bitmap_create();
  639. component->add_child = starpu_sched_component_add_child;
  640. component->remove_child = starpu_sched_component_remove_child;
  641. component->add_parent = starpu_sched_component_add_parent;
  642. component->remove_parent = starpu_sched_component_remove_parent;
  643. component->pull_task = starpu_sched_component_parents_pull_task;
  644. component->can_push = starpu_sched_component_can_push;
  645. component->can_pull = starpu_sched_component_can_pull;
  646. component->estimated_load = starpu_sched_component_estimated_load;
  647. component->estimated_end = starpu_sched_component_estimated_end_min;
  648. component->deinit_data = take_component_and_does_nothing;
  649. component->notify_change_workers = take_component_and_does_nothing;
  650. component->name = strdup(name);
  651. _STARPU_TRACE_SCHED_COMPONENT_NEW(component);
  652. return component;
  653. }