affinity.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /* Copyright (C) 2006-2015 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. /* This is a Linux specific implementation of a CPU affinity setting. */
  21. #ifndef _GNU_SOURCE
  22. #define _GNU_SOURCE 1
  23. #endif
  24. #include "libgomp.h"
  25. #include "proc.h"
  26. #include <errno.h>
  27. #include <stdlib.h>
  28. #include <stdio.h>
  29. #include <string.h>
  30. #include <unistd.h>
  31. #ifdef HAVE_PTHREAD_AFFINITY_NP
  32. #ifndef CPU_ALLOC_SIZE
  33. #define CPU_ISSET_S(idx, size, set) CPU_ISSET(idx, set)
  34. #define CPU_ZERO_S(size, set) CPU_ZERO(set)
  35. #define CPU_SET_S(idx, size, set) CPU_SET(idx, set)
  36. #define CPU_CLR_S(idx, size, set) CPU_CLR(idx, set)
  37. #endif
  38. void
  39. gomp_init_affinity (void)
  40. {
  41. if (gomp_places_list == NULL)
  42. {
  43. if (!gomp_affinity_init_level (1, ULONG_MAX, true))
  44. return;
  45. }
  46. struct gomp_thread *thr = gomp_thread ();
  47. pthread_setaffinity_np (pthread_self (), gomp_cpuset_size,
  48. (cpu_set_t *) gomp_places_list[0]);
  49. thr->place = 1;
  50. thr->ts.place_partition_off = 0;
  51. thr->ts.place_partition_len = gomp_places_list_len;
  52. }
  53. void
  54. gomp_init_thread_affinity (pthread_attr_t *attr, unsigned int place)
  55. {
  56. pthread_attr_setaffinity_np (attr, gomp_cpuset_size,
  57. (cpu_set_t *) gomp_places_list[place]);
  58. }
  59. void **
  60. gomp_affinity_alloc (unsigned long count, bool quiet)
  61. {
  62. unsigned long i;
  63. void **ret;
  64. char *p;
  65. if (gomp_cpusetp == NULL)
  66. {
  67. if (!quiet)
  68. gomp_error ("Could not get CPU affinity set");
  69. return NULL;
  70. }
  71. ret = malloc (count * sizeof (void *) + count * gomp_cpuset_size);
  72. if (ret == NULL)
  73. {
  74. if (!quiet)
  75. gomp_error ("Out of memory trying to allocate places list");
  76. return NULL;
  77. }
  78. p = (char *) (ret + count);
  79. for (i = 0; i < count; i++, p += gomp_cpuset_size)
  80. ret[i] = p;
  81. return ret;
  82. }
  83. void
  84. gomp_affinity_init_place (void *p)
  85. {
  86. cpu_set_t *cpusetp = (cpu_set_t *) p;
  87. CPU_ZERO_S (gomp_cpuset_size, cpusetp);
  88. }
  89. bool
  90. gomp_affinity_add_cpus (void *p, unsigned long num,
  91. unsigned long len, long stride, bool quiet)
  92. {
  93. cpu_set_t *cpusetp = (cpu_set_t *) p;
  94. unsigned long max = 8 * gomp_cpuset_size;
  95. for (;;)
  96. {
  97. if (num >= max)
  98. {
  99. if (!quiet)
  100. gomp_error ("Logical CPU number %lu out of range", num);
  101. return false;
  102. }
  103. CPU_SET_S (num, gomp_cpuset_size, cpusetp);
  104. if (--len == 0)
  105. return true;
  106. if ((stride < 0 && num + stride > num)
  107. || (stride > 0 && num + stride < num))
  108. {
  109. if (!quiet)
  110. gomp_error ("Logical CPU number %lu+%ld out of range",
  111. num, stride);
  112. return false;
  113. }
  114. num += stride;
  115. }
  116. }
  117. bool
  118. gomp_affinity_remove_cpu (void *p, unsigned long num)
  119. {
  120. cpu_set_t *cpusetp = (cpu_set_t *) p;
  121. if (num >= 8 * gomp_cpuset_size)
  122. {
  123. gomp_error ("Logical CPU number %lu out of range", num);
  124. return false;
  125. }
  126. if (!CPU_ISSET_S (num, gomp_cpuset_size, cpusetp))
  127. {
  128. gomp_error ("Logical CPU %lu to be removed is not in the set", num);
  129. return false;
  130. }
  131. CPU_CLR_S (num, gomp_cpuset_size, cpusetp);
  132. return true;
  133. }
  134. bool
  135. gomp_affinity_copy_place (void *p, void *q, long stride)
  136. {
  137. unsigned long i, max = 8 * gomp_cpuset_size;
  138. cpu_set_t *destp = (cpu_set_t *) p;
  139. cpu_set_t *srcp = (cpu_set_t *) q;
  140. CPU_ZERO_S (gomp_cpuset_size, destp);
  141. for (i = 0; i < max; i++)
  142. if (CPU_ISSET_S (i, gomp_cpuset_size, srcp))
  143. {
  144. if ((stride < 0 && i + stride > i)
  145. || (stride > 0 && (i + stride < i || i + stride >= max)))
  146. {
  147. gomp_error ("Logical CPU number %lu+%ld out of range", i, stride);
  148. return false;
  149. }
  150. CPU_SET_S (i + stride, gomp_cpuset_size, destp);
  151. }
  152. return true;
  153. }
  154. bool
  155. gomp_affinity_same_place (void *p, void *q)
  156. {
  157. #ifdef CPU_EQUAL_S
  158. return CPU_EQUAL_S (gomp_cpuset_size, (cpu_set_t *) p, (cpu_set_t *) q);
  159. #else
  160. return memcmp (p, q, gomp_cpuset_size) == 0;
  161. #endif
  162. }
  163. bool
  164. gomp_affinity_finalize_place_list (bool quiet)
  165. {
  166. unsigned long i, j;
  167. for (i = 0, j = 0; i < gomp_places_list_len; i++)
  168. {
  169. cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[i];
  170. bool nonempty = false;
  171. #ifdef CPU_AND_S
  172. CPU_AND_S (gomp_cpuset_size, cpusetp, cpusetp, gomp_cpusetp);
  173. nonempty = gomp_cpuset_popcount (gomp_cpuset_size, cpusetp) != 0;
  174. #else
  175. unsigned long k, max = gomp_cpuset_size / sizeof (cpusetp->__bits[0]);
  176. for (k = 0; k < max; k++)
  177. if ((cpusetp->__bits[k] &= gomp_cpusetp->__bits[k]) != 0)
  178. nonempty = true;
  179. #endif
  180. if (nonempty)
  181. gomp_places_list[j++] = gomp_places_list[i];
  182. }
  183. if (j == 0)
  184. {
  185. if (!quiet)
  186. gomp_error ("None of the places contain usable logical CPUs");
  187. return false;
  188. }
  189. else if (j < gomp_places_list_len)
  190. {
  191. if (!quiet)
  192. gomp_error ("Number of places reduced from %ld to %ld because some "
  193. "places didn't contain any usable logical CPUs",
  194. gomp_places_list_len, j);
  195. gomp_places_list_len = j;
  196. }
  197. return true;
  198. }
  199. bool
  200. gomp_affinity_init_level (int level, unsigned long count, bool quiet)
  201. {
  202. unsigned long i, max = 8 * gomp_cpuset_size;
  203. if (gomp_cpusetp)
  204. {
  205. unsigned long maxcount
  206. = gomp_cpuset_popcount (gomp_cpuset_size, gomp_cpusetp);
  207. if (count > maxcount)
  208. count = maxcount;
  209. }
  210. gomp_places_list = gomp_affinity_alloc (count, quiet);
  211. gomp_places_list_len = 0;
  212. if (gomp_places_list == NULL)
  213. return false;
  214. /* SMT (threads). */
  215. if (level == 1)
  216. {
  217. for (i = 0; i < max && gomp_places_list_len < count; i++)
  218. if (CPU_ISSET_S (i, gomp_cpuset_size, gomp_cpusetp))
  219. {
  220. gomp_affinity_init_place (gomp_places_list[gomp_places_list_len]);
  221. gomp_affinity_add_cpus (gomp_places_list[gomp_places_list_len],
  222. i, 1, 0, true);
  223. ++gomp_places_list_len;
  224. }
  225. return true;
  226. }
  227. else
  228. {
  229. char name[sizeof ("/sys/devices/system/cpu/cpu/topology/"
  230. "thread_siblings_list") + 3 * sizeof (unsigned long)];
  231. size_t prefix_len = sizeof ("/sys/devices/system/cpu/cpu") - 1;
  232. cpu_set_t *copy = gomp_alloca (gomp_cpuset_size);
  233. FILE *f;
  234. char *line = NULL;
  235. size_t linelen = 0;
  236. memcpy (name, "/sys/devices/system/cpu/cpu", prefix_len);
  237. memcpy (copy, gomp_cpusetp, gomp_cpuset_size);
  238. for (i = 0; i < max && gomp_places_list_len < count; i++)
  239. if (CPU_ISSET_S (i, gomp_cpuset_size, copy))
  240. {
  241. sprintf (name + prefix_len, "%lu/topology/%s_siblings_list",
  242. i, level == 2 ? "thread" : "core");
  243. f = fopen (name, "r");
  244. if (f != NULL)
  245. {
  246. if (getline (&line, &linelen, f) > 0)
  247. {
  248. char *p = line;
  249. bool seen_i = false;
  250. void *pl = gomp_places_list[gomp_places_list_len];
  251. gomp_affinity_init_place (pl);
  252. while (*p && *p != '\n')
  253. {
  254. unsigned long first, last;
  255. errno = 0;
  256. first = strtoul (p, &p, 10);
  257. if (errno)
  258. break;
  259. last = first;
  260. if (*p == '-')
  261. {
  262. errno = 0;
  263. last = strtoul (p + 1, &p, 10);
  264. if (errno || last < first)
  265. break;
  266. }
  267. for (; first <= last; first++)
  268. if (CPU_ISSET_S (first, gomp_cpuset_size, copy)
  269. && gomp_affinity_add_cpus (pl, first, 1, 0,
  270. true))
  271. {
  272. CPU_CLR_S (first, gomp_cpuset_size, copy);
  273. if (first == i)
  274. seen_i = true;
  275. }
  276. if (*p == ',')
  277. ++p;
  278. }
  279. if (seen_i)
  280. gomp_places_list_len++;
  281. }
  282. fclose (f);
  283. }
  284. }
  285. if (gomp_places_list_len == 0)
  286. {
  287. if (!quiet)
  288. gomp_error ("Error reading %s topology",
  289. level == 2 ? "core" : "socket");
  290. free (gomp_places_list);
  291. gomp_places_list = NULL;
  292. return false;
  293. }
  294. return true;
  295. }
  296. return false;
  297. }
  298. void
  299. gomp_affinity_print_place (void *p)
  300. {
  301. unsigned long i, max = 8 * gomp_cpuset_size, len;
  302. cpu_set_t *cpusetp = (cpu_set_t *) p;
  303. bool notfirst = false;
  304. for (i = 0, len = 0; i < max; i++)
  305. if (CPU_ISSET_S (i, gomp_cpuset_size, cpusetp))
  306. {
  307. if (len == 0)
  308. {
  309. if (notfirst)
  310. fputc (',', stderr);
  311. notfirst = true;
  312. fprintf (stderr, "%lu", i);
  313. }
  314. ++len;
  315. }
  316. else
  317. {
  318. if (len > 1)
  319. fprintf (stderr, ":%lu", len);
  320. len = 0;
  321. }
  322. if (len > 1)
  323. fprintf (stderr, ":%lu", len);
  324. }
  325. #else
  326. #include "../posix/affinity.c"
  327. #endif