knobs.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918
  1. /* StarPU --- Runtime system for heterogeneous multicore architectures.
  2. *
  3. * Copyright (C) 2019-2020 Université de Bordeaux, CNRS (LaBRI UMR 5800), Inria
  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. /* Performance counters and configurable knobs */
  17. #include <stdlib.h>
  18. #include <stdint.h>
  19. #include <starpu.h>
  20. #include <common/config.h>
  21. #include <common/starpu_spinlock.h>
  22. #include <core/workers.h>
  23. #include <common/knobs.h>
  24. /* Performance Monitoring */
  25. struct perf_counter_array
  26. {
  27. int size;
  28. struct starpu_perf_counter *array;
  29. int updater_array_size;
  30. void (**updater_array)(struct starpu_perf_counter_sample *sample, void *context);
  31. };
  32. static struct perf_counter_array global_counters = { .size = 0, .array = NULL, .updater_array_size = 0, .updater_array = NULL };
  33. static struct perf_counter_array per_worker_counters = { .size = 0, .array = NULL, .updater_array_size = 0, .updater_array = NULL };
  34. static struct perf_counter_array per_codelet_counters = { .size = 0, .array = NULL, .updater_array_size = 0, .updater_array = NULL };
  35. static struct starpu_perf_counter_sample global_sample = { .scope = starpu_perf_counter_scope_global, .listener = NULL, .value_array = NULL };
  36. /* - */
  37. void _starpu_perf_counter_sample_init(struct starpu_perf_counter_sample *sample, enum starpu_perf_counter_scope scope)
  38. {
  39. STARPU_ASSERT_PERF_COUNTER_SCOPE_DEFINED(scope);
  40. sample->scope = scope;
  41. sample->listener = NULL;
  42. sample->value_array = NULL;
  43. _starpu_spin_init(&sample->lock);
  44. }
  45. void _starpu_perf_counter_sample_exit(struct starpu_perf_counter_sample *sample)
  46. {
  47. STARPU_ASSERT(sample->listener == NULL);
  48. sample->listener = NULL;
  49. if (sample->value_array)
  50. {
  51. free(sample->value_array);
  52. }
  53. sample->value_array = NULL;
  54. sample->scope = starpu_perf_counter_scope_undefined;
  55. _starpu_spin_destroy(&sample->lock);
  56. }
  57. /* - */
  58. void _starpu_perf_counter_init(struct _starpu_machine_config *pconfig)
  59. {
  60. if (pconfig->conf.start_perf_counter_collection)
  61. {
  62. /* start perf counter collection immediately */
  63. pconfig->perf_counter_pause_depth = 0;
  64. }
  65. else
  66. {
  67. /* defer perf counter collection until call to
  68. * starpu_perf_counter_start_collection () */
  69. pconfig->perf_counter_pause_depth = 1;
  70. }
  71. STARPU_ASSERT(!_starpu_machine_is_running());
  72. _starpu_perf_counter_sample_init(&global_sample, starpu_perf_counter_scope_global);
  73. /* call counter registration routines in each modules */
  74. _starpu__task_c__register_counters();
  75. }
  76. void _starpu_perf_counter_exit(void)
  77. {
  78. STARPU_ASSERT(!_starpu_machine_is_running());
  79. _starpu_perf_counter_unregister_all_scopes();
  80. _starpu_perf_counter_sample_exit(&global_sample);
  81. }
  82. /* - */
  83. void starpu_perf_counter_collection_start()
  84. {
  85. STARPU_HG_DISABLE_CHECKING(_starpu_config.perf_counter_pause_depth);
  86. (void)STARPU_ATOMIC_ADD(&_starpu_config.perf_counter_pause_depth, -1);
  87. }
  88. void starpu_perf_counter_collection_stop()
  89. {
  90. STARPU_HG_DISABLE_CHECKING(_starpu_config.perf_counter_pause_depth);
  91. (void)STARPU_ATOMIC_ADD(&_starpu_config.perf_counter_pause_depth, +1);
  92. }
  93. /* - */
  94. int starpu_perf_counter_scope_name_to_id(const char * const name)
  95. {
  96. if (strcmp(name, "global") == 0)
  97. return starpu_perf_counter_scope_global;
  98. if (strcmp(name, "per_worker") == 0)
  99. return starpu_perf_counter_scope_per_worker;
  100. if (strcmp(name, "per_codelet") == 0)
  101. return starpu_perf_counter_scope_per_codelet;
  102. return -1;
  103. }
  104. const char *starpu_perf_counter_scope_id_to_name(const enum starpu_perf_counter_scope scope)
  105. {
  106. switch (scope)
  107. {
  108. case starpu_perf_counter_scope_global:
  109. return "global";
  110. case starpu_perf_counter_scope_per_worker:
  111. return "per_worker";
  112. case starpu_perf_counter_scope_per_codelet:
  113. return "per_codelet";
  114. default:
  115. return NULL;
  116. };
  117. }
  118. /* - */
  119. int starpu_perf_counter_type_name_to_id(const char * const name)
  120. {
  121. if (strcmp(name, "int32") == 0)
  122. return starpu_perf_counter_type_int32;
  123. if (strcmp(name, "int64") == 0)
  124. return starpu_perf_counter_type_int64;
  125. if (strcmp(name, "float") == 0)
  126. return starpu_perf_counter_type_float;
  127. if (strcmp(name, "double") == 0)
  128. return starpu_perf_counter_type_double;
  129. return -1;
  130. }
  131. const char *starpu_perf_counter_type_id_to_name(const enum starpu_perf_counter_type type)
  132. {
  133. switch (type)
  134. {
  135. case starpu_perf_counter_type_int32:
  136. return "int32";
  137. case starpu_perf_counter_type_int64:
  138. return "int64";
  139. case starpu_perf_counter_type_float:
  140. return "float";
  141. case starpu_perf_counter_type_double:
  142. return "double";
  143. default:
  144. return NULL;
  145. };
  146. }
  147. static struct perf_counter_array *_get_counters(const enum starpu_perf_counter_scope scope)
  148. {
  149. STARPU_ASSERT_PERF_COUNTER_SCOPE_DEFINED(scope);
  150. switch (scope)
  151. {
  152. case starpu_perf_counter_scope_global:
  153. return &global_counters;
  154. case starpu_perf_counter_scope_per_worker:
  155. return &per_worker_counters;
  156. case starpu_perf_counter_scope_per_codelet:
  157. return &per_codelet_counters;
  158. default:
  159. STARPU_ABORT();
  160. };
  161. };
  162. /* - */
  163. int _starpu_perf_counter_register(enum starpu_perf_counter_scope scope, const char *name, enum starpu_perf_counter_type type, const char *help)
  164. {
  165. STARPU_ASSERT(!_starpu_machine_is_running());
  166. struct perf_counter_array * const counters = _get_counters(scope);
  167. STARPU_ASSERT_PERF_COUNTER_TYPE_DEFINED(type);
  168. const int index = counters->size++;
  169. _STARPU_REALLOC(counters->array, counters->size * sizeof(*counters->array));
  170. struct starpu_perf_counter * const new_counter = &counters->array[index];
  171. const int id = _starpu_perf_counter_id_build(scope, index);
  172. new_counter->id = id;
  173. new_counter->name = name;
  174. new_counter->help = help;
  175. new_counter->type = type;
  176. return id;
  177. }
  178. static void _unregister_counter_scope(enum starpu_perf_counter_scope scope)
  179. {
  180. STARPU_ASSERT(!_starpu_machine_is_running());
  181. struct perf_counter_array * const counters = _get_counters(scope);
  182. free(counters->array);
  183. counters->array = NULL;
  184. free(counters->updater_array);
  185. counters->updater_array = NULL;
  186. counters->size = 0;
  187. }
  188. void _starpu_perf_counter_unregister_all_scopes(void)
  189. {
  190. STARPU_ASSERT(!_starpu_machine_is_running());
  191. _unregister_counter_scope(starpu_perf_counter_scope_global);
  192. _unregister_counter_scope(starpu_perf_counter_scope_per_worker);
  193. _unregister_counter_scope(starpu_perf_counter_scope_per_codelet);
  194. }
  195. /* - */
  196. int starpu_perf_counter_nb(enum starpu_perf_counter_scope scope)
  197. {
  198. const struct perf_counter_array * const counters = _get_counters(scope);
  199. return counters->size;
  200. }
  201. int starpu_perf_counter_nth_to_id(enum starpu_perf_counter_scope scope, int nth)
  202. {
  203. return _starpu_perf_counter_id_build(scope, nth);
  204. }
  205. int starpu_perf_counter_name_to_id(enum starpu_perf_counter_scope scope, const char *name)
  206. {
  207. const struct perf_counter_array * const counters = _get_counters(scope);
  208. int index;
  209. for (index = 0; index < counters->size; index++)
  210. {
  211. if (strcmp(name, counters->array[index].name) == 0)
  212. {
  213. return _starpu_perf_counter_id_build(scope, index);
  214. }
  215. }
  216. return -1;
  217. }
  218. const char *starpu_perf_counter_id_to_name(int id)
  219. {
  220. const int scope = _starpu_perf_counter_id_get_scope(id);
  221. const int index = _starpu_perf_counter_id_get_index(id);
  222. const struct perf_counter_array * const counters = _get_counters(scope);
  223. if (index < 0 || index >= counters->size)
  224. return NULL;
  225. return counters->array[index].name;
  226. }
  227. const char *starpu_perf_counter_get_help_string(int id)
  228. {
  229. const int scope = _starpu_perf_counter_id_get_scope(id);
  230. const int index = _starpu_perf_counter_id_get_index(id);
  231. const struct perf_counter_array * const counters = _get_counters(scope);
  232. STARPU_ASSERT(index >= 0 && index < counters->size);
  233. return counters->array[index].help;
  234. }
  235. int starpu_perf_counter_get_type_id(int id)
  236. {
  237. const int scope = _starpu_perf_counter_id_get_scope(id);
  238. const int index = _starpu_perf_counter_id_get_index(id);
  239. const struct perf_counter_array * const counters = _get_counters(scope);
  240. STARPU_ASSERT(index >= 0 && index < counters->size);
  241. return counters->array[index].type;
  242. }
  243. /* - */
  244. void starpu_perf_counter_list_avail(enum starpu_perf_counter_scope scope)
  245. {
  246. const struct perf_counter_array * const counters = _get_counters(scope);
  247. int index;
  248. for (index = 0; index < counters->size; index++)
  249. {
  250. const struct starpu_perf_counter * const counter = &counters->array[index];
  251. printf("0x%08x:%s [%s] - %s\n", _starpu_perf_counter_id_build(scope, index), counter->name, starpu_perf_counter_type_id_to_name(counter->type), counter->help);
  252. }
  253. }
  254. void starpu_perf_counter_list_all_avail(void)
  255. {
  256. printf("scope: global\n");
  257. starpu_perf_counter_list_avail(starpu_perf_counter_scope_global);
  258. printf("scope: per_worker\n");
  259. starpu_perf_counter_list_avail(starpu_perf_counter_scope_per_worker);
  260. printf("scope: per_codelet\n");
  261. starpu_perf_counter_list_avail(starpu_perf_counter_scope_per_codelet);
  262. }
  263. /* - */
  264. struct starpu_perf_counter_set *starpu_perf_counter_set_alloc(enum starpu_perf_counter_scope scope)
  265. {
  266. struct perf_counter_array *counters = _get_counters(scope);
  267. struct starpu_perf_counter_set *set;
  268. _STARPU_MALLOC(set, sizeof(*set));
  269. set->scope = scope;
  270. set->size = counters->size;
  271. _STARPU_CALLOC(set->index_array, set->size, sizeof(*set->index_array));
  272. return set;
  273. }
  274. void starpu_perf_counter_set_free(struct starpu_perf_counter_set *set)
  275. {
  276. memset(set->index_array, 0, set->size*sizeof(*set->index_array));
  277. free(set->index_array);
  278. memset(set, 0, sizeof(*set));
  279. free(set);
  280. }
  281. /* - */
  282. void starpu_perf_counter_set_enable_id(struct starpu_perf_counter_set *set, int id)
  283. {
  284. const int index = _starpu_perf_counter_id_get_index(id);
  285. STARPU_ASSERT(index >= 0 && index < set->size);
  286. set->index_array[index] = 1;
  287. }
  288. void starpu_perf_counter_set_disable_id(struct starpu_perf_counter_set *set, int id)
  289. {
  290. const int index = _starpu_perf_counter_id_get_index(id);
  291. STARPU_ASSERT(index >= 0 && index < set->size);
  292. set->index_array[index] = 0;
  293. }
  294. /* - */
  295. struct starpu_perf_counter_listener *starpu_perf_counter_listener_init(struct starpu_perf_counter_set *set,
  296. void (*callback)(struct starpu_perf_counter_listener *listener, struct starpu_perf_counter_sample *sample, void *context),
  297. void *user_arg)
  298. {
  299. struct starpu_perf_counter_listener *listener;
  300. _STARPU_MALLOC(listener, sizeof(*listener));
  301. listener->set = set;
  302. listener->callback = callback;
  303. listener->user_arg = user_arg;
  304. return listener;
  305. }
  306. void starpu_perf_counter_listener_exit(struct starpu_perf_counter_listener *listener)
  307. {
  308. memset(listener, 0, sizeof(*listener));
  309. free(listener);
  310. }
  311. /* - */
  312. static void set_listener(struct starpu_perf_counter_sample *sample, struct starpu_perf_counter_listener *listener)
  313. {
  314. _starpu_spin_lock(&sample->lock);
  315. STARPU_ASSERT(sample->listener == NULL);
  316. STARPU_ASSERT(listener->set != NULL);
  317. STARPU_ASSERT(listener->set->scope == sample->scope);
  318. sample->listener = listener;
  319. /* Assume a single listener, for now, which sets the set of counters to monitor */
  320. STARPU_ASSERT(sample->value_array == NULL);
  321. _STARPU_CALLOC(sample->value_array, sample->listener->set->size, sizeof(*sample->value_array));
  322. _starpu_spin_unlock(&sample->lock);
  323. }
  324. void starpu_perf_counter_set_global_listener(struct starpu_perf_counter_listener *listener)
  325. {
  326. set_listener(&global_sample, listener);
  327. }
  328. void starpu_perf_counter_set_per_worker_listener(unsigned workerid, struct starpu_perf_counter_listener *listener)
  329. {
  330. struct _starpu_worker *worker = _starpu_get_worker_struct(workerid);
  331. set_listener(&worker->perf_counter_sample, listener);
  332. }
  333. void starpu_perf_counter_set_all_per_worker_listeners(struct starpu_perf_counter_listener *listener)
  334. {
  335. unsigned nworkers = _starpu_worker_get_count();
  336. unsigned workerid;
  337. for (workerid = 0; workerid < nworkers; workerid++)
  338. {
  339. starpu_perf_counter_set_per_worker_listener(workerid, listener);
  340. }
  341. }
  342. void starpu_perf_counter_set_per_codelet_listener(struct starpu_codelet *cl, struct starpu_perf_counter_listener *listener)
  343. {
  344. STARPU_ASSERT(cl->perf_counter_values == NULL);
  345. _STARPU_CALLOC(cl->perf_counter_values, 1, sizeof(*cl->perf_counter_values));
  346. STARPU_ASSERT(cl->perf_counter_sample == NULL);
  347. _STARPU_MALLOC(cl->perf_counter_sample, sizeof(*cl->perf_counter_sample));
  348. _starpu_perf_counter_sample_init(cl->perf_counter_sample, starpu_perf_counter_scope_per_codelet);
  349. set_listener(cl->perf_counter_sample, listener);
  350. }
  351. /* - */
  352. void unset_listener(struct starpu_perf_counter_sample *sample)
  353. {
  354. _starpu_spin_lock(&sample->lock);
  355. STARPU_ASSERT(sample->listener != NULL);
  356. memset(sample->value_array, 0, sample->listener->set->size * sizeof(*sample->value_array));
  357. free(sample->value_array);
  358. sample->value_array = NULL;
  359. sample->listener = NULL;
  360. _starpu_spin_unlock(&sample->lock);
  361. }
  362. void starpu_perf_counter_unset_global_listener()
  363. {
  364. unset_listener(&global_sample);
  365. }
  366. void starpu_perf_counter_unset_per_worker_listener(unsigned workerid)
  367. {
  368. struct _starpu_worker *worker = _starpu_get_worker_struct(workerid);
  369. unset_listener(&worker->perf_counter_sample);
  370. }
  371. void starpu_perf_counter_unset_all_per_worker_listeners(void)
  372. {
  373. unsigned nworkers = _starpu_worker_get_count();
  374. unsigned workerid;
  375. for (workerid = 0; workerid < nworkers; workerid++)
  376. {
  377. starpu_perf_counter_unset_per_worker_listener(workerid);
  378. }
  379. }
  380. void starpu_perf_counter_unset_per_codelet_listener(struct starpu_codelet *cl)
  381. {
  382. STARPU_ASSERT(cl->perf_counter_sample != NULL);
  383. unset_listener(cl->perf_counter_sample);
  384. _starpu_perf_counter_sample_exit(cl->perf_counter_sample);
  385. free(cl->perf_counter_sample);
  386. cl->perf_counter_sample = NULL;
  387. free(cl->perf_counter_values);
  388. cl->perf_counter_values = NULL;
  389. }
  390. /* - */
  391. void _starpu_perf_counter_register_updater(enum starpu_perf_counter_scope scope, void (*updater)(struct starpu_perf_counter_sample *sample, void *context))
  392. {
  393. STARPU_ASSERT(!_starpu_machine_is_running());
  394. struct perf_counter_array *counters = _get_counters(scope);
  395. int upd_id;
  396. upd_id = counters->updater_array_size++;
  397. _STARPU_REALLOC(counters->updater_array, counters->updater_array_size * sizeof(*counters->updater_array));
  398. counters->updater_array[upd_id] = updater;
  399. }
  400. /* - */
  401. static void update_sample(struct starpu_perf_counter_sample *sample, void *context)
  402. {
  403. if (sample->listener == NULL)
  404. return;
  405. _starpu_spin_lock(&sample->lock);
  406. struct perf_counter_array *counters = _get_counters(sample->scope);
  407. /* for now, we assume that a sample will only be updated if it has a listener plugged, with a non-empty set */
  408. if (sample->listener != NULL && sample->listener->set != NULL)
  409. {
  410. if (counters->updater_array_size > 0)
  411. {
  412. int upd_id;
  413. for (upd_id = 0; upd_id < counters->updater_array_size; upd_id++)
  414. {
  415. counters->updater_array[upd_id](sample, context);
  416. }
  417. if (sample->listener != NULL)
  418. {
  419. sample->listener->callback(sample->listener, sample, context);
  420. }
  421. }
  422. }
  423. _starpu_spin_unlock(&sample->lock);
  424. }
  425. void _starpu_perf_counter_update_global_sample(void)
  426. {
  427. update_sample(&global_sample, NULL);
  428. }
  429. void _starpu_perf_counter_update_per_worker_sample(unsigned workerid)
  430. {
  431. struct _starpu_worker *worker = _starpu_get_worker_struct(workerid);
  432. update_sample(&worker->perf_counter_sample, worker);
  433. }
  434. void _starpu_perf_counter_update_per_codelet_sample(struct starpu_codelet *cl)
  435. {
  436. update_sample(cl->perf_counter_sample, cl);
  437. }
  438. #define STARPU_PERF_COUNTER_SAMPLE_GET_TYPED_VALUE(STRING, TYPE) \
  439. TYPE starpu_perf_counter_sample_get_##STRING##_value(struct starpu_perf_counter_sample *sample, const int counter_id) \
  440. { \
  441. STARPU_ASSERT(starpu_perf_counter_get_type_id(counter_id) == starpu_perf_counter_type_##STRING); \
  442. STARPU_ASSERT(sample->listener != NULL && sample->listener->set != NULL); \
  443. STARPU_ASSERT(_starpu_perf_counter_id_get_scope(counter_id) == sample->listener->set->scope); \
  444. \
  445. const struct starpu_perf_counter_set * const set = sample->listener->set; \
  446. const int index = _starpu_perf_counter_id_get_index(counter_id); \
  447. STARPU_ASSERT(index < set->size); \
  448. STARPU_ASSERT(set->index_array[index] > 0); \
  449. return sample->value_array[index].STRING##_val; \
  450. }
  451. STARPU_PERF_COUNTER_SAMPLE_GET_TYPED_VALUE(int32, int32_t);
  452. STARPU_PERF_COUNTER_SAMPLE_GET_TYPED_VALUE(int64, int64_t);
  453. STARPU_PERF_COUNTER_SAMPLE_GET_TYPED_VALUE(float, float);
  454. STARPU_PERF_COUNTER_SAMPLE_GET_TYPED_VALUE(double, double);
  455. #undef STARPU_PERF_COUNTER_SAMPLE_GET_TYPED_VALUE
  456. /* -------------------------------------------------------------------- */
  457. /* Performance Steering */
  458. struct perf_knob_array
  459. {
  460. int size;
  461. struct starpu_perf_knob *array;
  462. };
  463. static struct perf_knob_array global_knobs = { .size = 0, .array = NULL };
  464. static struct perf_knob_array per_worker_knobs = { .size = 0, .array = NULL };
  465. static struct perf_knob_array per_scheduler_knobs = { .size = 0, .array = NULL };
  466. void _starpu_perf_knob_init(void)
  467. {
  468. STARPU_ASSERT(!_starpu_machine_is_running());
  469. /* call knob registration routines in each modules */
  470. _starpu__workers_c__register_knobs();
  471. _starpu__task_c__register_knobs();
  472. _starpu__dmda_c__register_knobs();
  473. }
  474. void _starpu_perf_knob_exit(void)
  475. {
  476. STARPU_ASSERT(!_starpu_machine_is_running());
  477. _starpu_perf_knob_unregister_all_scopes();
  478. _starpu__workers_c__unregister_knobs();
  479. _starpu__task_c__unregister_knobs();
  480. _starpu__dmda_c__unregister_knobs();
  481. }
  482. /* - */
  483. int starpu_perf_knob_scope_name_to_id(const char * const name)
  484. {
  485. if (strcmp(name, "global") == 0)
  486. return starpu_perf_knob_scope_global;
  487. if (strcmp(name, "per_worker") == 0)
  488. return starpu_perf_knob_scope_per_worker;
  489. if (strcmp(name, "per_scheduler") == 0)
  490. return starpu_perf_knob_scope_per_scheduler;
  491. return -1;
  492. }
  493. const char *starpu_perf_knob_scope_id_to_name(const enum starpu_perf_knob_scope scope)
  494. {
  495. switch (scope)
  496. {
  497. case starpu_perf_knob_scope_global:
  498. return "global";
  499. case starpu_perf_knob_scope_per_worker:
  500. return "per_worker";
  501. case starpu_perf_knob_scope_per_scheduler:
  502. return "per_scheduler";
  503. default:
  504. return NULL;
  505. };
  506. }
  507. /* - */
  508. int starpu_perf_knob_type_name_to_id(const char * const name)
  509. {
  510. if (strcmp(name, "int32") == 0)
  511. return starpu_perf_knob_type_int32;
  512. if (strcmp(name, "int64") == 0)
  513. return starpu_perf_knob_type_int64;
  514. if (strcmp(name, "float") == 0)
  515. return starpu_perf_knob_type_float;
  516. if (strcmp(name, "double") == 0)
  517. return starpu_perf_knob_type_double;
  518. return -1;
  519. }
  520. const char *starpu_perf_knob_type_id_to_name(const enum starpu_perf_knob_type type)
  521. {
  522. switch (type)
  523. {
  524. case starpu_perf_knob_type_int32:
  525. return "int32";
  526. case starpu_perf_knob_type_int64:
  527. return "int64";
  528. case starpu_perf_knob_type_float:
  529. return "float";
  530. case starpu_perf_knob_type_double:
  531. return "double";
  532. default:
  533. return NULL;
  534. };
  535. }
  536. static struct perf_knob_array *_get_knobs(const enum starpu_perf_knob_scope scope)
  537. {
  538. STARPU_ASSERT_PERF_KNOB_SCOPE_DEFINED(scope);
  539. switch (scope)
  540. {
  541. case starpu_perf_knob_scope_global:
  542. return &global_knobs;
  543. case starpu_perf_knob_scope_per_worker:
  544. return &per_worker_knobs;
  545. case starpu_perf_knob_scope_per_scheduler:
  546. return &per_scheduler_knobs;
  547. default:
  548. STARPU_ABORT();
  549. };
  550. };
  551. /* - */
  552. struct starpu_perf_knob_group *_starpu_perf_knob_group_register(
  553. enum starpu_perf_knob_scope scope,
  554. void (*set_func)(const struct starpu_perf_knob * const knob, void *context, const struct starpu_perf_knob_value * const value),
  555. void (*get_func)(const struct starpu_perf_knob * const knob, void *context, struct starpu_perf_knob_value * const value))
  556. {
  557. STARPU_ASSERT_PERF_KNOB_SCOPE_DEFINED(scope);
  558. STARPU_ASSERT(set_func != NULL);
  559. STARPU_ASSERT(get_func != NULL);
  560. struct starpu_perf_knob_group *new_group;
  561. _STARPU_MALLOC(new_group, sizeof(*new_group));
  562. new_group->scope = scope;
  563. new_group->set = set_func;
  564. new_group->get = get_func;
  565. new_group->array_size = 0;
  566. new_group->array = NULL;
  567. return new_group;
  568. }
  569. void _starpu_perf_knob_group_unregister(struct starpu_perf_knob_group *group)
  570. {
  571. STARPU_ASSERT((group->array_size > 0 && group->array != NULL) || (group->array_size = 0 && group->array == NULL));
  572. if (group->array != NULL)
  573. {
  574. free(group->array);
  575. }
  576. memset(group, 0, sizeof(*group));
  577. free(group);
  578. }
  579. /* - */
  580. int _starpu_perf_knob_register(struct starpu_perf_knob_group *group, const char *name, enum starpu_perf_knob_type type, const char *help)
  581. {
  582. STARPU_ASSERT(!_starpu_machine_is_running());
  583. struct perf_knob_array * const knobs = _get_knobs(group->scope);
  584. STARPU_ASSERT_PERF_KNOB_TYPE_DEFINED(type);
  585. const int index = knobs->size++;
  586. _STARPU_REALLOC(knobs->array, knobs->size * sizeof(*knobs->array));
  587. struct starpu_perf_knob * const new_knob = &knobs->array[index];
  588. const int id = _starpu_perf_knob_id_build(group->scope, index);
  589. new_knob->id = id;
  590. new_knob->name = name;
  591. new_knob->help = help;
  592. new_knob->type = type;
  593. new_knob->group = group;
  594. new_knob->id_in_group = group->array_size++;
  595. _STARPU_REALLOC(group->array, group->array_size * sizeof(*group->array));
  596. group->array[new_knob->id_in_group] = new_knob;
  597. return id;
  598. }
  599. static void _unregister_knob_scope(enum starpu_perf_knob_scope scope)
  600. {
  601. STARPU_ASSERT(!_starpu_machine_is_running());
  602. struct perf_knob_array * const knobs = _get_knobs(scope);
  603. free(knobs->array);
  604. knobs->array = NULL;
  605. knobs->size = 0;
  606. }
  607. void _starpu_perf_knob_unregister_all_scopes(void)
  608. {
  609. STARPU_ASSERT(!_starpu_machine_is_running());
  610. _unregister_knob_scope(starpu_perf_knob_scope_global);
  611. _unregister_knob_scope(starpu_perf_knob_scope_per_worker);
  612. _unregister_knob_scope(starpu_perf_knob_scope_per_scheduler);
  613. }
  614. /* - */
  615. int starpu_perf_knob_nb(enum starpu_perf_knob_scope scope)
  616. {
  617. const struct perf_knob_array * const knobs = _get_knobs(scope);
  618. return knobs->size;
  619. }
  620. int starpu_perf_knob_nth_to_id(enum starpu_perf_knob_scope scope, int nth)
  621. {
  622. return _starpu_perf_knob_id_build(scope, nth);
  623. }
  624. int starpu_perf_knob_name_to_id(enum starpu_perf_knob_scope scope, const char *name)
  625. {
  626. const struct perf_knob_array * const knobs = _get_knobs(scope);
  627. int index;
  628. for (index = 0; index < knobs->size; index++)
  629. {
  630. if (strcmp(name, knobs->array[index].name) == 0)
  631. {
  632. return _starpu_perf_knob_id_build(scope, index);
  633. }
  634. }
  635. return -1;
  636. }
  637. const char *starpu_perf_knob_id_to_name(int id)
  638. {
  639. const int scope = _starpu_perf_knob_id_get_scope(id);
  640. const int index = _starpu_perf_knob_id_get_index(id);
  641. const struct perf_knob_array * const knobs = _get_knobs(scope);
  642. if (index < 0 || index >= knobs->size)
  643. return NULL;
  644. return knobs->array[index].name;
  645. }
  646. const char *starpu_perf_knob_get_help_string(int id)
  647. {
  648. const int scope = _starpu_perf_knob_id_get_scope(id);
  649. const int index = _starpu_perf_knob_id_get_index(id);
  650. const struct perf_knob_array * const knobs = _get_knobs(scope);
  651. STARPU_ASSERT(index >= 0 && index < knobs->size);
  652. return knobs->array[index].help;
  653. }
  654. int starpu_perf_knob_get_type_id(int id)
  655. {
  656. const int scope = _starpu_perf_knob_id_get_scope(id);
  657. const int index = _starpu_perf_knob_id_get_index(id);
  658. const struct perf_knob_array * const knobs = _get_knobs(scope);
  659. STARPU_ASSERT(index >= 0 && index < knobs->size);
  660. return knobs->array[index].type;
  661. }
  662. static struct starpu_perf_knob *get_knob(int id)
  663. {
  664. const int scope = _starpu_perf_knob_id_get_scope(id);
  665. struct perf_knob_array *knobs = _get_knobs(scope);
  666. const int index = _starpu_perf_knob_id_get_index(id);
  667. STARPU_ASSERT(index >= 0 && index < knobs->size);
  668. return &knobs->array[index];
  669. }
  670. /* - */
  671. void starpu_perf_knob_list_avail(enum starpu_perf_knob_scope scope)
  672. {
  673. const struct perf_knob_array * const knobs = _get_knobs(scope);
  674. int index;
  675. for (index = 0; index < knobs->size; index++)
  676. {
  677. const struct starpu_perf_knob * const knob = &knobs->array[index];
  678. printf("0x%08x:%s [%s] - %s\n", _starpu_perf_knob_id_build(scope, index), knob->name, starpu_perf_knob_type_id_to_name(knob->type), knob->help);
  679. }
  680. }
  681. void starpu_perf_knob_list_all_avail(void)
  682. {
  683. printf("scope: global\n");
  684. starpu_perf_knob_list_avail(starpu_perf_knob_scope_global);
  685. printf("scope: per_worker\n");
  686. starpu_perf_knob_list_avail(starpu_perf_knob_scope_per_worker);
  687. printf("scope: per_scheduler\n");
  688. starpu_perf_knob_list_avail(starpu_perf_knob_scope_per_scheduler);
  689. }
  690. #define __STARPU_PERF_KNOB_SET_TYPED_VALUE(SCOPE_NAME, STRING, TYPE) \
  691. void starpu_perf_knob_set_##SCOPE_NAME##_##STRING##_value(const int knob_id, const TYPE value) \
  692. { \
  693. STARPU_ASSERT(_starpu_perf_knob_id_get_scope(knob_id) == starpu_perf_knob_scope_global); \
  694. const struct starpu_perf_knob * const knob = get_knob(knob_id); \
  695. STARPU_ASSERT(starpu_perf_knob_get_type_id(knob_id) == starpu_perf_knob_type_##STRING); \
  696. const struct starpu_perf_knob_group * const knob_group = knob->group; \
  697. const struct starpu_perf_knob_value kv = { .val_##TYPE = value }; \
  698. knob_group->set(knob, NULL, &kv); \
  699. }
  700. __STARPU_PERF_KNOB_SET_TYPED_VALUE(global, int32, int32_t);
  701. __STARPU_PERF_KNOB_SET_TYPED_VALUE(global, int64, int64_t);
  702. __STARPU_PERF_KNOB_SET_TYPED_VALUE(global, float, float);
  703. __STARPU_PERF_KNOB_SET_TYPED_VALUE(global, double, double);
  704. #undef __STARPU_PERF_KNOB_SAMPLE_SET_TYPED_VALUE
  705. #define __STARPU_PERF_KNOB_GET_TYPED_VALUE(SCOPE_NAME, STRING, TYPE) \
  706. TYPE starpu_perf_knob_get_##SCOPE_NAME##_##STRING##_value(const int knob_id) \
  707. { \
  708. STARPU_ASSERT(_starpu_perf_knob_id_get_scope(knob_id) == starpu_perf_knob_scope_global); \
  709. const struct starpu_perf_knob * const knob = get_knob(knob_id); \
  710. STARPU_ASSERT(starpu_perf_knob_get_type_id(knob_id) == starpu_perf_knob_type_##STRING); \
  711. const struct starpu_perf_knob_group * const knob_group = knob->group; \
  712. struct starpu_perf_knob_value kv; \
  713. knob_group->get(knob, NULL, &kv); \
  714. return kv.val_##TYPE; \
  715. }
  716. __STARPU_PERF_KNOB_GET_TYPED_VALUE(global, int32, int32_t);
  717. __STARPU_PERF_KNOB_GET_TYPED_VALUE(global, int64, int64_t);
  718. __STARPU_PERF_KNOB_GET_TYPED_VALUE(global, float, float);
  719. __STARPU_PERF_KNOB_GET_TYPED_VALUE(global, double, double);
  720. #undef __STARPU_PERF_KNOB_SAMPLE_GET_TYPED_VALUE
  721. #define __STARPU_PERF_KNOB_SET_TYPED_VALUE_WITH_CONTEXT(SCOPE_NAME, STRING, TYPE, CONTEXT_TYPE, CONTEXT_VAR) \
  722. void starpu_perf_knob_set_##SCOPE_NAME##_##STRING##_value(const int knob_id, CONTEXT_TYPE CONTEXT_VAR, const TYPE value) \
  723. { \
  724. STARPU_ASSERT(_starpu_perf_knob_id_get_scope(knob_id) == starpu_perf_knob_scope_##SCOPE_NAME); \
  725. const struct starpu_perf_knob * const knob = get_knob(knob_id); \
  726. STARPU_ASSERT(starpu_perf_knob_get_type_id(knob_id) == starpu_perf_knob_type_##STRING); \
  727. const struct starpu_perf_knob_group * const knob_group = knob->group; \
  728. const struct starpu_perf_knob_value kv = { .val_##TYPE = value }; \
  729. knob_group->set(knob, &CONTEXT_VAR, &kv); \
  730. }
  731. __STARPU_PERF_KNOB_SET_TYPED_VALUE_WITH_CONTEXT(per_worker, int32, int32_t, unsigned, workerid);
  732. __STARPU_PERF_KNOB_SET_TYPED_VALUE_WITH_CONTEXT(per_worker, int64, int64_t, unsigned, workerid);
  733. __STARPU_PERF_KNOB_SET_TYPED_VALUE_WITH_CONTEXT(per_worker, float, float, unsigned, workerid);
  734. __STARPU_PERF_KNOB_SET_TYPED_VALUE_WITH_CONTEXT(per_worker, double, double, unsigned, workerid);
  735. __STARPU_PERF_KNOB_SET_TYPED_VALUE_WITH_CONTEXT(per_scheduler, int32, int32_t, const char *, sched_policy_name);
  736. __STARPU_PERF_KNOB_SET_TYPED_VALUE_WITH_CONTEXT(per_scheduler, int64, int64_t, const char *, sched_policy_name);
  737. __STARPU_PERF_KNOB_SET_TYPED_VALUE_WITH_CONTEXT(per_scheduler, float, float, const char *, sched_policy_name);
  738. __STARPU_PERF_KNOB_SET_TYPED_VALUE_WITH_CONTEXT(per_scheduler, double, double, const char *, sched_policy_name);
  739. #undef __STARPU_PERF_KNOB_SAMPLE_SET_TYPED_VALUE_WITH_CONTEXT
  740. #define __STARPU_PERF_KNOB_GET_TYPED_VALUE_WITH_CONTEXT(SCOPE_NAME, STRING, TYPE, CONTEXT_TYPE, CONTEXT_VAR) \
  741. TYPE starpu_perf_knob_get_##SCOPE_NAME##_##STRING##_value(const int knob_id, CONTEXT_TYPE CONTEXT_VAR) \
  742. { \
  743. STARPU_ASSERT(_starpu_perf_knob_id_get_scope(knob_id) == starpu_perf_knob_scope_##SCOPE_NAME); \
  744. const struct starpu_perf_knob * const knob = get_knob(knob_id); \
  745. STARPU_ASSERT(starpu_perf_knob_get_type_id(knob_id) == starpu_perf_knob_type_##STRING); \
  746. const struct starpu_perf_knob_group * const knob_group = knob->group; \
  747. struct starpu_perf_knob_value kv; \
  748. knob_group->get(knob, &CONTEXT_VAR, &kv); \
  749. return kv.val_##TYPE; \
  750. }
  751. __STARPU_PERF_KNOB_GET_TYPED_VALUE_WITH_CONTEXT(per_worker, int32, int32_t, unsigned, workerid);
  752. __STARPU_PERF_KNOB_GET_TYPED_VALUE_WITH_CONTEXT(per_worker, int64, int64_t, unsigned, workerid);
  753. __STARPU_PERF_KNOB_GET_TYPED_VALUE_WITH_CONTEXT(per_worker, float, float, unsigned, workerid);
  754. __STARPU_PERF_KNOB_GET_TYPED_VALUE_WITH_CONTEXT(per_worker, double, double, unsigned, workerid);
  755. __STARPU_PERF_KNOB_GET_TYPED_VALUE_WITH_CONTEXT(per_scheduler, int32, int32_t, const char *, sched_policy_name);
  756. __STARPU_PERF_KNOB_GET_TYPED_VALUE_WITH_CONTEXT(per_scheduler, int64, int64_t, const char *, sched_policy_name);
  757. __STARPU_PERF_KNOB_GET_TYPED_VALUE_WITH_CONTEXT(per_scheduler, float, float, const char *, sched_policy_name);
  758. __STARPU_PERF_KNOB_GET_TYPED_VALUE_WITH_CONTEXT(per_scheduler, double, double, const char *, sched_policy_name);
  759. #undef __STARPU_PERF_KNOB_SAMPLE_GET_TYPED_VALUE_WITH_CONTEXT