cpumap.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  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. static struct cpu_map *cpu_map__default_new(void)
  8. {
  9. struct cpu_map *cpus;
  10. int nr_cpus;
  11. nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
  12. if (nr_cpus < 0)
  13. return NULL;
  14. cpus = malloc(sizeof(*cpus) + nr_cpus * sizeof(int));
  15. if (cpus != NULL) {
  16. int i;
  17. for (i = 0; i < nr_cpus; ++i)
  18. cpus->map[i] = i;
  19. cpus->nr = nr_cpus;
  20. }
  21. return cpus;
  22. }
  23. static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
  24. {
  25. size_t payload_size = nr_cpus * sizeof(int);
  26. struct cpu_map *cpus = malloc(sizeof(*cpus) + payload_size);
  27. if (cpus != NULL) {
  28. cpus->nr = nr_cpus;
  29. memcpy(cpus->map, tmp_cpus, payload_size);
  30. }
  31. return cpus;
  32. }
  33. struct cpu_map *cpu_map__read(FILE *file)
  34. {
  35. struct cpu_map *cpus = NULL;
  36. int nr_cpus = 0;
  37. int *tmp_cpus = NULL, *tmp;
  38. int max_entries = 0;
  39. int n, cpu, prev;
  40. char sep;
  41. sep = 0;
  42. prev = -1;
  43. for (;;) {
  44. n = fscanf(file, "%u%c", &cpu, &sep);
  45. if (n <= 0)
  46. break;
  47. if (prev >= 0) {
  48. int new_max = nr_cpus + cpu - prev - 1;
  49. if (new_max >= max_entries) {
  50. max_entries = new_max + MAX_NR_CPUS / 2;
  51. tmp = realloc(tmp_cpus, max_entries * sizeof(int));
  52. if (tmp == NULL)
  53. goto out_free_tmp;
  54. tmp_cpus = tmp;
  55. }
  56. while (++prev < cpu)
  57. tmp_cpus[nr_cpus++] = prev;
  58. }
  59. if (nr_cpus == max_entries) {
  60. max_entries += MAX_NR_CPUS;
  61. tmp = realloc(tmp_cpus, max_entries * sizeof(int));
  62. if (tmp == NULL)
  63. goto out_free_tmp;
  64. tmp_cpus = tmp;
  65. }
  66. tmp_cpus[nr_cpus++] = cpu;
  67. if (n == 2 && sep == '-')
  68. prev = cpu;
  69. else
  70. prev = -1;
  71. if (n == 1 || sep == '\n')
  72. break;
  73. }
  74. if (nr_cpus > 0)
  75. cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
  76. else
  77. cpus = cpu_map__default_new();
  78. out_free_tmp:
  79. free(tmp_cpus);
  80. return cpus;
  81. }
  82. static struct cpu_map *cpu_map__read_all_cpu_map(void)
  83. {
  84. struct cpu_map *cpus = NULL;
  85. FILE *onlnf;
  86. onlnf = fopen("/sys/devices/system/cpu/online", "r");
  87. if (!onlnf)
  88. return cpu_map__default_new();
  89. cpus = cpu_map__read(onlnf);
  90. fclose(onlnf);
  91. return cpus;
  92. }
  93. struct cpu_map *cpu_map__new(const char *cpu_list)
  94. {
  95. struct cpu_map *cpus = NULL;
  96. unsigned long start_cpu, end_cpu = 0;
  97. char *p = NULL;
  98. int i, nr_cpus = 0;
  99. int *tmp_cpus = NULL, *tmp;
  100. int max_entries = 0;
  101. if (!cpu_list)
  102. return cpu_map__read_all_cpu_map();
  103. if (!isdigit(*cpu_list))
  104. goto out;
  105. while (isdigit(*cpu_list)) {
  106. p = NULL;
  107. start_cpu = strtoul(cpu_list, &p, 0);
  108. if (start_cpu >= INT_MAX
  109. || (*p != '\0' && *p != ',' && *p != '-'))
  110. goto invalid;
  111. if (*p == '-') {
  112. cpu_list = ++p;
  113. p = NULL;
  114. end_cpu = strtoul(cpu_list, &p, 0);
  115. if (end_cpu >= INT_MAX || (*p != '\0' && *p != ','))
  116. goto invalid;
  117. if (end_cpu < start_cpu)
  118. goto invalid;
  119. } else {
  120. end_cpu = start_cpu;
  121. }
  122. for (; start_cpu <= end_cpu; start_cpu++) {
  123. /* check for duplicates */
  124. for (i = 0; i < nr_cpus; i++)
  125. if (tmp_cpus[i] == (int)start_cpu)
  126. goto invalid;
  127. if (nr_cpus == max_entries) {
  128. max_entries += MAX_NR_CPUS;
  129. tmp = realloc(tmp_cpus, max_entries * sizeof(int));
  130. if (tmp == NULL)
  131. goto invalid;
  132. tmp_cpus = tmp;
  133. }
  134. tmp_cpus[nr_cpus++] = (int)start_cpu;
  135. }
  136. if (*p)
  137. ++p;
  138. cpu_list = p;
  139. }
  140. if (nr_cpus > 0)
  141. cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
  142. else
  143. cpus = cpu_map__default_new();
  144. invalid:
  145. free(tmp_cpus);
  146. out:
  147. return cpus;
  148. }
  149. size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
  150. {
  151. int i;
  152. size_t printed = fprintf(fp, "%d cpu%s: ",
  153. map->nr, map->nr > 1 ? "s" : "");
  154. for (i = 0; i < map->nr; ++i)
  155. printed += fprintf(fp, "%s%d", i ? ", " : "", map->map[i]);
  156. return printed + fprintf(fp, "\n");
  157. }
  158. struct cpu_map *cpu_map__dummy_new(void)
  159. {
  160. struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
  161. if (cpus != NULL) {
  162. cpus->nr = 1;
  163. cpus->map[0] = -1;
  164. }
  165. return cpus;
  166. }
  167. void cpu_map__delete(struct cpu_map *map)
  168. {
  169. free(map);
  170. }
  171. int cpu_map__get_socket(struct cpu_map *map, int idx)
  172. {
  173. FILE *fp;
  174. const char *mnt;
  175. char path[PATH_MAX];
  176. int cpu, ret;
  177. if (idx > map->nr)
  178. return -1;
  179. cpu = map->map[idx];
  180. mnt = sysfs_find_mountpoint();
  181. if (!mnt)
  182. return -1;
  183. sprintf(path,
  184. "%s/devices/system/cpu/cpu%d/topology/physical_package_id",
  185. mnt, cpu);
  186. fp = fopen(path, "r");
  187. if (!fp)
  188. return -1;
  189. ret = fscanf(fp, "%d", &cpu);
  190. fclose(fp);
  191. return ret == 1 ? cpu : -1;
  192. }
  193. int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp)
  194. {
  195. struct cpu_map *sock;
  196. int nr = cpus->nr;
  197. int cpu, s1, s2;
  198. sock = calloc(1, sizeof(*sock) + nr * sizeof(int));
  199. if (!sock)
  200. return -1;
  201. for (cpu = 0; cpu < nr; cpu++) {
  202. s1 = cpu_map__get_socket(cpus, cpu);
  203. for (s2 = 0; s2 < sock->nr; s2++) {
  204. if (s1 == sock->map[s2])
  205. break;
  206. }
  207. if (s2 == sock->nr) {
  208. sock->map[sock->nr] = s1;
  209. sock->nr++;
  210. }
  211. }
  212. *sockp = sock;
  213. return 0;
  214. }