Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
20struct 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
27void 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
35void __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
62struct 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
82out:
83 up_read(&env->bpf_progs.lock);
84 return node;
85}
86
87bool 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
97bool __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
125struct 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
135struct 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 */
155static 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
194static void perf_env__purge_bpf(struct perf_env *env __maybe_unused)
195{
196}
197#endif // HAVE_LIBBPF_SUPPORT
198
199void 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
250void 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
260static 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
273int 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
281int 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;
303out_free:
304 zfree(&env->cmdline_argv);
305out_enomem:
306 return -ENOMEM;
307}
308
309int 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
339int 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
369error:
370 strbuf_release(&sb);
371 return -1;
372}
373
374int 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
390static 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
403static 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
411const char *perf_env__raw_arch(struct perf_env *env)
412{
413 return env && !perf_env__read_arch(env) ? env->arch : "unknown";
414}
415
416int 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
421void 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 */
432static 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
460const 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
475const 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
487const 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
500int 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
513const 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
526int 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
565bool 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 }
579out_error:
580 return false;
581}
582
583char *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
626out:
627 free(cap_eq);
628 return NULL;
629}
630
631void 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
646bool 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
656bool 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}