affinity-fmt.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. /* Copyright (C) 2018-2022 Free Software Foundation, Inc.
  2. Contributed by Jakub Jelinek <jakub@redhat.com>.
  3. This file is part of the GNU Offloading and Multi Processing Library
  4. (libgomp).
  5. Libgomp is free software; you can redistribute it and/or modify it
  6. under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3, or (at your option)
  8. any later version.
  9. Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12. more details.
  13. Under Section 7 of GPL version 3, you are granted additional
  14. permissions described in the GCC Runtime Library Exception, version
  15. 3.1, as published by the Free Software Foundation.
  16. You should have received a copy of the GNU General Public License and
  17. a copy of the GCC Runtime Library Exception along with this program;
  18. see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. <http://www.gnu.org/licenses/>. */
  20. #include "libgomp.h"
  21. #include <string.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #ifdef HAVE_UNISTD_H
  25. #include <unistd.h>
  26. #endif
  27. #ifdef HAVE_INTTYPES_H
  28. # include <inttypes.h> /* For PRIx64. */
  29. #endif
  30. #ifdef HAVE_UNAME
  31. #include <sys/utsname.h>
  32. #endif
  33. ialias_redirect (omp_get_team_num)
  34. ialias_redirect (omp_get_num_teams)
  35. bool
  36. gomp_print_string (const char *str, size_t len)
  37. {
  38. return fwrite (str, 1, len, stderr) != len;
  39. }
  40. void
  41. gomp_set_affinity_format (const char *format, size_t len)
  42. {
  43. if (len < gomp_affinity_format_len)
  44. memcpy (gomp_affinity_format_var, format, len);
  45. else
  46. {
  47. char *p;
  48. if (gomp_affinity_format_len)
  49. p = gomp_realloc (gomp_affinity_format_var, len + 1);
  50. else
  51. p = gomp_malloc (len + 1);
  52. memcpy (p, format, len);
  53. gomp_affinity_format_var = p;
  54. gomp_affinity_format_len = len + 1;
  55. }
  56. gomp_affinity_format_var[len] = '\0';
  57. }
  58. void
  59. omp_set_affinity_format (const char *format)
  60. {
  61. gomp_set_affinity_format (format, strlen (format));
  62. }
  63. size_t
  64. omp_get_affinity_format (char *buffer, size_t size)
  65. {
  66. size_t len = strlen (gomp_affinity_format_var);
  67. if (size)
  68. {
  69. if (len < size)
  70. memcpy (buffer, gomp_affinity_format_var, len + 1);
  71. else
  72. {
  73. memcpy (buffer, gomp_affinity_format_var, size - 1);
  74. buffer[size - 1] = '\0';
  75. }
  76. }
  77. return len;
  78. }
  79. void
  80. gomp_display_string (char *buffer, size_t size, size_t *ret,
  81. const char *str, size_t len)
  82. {
  83. size_t r = *ret;
  84. if (size && r < size)
  85. {
  86. size_t l = len;
  87. if (size - r < len)
  88. l = size - r;
  89. memcpy (buffer + r, str, l);
  90. }
  91. *ret += len;
  92. if (__builtin_expect (r > *ret, 0))
  93. gomp_fatal ("overflow in omp_capture_affinity");
  94. }
  95. static void
  96. gomp_display_repeat (char *buffer, size_t size, size_t *ret,
  97. char c, size_t len)
  98. {
  99. size_t r = *ret;
  100. if (size && r < size)
  101. {
  102. size_t l = len;
  103. if (size - r < len)
  104. l = size - r;
  105. memset (buffer + r, c, l);
  106. }
  107. *ret += len;
  108. if (__builtin_expect (r > *ret, 0))
  109. gomp_fatal ("overflow in omp_capture_affinity");
  110. }
  111. static void
  112. gomp_display_num (char *buffer, size_t size, size_t *ret,
  113. bool zero, bool right, size_t sz, char *buf)
  114. {
  115. size_t l = strlen (buf);
  116. if (sz == (size_t) -1 || l >= sz)
  117. {
  118. gomp_display_string (buffer, size, ret, buf, l);
  119. return;
  120. }
  121. if (zero)
  122. {
  123. if (buf[0] == '-')
  124. gomp_display_string (buffer, size, ret, buf, 1);
  125. else if (buf[0] == '0' && buf[1] == 'x')
  126. gomp_display_string (buffer, size, ret, buf, 2);
  127. gomp_display_repeat (buffer, size, ret, '0', sz - l);
  128. if (buf[0] == '-')
  129. gomp_display_string (buffer, size, ret, buf + 1, l - 1);
  130. else if (buf[0] == '0' && buf[1] == 'x')
  131. gomp_display_string (buffer, size, ret, buf + 2, l - 2);
  132. else
  133. gomp_display_string (buffer, size, ret, buf, l);
  134. }
  135. else if (right)
  136. {
  137. gomp_display_repeat (buffer, size, ret, ' ', sz - l);
  138. gomp_display_string (buffer, size, ret, buf, l);
  139. }
  140. else
  141. {
  142. gomp_display_string (buffer, size, ret, buf, l);
  143. gomp_display_repeat (buffer, size, ret, ' ', sz - l);
  144. }
  145. }
  146. static void
  147. gomp_display_int (char *buffer, size_t size, size_t *ret,
  148. bool zero, bool right, size_t sz, int num)
  149. {
  150. char buf[3 * sizeof (int) + 2];
  151. sprintf (buf, "%d", num);
  152. gomp_display_num (buffer, size, ret, zero, right, sz, buf);
  153. }
  154. static void
  155. gomp_display_string_len (char *buffer, size_t size, size_t *ret,
  156. bool right, size_t sz, char *str, size_t len)
  157. {
  158. if (sz == (size_t) -1 || len >= sz)
  159. {
  160. gomp_display_string (buffer, size, ret, str, len);
  161. return;
  162. }
  163. if (right)
  164. {
  165. gomp_display_repeat (buffer, size, ret, ' ', sz - len);
  166. gomp_display_string (buffer, size, ret, str, len);
  167. }
  168. else
  169. {
  170. gomp_display_string (buffer, size, ret, str, len);
  171. gomp_display_repeat (buffer, size, ret, ' ', sz - len);
  172. }
  173. }
  174. static void
  175. gomp_display_hostname (char *buffer, size_t size, size_t *ret,
  176. bool right, size_t sz)
  177. {
  178. #ifdef HAVE_GETHOSTNAME
  179. {
  180. char buf[256];
  181. char *b = buf;
  182. size_t len = 256;
  183. do
  184. {
  185. b[len - 1] = '\0';
  186. if (gethostname (b, len - 1) == 0)
  187. {
  188. size_t l = strlen (b);
  189. if (l < len - 1)
  190. {
  191. gomp_display_string_len (buffer, size, ret,
  192. right, sz, b, l);
  193. if (b != buf)
  194. free (b);
  195. return;
  196. }
  197. }
  198. if (len == 1048576)
  199. break;
  200. len = len * 2;
  201. if (len == 512)
  202. b = gomp_malloc (len);
  203. else
  204. b = gomp_realloc (b, len);
  205. }
  206. while (1);
  207. if (b != buf)
  208. free (b);
  209. }
  210. #endif
  211. #ifdef HAVE_UNAME
  212. {
  213. struct utsname buf;
  214. if (uname (&buf) == 0)
  215. {
  216. gomp_display_string_len (buffer, size, ret, right, sz,
  217. buf.nodename, strlen (buf.nodename));
  218. return;
  219. }
  220. }
  221. #endif
  222. gomp_display_string_len (buffer, size, ret, right, sz, "node", 4);
  223. }
  224. struct affinity_types_struct {
  225. char long_str[18];
  226. char long_len;
  227. char short_c; };
  228. static struct affinity_types_struct affinity_types[] =
  229. {
  230. #define AFFINITY_TYPE(l, s) \
  231. { #l, sizeof (#l) - 1, s }
  232. AFFINITY_TYPE (team_num, 't'),
  233. AFFINITY_TYPE (num_teams, 'T'),
  234. AFFINITY_TYPE (nesting_level, 'L'),
  235. AFFINITY_TYPE (thread_num, 'n'),
  236. AFFINITY_TYPE (num_threads, 'N'),
  237. AFFINITY_TYPE (ancestor_tnum, 'a'),
  238. AFFINITY_TYPE (host, 'H'),
  239. AFFINITY_TYPE (process_id, 'P'),
  240. AFFINITY_TYPE (native_thread_id, 'i'),
  241. AFFINITY_TYPE (thread_affinity, 'A')
  242. #undef AFFINITY_TYPE
  243. };
  244. size_t
  245. gomp_display_affinity (char *buffer, size_t size,
  246. const char *format, gomp_thread_handle handle,
  247. struct gomp_team_state *ts, unsigned int place)
  248. {
  249. size_t ret = 0;
  250. do
  251. {
  252. const char *p = strchr (format, '%');
  253. bool zero = false;
  254. bool right = false;
  255. size_t sz = -1;
  256. char c;
  257. int val;
  258. if (p == NULL)
  259. p = strchr (format, '\0');
  260. if (p != format)
  261. gomp_display_string (buffer, size, &ret,
  262. format, p - format);
  263. if (*p == '\0')
  264. break;
  265. p++;
  266. if (*p == '%')
  267. {
  268. gomp_display_string (buffer, size, &ret, "%", 1);
  269. format = p + 1;
  270. continue;
  271. }
  272. if (*p == '0')
  273. {
  274. zero = true;
  275. p++;
  276. if (*p != '.')
  277. gomp_fatal ("leading zero not followed by dot in affinity format");
  278. }
  279. if (*p == '.')
  280. {
  281. right = true;
  282. p++;
  283. }
  284. if (*p >= '1' && *p <= '9')
  285. {
  286. char *end;
  287. sz = strtoul (p, &end, 10);
  288. p = end;
  289. }
  290. else if (zero || right)
  291. gomp_fatal ("leading zero or right justification in affinity format "
  292. "requires size");
  293. c = *p;
  294. if (c == '{')
  295. {
  296. int i;
  297. for (i = 0;
  298. i < sizeof (affinity_types) / sizeof (affinity_types[0]); ++i)
  299. if (strncmp (p + 1, affinity_types[i].long_str,
  300. affinity_types[i].long_len) == 0
  301. && p[affinity_types[i].long_len + 1] == '}')
  302. {
  303. c = affinity_types[i].short_c;
  304. p += affinity_types[i].long_len + 1;
  305. break;
  306. }
  307. if (c == '{')
  308. {
  309. char *q = strchr (p + 1, '}');
  310. if (q)
  311. gomp_fatal ("unsupported long type name '%.*s' in affinity "
  312. "format", (int) (q - (p + 1)), p + 1);
  313. else
  314. gomp_fatal ("unterminated long type name '%s' in affinity "
  315. "format", p + 1);
  316. }
  317. }
  318. switch (c)
  319. {
  320. case 't':
  321. val = omp_get_team_num ();
  322. goto do_int;
  323. case 'T':
  324. val = omp_get_num_teams ();
  325. goto do_int;
  326. case 'L':
  327. val = ts->level;
  328. goto do_int;
  329. case 'n':
  330. val = ts->team_id;
  331. goto do_int;
  332. case 'N':
  333. val = ts->team ? ts->team->nthreads : 1;
  334. goto do_int;
  335. case 'a':
  336. val = ts->team ? ts->team->prev_ts.team_id : -1;
  337. goto do_int;
  338. case 'H':
  339. gomp_display_hostname (buffer, size, &ret, right, sz);
  340. break;
  341. case 'P':
  342. #ifdef HAVE_GETPID
  343. val = getpid ();
  344. #else
  345. val = 0;
  346. #endif
  347. goto do_int;
  348. case 'i':
  349. #if defined(LIBGOMP_USE_PTHREADS) && defined(__GNUC__)
  350. {
  351. char buf[3 * (sizeof (handle) + sizeof (uintptr_t) + sizeof (int))
  352. + 4];
  353. /* This macro returns expr unmodified for integral or pointer
  354. types and 0 for anything else (e.g. aggregates). */
  355. #define gomp_nonaggregate(expr) \
  356. __builtin_choose_expr (__builtin_classify_type (expr) == 1 \
  357. || __builtin_classify_type (expr) == 5, expr, 0)
  358. /* This macro returns expr unmodified for integral types,
  359. (uintptr_t) (expr) for pointer types and 0 for anything else
  360. (e.g. aggregates). */
  361. #define gomp_integral(expr) \
  362. __builtin_choose_expr (__builtin_classify_type (expr) == 5, \
  363. (uintptr_t) gomp_nonaggregate (expr), \
  364. gomp_nonaggregate (expr))
  365. if (sizeof (gomp_integral (handle)) == sizeof (unsigned long))
  366. sprintf (buf, "0x%lx", (unsigned long) gomp_integral (handle));
  367. #if defined (HAVE_INTTYPES_H) && defined (PRIx64)
  368. else if (sizeof (gomp_integral (handle)) == sizeof (uint64_t))
  369. sprintf (buf, "0x%" PRIx64, (uint64_t) gomp_integral (handle));
  370. #else
  371. else if (sizeof (gomp_integral (handle))
  372. == sizeof (unsigned long long))
  373. sprintf (buf, "0x%llx",
  374. (unsigned long long) gomp_integral (handle));
  375. #endif
  376. else
  377. sprintf (buf, "0x%x", (unsigned int) gomp_integral (handle));
  378. gomp_display_num (buffer, size, &ret, zero, right, sz, buf);
  379. break;
  380. }
  381. #else
  382. val = 0;
  383. goto do_int;
  384. #endif
  385. case 'A':
  386. if (sz == (size_t) -1)
  387. gomp_display_affinity_place (buffer, size, &ret,
  388. place - 1);
  389. else if (right)
  390. {
  391. size_t len = 0;
  392. gomp_display_affinity_place (NULL, 0, &len, place - 1);
  393. if (len < sz)
  394. gomp_display_repeat (buffer, size, &ret, ' ', sz - len);
  395. gomp_display_affinity_place (buffer, size, &ret, place - 1);
  396. }
  397. else
  398. {
  399. size_t start = ret;
  400. gomp_display_affinity_place (buffer, size, &ret, place - 1);
  401. if (ret - start < sz)
  402. gomp_display_repeat (buffer, size, &ret, ' ', sz - (ret - start));
  403. }
  404. break;
  405. do_int:
  406. gomp_display_int (buffer, size, &ret, zero, right, sz, val);
  407. break;
  408. default:
  409. gomp_fatal ("unsupported type %c in affinity format", c);
  410. }
  411. format = p + 1;
  412. }
  413. while (1);
  414. return ret;
  415. }
  416. size_t
  417. omp_capture_affinity (char *buffer, size_t size, const char *format)
  418. {
  419. struct gomp_thread *thr = gomp_thread ();
  420. size_t ret
  421. = gomp_display_affinity (buffer, size,
  422. format && *format
  423. ? format : gomp_affinity_format_var,
  424. gomp_thread_self (), &thr->ts, thr->place);
  425. if (size)
  426. {
  427. if (ret >= size)
  428. buffer[size - 1] = '\0';
  429. else
  430. buffer[ret] = '\0';
  431. }
  432. return ret;
  433. }
  434. ialias (omp_capture_affinity)
  435. void
  436. omp_display_affinity (const char *format)
  437. {
  438. char buf[512];
  439. char *b;
  440. size_t ret = ialias_call (omp_capture_affinity) (buf, sizeof buf, format);
  441. if (ret < sizeof buf)
  442. {
  443. buf[ret] = '\n';
  444. gomp_print_string (buf, ret + 1);
  445. return;
  446. }
  447. b = gomp_malloc (ret + 1);
  448. ialias_call (omp_capture_affinity) (b, ret + 1, format);
  449. b[ret] = '\n';
  450. gomp_print_string (b, ret + 1);
  451. free (b);
  452. }
  453. void
  454. gomp_display_affinity_thread (gomp_thread_handle handle,
  455. struct gomp_team_state *ts, unsigned int place)
  456. {
  457. char buf[512];
  458. char *b;
  459. size_t ret = gomp_display_affinity (buf, sizeof buf, gomp_affinity_format_var,
  460. handle, ts, place);
  461. if (ret < sizeof buf)
  462. {
  463. buf[ret] = '\n';
  464. gomp_print_string (buf, ret + 1);
  465. return;
  466. }
  467. b = gomp_malloc (ret + 1);
  468. gomp_display_affinity (b, ret + 1, gomp_affinity_format_var,
  469. handle, ts, place);
  470. b[ret] = '\n';
  471. gomp_print_string (b, ret + 1);
  472. free (b);
  473. }