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