policy_tools.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. /* StarPU --- Runtime system for heterogeneous multicore architectures.
  2. *
  3. * Copyright (C) 2010-2016 Inria
  4. * Copyright (C) 2013-2014,2016-2017 CNRS
  5. * Copyright (C) 2013-2015,2017 Université de Bordeaux
  6. *
  7. * StarPU is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as published by
  9. * the Free Software Foundation; either version 2.1 of the License, or (at
  10. * your option) any later version.
  11. *
  12. * StarPU is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. *
  16. * See the GNU Lesser General Public License in COPYING.LGPL for more details.
  17. */
  18. #include "sc_hypervisor_policy.h"
  19. #include "sc_hypervisor_intern.h"
  20. #include "sc_hypervisor_lp.h"
  21. static int _compute_priority(unsigned sched_ctx)
  22. {
  23. struct sc_hypervisor_policy_config *config = sc_hypervisor_get_config(sched_ctx);
  24. int total_priority = 0;
  25. struct starpu_worker_collection *workers = starpu_sched_ctx_get_worker_collection(sched_ctx);
  26. int worker;
  27. struct starpu_sched_ctx_iterator it;
  28. workers->init_iterator(workers, &it);
  29. while(workers->has_next(workers, &it))
  30. {
  31. worker = workers->get_next(workers, &it);
  32. total_priority += config->priority[worker];
  33. }
  34. return total_priority;
  35. }
  36. /* find the context with the lowest priority */
  37. unsigned sc_hypervisor_find_lowest_prio_sched_ctx(unsigned req_sched_ctx, int nworkers_to_move)
  38. {
  39. int i;
  40. int highest_priority = -1;
  41. int current_priority = 0;
  42. unsigned sched_ctx = STARPU_NMAX_SCHED_CTXS;
  43. unsigned *sched_ctxs = sc_hypervisor_get_sched_ctxs();
  44. int nsched_ctxs = sc_hypervisor_get_nsched_ctxs();
  45. struct sc_hypervisor_policy_config *config = NULL;
  46. for(i = 0; i < nsched_ctxs; i++)
  47. {
  48. if(sched_ctxs[i] != STARPU_NMAX_SCHED_CTXS && sched_ctxs[i] != req_sched_ctx)
  49. {
  50. int nworkers = (int)starpu_sched_ctx_get_nworkers(sched_ctxs[i]);
  51. config = sc_hypervisor_get_config(sched_ctxs[i]);
  52. if((nworkers + nworkers_to_move) <= config->max_nworkers)
  53. {
  54. current_priority = _compute_priority(sched_ctxs[i]);
  55. if (highest_priority < current_priority)
  56. {
  57. highest_priority = current_priority;
  58. sched_ctx = sched_ctxs[i];
  59. }
  60. }
  61. }
  62. }
  63. return sched_ctx;
  64. }
  65. int* sc_hypervisor_get_idlest_workers_in_list(int *start, int *workers, int nall_workers, int *nworkers, enum starpu_worker_archtype arch)
  66. {
  67. int *curr_workers = (int*)malloc((*nworkers)*sizeof(int));
  68. int w, worker;
  69. int nfound_workers = 0;
  70. for(w = 0; w < nall_workers; w++)
  71. {
  72. if(nfound_workers >= *nworkers)
  73. break;
  74. worker = workers == NULL ? w : workers[w];
  75. enum starpu_worker_archtype curr_arch = starpu_worker_get_type(worker);
  76. if(arch == STARPU_ANY_WORKER || curr_arch == arch)
  77. {
  78. if(w >= *start)
  79. {
  80. curr_workers[nfound_workers++] = worker;
  81. *start = w+1;
  82. }
  83. }
  84. }
  85. if(nfound_workers < *nworkers)
  86. *nworkers = nfound_workers;
  87. return curr_workers;
  88. }
  89. /* get first nworkers with the highest idle time in the context */
  90. int* sc_hypervisor_get_idlest_workers(unsigned sched_ctx, int *nworkers, enum starpu_worker_archtype arch)
  91. {
  92. struct sc_hypervisor_wrapper* sc_w = sc_hypervisor_get_wrapper(sched_ctx);
  93. struct sc_hypervisor_policy_config *config = sc_hypervisor_get_config(sched_ctx);
  94. int *curr_workers = (int*)malloc((*nworkers) * sizeof(int));
  95. int i;
  96. for(i = 0; i < *nworkers; i++)
  97. curr_workers[i] = -1;
  98. struct starpu_worker_collection *workers = starpu_sched_ctx_get_worker_collection(sched_ctx);
  99. int index;
  100. int worker;
  101. int considered = 0;
  102. struct starpu_sched_ctx_iterator it;
  103. workers->init_iterator(workers, &it);
  104. for(index = 0; index < *nworkers; index++)
  105. {
  106. while(workers->has_next(workers, &it))
  107. {
  108. considered = 0;
  109. worker = workers->get_next(workers, &it);
  110. enum starpu_worker_archtype curr_arch = starpu_worker_get_type(worker);
  111. if(arch == STARPU_ANY_WORKER || curr_arch == arch)
  112. {
  113. if(!config->fixed_workers[worker])
  114. {
  115. for(i = 0; i < index; i++)
  116. {
  117. if(curr_workers[i] == worker)
  118. {
  119. considered = 1;
  120. break;
  121. }
  122. }
  123. if(!considered)
  124. {
  125. /* the first iteration*/
  126. if(curr_workers[index] < 0)
  127. curr_workers[index] = worker;
  128. /* small priority worker is the first to leave the ctx*/
  129. else if(config->priority[worker] <
  130. config->priority[curr_workers[index]])
  131. curr_workers[index] = worker;
  132. /* if we don't consider priorities check for the workers
  133. with the biggest idle time */
  134. else if(config->priority[worker] ==
  135. config->priority[curr_workers[index]])
  136. {
  137. double worker_idle_time = sc_w->current_idle_time[worker];
  138. double curr_worker_idle_time = sc_w->current_idle_time[curr_workers[index]];
  139. if(worker_idle_time > curr_worker_idle_time)
  140. curr_workers[index] = worker;
  141. }
  142. }
  143. }
  144. }
  145. }
  146. if(curr_workers[index] < 0)
  147. {
  148. *nworkers = index;
  149. break;
  150. }
  151. }
  152. return curr_workers;
  153. }
  154. /* get the number of workers in the context that are allowed to be moved (that are not fixed) */
  155. int sc_hypervisor_get_movable_nworkers(struct sc_hypervisor_policy_config *config, unsigned sched_ctx, enum starpu_worker_archtype arch)
  156. {
  157. struct starpu_worker_collection *workers = starpu_sched_ctx_get_worker_collection(sched_ctx);
  158. int potential_workers = 0;
  159. int worker;
  160. struct starpu_sched_ctx_iterator it;
  161. workers->init_iterator(workers, &it);
  162. while(workers->has_next(workers, &it))
  163. {
  164. worker = workers->get_next(workers, &it);
  165. enum starpu_worker_archtype curr_arch = starpu_worker_get_type(worker);
  166. if(arch == STARPU_ANY_WORKER || curr_arch == arch)
  167. {
  168. if(!config->fixed_workers[worker])
  169. potential_workers++;
  170. }
  171. }
  172. return potential_workers;
  173. }
  174. /* compute the number of workers that should be moved depending:
  175. - on the min/max number of workers in a context imposed by the user,
  176. - on the resource granularity imposed by the user for the resizing process*/
  177. int sc_hypervisor_compute_nworkers_to_move(unsigned req_sched_ctx)
  178. {
  179. struct sc_hypervisor_policy_config *config = sc_hypervisor_get_config(req_sched_ctx);
  180. int nworkers = (int)starpu_sched_ctx_get_nworkers(req_sched_ctx);
  181. int nworkers_to_move = 0;
  182. int potential_moving_workers = (int)sc_hypervisor_get_movable_nworkers(config, req_sched_ctx, STARPU_ANY_WORKER);
  183. if(potential_moving_workers > 0)
  184. {
  185. if(potential_moving_workers <= config->min_nworkers)
  186. /* if we have to give more than min better give it all */
  187. /* => empty ctx will block until having the required workers */
  188. nworkers_to_move = potential_moving_workers;
  189. else if(potential_moving_workers > config->max_nworkers)
  190. {
  191. if((potential_moving_workers - config->granularity) > config->max_nworkers)
  192. // nworkers_to_move = config->granularity;
  193. nworkers_to_move = potential_moving_workers;
  194. else
  195. nworkers_to_move = potential_moving_workers - config->max_nworkers;
  196. }
  197. else if(potential_moving_workers > config->granularity)
  198. {
  199. if((nworkers - config->granularity) > config->min_nworkers)
  200. nworkers_to_move = config->granularity;
  201. else
  202. nworkers_to_move = potential_moving_workers - config->min_nworkers;
  203. }
  204. else
  205. {
  206. int nfixed_workers = nworkers - potential_moving_workers;
  207. if(nfixed_workers >= config->min_nworkers)
  208. nworkers_to_move = potential_moving_workers;
  209. else
  210. nworkers_to_move = potential_moving_workers - (config->min_nworkers - nfixed_workers);
  211. }
  212. if((nworkers - nworkers_to_move) > config->max_nworkers)
  213. nworkers_to_move = nworkers - config->max_nworkers;
  214. }
  215. return nworkers_to_move;
  216. }
  217. unsigned sc_hypervisor_policy_resize(unsigned sender_sched_ctx, unsigned receiver_sched_ctx, unsigned force_resize, unsigned now)
  218. {
  219. int ret = 1;
  220. if(force_resize)
  221. STARPU_PTHREAD_MUTEX_LOCK(&act_hypervisor_mutex);
  222. else
  223. ret = starpu_pthread_mutex_trylock(&act_hypervisor_mutex);
  224. if(ret != EBUSY)
  225. {
  226. int nworkers_to_move = sc_hypervisor_compute_nworkers_to_move(sender_sched_ctx);
  227. if(nworkers_to_move > 0)
  228. {
  229. unsigned poor_sched_ctx = STARPU_NMAX_SCHED_CTXS;
  230. if(receiver_sched_ctx == STARPU_NMAX_SCHED_CTXS)
  231. {
  232. poor_sched_ctx = sc_hypervisor_find_lowest_prio_sched_ctx(sender_sched_ctx, (unsigned)nworkers_to_move);
  233. }
  234. else
  235. {
  236. poor_sched_ctx = receiver_sched_ctx;
  237. struct sc_hypervisor_policy_config *config = sc_hypervisor_get_config(poor_sched_ctx);
  238. int nworkers = (int)starpu_sched_ctx_get_nworkers(poor_sched_ctx);
  239. int nshared_workers = (int)starpu_sched_ctx_get_nshared_workers(sender_sched_ctx, poor_sched_ctx);
  240. if((nworkers+nworkers_to_move-nshared_workers) > config->max_nworkers)
  241. nworkers_to_move = nworkers > config->max_nworkers ? 0 : (config->max_nworkers - nworkers+nshared_workers);
  242. if(nworkers_to_move == 0) poor_sched_ctx = STARPU_NMAX_SCHED_CTXS;
  243. }
  244. if(poor_sched_ctx != STARPU_NMAX_SCHED_CTXS)
  245. {
  246. int *workers_to_move = sc_hypervisor_get_idlest_workers(sender_sched_ctx, &nworkers_to_move, STARPU_ANY_WORKER);
  247. sc_hypervisor_move_workers(sender_sched_ctx, poor_sched_ctx, workers_to_move, nworkers_to_move, now);
  248. struct sc_hypervisor_policy_config *new_config = sc_hypervisor_get_config(poor_sched_ctx);
  249. int i;
  250. for(i = 0; i < nworkers_to_move; i++)
  251. new_config->max_idle[workers_to_move[i]] = new_config->max_idle[workers_to_move[i]] !=MAX_IDLE_TIME ? new_config->max_idle[workers_to_move[i]] : new_config->new_workers_max_idle;
  252. free(workers_to_move);
  253. }
  254. }
  255. STARPU_PTHREAD_MUTEX_UNLOCK(&act_hypervisor_mutex);
  256. return 1;
  257. }
  258. return 0;
  259. }
  260. unsigned sc_hypervisor_policy_resize_to_unknown_receiver(unsigned sender_sched_ctx, unsigned now)
  261. {
  262. return sc_hypervisor_policy_resize(sender_sched_ctx, STARPU_NMAX_SCHED_CTXS, 0, now);
  263. }
  264. double sc_hypervisor_get_slowest_ctx_exec_time(void)
  265. {
  266. unsigned *sched_ctxs = sc_hypervisor_get_sched_ctxs();
  267. int nsched_ctxs = sc_hypervisor_get_nsched_ctxs();
  268. /* double curr_time = starpu_timing_now(); */
  269. double slowest_time = 0.0;
  270. int s;
  271. struct sc_hypervisor_wrapper* sc_w;
  272. for(s = 0; s < nsched_ctxs; s++)
  273. {
  274. sc_w = sc_hypervisor_get_wrapper(sched_ctxs[s]);
  275. // double elapsed_time = (curr_time - sc_w->start_time)/1000000;
  276. struct sc_hypervisor_policy_config *config = sc_hypervisor_get_config(sc_w->sched_ctx);
  277. double elapsed_time = (config->ispeed_ctx_sample/1000000000.0)/sc_hypervisor_get_ctx_speed(sc_w);
  278. if(elapsed_time > slowest_time)
  279. slowest_time = elapsed_time;
  280. }
  281. return slowest_time;
  282. }
  283. double sc_hypervisor_get_fastest_ctx_exec_time(void)
  284. {
  285. unsigned *sched_ctxs = sc_hypervisor_get_sched_ctxs();
  286. int nsched_ctxs = sc_hypervisor_get_nsched_ctxs();
  287. double curr_time = starpu_timing_now();
  288. double fastest_time = curr_time;
  289. int s;
  290. struct sc_hypervisor_wrapper* sc_w;
  291. for(s = 0; s < nsched_ctxs; s++)
  292. {
  293. sc_w = sc_hypervisor_get_wrapper(sched_ctxs[s]);
  294. struct sc_hypervisor_policy_config *config = sc_hypervisor_get_config(sc_w->sched_ctx);
  295. double elapsed_time = (config->ispeed_ctx_sample/1000000000.0)/sc_hypervisor_get_ctx_speed(sc_w);
  296. if(elapsed_time < fastest_time)
  297. fastest_time = elapsed_time;
  298. }
  299. return fastest_time;
  300. }
  301. void sc_hypervisor_group_workers_by_type(struct types_of_workers *tw, int *total_nw)
  302. {
  303. unsigned w;
  304. for(w = 0; w < tw->nw; w++)
  305. total_nw[w] = 0;
  306. if(tw->ncpus != 0)
  307. {
  308. total_nw[0] = tw->ncpus;
  309. if(tw->ncuda != 0)
  310. total_nw[1] = tw->ncuda;
  311. }
  312. else
  313. {
  314. if(tw->ncuda != 0)
  315. total_nw[0] =tw->ncuda;
  316. }
  317. }
  318. enum starpu_worker_archtype sc_hypervisor_get_arch_for_index(unsigned w, struct types_of_workers *tw)
  319. {
  320. if(w == 0)
  321. {
  322. if(tw->ncpus != 0)
  323. return STARPU_CPU_WORKER;
  324. else
  325. return STARPU_CUDA_WORKER;
  326. }
  327. else
  328. if(tw->ncuda != 0)
  329. return STARPU_CUDA_WORKER;
  330. return STARPU_CPU_WORKER;
  331. }
  332. unsigned sc_hypervisor_get_index_for_arch(enum starpu_worker_archtype arch, struct types_of_workers *tw)
  333. {
  334. if(arch == STARPU_CPU_WORKER)
  335. {
  336. if(tw->ncpus != 0)
  337. return 0;
  338. }
  339. else
  340. {
  341. if(arch == STARPU_CUDA_WORKER)
  342. {
  343. if(tw->ncpus != 0)
  344. return 1;
  345. else
  346. return 0;
  347. }
  348. }
  349. return 0;
  350. }
  351. void sc_hypervisor_get_tasks_times(int nw, int nt, double times[nw][nt], int *workers, unsigned size_ctxs, struct sc_hypervisor_policy_task_pool *task_pools)
  352. {
  353. struct sc_hypervisor_policy_task_pool *tp;
  354. int w, t;
  355. for(w = 0; w < nw; w++)
  356. for(t = 0; t < nt; t++)
  357. times[w][t] = NAN;
  358. for (w = 0; w < nw; w++)
  359. {
  360. for (t = 0, tp = task_pools; tp; t++, tp = tp->next)
  361. {
  362. int worker = workers == NULL ? w : workers[w];
  363. struct starpu_perfmodel_arch* arch = starpu_worker_get_perf_archtype(worker, STARPU_NMAX_SCHED_CTXS);
  364. double length = starpu_perfmodel_history_based_expected_perf(tp->cl->model, arch, tp->footprint);
  365. if (isnan(length))
  366. times[w][t] = NAN;
  367. else
  368. {
  369. times[w][t] = (length / 1000.);
  370. double transfer_time = 0.0;
  371. unsigned worker_in_ctx = starpu_sched_ctx_contains_worker(worker, tp->sched_ctx_id);
  372. enum starpu_worker_archtype arch = starpu_worker_get_type(worker);
  373. if(!worker_in_ctx && !size_ctxs)
  374. {
  375. if(arch == STARPU_CUDA_WORKER)
  376. {
  377. double transfer_speed = starpu_transfer_bandwidth(STARPU_MAIN_RAM, starpu_worker_get_memory_node(worker));
  378. if(transfer_speed > 0.0)
  379. transfer_time += (tp->data_size / transfer_speed) / 1000. ;
  380. double latency = starpu_transfer_latency(STARPU_MAIN_RAM, starpu_worker_get_memory_node(worker));
  381. transfer_time += latency/1000.;
  382. // transfer_time *=4;
  383. }
  384. else if(arch == STARPU_CPU_WORKER)
  385. {
  386. if(!starpu_sched_ctx_contains_type_of_worker(arch, tp->sched_ctx_id))
  387. {
  388. double transfer_speed = starpu_transfer_bandwidth(starpu_worker_get_memory_node(worker), STARPU_MAIN_RAM);
  389. if(transfer_speed > 0.0)
  390. transfer_time += (tp->data_size / transfer_speed) / 1000. ;
  391. double latency = starpu_transfer_latency(starpu_worker_get_memory_node(worker), STARPU_MAIN_RAM);
  392. transfer_time += latency / 1000.;
  393. }
  394. }
  395. }
  396. // printf("%d/%d %s x %d time = %lf transfer_time = %lf\n", w, tp->sched_ctx_id, tp->cl->model->symbol, tp->n, times[w][t], transfer_time);
  397. times[w][t] += transfer_time;
  398. }
  399. // printf("sc%d w%d task %s nt %d times %lf s\n", tp->sched_ctx_id, w, tp->cl->model->symbol, tp->n, times[w][t]);
  400. }
  401. }
  402. }
  403. unsigned sc_hypervisor_check_idle(unsigned sched_ctx, int worker)
  404. {
  405. struct sc_hypervisor_wrapper* sc_w = sc_hypervisor_get_wrapper(sched_ctx);
  406. struct sc_hypervisor_policy_config *config = sc_w->config;
  407. if(config != NULL)
  408. {
  409. if(sc_w->idle_time[worker] > config->max_idle[worker])
  410. {
  411. // printf("w%d/ctx%d: current idle %lf max_idle %lf\n", worker, sched_ctx, sc_w->idle_time[worker], config->max_idle[worker]);
  412. return 1;
  413. }
  414. }
  415. return 0;
  416. }
  417. /* check if there is a big speed gap between the contexts */
  418. unsigned sc_hypervisor_check_speed_gap_btw_ctxs(unsigned *sched_ctxs_in, int ns_in, int *workers_in, int nworkers_in)
  419. {
  420. unsigned *sched_ctxs = sched_ctxs_in == NULL ? sc_hypervisor_get_sched_ctxs() : sched_ctxs_in;
  421. int ns = ns_in == -1 ? sc_hypervisor_get_nsched_ctxs() : ns_in;
  422. int *workers = workers_in;
  423. int nworkers = nworkers_in == -1 ? starpu_worker_get_count() : nworkers_in;
  424. int i = 0, j = 0;
  425. struct sc_hypervisor_wrapper* sc_w;
  426. struct sc_hypervisor_wrapper* other_sc_w;
  427. double optimal_v[ns];
  428. unsigned has_opt_v = 1;
  429. for(i = 0; i < ns; i++)
  430. {
  431. optimal_v[i] = _get_optimal_v(sched_ctxs[i]);
  432. if(optimal_v[i] == 0.0)
  433. {
  434. has_opt_v = 0;
  435. break;
  436. }
  437. }
  438. /*if an optimal speed has not been computed yet do it now */
  439. if(!has_opt_v)
  440. {
  441. struct types_of_workers *tw = sc_hypervisor_get_types_of_workers(workers, nworkers);
  442. int nw = tw->nw;
  443. double nworkers_per_ctx[ns][nw];
  444. int total_nw[nw];
  445. sc_hypervisor_group_workers_by_type(tw, total_nw);
  446. // double vmax = sc_hypervisor_lp_get_nworkers_per_ctx(ns, nw, nworkers_per_ctx, total_nw, tw, sched_ctxs);
  447. // if(vmax != 0.0)
  448. {
  449. for(i = 0; i < ns; i++)
  450. {
  451. sc_w = sc_hypervisor_get_wrapper(sched_ctxs[i]);
  452. double v[nw];
  453. optimal_v[i] = 0.0;
  454. int w;
  455. for(w = 0; w < nw; w++)
  456. {
  457. v[w] = sc_hypervisor_get_speed(sc_w, sc_hypervisor_get_arch_for_index(w, tw));
  458. optimal_v[i] += nworkers_per_ctx[i][w] == -1.0 ? 0.0 : nworkers_per_ctx[i][w]*v[w];
  459. }
  460. _set_optimal_v(sched_ctxs[i], optimal_v[i]);
  461. }
  462. has_opt_v = 1;
  463. }
  464. free(tw);
  465. }
  466. /* if we have an optimal speed for each type of worker compare the monitored one with the
  467. theoretical one */
  468. if(has_opt_v)
  469. {
  470. for(i = 0; i < ns; i++)
  471. {
  472. sc_w = sc_hypervisor_get_wrapper(sched_ctxs[i]);
  473. double ctx_v = sc_hypervisor_get_ctx_speed(sc_w);
  474. if(ctx_v == -1.0)
  475. return 0;
  476. }
  477. for(i = 0; i < ns; i++)
  478. {
  479. sc_w = sc_hypervisor_get_wrapper(sched_ctxs[i]);
  480. double ctx_v = sc_hypervisor_get_ctx_speed(sc_w);
  481. ctx_v = ctx_v < 0.01 ? 0.0 : ctx_v;
  482. double max_vel = _get_max_speed_gap();
  483. if(ctx_v != -1.0 && ((ctx_v < (1-max_vel)*optimal_v[i]) || ctx_v > (1+max_vel)*optimal_v[i]))
  484. {
  485. return 1;
  486. }
  487. }
  488. }
  489. else /* if we have not been able to compute a theoretical speed consider the env variable
  490. SC_MAX_SPEED_GAP and compare the speed of the contexts, whenever the difference
  491. btw them is greater than the max value the function returns true */
  492. {
  493. for(i = 0; i < ns; i++)
  494. {
  495. sc_w = sc_hypervisor_get_wrapper(sched_ctxs[i]);
  496. double ctx_v = sc_hypervisor_get_ctx_speed(sc_w);
  497. if(ctx_v != -1.0)
  498. {
  499. for(j = 0; j < ns; j++)
  500. {
  501. if(sched_ctxs[i] != sched_ctxs[j])
  502. {
  503. unsigned nworkers = starpu_sched_ctx_get_nworkers(sched_ctxs[j]);
  504. if(nworkers == 0)
  505. return 1;
  506. other_sc_w = sc_hypervisor_get_wrapper(sched_ctxs[j]);
  507. double other_ctx_v = sc_hypervisor_get_ctx_speed(other_sc_w);
  508. if(other_ctx_v != -1.0)
  509. {
  510. double gap = ctx_v < other_ctx_v ? other_ctx_v / ctx_v : ctx_v / other_ctx_v;
  511. double max_vel = _get_max_speed_gap();
  512. if(gap > max_vel)
  513. return 1;
  514. }
  515. }
  516. }
  517. }
  518. }
  519. }
  520. return 0;
  521. }
  522. unsigned sc_hypervisor_check_speed_gap_btw_ctxs_on_level(int level, int *workers_in, int nworkers_in, unsigned father_sched_ctx_id, unsigned **sched_ctxs, int *nsched_ctxs)
  523. {
  524. sc_hypervisor_get_ctxs_on_level(sched_ctxs, nsched_ctxs, level, father_sched_ctx_id);
  525. if(*nsched_ctxs > 0)
  526. return sc_hypervisor_check_speed_gap_btw_ctxs(*sched_ctxs, *nsched_ctxs, workers_in, nworkers_in);
  527. return 0;
  528. }
  529. unsigned sc_hypervisor_criteria_fulfilled(unsigned sched_ctx, int worker)
  530. {
  531. unsigned criteria = sc_hypervisor_get_resize_criteria();
  532. if(criteria != SC_NOTHING)
  533. {
  534. if(criteria == SC_IDLE)
  535. return sc_hypervisor_check_idle(sched_ctx, worker);
  536. else
  537. return sc_hypervisor_check_speed_gap_btw_ctxs(NULL, -1, NULL, -1);
  538. }
  539. else
  540. return 0;
  541. }