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/ctype.h> 7 #include <linux/zalloc.h> 8 #include "cgroup.h" 9 #include <errno.h> 10 #include <sys/utsname.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include "pmus.h" 14 #include "strbuf.h" 15 16 struct perf_env perf_env; 17 18 #ifdef HAVE_LIBBPF_SUPPORT 19 #include "bpf-event.h" 20 #include "bpf-utils.h" 21 #include <bpf/libbpf.h> 22 23 bool perf_env__insert_bpf_prog_info(struct perf_env *env, 24 struct bpf_prog_info_node *info_node) 25 { 26 bool ret; 27 28 down_write(&env->bpf_progs.lock); 29 ret = __perf_env__insert_bpf_prog_info(env, info_node); 30 up_write(&env->bpf_progs.lock); 31 32 return ret; 33 } 34 35 bool __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 false; 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 return true; 61 } 62 63 struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env, 64 __u32 prog_id) 65 { 66 struct bpf_prog_info_node *node = NULL; 67 struct rb_node *n; 68 69 down_read(&env->bpf_progs.lock); 70 n = env->bpf_progs.infos.rb_node; 71 72 while (n) { 73 node = rb_entry(n, struct bpf_prog_info_node, rb_node); 74 if (prog_id < node->info_linear->info.id) 75 n = n->rb_left; 76 else if (prog_id > node->info_linear->info.id) 77 n = n->rb_right; 78 else 79 goto out; 80 } 81 node = NULL; 82 83 out: 84 up_read(&env->bpf_progs.lock); 85 return node; 86 } 87 88 bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node) 89 { 90 bool ret; 91 92 down_write(&env->bpf_progs.lock); 93 ret = __perf_env__insert_btf(env, btf_node); 94 up_write(&env->bpf_progs.lock); 95 return ret; 96 } 97 98 bool __perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node) 99 { 100 struct rb_node *parent = NULL; 101 __u32 btf_id = btf_node->id; 102 struct btf_node *node; 103 struct rb_node **p; 104 105 p = &env->bpf_progs.btfs.rb_node; 106 107 while (*p != NULL) { 108 parent = *p; 109 node = rb_entry(parent, struct btf_node, rb_node); 110 if (btf_id < node->id) { 111 p = &(*p)->rb_left; 112 } else if (btf_id > node->id) { 113 p = &(*p)->rb_right; 114 } else { 115 pr_debug("duplicated btf %u\n", btf_id); 116 return false; 117 } 118 } 119 120 rb_link_node(&btf_node->rb_node, parent, p); 121 rb_insert_color(&btf_node->rb_node, &env->bpf_progs.btfs); 122 env->bpf_progs.btfs_cnt++; 123 return true; 124 } 125 126 struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id) 127 { 128 struct btf_node *res; 129 130 down_read(&env->bpf_progs.lock); 131 res = __perf_env__find_btf(env, btf_id); 132 up_read(&env->bpf_progs.lock); 133 return res; 134 } 135 136 struct btf_node *__perf_env__find_btf(struct perf_env *env, __u32 btf_id) 137 { 138 struct btf_node *node = NULL; 139 struct rb_node *n; 140 141 n = env->bpf_progs.btfs.rb_node; 142 143 while (n) { 144 node = rb_entry(n, struct btf_node, rb_node); 145 if (btf_id < node->id) 146 n = n->rb_left; 147 else if (btf_id > node->id) 148 n = n->rb_right; 149 else 150 return node; 151 } 152 return NULL; 153 } 154 155 /* purge data in bpf_progs.infos tree */ 156 static void perf_env__purge_bpf(struct perf_env *env) 157 { 158 struct rb_root *root; 159 struct rb_node *next; 160 161 down_write(&env->bpf_progs.lock); 162 163 root = &env->bpf_progs.infos; 164 next = rb_first(root); 165 166 while (next) { 167 struct bpf_prog_info_node *node; 168 169 node = rb_entry(next, struct bpf_prog_info_node, rb_node); 170 next = rb_next(&node->rb_node); 171 rb_erase(&node->rb_node, root); 172 zfree(&node->info_linear); 173 free(node); 174 } 175 176 env->bpf_progs.infos_cnt = 0; 177 178 root = &env->bpf_progs.btfs; 179 next = rb_first(root); 180 181 while (next) { 182 struct btf_node *node; 183 184 node = rb_entry(next, struct btf_node, rb_node); 185 next = rb_next(&node->rb_node); 186 rb_erase(&node->rb_node, root); 187 free(node); 188 } 189 190 env->bpf_progs.btfs_cnt = 0; 191 192 up_write(&env->bpf_progs.lock); 193 } 194 #else // HAVE_LIBBPF_SUPPORT 195 static void perf_env__purge_bpf(struct perf_env *env __maybe_unused) 196 { 197 } 198 #endif // HAVE_LIBBPF_SUPPORT 199 200 void perf_env__exit(struct perf_env *env) 201 { 202 int i, j; 203 204 perf_env__purge_bpf(env); 205 perf_env__purge_cgroups(env); 206 zfree(&env->hostname); 207 zfree(&env->os_release); 208 zfree(&env->version); 209 zfree(&env->arch); 210 zfree(&env->cpu_desc); 211 zfree(&env->cpuid); 212 zfree(&env->cmdline); 213 zfree(&env->cmdline_argv); 214 zfree(&env->sibling_dies); 215 zfree(&env->sibling_cores); 216 zfree(&env->sibling_threads); 217 zfree(&env->pmu_mappings); 218 zfree(&env->cpu); 219 for (i = 0; i < env->nr_cpu_pmu_caps; i++) 220 zfree(&env->cpu_pmu_caps[i]); 221 zfree(&env->cpu_pmu_caps); 222 zfree(&env->numa_map); 223 224 for (i = 0; i < env->nr_numa_nodes; i++) 225 perf_cpu_map__put(env->numa_nodes[i].map); 226 zfree(&env->numa_nodes); 227 228 for (i = 0; i < env->caches_cnt; i++) 229 cpu_cache_level__free(&env->caches[i]); 230 zfree(&env->caches); 231 232 for (i = 0; i < env->nr_memory_nodes; i++) 233 zfree(&env->memory_nodes[i].set); 234 zfree(&env->memory_nodes); 235 236 for (i = 0; i < env->nr_hybrid_nodes; i++) { 237 zfree(&env->hybrid_nodes[i].pmu_name); 238 zfree(&env->hybrid_nodes[i].cpus); 239 } 240 zfree(&env->hybrid_nodes); 241 242 for (i = 0; i < env->nr_pmus_with_caps; i++) { 243 for (j = 0; j < env->pmu_caps[i].nr_caps; j++) 244 zfree(&env->pmu_caps[i].caps[j]); 245 zfree(&env->pmu_caps[i].caps); 246 zfree(&env->pmu_caps[i].pmu_name); 247 } 248 zfree(&env->pmu_caps); 249 } 250 251 void perf_env__init(struct perf_env *env) 252 { 253 #ifdef HAVE_LIBBPF_SUPPORT 254 env->bpf_progs.infos = RB_ROOT; 255 env->bpf_progs.btfs = RB_ROOT; 256 init_rwsem(&env->bpf_progs.lock); 257 #endif 258 env->kernel_is_64_bit = -1; 259 } 260 261 static void perf_env__init_kernel_mode(struct perf_env *env) 262 { 263 const char *arch = perf_env__raw_arch(env); 264 265 if (!strncmp(arch, "x86_64", 6) || !strncmp(arch, "aarch64", 7) || 266 !strncmp(arch, "arm64", 5) || !strncmp(arch, "mips64", 6) || 267 !strncmp(arch, "parisc64", 8) || !strncmp(arch, "riscv64", 7) || 268 !strncmp(arch, "s390x", 5) || !strncmp(arch, "sparc64", 7)) 269 env->kernel_is_64_bit = 1; 270 else 271 env->kernel_is_64_bit = 0; 272 } 273 274 int perf_env__kernel_is_64_bit(struct perf_env *env) 275 { 276 if (env->kernel_is_64_bit == -1) 277 perf_env__init_kernel_mode(env); 278 279 return env->kernel_is_64_bit; 280 } 281 282 int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]) 283 { 284 int i; 285 286 /* do not include NULL termination */ 287 env->cmdline_argv = calloc(argc, sizeof(char *)); 288 if (env->cmdline_argv == NULL) 289 goto out_enomem; 290 291 /* 292 * Must copy argv contents because it gets moved around during option 293 * parsing: 294 */ 295 for (i = 0; i < argc ; i++) { 296 env->cmdline_argv[i] = argv[i]; 297 if (env->cmdline_argv[i] == NULL) 298 goto out_free; 299 } 300 301 env->nr_cmdline = argc; 302 303 return 0; 304 out_free: 305 zfree(&env->cmdline_argv); 306 out_enomem: 307 return -ENOMEM; 308 } 309 310 int perf_env__read_cpu_topology_map(struct perf_env *env) 311 { 312 int idx, nr_cpus; 313 314 if (env->cpu != NULL) 315 return 0; 316 317 if (env->nr_cpus_avail == 0) 318 env->nr_cpus_avail = cpu__max_present_cpu().cpu; 319 320 nr_cpus = env->nr_cpus_avail; 321 if (nr_cpus == -1) 322 return -EINVAL; 323 324 env->cpu = calloc(nr_cpus, sizeof(env->cpu[0])); 325 if (env->cpu == NULL) 326 return -ENOMEM; 327 328 for (idx = 0; idx < nr_cpus; ++idx) { 329 struct perf_cpu cpu = { .cpu = idx }; 330 331 env->cpu[idx].core_id = cpu__get_core_id(cpu); 332 env->cpu[idx].socket_id = cpu__get_socket_id(cpu); 333 env->cpu[idx].die_id = cpu__get_die_id(cpu); 334 } 335 336 env->nr_cpus_avail = nr_cpus; 337 return 0; 338 } 339 340 int perf_env__read_pmu_mappings(struct perf_env *env) 341 { 342 struct perf_pmu *pmu = NULL; 343 u32 pmu_num = 0; 344 struct strbuf sb; 345 346 while ((pmu = perf_pmus__scan(pmu))) 347 pmu_num++; 348 349 if (!pmu_num) { 350 pr_debug("pmu mappings not available\n"); 351 return -ENOENT; 352 } 353 env->nr_pmu_mappings = pmu_num; 354 355 if (strbuf_init(&sb, 128 * pmu_num) < 0) 356 return -ENOMEM; 357 358 while ((pmu = perf_pmus__scan(pmu))) { 359 if (strbuf_addf(&sb, "%u:%s", pmu->type, pmu->name) < 0) 360 goto error; 361 /* include a NULL character at the end */ 362 if (strbuf_add(&sb, "", 1) < 0) 363 goto error; 364 } 365 366 env->pmu_mappings = strbuf_detach(&sb, NULL); 367 368 return 0; 369 370 error: 371 strbuf_release(&sb); 372 return -1; 373 } 374 375 int perf_env__read_cpuid(struct perf_env *env) 376 { 377 char cpuid[128]; 378 int err = get_cpuid(cpuid, sizeof(cpuid)); 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__cpuid(struct perf_env *env) 476 { 477 int status; 478 479 if (!env || !env->cpuid) { /* Assume local operation */ 480 status = perf_env__read_cpuid(env); 481 if (status) 482 return NULL; 483 } 484 485 return env->cpuid; 486 } 487 488 int perf_env__nr_pmu_mappings(struct perf_env *env) 489 { 490 int status; 491 492 if (!env || !env->nr_pmu_mappings) { /* Assume local operation */ 493 status = perf_env__read_pmu_mappings(env); 494 if (status) 495 return 0; 496 } 497 498 return env->nr_pmu_mappings; 499 } 500 501 const char *perf_env__pmu_mappings(struct perf_env *env) 502 { 503 int status; 504 505 if (!env || !env->pmu_mappings) { /* Assume local operation */ 506 status = perf_env__read_pmu_mappings(env); 507 if (status) 508 return NULL; 509 } 510 511 return env->pmu_mappings; 512 } 513 514 int perf_env__numa_node(struct perf_env *env, struct perf_cpu cpu) 515 { 516 if (!env->nr_numa_map) { 517 struct numa_node *nn; 518 int i, nr = 0; 519 520 for (i = 0; i < env->nr_numa_nodes; i++) { 521 nn = &env->numa_nodes[i]; 522 nr = max(nr, perf_cpu_map__max(nn->map).cpu); 523 } 524 525 nr++; 526 527 /* 528 * We initialize the numa_map array to prepare 529 * it for missing cpus, which return node -1 530 */ 531 env->numa_map = malloc(nr * sizeof(int)); 532 if (!env->numa_map) 533 return -1; 534 535 for (i = 0; i < nr; i++) 536 env->numa_map[i] = -1; 537 538 env->nr_numa_map = nr; 539 540 for (i = 0; i < env->nr_numa_nodes; i++) { 541 struct perf_cpu tmp; 542 int j; 543 544 nn = &env->numa_nodes[i]; 545 perf_cpu_map__for_each_cpu(tmp, j, nn->map) 546 env->numa_map[tmp.cpu] = i; 547 } 548 } 549 550 return cpu.cpu >= 0 && cpu.cpu < env->nr_numa_map ? env->numa_map[cpu.cpu] : -1; 551 } 552 553 char *perf_env__find_pmu_cap(struct perf_env *env, const char *pmu_name, 554 const char *cap) 555 { 556 char *cap_eq; 557 int cap_size; 558 char **ptr; 559 int i, j; 560 561 if (!pmu_name || !cap) 562 return NULL; 563 564 cap_size = strlen(cap); 565 cap_eq = zalloc(cap_size + 2); 566 if (!cap_eq) 567 return NULL; 568 569 memcpy(cap_eq, cap, cap_size); 570 cap_eq[cap_size] = '='; 571 572 if (!strcmp(pmu_name, "cpu")) { 573 for (i = 0; i < env->nr_cpu_pmu_caps; i++) { 574 if (!strncmp(env->cpu_pmu_caps[i], cap_eq, cap_size + 1)) { 575 free(cap_eq); 576 return &env->cpu_pmu_caps[i][cap_size + 1]; 577 } 578 } 579 goto out; 580 } 581 582 for (i = 0; i < env->nr_pmus_with_caps; i++) { 583 if (strcmp(env->pmu_caps[i].pmu_name, pmu_name)) 584 continue; 585 586 ptr = env->pmu_caps[i].caps; 587 588 for (j = 0; j < env->pmu_caps[i].nr_caps; j++) { 589 if (!strncmp(ptr[j], cap_eq, cap_size + 1)) { 590 free(cap_eq); 591 return &ptr[j][cap_size + 1]; 592 } 593 } 594 } 595 596 out: 597 free(cap_eq); 598 return NULL; 599 } 600