1 // SPDX-License-Identifier: GPL-2.0 2 #include <api/fs/fs.h> 3 #include "../perf.h" 4 #include "cpumap.h" 5 #include "debug.h" 6 #include "event.h" 7 #include <assert.h> 8 #include <dirent.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <linux/bitmap.h> 12 #include "asm/bug.h" 13 14 #include <linux/ctype.h> 15 #include <linux/zalloc.h> 16 17 static int max_cpu_num; 18 static int max_present_cpu_num; 19 static int max_node_num; 20 static int *cpunode_map; 21 22 static struct perf_cpu_map *cpu_map__from_entries(struct cpu_map_entries *cpus) 23 { 24 struct perf_cpu_map *map; 25 26 map = perf_cpu_map__empty_new(cpus->nr); 27 if (map) { 28 unsigned i; 29 30 for (i = 0; i < cpus->nr; i++) { 31 /* 32 * Special treatment for -1, which is not real cpu number, 33 * and we need to use (int) -1 to initialize map[i], 34 * otherwise it would become 65535. 35 */ 36 if (cpus->cpu[i] == (u16) -1) 37 map->map[i] = -1; 38 else 39 map->map[i] = (int) cpus->cpu[i]; 40 } 41 } 42 43 return map; 44 } 45 46 static struct perf_cpu_map *cpu_map__from_mask(struct perf_record_record_cpu_map *mask) 47 { 48 struct perf_cpu_map *map; 49 int nr, nbits = mask->nr * mask->long_size * BITS_PER_BYTE; 50 51 nr = bitmap_weight(mask->mask, nbits); 52 53 map = perf_cpu_map__empty_new(nr); 54 if (map) { 55 int cpu, i = 0; 56 57 for_each_set_bit(cpu, mask->mask, nbits) 58 map->map[i++] = cpu; 59 } 60 return map; 61 62 } 63 64 struct perf_cpu_map *cpu_map__new_data(struct perf_record_cpu_map_data *data) 65 { 66 if (data->type == PERF_CPU_MAP__CPUS) 67 return cpu_map__from_entries((struct cpu_map_entries *)data->data); 68 else 69 return cpu_map__from_mask((struct perf_record_record_cpu_map *)data->data); 70 } 71 72 size_t cpu_map__fprintf(struct perf_cpu_map *map, FILE *fp) 73 { 74 #define BUFSIZE 1024 75 char buf[BUFSIZE]; 76 77 cpu_map__snprint(map, buf, sizeof(buf)); 78 return fprintf(fp, "%s\n", buf); 79 #undef BUFSIZE 80 } 81 82 struct perf_cpu_map *perf_cpu_map__empty_new(int nr) 83 { 84 struct perf_cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int) * nr); 85 86 if (cpus != NULL) { 87 int i; 88 89 cpus->nr = nr; 90 for (i = 0; i < nr; i++) 91 cpus->map[i] = -1; 92 93 refcount_set(&cpus->refcnt, 1); 94 } 95 96 return cpus; 97 } 98 99 static int cpu__get_topology_int(int cpu, const char *name, int *value) 100 { 101 char path[PATH_MAX]; 102 103 snprintf(path, PATH_MAX, 104 "devices/system/cpu/cpu%d/topology/%s", cpu, name); 105 106 return sysfs__read_int(path, value); 107 } 108 109 int cpu_map__get_socket_id(int cpu) 110 { 111 int value, ret = cpu__get_topology_int(cpu, "physical_package_id", &value); 112 return ret ?: value; 113 } 114 115 int cpu_map__get_socket(struct perf_cpu_map *map, int idx, void *data __maybe_unused) 116 { 117 int cpu; 118 119 if (idx > map->nr) 120 return -1; 121 122 cpu = map->map[idx]; 123 124 return cpu_map__get_socket_id(cpu); 125 } 126 127 static int cmp_ids(const void *a, const void *b) 128 { 129 return *(int *)a - *(int *)b; 130 } 131 132 int cpu_map__build_map(struct perf_cpu_map *cpus, struct perf_cpu_map **res, 133 int (*f)(struct perf_cpu_map *map, int cpu, void *data), 134 void *data) 135 { 136 struct perf_cpu_map *c; 137 int nr = cpus->nr; 138 int cpu, s1, s2; 139 140 /* allocate as much as possible */ 141 c = calloc(1, sizeof(*c) + nr * sizeof(int)); 142 if (!c) 143 return -1; 144 145 for (cpu = 0; cpu < nr; cpu++) { 146 s1 = f(cpus, cpu, data); 147 for (s2 = 0; s2 < c->nr; s2++) { 148 if (s1 == c->map[s2]) 149 break; 150 } 151 if (s2 == c->nr) { 152 c->map[c->nr] = s1; 153 c->nr++; 154 } 155 } 156 /* ensure we process id in increasing order */ 157 qsort(c->map, c->nr, sizeof(int), cmp_ids); 158 159 refcount_set(&c->refcnt, 1); 160 *res = c; 161 return 0; 162 } 163 164 int cpu_map__get_die_id(int cpu) 165 { 166 int value, ret = cpu__get_topology_int(cpu, "die_id", &value); 167 168 return ret ?: value; 169 } 170 171 int cpu_map__get_die(struct perf_cpu_map *map, int idx, void *data) 172 { 173 int cpu, die_id, s; 174 175 if (idx > map->nr) 176 return -1; 177 178 cpu = map->map[idx]; 179 180 die_id = cpu_map__get_die_id(cpu); 181 /* There is no die_id on legacy system. */ 182 if (die_id == -1) 183 die_id = 0; 184 185 s = cpu_map__get_socket(map, idx, data); 186 if (s == -1) 187 return -1; 188 189 /* 190 * Encode socket in bit range 15:8 191 * die_id is relative to socket, and 192 * we need a global id. So we combine 193 * socket + die id 194 */ 195 if (WARN_ONCE(die_id >> 8, "The die id number is too big.\n")) 196 return -1; 197 198 if (WARN_ONCE(s >> 8, "The socket id number is too big.\n")) 199 return -1; 200 201 return (s << 8) | (die_id & 0xff); 202 } 203 204 int cpu_map__get_core_id(int cpu) 205 { 206 int value, ret = cpu__get_topology_int(cpu, "core_id", &value); 207 return ret ?: value; 208 } 209 210 int cpu_map__get_core(struct perf_cpu_map *map, int idx, void *data) 211 { 212 int cpu, s_die; 213 214 if (idx > map->nr) 215 return -1; 216 217 cpu = map->map[idx]; 218 219 cpu = cpu_map__get_core_id(cpu); 220 221 /* s_die is the combination of socket + die id */ 222 s_die = cpu_map__get_die(map, idx, data); 223 if (s_die == -1) 224 return -1; 225 226 /* 227 * encode socket in bit range 31:24 228 * encode die id in bit range 23:16 229 * core_id is relative to socket and die, 230 * we need a global id. So we combine 231 * socket + die id + core id 232 */ 233 if (WARN_ONCE(cpu >> 16, "The core id number is too big.\n")) 234 return -1; 235 236 return (s_die << 16) | (cpu & 0xffff); 237 } 238 239 int cpu_map__build_socket_map(struct perf_cpu_map *cpus, struct perf_cpu_map **sockp) 240 { 241 return cpu_map__build_map(cpus, sockp, cpu_map__get_socket, NULL); 242 } 243 244 int cpu_map__build_die_map(struct perf_cpu_map *cpus, struct perf_cpu_map **diep) 245 { 246 return cpu_map__build_map(cpus, diep, cpu_map__get_die, NULL); 247 } 248 249 int cpu_map__build_core_map(struct perf_cpu_map *cpus, struct perf_cpu_map **corep) 250 { 251 return cpu_map__build_map(cpus, corep, cpu_map__get_core, NULL); 252 } 253 254 /* setup simple routines to easily access node numbers given a cpu number */ 255 static int get_max_num(char *path, int *max) 256 { 257 size_t num; 258 char *buf; 259 int err = 0; 260 261 if (filename__read_str(path, &buf, &num)) 262 return -1; 263 264 buf[num] = '\0'; 265 266 /* start on the right, to find highest node num */ 267 while (--num) { 268 if ((buf[num] == ',') || (buf[num] == '-')) { 269 num++; 270 break; 271 } 272 } 273 if (sscanf(&buf[num], "%d", max) < 1) { 274 err = -1; 275 goto out; 276 } 277 278 /* convert from 0-based to 1-based */ 279 (*max)++; 280 281 out: 282 free(buf); 283 return err; 284 } 285 286 /* Determine highest possible cpu in the system for sparse allocation */ 287 static void set_max_cpu_num(void) 288 { 289 const char *mnt; 290 char path[PATH_MAX]; 291 int ret = -1; 292 293 /* set up default */ 294 max_cpu_num = 4096; 295 max_present_cpu_num = 4096; 296 297 mnt = sysfs__mountpoint(); 298 if (!mnt) 299 goto out; 300 301 /* get the highest possible cpu number for a sparse allocation */ 302 ret = snprintf(path, PATH_MAX, "%s/devices/system/cpu/possible", mnt); 303 if (ret == PATH_MAX) { 304 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX); 305 goto out; 306 } 307 308 ret = get_max_num(path, &max_cpu_num); 309 if (ret) 310 goto out; 311 312 /* get the highest present cpu number for a sparse allocation */ 313 ret = snprintf(path, PATH_MAX, "%s/devices/system/cpu/present", mnt); 314 if (ret == PATH_MAX) { 315 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX); 316 goto out; 317 } 318 319 ret = get_max_num(path, &max_present_cpu_num); 320 321 out: 322 if (ret) 323 pr_err("Failed to read max cpus, using default of %d\n", max_cpu_num); 324 } 325 326 /* Determine highest possible node in the system for sparse allocation */ 327 static void set_max_node_num(void) 328 { 329 const char *mnt; 330 char path[PATH_MAX]; 331 int ret = -1; 332 333 /* set up default */ 334 max_node_num = 8; 335 336 mnt = sysfs__mountpoint(); 337 if (!mnt) 338 goto out; 339 340 /* get the highest possible cpu number for a sparse allocation */ 341 ret = snprintf(path, PATH_MAX, "%s/devices/system/node/possible", mnt); 342 if (ret == PATH_MAX) { 343 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX); 344 goto out; 345 } 346 347 ret = get_max_num(path, &max_node_num); 348 349 out: 350 if (ret) 351 pr_err("Failed to read max nodes, using default of %d\n", max_node_num); 352 } 353 354 int cpu__max_node(void) 355 { 356 if (unlikely(!max_node_num)) 357 set_max_node_num(); 358 359 return max_node_num; 360 } 361 362 int cpu__max_cpu(void) 363 { 364 if (unlikely(!max_cpu_num)) 365 set_max_cpu_num(); 366 367 return max_cpu_num; 368 } 369 370 int cpu__max_present_cpu(void) 371 { 372 if (unlikely(!max_present_cpu_num)) 373 set_max_cpu_num(); 374 375 return max_present_cpu_num; 376 } 377 378 379 int cpu__get_node(int cpu) 380 { 381 if (unlikely(cpunode_map == NULL)) { 382 pr_debug("cpu_map not initialized\n"); 383 return -1; 384 } 385 386 return cpunode_map[cpu]; 387 } 388 389 static int init_cpunode_map(void) 390 { 391 int i; 392 393 set_max_cpu_num(); 394 set_max_node_num(); 395 396 cpunode_map = calloc(max_cpu_num, sizeof(int)); 397 if (!cpunode_map) { 398 pr_err("%s: calloc failed\n", __func__); 399 return -1; 400 } 401 402 for (i = 0; i < max_cpu_num; i++) 403 cpunode_map[i] = -1; 404 405 return 0; 406 } 407 408 int cpu__setup_cpunode_map(void) 409 { 410 struct dirent *dent1, *dent2; 411 DIR *dir1, *dir2; 412 unsigned int cpu, mem; 413 char buf[PATH_MAX]; 414 char path[PATH_MAX]; 415 const char *mnt; 416 int n; 417 418 /* initialize globals */ 419 if (init_cpunode_map()) 420 return -1; 421 422 mnt = sysfs__mountpoint(); 423 if (!mnt) 424 return 0; 425 426 n = snprintf(path, PATH_MAX, "%s/devices/system/node", mnt); 427 if (n == PATH_MAX) { 428 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX); 429 return -1; 430 } 431 432 dir1 = opendir(path); 433 if (!dir1) 434 return 0; 435 436 /* walk tree and setup map */ 437 while ((dent1 = readdir(dir1)) != NULL) { 438 if (dent1->d_type != DT_DIR || sscanf(dent1->d_name, "node%u", &mem) < 1) 439 continue; 440 441 n = snprintf(buf, PATH_MAX, "%s/%s", path, dent1->d_name); 442 if (n == PATH_MAX) { 443 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX); 444 continue; 445 } 446 447 dir2 = opendir(buf); 448 if (!dir2) 449 continue; 450 while ((dent2 = readdir(dir2)) != NULL) { 451 if (dent2->d_type != DT_LNK || sscanf(dent2->d_name, "cpu%u", &cpu) < 1) 452 continue; 453 cpunode_map[cpu] = mem; 454 } 455 closedir(dir2); 456 } 457 closedir(dir1); 458 return 0; 459 } 460 461 bool cpu_map__has(struct perf_cpu_map *cpus, int cpu) 462 { 463 return perf_cpu_map__idx(cpus, cpu) != -1; 464 } 465 466 int cpu_map__cpu(struct perf_cpu_map *cpus, int idx) 467 { 468 return cpus->map[idx]; 469 } 470 471 size_t cpu_map__snprint(struct perf_cpu_map *map, char *buf, size_t size) 472 { 473 int i, cpu, start = -1; 474 bool first = true; 475 size_t ret = 0; 476 477 #define COMMA first ? "" : "," 478 479 for (i = 0; i < map->nr + 1; i++) { 480 bool last = i == map->nr; 481 482 cpu = last ? INT_MAX : map->map[i]; 483 484 if (start == -1) { 485 start = i; 486 if (last) { 487 ret += snprintf(buf + ret, size - ret, 488 "%s%d", COMMA, 489 map->map[i]); 490 } 491 } else if (((i - start) != (cpu - map->map[start])) || last) { 492 int end = i - 1; 493 494 if (start == end) { 495 ret += snprintf(buf + ret, size - ret, 496 "%s%d", COMMA, 497 map->map[start]); 498 } else { 499 ret += snprintf(buf + ret, size - ret, 500 "%s%d-%d", COMMA, 501 map->map[start], map->map[end]); 502 } 503 first = false; 504 start = i; 505 } 506 } 507 508 #undef COMMA 509 510 pr_debug2("cpumask list: %s\n", buf); 511 return ret; 512 } 513 514 static char hex_char(unsigned char val) 515 { 516 if (val < 10) 517 return val + '0'; 518 if (val < 16) 519 return val - 10 + 'a'; 520 return '?'; 521 } 522 523 size_t cpu_map__snprint_mask(struct perf_cpu_map *map, char *buf, size_t size) 524 { 525 int i, cpu; 526 char *ptr = buf; 527 unsigned char *bitmap; 528 int last_cpu = cpu_map__cpu(map, map->nr - 1); 529 530 if (buf == NULL) 531 return 0; 532 533 bitmap = zalloc(last_cpu / 8 + 1); 534 if (bitmap == NULL) { 535 buf[0] = '\0'; 536 return 0; 537 } 538 539 for (i = 0; i < map->nr; i++) { 540 cpu = cpu_map__cpu(map, i); 541 bitmap[cpu / 8] |= 1 << (cpu % 8); 542 } 543 544 for (cpu = last_cpu / 4 * 4; cpu >= 0; cpu -= 4) { 545 unsigned char bits = bitmap[cpu / 8]; 546 547 if (cpu % 8) 548 bits >>= 4; 549 else 550 bits &= 0xf; 551 552 *ptr++ = hex_char(bits); 553 if ((cpu % 32) == 0 && cpu > 0) 554 *ptr++ = ','; 555 } 556 *ptr = '\0'; 557 free(bitmap); 558 559 buf[size - 1] = '\0'; 560 return ptr - buf; 561 } 562 563 const struct perf_cpu_map *cpu_map__online(void) /* thread unsafe */ 564 { 565 static const struct perf_cpu_map *online = NULL; 566 567 if (!online) 568 online = perf_cpu_map__new(NULL); /* from /sys/devices/system/cpu/online */ 569 570 return online; 571 } 572