node_sched.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. /* StarPU --- Runtime system for heterogeneous multicore architectures.
  2. *
  3. * Copyright (C) 2013 Simon Archipoff
  4. *
  5. * StarPU is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU Lesser General Public License as published by
  7. * the Free Software Foundation; either version 2.1 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * StarPU is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. *
  14. * See the GNU Lesser General Public License in COPYING.LGPL for more details.
  15. */
  16. #include <core/jobs.h>
  17. #include <core/workers.h>
  18. #include <starpu_sched_node.h>
  19. #include <starpu_thread_util.h>
  20. #include <float.h>
  21. #include "sched_node.h"
  22. /* wake up worker workerid
  23. * if called by a worker it dont try to wake up himself
  24. */
  25. static void wake_simple_worker(int workerid)
  26. {
  27. STARPU_ASSERT(0 <= workerid && (unsigned) workerid < starpu_worker_get_count());
  28. starpu_pthread_mutex_t * sched_mutex;
  29. starpu_pthread_cond_t * sched_cond;
  30. if(workerid == starpu_worker_get_id())
  31. return;
  32. starpu_worker_get_sched_condition(workerid, &sched_mutex, &sched_cond);
  33. starpu_wakeup_worker(workerid, sched_cond, sched_mutex);
  34. /*
  35. STARPU_PTHREAD_MUTEX_LOCK(sched_mutex);
  36. STARPU_PTHREAD_COND_SIGNAL(sched_cond);
  37. STARPU_PTHREAD_MUTEX_UNLOCK(sched_mutex);
  38. */
  39. }
  40. /* wake up all workers of a combined workers
  41. * this function must not be called during a pop (however this should not
  42. * even be possible) or you will have a dead lock
  43. */
  44. static void wake_combined_worker(int workerid)
  45. {
  46. STARPU_ASSERT( 0 <= workerid
  47. && starpu_worker_get_count() <= (unsigned) workerid
  48. && (unsigned) workerid < starpu_worker_get_count() + starpu_combined_worker_get_count());
  49. struct _starpu_combined_worker * combined_worker = _starpu_get_combined_worker_struct(workerid);
  50. int * list = combined_worker->combined_workerid;
  51. int size = combined_worker->worker_size;
  52. int i;
  53. for(i = 0; i < size; i++)
  54. wake_simple_worker(list[i]);
  55. }
  56. /* this function must not be called on worker nodes :
  57. * because this wouldn't have sense
  58. * and should dead lock
  59. */
  60. void starpu_sched_node_wake_available_worker(struct starpu_sched_node * node, struct starpu_task * task)
  61. {
  62. (void)node;
  63. STARPU_ASSERT(node);
  64. STARPU_ASSERT(!starpu_sched_node_is_worker(node));
  65. #ifndef STARPU_NON_BLOCKING_DRIVERS
  66. int i;
  67. unsigned nimpl;
  68. for(i = starpu_bitmap_first(node->workers_in_ctx);
  69. i != -1;
  70. i = starpu_bitmap_next(node->workers_in_ctx, i))
  71. {
  72. for (nimpl = 0; nimpl < STARPU_MAXIMPLEMENTATIONS; nimpl++)
  73. {
  74. if (starpu_worker_can_execute_task(i, task, nimpl))
  75. {
  76. if(i < (int) starpu_worker_get_count())
  77. wake_simple_worker(i);
  78. else
  79. wake_combined_worker(i);
  80. goto out;
  81. }
  82. }
  83. }
  84. out:
  85. #endif
  86. }
  87. /* this function must not be called on worker nodes :
  88. * because this wouldn't have sense
  89. * and should dead lock
  90. */
  91. void starpu_sched_node_available(struct starpu_sched_node * node)
  92. {
  93. (void)node;
  94. STARPU_ASSERT(node);
  95. STARPU_ASSERT(!starpu_sched_node_is_worker(node));
  96. #ifndef STARPU_NON_BLOCKING_DRIVERS
  97. int i;
  98. for(i = starpu_bitmap_first(node->workers_in_ctx);
  99. i != -1;
  100. i = starpu_bitmap_next(node->workers_in_ctx, i))
  101. {
  102. if(i < (int) starpu_worker_get_count())
  103. wake_simple_worker(i);
  104. else
  105. wake_combined_worker(i);
  106. }
  107. #endif
  108. }
  109. /* default implementation for node->pop_task()
  110. * just perform a recursive call on father
  111. */
  112. static struct starpu_task * pop_task_node(struct starpu_sched_node * node, unsigned sched_ctx_id)
  113. {
  114. STARPU_ASSERT(sched_ctx_id < STARPU_NMAX_SCHED_CTXS);
  115. STARPU_ASSERT(node);
  116. if(node->fathers[sched_ctx_id] == NULL)
  117. return NULL;
  118. else
  119. return node->fathers[sched_ctx_id]->pop_task(node->fathers[sched_ctx_id], sched_ctx_id);
  120. }
  121. void starpu_sched_node_set_father(struct starpu_sched_node *node,
  122. struct starpu_sched_node *father_node,
  123. unsigned sched_ctx_id)
  124. {
  125. STARPU_ASSERT(sched_ctx_id < STARPU_NMAX_SCHED_CTXS);
  126. STARPU_ASSERT(node);
  127. node->fathers[sched_ctx_id] = father_node;
  128. }
  129. /******************************************************************************
  130. * functions for struct starpu_sched_policy interface *
  131. ******************************************************************************/
  132. int starpu_sched_tree_push_task(struct starpu_task * task)
  133. {
  134. STARPU_ASSERT(task);
  135. unsigned sched_ctx_id = task->sched_ctx;
  136. struct starpu_sched_tree *tree = starpu_sched_ctx_get_policy_data(sched_ctx_id);
  137. int workerid = starpu_worker_get_id();
  138. /* application should take tree->lock to prevent concurent acces from hypervisor
  139. * worker take they own mutexes
  140. */
  141. if(-1 == workerid)
  142. STARPU_PTHREAD_MUTEX_LOCK(&tree->lock);
  143. else
  144. _starpu_sched_node_lock_worker(workerid);
  145. int ret_val = tree->root->push_task(tree->root,task);
  146. if(-1 == workerid)
  147. STARPU_PTHREAD_MUTEX_UNLOCK(&tree->lock);
  148. else
  149. _starpu_sched_node_unlock_worker(workerid);
  150. return ret_val;
  151. }
  152. struct starpu_task * starpu_sched_tree_pop_task(unsigned sched_ctx_id)
  153. {
  154. STARPU_ASSERT(sched_ctx_id < STARPU_NMAX_SCHED_CTXS);
  155. int workerid = starpu_worker_get_id();
  156. struct starpu_sched_node * node = starpu_sched_node_worker_get(workerid);
  157. /* _starpu_sched_node_lock_worker(workerid) is called by node->pop_task()
  158. */
  159. struct starpu_task * task = node->pop_task(node, sched_ctx_id);
  160. return task;
  161. }
  162. void starpu_sched_tree_add_workers(unsigned sched_ctx_id, int *workerids, unsigned nworkers)
  163. {
  164. STARPU_ASSERT(sched_ctx_id < STARPU_NMAX_SCHED_CTXS);
  165. STARPU_ASSERT(workerids);
  166. struct starpu_sched_tree * t = starpu_sched_ctx_get_policy_data(sched_ctx_id);
  167. STARPU_PTHREAD_MUTEX_LOCK(&t->lock);
  168. _starpu_sched_node_lock_all_workers();
  169. unsigned i;
  170. for(i = 0; i < nworkers; i++)
  171. starpu_bitmap_set(t->workers, workerids[i]);
  172. starpu_sched_tree_update_workers_in_ctx(t);
  173. _starpu_sched_node_unlock_all_workers();
  174. STARPU_PTHREAD_MUTEX_UNLOCK(&t->lock);
  175. }
  176. void starpu_sched_tree_remove_workers(unsigned sched_ctx_id, int *workerids, unsigned nworkers)
  177. {
  178. STARPU_ASSERT(sched_ctx_id < STARPU_NMAX_SCHED_CTXS);
  179. STARPU_ASSERT(workerids);
  180. struct starpu_sched_tree * t = starpu_sched_ctx_get_policy_data(sched_ctx_id);
  181. STARPU_PTHREAD_MUTEX_LOCK(&t->lock);
  182. _starpu_sched_node_lock_all_workers();
  183. unsigned i;
  184. for(i = 0; i < nworkers; i++)
  185. starpu_bitmap_unset(t->workers, workerids[i]);
  186. starpu_sched_tree_update_workers_in_ctx(t);
  187. _starpu_sched_node_unlock_all_workers();
  188. STARPU_PTHREAD_MUTEX_UNLOCK(&t->lock);
  189. }
  190. void starpu_sched_node_destroy_rec(struct starpu_sched_node * node, unsigned sched_ctx_id)
  191. {
  192. if(node == NULL)
  193. return;
  194. struct starpu_sched_node ** stack = NULL;
  195. int top = -1;
  196. #define PUSH(n) \
  197. do{ \
  198. stack = realloc(stack, sizeof(*stack) * (top + 2)); \
  199. stack[++top] = n; \
  200. }while(0)
  201. #define POP() stack[top--]
  202. #define EMPTY() (top == -1)
  203. /* we want to delete all subtrees exept if a pointer in fathers point in an other tree
  204. * ie an other context
  205. */
  206. node->fathers[sched_ctx_id] = NULL;
  207. int shared = 0;
  208. {
  209. int i;
  210. for(i = 0; i < STARPU_NMAX_SCHED_CTXS; i++)
  211. if(node->fathers[i] != NULL)
  212. shared = 1;
  213. }
  214. if(!shared)
  215. PUSH(node);
  216. while(!EMPTY())
  217. {
  218. struct starpu_sched_node * n = POP();
  219. int i;
  220. for(i = 0; i < n->nchilds; i++)
  221. {
  222. struct starpu_sched_node * child = n->childs[i];
  223. int j;
  224. shared = 0;
  225. STARPU_ASSERT(child->fathers[sched_ctx_id] == n);
  226. child->fathers[sched_ctx_id] = NULL;
  227. for(j = 0; j < STARPU_NMAX_SCHED_CTXS; j++)
  228. {
  229. if(child->fathers[j] != NULL)/* child is shared */
  230. shared = 1;
  231. }
  232. if(!shared)/* if not shared we want to destroy it and his childs */
  233. PUSH(child);
  234. }
  235. starpu_sched_node_destroy(n);
  236. }
  237. free(stack);
  238. }
  239. struct starpu_sched_tree * starpu_sched_tree_create(unsigned sched_ctx_id)
  240. {
  241. STARPU_ASSERT(sched_ctx_id < STARPU_NMAX_SCHED_CTXS);
  242. struct starpu_sched_tree * t = malloc(sizeof(*t));
  243. memset(t, 0, sizeof(*t));
  244. t->sched_ctx_id = sched_ctx_id;
  245. t->workers = starpu_bitmap_create();
  246. STARPU_PTHREAD_MUTEX_INIT(&t->lock,NULL);
  247. return t;
  248. }
  249. void starpu_sched_tree_destroy(struct starpu_sched_tree * tree)
  250. {
  251. STARPU_ASSERT(tree);
  252. if(tree->root)
  253. starpu_sched_node_destroy_rec(tree->root, tree->sched_ctx_id);
  254. starpu_bitmap_destroy(tree->workers);
  255. STARPU_PTHREAD_MUTEX_DESTROY(&tree->lock);
  256. free(tree);
  257. }
  258. void starpu_sched_node_add_child(struct starpu_sched_node* node, struct starpu_sched_node * child)
  259. {
  260. STARPU_ASSERT(node && child);
  261. STARPU_ASSERT(!starpu_sched_node_is_worker(node));
  262. int i;
  263. for(i = 0; i < node->nchilds; i++){
  264. STARPU_ASSERT(node->childs[i] != node);
  265. STARPU_ASSERT(node->childs[i] != NULL);
  266. }
  267. node->childs = realloc(node->childs, sizeof(struct starpu_sched_node *) * (node->nchilds + 1));
  268. node->childs[node->nchilds] = child;
  269. node->nchilds++;
  270. }
  271. void starpu_sched_node_remove_child(struct starpu_sched_node * node, struct starpu_sched_node * child)
  272. {
  273. STARPU_ASSERT(node && child);
  274. STARPU_ASSERT(!starpu_sched_node_is_worker(node));
  275. int pos;
  276. for(pos = 0; pos < node->nchilds; pos++)
  277. if(node->childs[pos] == child)
  278. break;
  279. STARPU_ASSERT(pos != node->nchilds);
  280. node->childs[pos] = node->childs[--node->nchilds];
  281. }
  282. struct starpu_bitmap * _starpu_get_worker_mask(unsigned sched_ctx_id)
  283. {
  284. STARPU_ASSERT(sched_ctx_id < STARPU_NMAX_SCHED_CTXS);
  285. struct starpu_sched_tree * t = starpu_sched_ctx_get_policy_data(sched_ctx_id);
  286. STARPU_ASSERT(t);
  287. return t->workers;
  288. }
  289. static double estimated_load(struct starpu_sched_node * node)
  290. {
  291. double sum = 0.0;
  292. int i;
  293. for( i = 0; i < node->nchilds; i++)
  294. {
  295. struct starpu_sched_node * c = node->childs[i];
  296. sum += c->estimated_load(c);
  297. }
  298. return sum;
  299. }
  300. static double _starpu_sched_node_estimated_end_min(struct starpu_sched_node * node)
  301. {
  302. STARPU_ASSERT(node);
  303. double min = DBL_MAX;
  304. int i;
  305. for(i = 0; i < node->nchilds; i++)
  306. {
  307. double tmp = node->childs[i]->estimated_end(node->childs[i]);
  308. if(tmp < min)
  309. min = tmp;
  310. }
  311. return min;
  312. }
  313. /* this function find the best implementation or an implementation that need to be calibrated for a worker available
  314. * and set prediction in *length. nan if a implementation need to be calibrated, 0.0 if no perf model are available
  315. * return false if no worker on the node can execute that task
  316. */
  317. int STARPU_WARN_UNUSED_RESULT starpu_sched_node_execute_preds(struct starpu_sched_node * node, struct starpu_task * task, double * length)
  318. {
  319. STARPU_ASSERT(node && task);
  320. int can_execute = 0;
  321. starpu_task_bundle_t bundle = task->bundle;
  322. double len = DBL_MAX;
  323. int workerid;
  324. for(workerid = starpu_bitmap_first(node->workers_in_ctx);
  325. workerid != -1;
  326. workerid = starpu_bitmap_next(node->workers_in_ctx, workerid))
  327. {
  328. struct starpu_perfmodel_arch* archtype = starpu_worker_get_perf_archtype(workerid);
  329. int nimpl;
  330. for(nimpl = 0; nimpl < STARPU_MAXIMPLEMENTATIONS; nimpl++)
  331. {
  332. if(starpu_worker_can_execute_task(workerid,task,nimpl)
  333. || starpu_combined_worker_can_execute_task(workerid, task, nimpl))
  334. {
  335. double d;
  336. can_execute = 1;
  337. if(bundle)
  338. d = starpu_task_bundle_expected_length(bundle, archtype, nimpl);
  339. else
  340. d = starpu_task_expected_length(task, archtype, nimpl);
  341. if(isnan(d))
  342. {
  343. *length = d;
  344. return can_execute;
  345. }
  346. if(_STARPU_IS_ZERO(d) && !can_execute)
  347. {
  348. can_execute = 1;
  349. continue;
  350. }
  351. if(d < len)
  352. {
  353. len = d;
  354. }
  355. }
  356. }
  357. if(STARPU_SCHED_NODE_IS_HOMOGENEOUS(node))
  358. break;
  359. }
  360. if(len == DBL_MAX) /* we dont have perf model */
  361. len = 0.0;
  362. if(length)
  363. *length = len;
  364. return can_execute;
  365. }
  366. /* very similar function that dont compute prediction */
  367. int starpu_sched_node_can_execute_task(struct starpu_sched_node * node, struct starpu_task * task)
  368. {
  369. STARPU_ASSERT(task);
  370. STARPU_ASSERT(node);
  371. unsigned nimpl;
  372. int worker;
  373. for (nimpl = 0; nimpl < STARPU_MAXIMPLEMENTATIONS; nimpl++)
  374. for(worker = starpu_bitmap_first(node->workers_in_ctx);
  375. -1 != worker;
  376. worker = starpu_bitmap_next(node->workers_in_ctx, worker))
  377. if (starpu_worker_can_execute_task(worker, task, nimpl)
  378. || starpu_combined_worker_can_execute_task(worker, task, nimpl))
  379. return 1;
  380. return 0;
  381. }
  382. /* compute the average of transfer length for tasks on all workers
  383. * maybe this should be optimised if all workers are under the same numa node
  384. */
  385. double starpu_sched_node_transfer_length(struct starpu_sched_node * node, struct starpu_task * task)
  386. {
  387. STARPU_ASSERT(node && task);
  388. int nworkers = starpu_bitmap_cardinal(node->workers_in_ctx);
  389. double sum = 0.0;
  390. int worker;
  391. if(STARPU_SCHED_NODE_IS_SINGLE_MEMORY_NODE(node))
  392. {
  393. unsigned memory_node = starpu_worker_get_memory_node(starpu_bitmap_first(node->workers_in_ctx));
  394. if(task->bundle)
  395. return starpu_task_bundle_expected_data_transfer_time(task->bundle,memory_node);
  396. else
  397. return starpu_task_expected_data_transfer_time(memory_node, task);
  398. }
  399. for(worker = starpu_bitmap_first(node->workers_in_ctx);
  400. worker != -1;
  401. worker = starpu_bitmap_next(node->workers_in_ctx, worker))
  402. {
  403. unsigned memory_node = starpu_worker_get_memory_node(worker);
  404. if(task->bundle)
  405. {
  406. sum += starpu_task_bundle_expected_data_transfer_time(task->bundle,memory_node);
  407. }
  408. else
  409. {
  410. sum += starpu_task_expected_data_transfer_time(memory_node, task);
  411. /* sum += starpu_task_expected_conversion_time(task, starpu_worker_get_perf_archtype(worker), impl ?)
  412. * I dont know what to do as we dont know what implementation would be used here...
  413. */
  414. }
  415. }
  416. return sum / nworkers;
  417. }
  418. /* This function can be called by nodes when they think that a prefetching request can be submitted.
  419. * For example, it is currently used by the MCT node to begin the prefetching on accelerators
  420. * on which it pushed tasks as soon as possible.
  421. */
  422. void starpu_sched_node_prefetch_on_node(struct starpu_sched_node * node, struct starpu_task * task)
  423. {
  424. if (starpu_get_prefetch_flag() && (!task->prefetched)
  425. && (node->properties >= STARPU_SCHED_NODE_SINGLE_MEMORY_NODE))
  426. {
  427. int worker = starpu_bitmap_first(node->workers_in_ctx);
  428. unsigned memory_node = starpu_worker_get_memory_node(worker);
  429. starpu_prefetch_task_input_on_node(task, memory_node);
  430. task->prefetched = 1;
  431. }
  432. }
  433. /* The default implementation of the room function is a recursive call to its fathers.
  434. * A personally-made room in a node (like in prio nodes) is necessary to catch
  435. * this recursive call somewhere, if the user wants to exploit it.
  436. */
  437. void starpu_sched_node_room(struct starpu_sched_node * node, unsigned sched_ctx_id)
  438. {
  439. STARPU_ASSERT(sched_ctx_id < STARPU_NMAX_SCHED_CTXS);
  440. STARPU_ASSERT(node);
  441. struct starpu_sched_node * father = node->fathers[sched_ctx_id];
  442. if(father != NULL)
  443. father->room(father, sched_ctx_id);
  444. }
  445. /* An avail call will try to wake up one worker associated to the childs of the
  446. * node. It is currenly called by nodes which holds a queue (like fifo and prio
  447. * nodes) to signify its childs that a task has been pushed on its local queue.
  448. */
  449. int starpu_sched_node_avail(struct starpu_sched_node * node)
  450. {
  451. STARPU_ASSERT(node);
  452. int ret;
  453. if(node->nchilds > 0)
  454. {
  455. int i;
  456. for(i = 0; i < node->nchilds; i++)
  457. {
  458. struct starpu_sched_node * child = node->childs[i];
  459. ret = child->avail(child);
  460. if(ret)
  461. break;
  462. }
  463. }
  464. return 0;
  465. }
  466. void take_node_and_does_nothing(struct starpu_sched_node * node STARPU_ATTRIBUTE_UNUSED)
  467. {
  468. }
  469. struct starpu_sched_node * starpu_sched_node_create(void)
  470. {
  471. struct starpu_sched_node * node = malloc(sizeof(*node));
  472. memset(node,0,sizeof(*node));
  473. node->workers = starpu_bitmap_create();
  474. node->workers_in_ctx = starpu_bitmap_create();
  475. node->add_child = starpu_sched_node_add_child;
  476. node->remove_child = starpu_sched_node_remove_child;
  477. node->pop_task = pop_task_node;
  478. node->room = starpu_sched_node_room;
  479. node->avail = starpu_sched_node_avail;
  480. node->estimated_load = estimated_load;
  481. node->estimated_end = _starpu_sched_node_estimated_end_min;
  482. node->deinit_data = take_node_and_does_nothing;
  483. node->notify_change_workers = take_node_and_does_nothing;
  484. return node;
  485. }
  486. /* remove all child
  487. * for all child of node, if child->fathers[x] == node, set child->fathers[x] to null
  488. * call node->deinit_data
  489. */
  490. void starpu_sched_node_destroy(struct starpu_sched_node *node)
  491. {
  492. STARPU_ASSERT(node);
  493. if(starpu_sched_node_is_worker(node))
  494. return;
  495. int i,j;
  496. for(i = 0; i < node->nchilds; i++)
  497. {
  498. struct starpu_sched_node * child = node->childs[i];
  499. for(j = 0; j < STARPU_NMAX_SCHED_CTXS; j++)
  500. if(child->fathers[i] == node)
  501. child->fathers[i] = NULL;
  502. }
  503. while(node->nchilds != 0)
  504. node->remove_child(node, node->childs[0]);
  505. node->deinit_data(node);
  506. free(node->childs);
  507. starpu_bitmap_destroy(node->workers);
  508. starpu_bitmap_destroy(node->workers_in_ctx);
  509. free(node);
  510. }
  511. static void set_properties(struct starpu_sched_node * node)
  512. {
  513. STARPU_ASSERT(node);
  514. node->properties = 0;
  515. STARPU_ASSERT(starpu_bitmap_cardinal(node->workers_in_ctx) > 0);
  516. int worker = starpu_bitmap_first(node->workers_in_ctx);
  517. uint32_t first_worker = _starpu_get_worker_struct(worker)->worker_mask;
  518. unsigned first_memory_node = _starpu_get_worker_struct(worker)->memory_node;
  519. int is_homogeneous = 1;
  520. int is_all_same_node = 1;
  521. for(;
  522. worker != -1;
  523. worker = starpu_bitmap_next(node->workers_in_ctx, worker))
  524. {
  525. if(first_worker != _starpu_get_worker_struct(worker)->worker_mask)
  526. is_homogeneous = 0;
  527. if(first_memory_node != _starpu_get_worker_struct(worker)->memory_node)
  528. is_all_same_node = 0;
  529. }
  530. if(is_homogeneous)
  531. node->properties |= STARPU_SCHED_NODE_HOMOGENEOUS;
  532. if(is_all_same_node)
  533. node->properties |= STARPU_SCHED_NODE_SINGLE_MEMORY_NODE;
  534. }
  535. /* recursively set the node->workers member of node's subtree
  536. */
  537. void _starpu_sched_node_update_workers(struct starpu_sched_node * node)
  538. {
  539. STARPU_ASSERT(node);
  540. if(starpu_sched_node_is_worker(node))
  541. return;
  542. starpu_bitmap_unset_all(node->workers);
  543. int i;
  544. for(i = 0; i < node->nchilds; i++)
  545. {
  546. _starpu_sched_node_update_workers(node->childs[i]);
  547. starpu_bitmap_or(node->workers, node->childs[i]->workers);
  548. node->notify_change_workers(node);
  549. }
  550. }
  551. /* recursively set the node->workers_in_ctx in node's subtree
  552. */
  553. void _starpu_sched_node_update_workers_in_ctx(struct starpu_sched_node * node, unsigned sched_ctx_id)
  554. {
  555. STARPU_ASSERT(node);
  556. if(starpu_sched_node_is_worker(node))
  557. return;
  558. struct starpu_bitmap * workers_in_ctx = _starpu_get_worker_mask(sched_ctx_id);
  559. starpu_bitmap_unset_and(node->workers_in_ctx,node->workers, workers_in_ctx);
  560. int i,j;
  561. for(i = 0; i < node->nchilds; i++)
  562. {
  563. struct starpu_sched_node * child = node->childs[i];
  564. _starpu_sched_node_update_workers_in_ctx(child, sched_ctx_id);
  565. for(j = 0; j < STARPU_NMAX_SCHED_CTXS; j++)
  566. if(child->fathers[j] == node)
  567. {
  568. starpu_bitmap_or(node->workers_in_ctx, child->workers_in_ctx);
  569. break;
  570. }
  571. }
  572. set_properties(node);
  573. node->notify_change_workers(node);
  574. }
  575. void starpu_sched_tree_update_workers_in_ctx(struct starpu_sched_tree * t)
  576. {
  577. STARPU_ASSERT(t);
  578. _starpu_sched_node_update_workers_in_ctx(t->root, t->sched_ctx_id);
  579. }
  580. void starpu_sched_tree_update_workers(struct starpu_sched_tree * t)
  581. {
  582. STARPU_ASSERT(t);
  583. _starpu_sched_node_update_workers(t->root);
  584. }