cpumap.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. #include "util.h"
  2. #include "sysfs.h"
  3. #include "../perf.h"
  4. #include "cpumap.h"
  5. #include <assert.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. static struct cpu_map *cpu_map__default_new(void)
  9. {
  10. struct cpu_map *cpus;
  11. int nr_cpus;
  12. nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
  13. if (nr_cpus < 0)
  14. return NULL;
  15. cpus = malloc(sizeof(*cpus) + nr_cpus * sizeof(int));
  16. if (cpus != NULL) {
  17. int i;
  18. for (i = 0; i < nr_cpus; ++i)
  19. cpus->map[i] = i;
  20. cpus->nr = nr_cpus;
  21. }
  22. return cpus;
  23. }
  24. static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
  25. {
  26. size_t payload_size = nr_cpus * sizeof(int);
  27. struct cpu_map *cpus = malloc(sizeof(*cpus) + payload_size);
  28. if (cpus != NULL) {
  29. cpus->nr = nr_cpus;
  30. memcpy(cpus->map, tmp_cpus, payload_size);
  31. }
  32. return cpus;
  33. }
  34. struct cpu_map *cpu_map__read(FILE *file)
  35. {
  36. struct cpu_map *cpus = NULL;
  37. int nr_cpus = 0;
  38. int *tmp_cpus = NULL, *tmp;
  39. int max_entries = 0;
  40. int n, cpu, prev;
  41. char sep;
  42. sep = 0;
  43. prev = -1;
  44. for (;;) {
  45. n = fscanf(file, "%u%c", &cpu, &sep);
  46. if (n <= 0)
  47. break;
  48. if (prev >= 0) {
  49. int new_max = nr_cpus + cpu - prev - 1;
  50. if (new_max >= max_entries) {
  51. max_entries = new_max + MAX_NR_CPUS / 2;
  52. tmp = realloc(tmp_cpus, max_entries * sizeof(int));
  53. if (tmp == NULL)
  54. goto out_free_tmp;
  55. tmp_cpus = tmp;
  56. }
  57. while (++prev < cpu)
  58. tmp_cpus[nr_cpus++] = prev;
  59. }
  60. if (nr_cpus == max_entries) {
  61. max_entries += MAX_NR_CPUS;
  62. tmp = realloc(tmp_cpus, max_entries * sizeof(int));
  63. if (tmp == NULL)
  64. goto out_free_tmp;
  65. tmp_cpus = tmp;
  66. }
  67. tmp_cpus[nr_cpus++] = cpu;
  68. if (n == 2 && sep == '-')
  69. prev = cpu;
  70. else
  71. prev = -1;
  72. if (n == 1 || sep == '\n')
  73. break;
  74. }
  75. if (nr_cpus > 0)
  76. cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
  77. else
  78. cpus = cpu_map__default_new();
  79. out_free_tmp:
  80. free(tmp_cpus);
  81. return cpus;
  82. }
  83. static struct cpu_map *cpu_map__read_all_cpu_map(void)
  84. {
  85. struct cpu_map *cpus = NULL;
  86. FILE *onlnf;
  87. onlnf = fopen("/sys/devices/system/cpu/online", "r");
  88. if (!onlnf)
  89. return cpu_map__default_new();
  90. cpus = cpu_map__read(onlnf);
  91. fclose(onlnf);
  92. return cpus;
  93. }
  94. struct cpu_map *cpu_map__new(const char *cpu_list)
  95. {
  96. struct cpu_map *cpus = NULL;
  97. unsigned long start_cpu, end_cpu = 0;
  98. char *p = NULL;
  99. int i, nr_cpus = 0;
  100. int *tmp_cpus = NULL, *tmp;
  101. int max_entries = 0;
  102. if (!cpu_list)
  103. return cpu_map__read_all_cpu_map();
  104. if (!isdigit(*cpu_list))
  105. goto out;
  106. while (isdigit(*cpu_list)) {
  107. p = NULL;
  108. start_cpu = strtoul(cpu_list, &p, 0);
  109. if (start_cpu >= INT_MAX
  110. || (*p != '\0' && *p != ',' && *p != '-'))
  111. goto invalid;
  112. if (*p == '-') {
  113. cpu_list = ++p;
  114. p = NULL;
  115. end_cpu = strtoul(cpu_list, &p, 0);
  116. if (end_cpu >= INT_MAX || (*p != '\0' && *p != ','))
  117. goto invalid;
  118. if (end_cpu < start_cpu)
  119. goto invalid;
  120. } else {
  121. end_cpu = start_cpu;
  122. }
  123. for (; start_cpu <= end_cpu; start_cpu++) {
  124. /* check for duplicates */
  125. for (i = 0; i < nr_cpus; i++)
  126. if (tmp_cpus[i] == (int)start_cpu)
  127. goto invalid;
  128. if (nr_cpus == max_entries) {
  129. max_entries += MAX_NR_CPUS;
  130. tmp = realloc(tmp_cpus, max_entries * sizeof(int));
  131. if (tmp == NULL)
  132. goto invalid;
  133. tmp_cpus = tmp;
  134. }
  135. tmp_cpus[nr_cpus++] = (int)start_cpu;
  136. }
  137. if (*p)
  138. ++p;
  139. cpu_list = p;
  140. }
  141. if (nr_cpus > 0)
  142. cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
  143. else
  144. cpus = cpu_map__default_new();
  145. invalid:
  146. free(tmp_cpus);
  147. out:
  148. return cpus;
  149. }
  150. size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
  151. {
  152. int i;
  153. size_t printed = fprintf(fp, "%d cpu%s: ",
  154. map->nr, map->nr > 1 ? "s" : "");
  155. for (i = 0; i < map->nr; ++i)
  156. printed += fprintf(fp, "%s%d", i ? ", " : "", map->map[i]);
  157. return printed + fprintf(fp, "\n");
  158. }
  159. struct cpu_map *cpu_map__dummy_new(void)
  160. {
  161. struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
  162. if (cpus != NULL) {
  163. cpus->nr = 1;
  164. cpus->map[0] = -1;
  165. }
  166. return cpus;
  167. }
  168. void cpu_map__delete(struct cpu_map *map)
  169. {
  170. free(map);
  171. }
  172. int cpu_map__get_socket(struct cpu_map *map, int idx)
  173. {
  174. FILE *fp;
  175. const char *mnt;
  176. char path[PATH_MAX];
  177. int cpu, ret;
  178. if (idx > map->nr)
  179. return -1;
  180. cpu = map->map[idx];
  181. mnt = sysfs_find_mountpoint();
  182. if (!mnt)
  183. return -1;
  184. snprintf(path, PATH_MAX,
  185. "%s/devices/system/cpu/cpu%d/topology/physical_package_id",
  186. mnt, cpu);
  187. fp = fopen(path, "r");
  188. if (!fp)
  189. return -1;
  190. ret = fscanf(fp, "%d", &cpu);
  191. fclose(fp);
  192. return ret == 1 ? cpu : -1;
  193. }
  194. static int cmp_ids(const void *a, const void *b)
  195. {
  196. return *(int *)a - *(int *)b;
  197. }
  198. static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
  199. int (*f)(struct cpu_map *map, int cpu))
  200. {
  201. struct cpu_map *c;
  202. int nr = cpus->nr;
  203. int cpu, s1, s2;
  204. /* allocate as much as possible */
  205. c = calloc(1, sizeof(*c) + nr * sizeof(int));
  206. if (!c)
  207. return -1;
  208. for (cpu = 0; cpu < nr; cpu++) {
  209. s1 = f(cpus, cpu);
  210. for (s2 = 0; s2 < c->nr; s2++) {
  211. if (s1 == c->map[s2])
  212. break;
  213. }
  214. if (s2 == c->nr) {
  215. c->map[c->nr] = s1;
  216. c->nr++;
  217. }
  218. }
  219. /* ensure we process id in increasing order */
  220. qsort(c->map, c->nr, sizeof(int), cmp_ids);
  221. *res = c;
  222. return 0;
  223. }
  224. int cpu_map__get_core(struct cpu_map *map, int idx)
  225. {
  226. FILE *fp;
  227. const char *mnt;
  228. char path[PATH_MAX];
  229. int cpu, ret, s;
  230. if (idx > map->nr)
  231. return -1;
  232. cpu = map->map[idx];
  233. mnt = sysfs_find_mountpoint();
  234. if (!mnt)
  235. return -1;
  236. snprintf(path, PATH_MAX,
  237. "%s/devices/system/cpu/cpu%d/topology/core_id",
  238. mnt, cpu);
  239. fp = fopen(path, "r");
  240. if (!fp)
  241. return -1;
  242. ret = fscanf(fp, "%d", &cpu);
  243. fclose(fp);
  244. if (ret != 1)
  245. return -1;
  246. s = cpu_map__get_socket(map, idx);
  247. if (s == -1)
  248. return -1;
  249. /*
  250. * encode socket in upper 16 bits
  251. * core_id is relative to socket, and
  252. * we need a global id. So we combine
  253. * socket+ core id
  254. */
  255. return (s << 16) | (cpu & 0xffff);
  256. }
  257. int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp)
  258. {
  259. return cpu_map__build_map(cpus, sockp, cpu_map__get_socket);
  260. }
  261. int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep)
  262. {
  263. return cpu_map__build_map(cpus, corep, cpu_map__get_core);
  264. }