1 // SPDX-License-Identifier: GPL-2.0 2 #include "cpumap.h" 3 #include "debug.h" 4 #include "env.h" 5 #include "util/header.h" 6 #include "linux/compiler.h" 7 #include <linux/ctype.h> 8 #include <linux/string.h> 9 #include <linux/zalloc.h> 10 #include "cgroup.h" 11 #include <errno.h> 12 #include <sys/utsname.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include "pmu.h" 16 #include "pmus.h" 17 #include "strbuf.h" 18 #include "trace/beauty/beauty.h" 19 20 struct perf_env perf_env; 21 22 #ifdef HAVE_LIBBPF_SUPPORT 23 #include "bpf-event.h" 24 #include "bpf-utils.h" 25 #include <bpf/libbpf.h> 26 27 void perf_env__insert_bpf_prog_info(struct perf_env *env, 28 struct bpf_prog_info_node *info_node) 29 { 30 down_write(&env->bpf_progs.lock); 31 __perf_env__insert_bpf_prog_info(env, info_node); 32 up_write(&env->bpf_progs.lock); 33 } 34 35 void __perf_env__insert_bpf_prog_info(struct perf_env *env, struct bpf_prog_info_node *info_node) 36 { 37 __u32 prog_id = info_node->info_linear->info.id; 38 struct bpf_prog_info_node *node; 39 struct rb_node *parent = NULL; 40 struct rb_node **p; 41 42 p = &env->bpf_progs.infos.rb_node; 43 44 while (*p != NULL) { 45 parent = *p; 46 node = rb_entry(parent, struct bpf_prog_info_node, rb_node); 47 if (prog_id < node->info_linear->info.id) { 48 p = &(*p)->rb_left; 49 } else if (prog_id > node->info_linear->info.id) { 50 p = &(*p)->rb_right; 51 } else { 52 pr_debug("duplicated bpf prog info %u\n", prog_id); 53 return; 54 } 55 } 56 57 rb_link_node(&info_node->rb_node, parent, p); 58 rb_insert_color(&info_node->rb_node, &env->bpf_progs.infos); 59 env->bpf_progs.infos_cnt++; 60 } 61 62 struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env, 63 __u32 prog_id) 64 { 65 struct bpf_prog_info_node *node = NULL; 66 struct rb_node *n; 67 68 down_read(&env->bpf_progs.lock); 69 n = env->bpf_progs.infos.rb_node; 70 71 while (n) { 72 node = rb_entry(n, struct bpf_prog_info_node, rb_node); 73 if (prog_id < node->info_linear->info.id) 74 n = n->rb_left; 75 else if (prog_id > node->info_linear->info.id) 76 n = n->rb_right; 77 else 78 goto out; 79 } 80 node = NULL; 81 82 out: 83 up_read(&env->bpf_progs.lock); 84 return node; 85 } 86 87 bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node) 88 { 89 bool ret; 90 91 down_write(&env->bpf_progs.lock); 92 ret = __perf_env__insert_btf(env, btf_node); 93 up_write(&env->bpf_progs.lock); 94 return ret; 95 } 96 97 bool __perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node) 98 { 99 struct rb_node *parent = NULL; 100 __u32 btf_id = btf_node->id; 101 struct btf_node *node; 102 struct rb_node **p; 103 104 p = &env->bpf_progs.btfs.rb_node; 105 106 while (*p != NULL) { 107 parent = *p; 108 node = rb_entry(parent, struct btf_node, rb_node); 109 if (btf_id < node->id) { 110 p = &(*p)->rb_left; 111 } else if (btf_id > node->id) { 112 p = &(*p)->rb_right; 113 } else { 114 pr_debug("duplicated btf %u\n", btf_id); 115 return false; 116 } 117 } 118 119 rb_link_node(&btf_node->rb_node, parent, p); 120 rb_insert_color(&btf_node->rb_node, &env->bpf_progs.btfs); 121 env->bpf_progs.btfs_cnt++; 122 return true; 123 } 124 125 struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id) 126 { 127 struct btf_node *res; 128 129 down_read(&env->bpf_progs.lock); 130 res = __perf_env__find_btf(env, btf_id); 131 up_read(&env->bpf_progs.lock); 132 return res; 133 } 134 135 struct btf_node *__perf_env__find_btf(struct perf_env *env, __u32 btf_id) 136 { 137 struct btf_node *node = NULL; 138 struct rb_node *n; 139 140 n = env->bpf_progs.btfs.rb_node; 141 142 while (n) { 143 node = rb_entry(n, struct btf_node, rb_node); 144 if (btf_id < node->id) 145 n = n->rb_left; 146 else if (btf_id > node->id) 147 n = n->rb_right; 148 else 149 return node; 150 } 151 return NULL; 152 } 153 154 /* purge data in bpf_progs.infos tree */ 155 static void perf_env__purge_bpf(struct perf_env *env) 156 { 157 struct rb_root *root; 158 struct rb_node *next; 159 160 down_write(&env->bpf_progs.lock); 161 162 root = &env->bpf_progs.infos; 163 next = rb_first(root); 164 165 while (next) { 166 struct bpf_prog_info_node *node; 167 168 node = rb_entry(next, struct bpf_prog_info_node, rb_node); 169 next = rb_next(&node->rb_node); 170 rb_erase(&node->rb_node, root); 171 zfree(&node->info_linear); 172 free(node); 173 } 174 175 env->bpf_progs.infos_cnt = 0; 176 177 root = &env->bpf_progs.btfs; 178 next = rb_first(root); 179 180 while (next) { 181 struct btf_node *node; 182 183 node = rb_entry(next, struct btf_node, rb_node); 184 next = rb_next(&node->rb_node); 185 rb_erase(&node->rb_node, root); 186 free(node); 187 } 188 189 env->bpf_progs.btfs_cnt = 0; 190 191 up_write(&env->bpf_progs.lock); 192 } 193 #else // HAVE_LIBBPF_SUPPORT 194 static void perf_env__purge_bpf(struct perf_env *env __maybe_unused) 195 { 196 } 197 #endif // HAVE_LIBBPF_SUPPORT 198 199 void perf_env__exit(struct perf_env *env) 200 { 201 int i, j; 202 203 perf_env__purge_bpf(env); 204 perf_env__purge_cgroups(env); 205 zfree(&env->hostname); 206 zfree(&env->os_release); 207 zfree(&env->version); 208 zfree(&env->arch); 209 zfree(&env->cpu_desc); 210 zfree(&env->cpuid); 211 zfree(&env->cmdline); 212 zfree(&env->cmdline_argv); 213 zfree(&env->sibling_dies); 214 zfree(&env->sibling_cores); 215 zfree(&env->sibling_threads); 216 zfree(&env->pmu_mappings); 217 zfree(&env->cpu); 218 for (i = 0; i < env->nr_cpu_pmu_caps; i++) 219 zfree(&env->cpu_pmu_caps[i]); 220 zfree(&env->cpu_pmu_caps); 221 zfree(&env->numa_map); 222 223 for (i = 0; i < env->nr_numa_nodes; i++) 224 perf_cpu_map__put(env->numa_nodes[i].map); 225 zfree(&env->numa_nodes); 226 227 for (i = 0; i < env->caches_cnt; i++) 228 cpu_cache_level__free(&env->caches[i]); 229 zfree(&env->caches); 230 231 for (i = 0; i < env->nr_memory_nodes; i++) 232 zfree(&env->memory_nodes[i].set); 233 zfree(&env->memory_nodes); 234 235 for (i = 0; i < env->nr_hybrid_nodes; i++) { 236 zfree(&env->hybrid_nodes[i].pmu_name); 237 zfree(&env->hybrid_nodes[i].cpus); 238 } 239 zfree(&env->hybrid_nodes); 240 241 for (i = 0; i < env->nr_pmus_with_caps; i++) { 242 for (j = 0; j < env->pmu_caps[i].nr_caps; j++) 243 zfree(&env->pmu_caps[i].caps[j]); 244 zfree(&env->pmu_caps[i].caps); 245 zfree(&env->pmu_caps[i].pmu_name); 246 } 247 zfree(&env->pmu_caps); 248 } 249 250 void perf_env__init(struct perf_env *env) 251 { 252 #ifdef HAVE_LIBBPF_SUPPORT 253 env->bpf_progs.infos = RB_ROOT; 254 env->bpf_progs.btfs = RB_ROOT; 255 init_rwsem(&env->bpf_progs.lock); 256 #endif 257 env->kernel_is_64_bit = -1; 258 } 259 260 static void perf_env__init_kernel_mode(struct perf_env *env) 261 { 262 const char *arch = perf_env__raw_arch(env); 263 264 if (!strncmp(arch, "x86_64", 6) || !strncmp(arch, "aarch64", 7) || 265 !strncmp(arch, "arm64", 5) || !strncmp(arch, "mips64", 6) || 266 !strncmp(arch, "parisc64", 8) || !strncmp(arch, "riscv64", 7) || 267 !strncmp(arch, "s390x", 5) || !strncmp(arch, "sparc64", 7)) 268 env->kernel_is_64_bit = 1; 269 else 270 env->kernel_is_64_bit = 0; 271 } 272 273 int perf_env__kernel_is_64_bit(struct perf_env *env) 274 { 275 if (env->kernel_is_64_bit == -1) 276 perf_env__init_kernel_mode(env); 277 278 return env->kernel_is_64_bit; 279 } 280 281 int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]) 282 { 283 int i; 284 285 /* do not include NULL termination */ 286 env->cmdline_argv = calloc(argc, sizeof(char *)); 287 if (env->cmdline_argv == NULL) 288 goto out_enomem; 289 290 /* 291 * Must copy argv contents because it gets moved around during option 292 * parsing: 293 */ 294 for (i = 0; i < argc ; i++) { 295 env->cmdline_argv[i] = argv[i]; 296 if (env->cmdline_argv[i] == NULL) 297 goto out_free; 298 } 299 300 env->nr_cmdline = argc; 301 302 return 0; 303 out_free: 304 zfree(&env->cmdline_argv); 305 out_enomem: 306 return -ENOMEM; 307 } 308 309 int perf_env__read_cpu_topology_map(struct perf_env *env) 310 { 311 int idx, nr_cpus; 312 313 if (env->cpu != NULL) 314 return 0; 315 316 if (env->nr_cpus_avail == 0) 317 env->nr_cpus_avail = cpu__max_present_cpu().cpu; 318 319 nr_cpus = env->nr_cpus_avail; 320 if (nr_cpus == -1) 321 return -EINVAL; 322 323 env->cpu = calloc(nr_cpus, sizeof(env->cpu[0])); 324 if (env->cpu == NULL) 325 return -ENOMEM; 326 327 for (idx = 0; idx < nr_cpus; ++idx) { 328 struct perf_cpu cpu = { .cpu = idx }; 329 330 env->cpu[idx].core_id = cpu__get_core_id(cpu); 331 env->cpu[idx].socket_id = cpu__get_socket_id(cpu); 332 env->cpu[idx].die_id = cpu__get_die_id(cpu); 333 } 334 335 env->nr_cpus_avail = nr_cpus; 336 return 0; 337 } 338 339 int perf_env__read_pmu_mappings(struct perf_env *env) 340 { 341 struct perf_pmu *pmu = NULL; 342 u32 pmu_num = 0; 343 struct strbuf sb; 344 345 while ((pmu = perf_pmus__scan(pmu))) 346 pmu_num++; 347 348 if (!pmu_num) { 349 pr_debug("pmu mappings not available\n"); 350 return -ENOENT; 351 } 352 env->nr_pmu_mappings = pmu_num; 353 354 if (strbuf_init(&sb, 128 * pmu_num) < 0) 355 return -ENOMEM; 356 357 while ((pmu = perf_pmus__scan(pmu))) { 358 if (strbuf_addf(&sb, "%u:%s", pmu->type, pmu->name) < 0) 359 goto error; 360 /* include a NULL character at the end */ 361 if (strbuf_add(&sb, "", 1) < 0) 362 goto error; 363 } 364 365 env->pmu_mappings = strbuf_detach(&sb, NULL); 366 367 return 0; 368 369 error: 370 strbuf_release(&sb); 371 return -1; 372 } 373 374 int perf_env__read_cpuid(struct perf_env *env) 375 { 376 char cpuid[128]; 377 struct perf_cpu cpu = {-1}; 378 int err = get_cpuid(cpuid, sizeof(cpuid), cpu); 379 380 if (err) 381 return err; 382 383 free(env->cpuid); 384 env->cpuid = strdup(cpuid); 385 if (env->cpuid == NULL) 386 return ENOMEM; 387 return 0; 388 } 389 390 static int perf_env__read_arch(struct perf_env *env) 391 { 392 struct utsname uts; 393 394 if (env->arch) 395 return 0; 396 397 if (!uname(&uts)) 398 env->arch = strdup(uts.machine); 399 400 return env->arch ? 0 : -ENOMEM; 401 } 402 403 static int perf_env__read_nr_cpus_avail(struct perf_env *env) 404 { 405 if (env->nr_cpus_avail == 0) 406 env->nr_cpus_avail = cpu__max_present_cpu().cpu; 407 408 return env->nr_cpus_avail ? 0 : -ENOENT; 409 } 410 411 const char *perf_env__raw_arch(struct perf_env *env) 412 { 413 return env && !perf_env__read_arch(env) ? env->arch : "unknown"; 414 } 415 416 int perf_env__nr_cpus_avail(struct perf_env *env) 417 { 418 return env && !perf_env__read_nr_cpus_avail(env) ? env->nr_cpus_avail : 0; 419 } 420 421 void cpu_cache_level__free(struct cpu_cache_level *cache) 422 { 423 zfree(&cache->type); 424 zfree(&cache->map); 425 zfree(&cache->size); 426 } 427 428 /* 429 * Return architecture name in a normalized form. 430 * The conversion logic comes from the Makefile. 431 */ 432 static const char *normalize_arch(char *arch) 433 { 434 if (!strcmp(arch, "x86_64")) 435 return "x86"; 436 if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6') 437 return "x86"; 438 if (!strcmp(arch, "sun4u") || !strncmp(arch, "sparc", 5)) 439 return "sparc"; 440 if (!strncmp(arch, "aarch64", 7) || !strncmp(arch, "arm64", 5)) 441 return "arm64"; 442 if (!strncmp(arch, "arm", 3) || !strcmp(arch, "sa110")) 443 return "arm"; 444 if (!strncmp(arch, "s390", 4)) 445 return "s390"; 446 if (!strncmp(arch, "parisc", 6)) 447 return "parisc"; 448 if (!strncmp(arch, "powerpc", 7) || !strncmp(arch, "ppc", 3)) 449 return "powerpc"; 450 if (!strncmp(arch, "mips", 4)) 451 return "mips"; 452 if (!strncmp(arch, "sh", 2) && isdigit(arch[2])) 453 return "sh"; 454 if (!strncmp(arch, "loongarch", 9)) 455 return "loongarch"; 456 457 return arch; 458 } 459 460 const char *perf_env__arch(struct perf_env *env) 461 { 462 char *arch_name; 463 464 if (!env || !env->arch) { /* Assume local operation */ 465 static struct utsname uts = { .machine[0] = '\0', }; 466 if (uts.machine[0] == '\0' && uname(&uts) < 0) 467 return NULL; 468 arch_name = uts.machine; 469 } else 470 arch_name = env->arch; 471 472 return normalize_arch(arch_name); 473 } 474 475 const char *perf_env__arch_strerrno(struct perf_env *env __maybe_unused, int err __maybe_unused) 476 { 477 #if defined(HAVE_SYSCALL_TABLE_SUPPORT) && defined(HAVE_LIBTRACEEVENT) 478 if (env->arch_strerrno == NULL) 479 env->arch_strerrno = arch_syscalls__strerrno_function(perf_env__arch(env)); 480 481 return env->arch_strerrno ? env->arch_strerrno(err) : "no arch specific strerrno function"; 482 #else 483 return "!(HAVE_SYSCALL_TABLE_SUPPORT && HAVE_LIBTRACEEVENT)"; 484 #endif 485 } 486 487 const char *perf_env__cpuid(struct perf_env *env) 488 { 489 int status; 490 491 if (!env->cpuid) { /* Assume local operation */ 492 status = perf_env__read_cpuid(env); 493 if (status) 494 return NULL; 495 } 496 497 return env->cpuid; 498 } 499 500 int perf_env__nr_pmu_mappings(struct perf_env *env) 501 { 502 int status; 503 504 if (!env->nr_pmu_mappings) { /* Assume local operation */ 505 status = perf_env__read_pmu_mappings(env); 506 if (status) 507 return 0; 508 } 509 510 return env->nr_pmu_mappings; 511 } 512 513 const char *perf_env__pmu_mappings(struct perf_env *env) 514 { 515 int status; 516 517 if (!env->pmu_mappings) { /* Assume local operation */ 518 status = perf_env__read_pmu_mappings(env); 519 if (status) 520 return NULL; 521 } 522 523 return env->pmu_mappings; 524 } 525 526 int perf_env__numa_node(struct perf_env *env, struct perf_cpu cpu) 527 { 528 if (!env->nr_numa_map) { 529 struct numa_node *nn; 530 int i, nr = 0; 531 532 for (i = 0; i < env->nr_numa_nodes; i++) { 533 nn = &env->numa_nodes[i]; 534 nr = max(nr, perf_cpu_map__max(nn->map).cpu); 535 } 536 537 nr++; 538 539 /* 540 * We initialize the numa_map array to prepare 541 * it for missing cpus, which return node -1 542 */ 543 env->numa_map = malloc(nr * sizeof(int)); 544 if (!env->numa_map) 545 return -1; 546 547 for (i = 0; i < nr; i++) 548 env->numa_map[i] = -1; 549 550 env->nr_numa_map = nr; 551 552 for (i = 0; i < env->nr_numa_nodes; i++) { 553 struct perf_cpu tmp; 554 int j; 555 556 nn = &env->numa_nodes[i]; 557 perf_cpu_map__for_each_cpu(tmp, j, nn->map) 558 env->numa_map[tmp.cpu] = i; 559 } 560 } 561 562 return cpu.cpu >= 0 && cpu.cpu < env->nr_numa_map ? env->numa_map[cpu.cpu] : -1; 563 } 564 565 bool perf_env__has_pmu_mapping(struct perf_env *env, const char *pmu_name) 566 { 567 char *pmu_mapping = env->pmu_mappings, *colon; 568 569 for (int i = 0; i < env->nr_pmu_mappings; ++i) { 570 if (strtoul(pmu_mapping, &colon, 0) == ULONG_MAX || *colon != ':') 571 goto out_error; 572 573 pmu_mapping = colon + 1; 574 if (strcmp(pmu_mapping, pmu_name) == 0) 575 return true; 576 577 pmu_mapping += strlen(pmu_mapping) + 1; 578 } 579 out_error: 580 return false; 581 } 582 583 char *perf_env__find_pmu_cap(struct perf_env *env, const char *pmu_name, 584 const char *cap) 585 { 586 char *cap_eq; 587 int cap_size; 588 char **ptr; 589 int i, j; 590 591 if (!pmu_name || !cap) 592 return NULL; 593 594 cap_size = strlen(cap); 595 cap_eq = zalloc(cap_size + 2); 596 if (!cap_eq) 597 return NULL; 598 599 memcpy(cap_eq, cap, cap_size); 600 cap_eq[cap_size] = '='; 601 602 if (!strcmp(pmu_name, "cpu")) { 603 for (i = 0; i < env->nr_cpu_pmu_caps; i++) { 604 if (!strncmp(env->cpu_pmu_caps[i], cap_eq, cap_size + 1)) { 605 free(cap_eq); 606 return &env->cpu_pmu_caps[i][cap_size + 1]; 607 } 608 } 609 goto out; 610 } 611 612 for (i = 0; i < env->nr_pmus_with_caps; i++) { 613 if (strcmp(env->pmu_caps[i].pmu_name, pmu_name)) 614 continue; 615 616 ptr = env->pmu_caps[i].caps; 617 618 for (j = 0; j < env->pmu_caps[i].nr_caps; j++) { 619 if (!strncmp(ptr[j], cap_eq, cap_size + 1)) { 620 free(cap_eq); 621 return &ptr[j][cap_size + 1]; 622 } 623 } 624 } 625 626 out: 627 free(cap_eq); 628 return NULL; 629 } 630 631 void perf_env__find_br_cntr_info(struct perf_env *env, 632 unsigned int *nr, 633 unsigned int *width) 634 { 635 if (nr) { 636 *nr = env->cpu_pmu_caps ? env->br_cntr_nr : 637 env->pmu_caps->br_cntr_nr; 638 } 639 640 if (width) { 641 *width = env->cpu_pmu_caps ? env->br_cntr_width : 642 env->pmu_caps->br_cntr_width; 643 } 644 } 645 646 bool perf_env__is_x86_amd_cpu(struct perf_env *env) 647 { 648 static int is_amd; /* 0: Uninitialized, 1: Yes, -1: No */ 649 650 if (is_amd == 0) 651 is_amd = env->cpuid && strstarts(env->cpuid, "AuthenticAMD") ? 1 : -1; 652 653 return is_amd >= 1 ? true : false; 654 } 655 656 bool x86__is_amd_cpu(void) 657 { 658 struct perf_env env = { .total_mem = 0, }; 659 bool is_amd; 660 661 perf_env__cpuid(&env); 662 is_amd = perf_env__is_x86_amd_cpu(&env); 663 perf_env__exit(&env); 664 665 return is_amd; 666 } 667