starpu_replay_sched.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /* StarPU --- Runtime system for heterogeneous multicore architectures.
  2. *
  3. * Copyright (C) 2016-2017 Université de Bordeaux
  4. * Copyright (C) 2017 Erwan Leria
  5. *
  6. * StarPU is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as published by
  8. * the Free Software Foundation; either version 2.1 of the License, or (at
  9. * your option) any later version.
  10. *
  11. * StarPU is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. *
  15. * See the GNU Lesser General Public License in COPYING.LGPL for more details.
  16. */
  17. /*
  18. * This reads a sched.rec file and mangles submitted tasks according to the hint
  19. * from that file.
  20. */
  21. #include <starpu.h>
  22. #include <unistd.h>
  23. #include <stdio.h>
  24. #include <math.h>
  25. #include <common/uthash.h>
  26. #include <common/utils.h>
  27. /*
  28. sched.rec files look like this:
  29. Tag: 1234
  30. Priority: 12
  31. ExecuteOnSpecificWorker: 1
  32. Workers: 0 1 2
  33. DependsOn: 1235
  34. Prefetch: 1234
  35. DependsOn: 1233
  36. */
  37. #define CPY(src, dst, n) memcpy(dst, src, n * sizeof(*dst))
  38. static unsigned long submitorder; /* Also use as prefetchtag */
  39. static int priority;
  40. static int eosw;
  41. static int workerorder;
  42. static int memnode;
  43. static unsigned workers[STARPU_NMAXWORKERS];
  44. static unsigned nworkers;
  45. static unsigned dependson[STARPU_NMAXBUFS];
  46. static unsigned ndependson;
  47. static unsigned params[STARPU_NMAXBUFS];
  48. static unsigned nparams;
  49. static enum sched_type {
  50. NormalTask,
  51. PrefetchTask,
  52. } sched_type;
  53. static struct starpu_codelet cl_prefetch = {
  54. .where = STARPU_NOWHERE,
  55. .nbuffers = 1,
  56. .modes = { STARPU_R },
  57. };
  58. static struct task
  59. {
  60. UT_hash_handle hh;
  61. unsigned long submitorder;
  62. int priority;
  63. int memnode;
  64. unsigned dependson[STARPU_NMAXBUFS];
  65. unsigned ndependson;
  66. struct starpu_task *depends_tasks[STARPU_NMAXBUFS];
  67. /* For real tasks */
  68. int eosw;
  69. int workerorder;
  70. unsigned workers[STARPU_NMAXWORKERS];
  71. unsigned nworkers;
  72. /* For prefetch tasks */
  73. unsigned params[STARPU_NMAXBUFS];
  74. unsigned nparams;
  75. struct starpu_task *pref_task; /* Actual prefetch task */
  76. } *mangled_tasks, *prefetch_tasks;
  77. static struct dep {
  78. UT_hash_handle hh;
  79. unsigned long submitorder;
  80. struct task *task;
  81. unsigned i;
  82. } *dependences;
  83. static void reset(void) {
  84. submitorder = 0;
  85. priority = 0;
  86. eosw = -1;
  87. nworkers = 0;
  88. ndependson = 0;
  89. sched_type = NormalTask;
  90. nparams = 0;
  91. memnode = -1;
  92. workerorder = -1;
  93. }
  94. /* TODO : respecter l'ordre de soumission des tâches SubmitOrder */
  95. // TODO: call SchedRecInit
  96. static void checkField(char * s)
  97. {
  98. /* Record various information */
  99. #define TEST(field) (!strncmp(s, field": ", strlen(field) + 2))
  100. if (TEST("SubmitOrder"))
  101. {
  102. s = s + sizeof("SubmitOrder: ");
  103. submitorder = strtol(s, NULL, 16);
  104. }
  105. else if (TEST("Priority"))
  106. {
  107. s = s + sizeof("Priority: ");
  108. priority = strtol(s, NULL, 10);
  109. }
  110. else if (TEST("ExecuteOnSpecificWorker"))
  111. {
  112. eosw = strtol(s, NULL, 10);
  113. }
  114. else if (TEST("Workers"))
  115. {
  116. s = s + sizeof("Workers: ");
  117. char * delim = " ";
  118. char * token = strtok(s, delim);
  119. int i = 0;
  120. while (token != NULL)
  121. {
  122. int k = strtol(token, NULL, 10);
  123. workers[k/sizeof(*workers)] |= (1 << (k%(sizeof(*workers))));
  124. i++;
  125. }
  126. nworkers = i;
  127. }
  128. else if (TEST("DependsOn"))
  129. {
  130. /* NOTE : dependsons (in the sched.rec) should be the submit orders of the dependences,
  131. otherwise it can occur an undefined behaviour
  132. (contrary to the tasks.rec where dependences are jobids */
  133. unsigned i = 0;
  134. char * delim = " ";
  135. char * token = strtok(s+sizeof("DependsOn: "), delim);
  136. while (token != NULL)
  137. {
  138. dependson[i] = strtol(token, NULL, 10);
  139. i++;
  140. }
  141. ndependson = i;
  142. }
  143. else if (TEST("Prefetch"))
  144. {
  145. s = s + sizeof("Prefetch: ");
  146. submitorder = strtol(s, NULL, 10);
  147. sched_type = PrefetchTask;
  148. }
  149. else if (TEST("Parameters"))
  150. {
  151. s = s + sizeof("Parameters: ");
  152. char * delim = " ";
  153. char * token = strtok(s, delim);
  154. int i = 0;
  155. while (token != NULL)
  156. {
  157. params[i] = strtol(token, NULL, 10);
  158. i++;
  159. }
  160. nparams = i;
  161. }
  162. else if (TEST("MemoryNode"))
  163. {
  164. s = s + sizeof("MemoryNode: ");
  165. memnode = strtol(s, NULL, 10);
  166. }
  167. else if (TEST("Workerorder"))
  168. {
  169. s = s + sizeof("Workerorder: ");
  170. workerorder = strtol(s, NULL, 10);
  171. }
  172. }
  173. void schedRecInit(const char * filename)
  174. {
  175. FILE * f = fopen(filename, "r");
  176. if(f == NULL)
  177. {
  178. return;
  179. }
  180. size_t lnsize = 128;
  181. char * s = malloc(sizeof(*s) * lnsize);
  182. reset();
  183. while(!feof(f))
  184. {
  185. char *ln;
  186. /* Get the line */
  187. if (!fgets(s, lnsize, f))
  188. {
  189. return;
  190. }
  191. while (!(ln = strchr(s, '\n')))
  192. {
  193. _STARPU_REALLOC(s, lnsize * 2);
  194. if (!fgets(s + lnsize-1, lnsize+1, f))
  195. {
  196. return;
  197. }
  198. lnsize *= 2;
  199. }
  200. if (ln == s)
  201. {
  202. /* Empty line, doit */
  203. struct task * task;
  204. unsigned i;
  205. _STARPU_MALLOC(task, sizeof(*task));
  206. task->submitorder = submitorder;
  207. task->priority = priority;
  208. task->memnode = memnode;
  209. CPY(dependson, task->dependson, ndependson);
  210. task->ndependson = ndependson;
  211. /* Also record submitorder of tasks that this one will need to depend on */
  212. for (i = 0; i < ndependson; i++) {
  213. struct dep *dep;
  214. struct starpu_task *starpu_task;
  215. _STARPU_MALLOC(dep, sizeof(*dep));
  216. dep->task = task;
  217. dep->i = i;
  218. dep->submitorder = task->dependson[i];
  219. HASH_ADD(hh, dependences, submitorder, sizeof(submitorder), dep);
  220. /* Create the intermediate task */
  221. starpu_task = dep->task->depends_tasks[i] = starpu_task_create();
  222. starpu_task->cl = NULL;
  223. starpu_task->destroy = 0;
  224. starpu_task->no_submitorder = 1;
  225. }
  226. break;
  227. switch (sched_type)
  228. {
  229. case NormalTask:
  230. /* A new task to mangle, record what needs to be done */
  231. task->eosw = eosw;
  232. task->workerorder = workerorder;
  233. CPY(workers, task->workers, nworkers);
  234. task->nworkers = nworkers;
  235. STARPU_ASSERT(nparams == 0);
  236. break;
  237. case PrefetchTask:
  238. STARPU_ASSERT(eosw == -1);
  239. STARPU_ASSERT(workerorder == -1);
  240. STARPU_ASSERT(nworkers == 0);
  241. CPY(params, task->params, nparams);
  242. task->nparams = nparams;
  243. break;
  244. }
  245. HASH_ADD(hh, mangled_tasks, submitorder, sizeof(submitorder), task);
  246. reset();
  247. }
  248. else checkField(s);
  249. }
  250. }
  251. static void do_prefetch(void *arg)
  252. {
  253. unsigned node = (uintptr_t) arg;
  254. starpu_data_idle_prefetch_on_node(starpu_task_get_current()->handles[0], node, 1);
  255. }
  256. void applySchedRec(struct starpu_task * starpu_task, unsigned long submit_order)
  257. {
  258. struct task *task;
  259. struct dep *dep;
  260. int ret;
  261. HASH_FIND(hh, dependences, &submit_order, sizeof(submit_order), dep);
  262. if (dep)
  263. {
  264. /* Some task will depend on this one, make the dependency */
  265. starpu_task_declare_deps_array(dep->task->depends_tasks[dep->i], 1, &starpu_task);
  266. ret = starpu_task_submit(dep->task->depends_tasks[dep->i]);
  267. STARPU_ASSERT(ret == 0);
  268. }
  269. HASH_FIND(hh, prefetch_tasks, &submit_order, sizeof(submit_order), task);
  270. if (task) {
  271. /* We want to submit a prefetch for this task */
  272. struct starpu_task *pref_task;
  273. pref_task = task->pref_task = starpu_task_create();
  274. pref_task->cl = &cl_prefetch;
  275. pref_task->destroy = 1;
  276. pref_task->no_submitorder = 1;
  277. pref_task->callback_arg = (void*)(uintptr_t) task->memnode;
  278. pref_task->callback_func = do_prefetch;
  279. /* TODO: more params */
  280. pref_task->handles[0] = starpu_task->handles[0];
  281. /* Make it depend on intermediate tasks */
  282. if (task->ndependson)
  283. starpu_task_declare_deps_array(pref_task, task->ndependson, task->depends_tasks);
  284. ret = starpu_task_submit(pref_task);
  285. STARPU_ASSERT(ret == 0);
  286. }
  287. HASH_FIND(hh, mangled_tasks, &submit_order, sizeof(submit_order), task);
  288. if (task == NULL)
  289. /* Nothing to do for this */
  290. return;
  291. starpu_task->workerorder = task->workerorder;
  292. starpu_task->priority = task->priority;
  293. starpu_task->workerids_len = task->nworkers;
  294. _STARPU_MALLOC(starpu_task->workerids, task->nworkers * sizeof(*starpu_task->workerids));
  295. CPY(task->workers, starpu_task->workerids, task->nworkers);
  296. if (task->ndependson)
  297. starpu_task_declare_deps_array(starpu_task, task->ndependson, task->depends_tasks);
  298. /* And now, let it go! */
  299. }