1 // SPDX-License-Identifier: GPL-2.0
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>
12 #include <sys/utsname.h>
18 #include "trace/beauty/beauty.h"
20 struct perf_env perf_env
;
22 #ifdef HAVE_LIBBPF_SUPPORT
23 #include "bpf-event.h"
24 #include "bpf-utils.h"
25 #include <bpf/libbpf.h>
27 void perf_env__insert_bpf_prog_info(struct perf_env
*env
,
28 struct bpf_prog_info_node
*info_node
)
30 down_write(&env
->bpf_progs
.lock
);
31 __perf_env__insert_bpf_prog_info(env
, info_node
);
32 up_write(&env
->bpf_progs
.lock
);
35 void __perf_env__insert_bpf_prog_info(struct perf_env
*env
, struct bpf_prog_info_node
*info_node
)
37 __u32 prog_id
= info_node
->info_linear
->info
.id
;
38 struct bpf_prog_info_node
*node
;
39 struct rb_node
*parent
= NULL
;
42 p
= &env
->bpf_progs
.infos
.rb_node
;
46 node
= rb_entry(parent
, struct bpf_prog_info_node
, rb_node
);
47 if (prog_id
< node
->info_linear
->info
.id
) {
49 } else if (prog_id
> node
->info_linear
->info
.id
) {
52 pr_debug("duplicated bpf prog info %u\n", prog_id
);
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
++;
62 struct bpf_prog_info_node
*perf_env__find_bpf_prog_info(struct perf_env
*env
,
65 struct bpf_prog_info_node
*node
= NULL
;
68 down_read(&env
->bpf_progs
.lock
);
69 n
= env
->bpf_progs
.infos
.rb_node
;
72 node
= rb_entry(n
, struct bpf_prog_info_node
, rb_node
);
73 if (prog_id
< node
->info_linear
->info
.id
)
75 else if (prog_id
> node
->info_linear
->info
.id
)
83 up_read(&env
->bpf_progs
.lock
);
87 bool perf_env__insert_btf(struct perf_env
*env
, struct btf_node
*btf_node
)
91 down_write(&env
->bpf_progs
.lock
);
92 ret
= __perf_env__insert_btf(env
, btf_node
);
93 up_write(&env
->bpf_progs
.lock
);
97 bool __perf_env__insert_btf(struct perf_env
*env
, struct btf_node
*btf_node
)
99 struct rb_node
*parent
= NULL
;
100 __u32 btf_id
= btf_node
->id
;
101 struct btf_node
*node
;
104 p
= &env
->bpf_progs
.btfs
.rb_node
;
108 node
= rb_entry(parent
, struct btf_node
, rb_node
);
109 if (btf_id
< node
->id
) {
111 } else if (btf_id
> node
->id
) {
114 pr_debug("duplicated btf %u\n", btf_id
);
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
++;
125 struct btf_node
*perf_env__find_btf(struct perf_env
*env
, __u32 btf_id
)
127 struct btf_node
*res
;
129 down_read(&env
->bpf_progs
.lock
);
130 res
= __perf_env__find_btf(env
, btf_id
);
131 up_read(&env
->bpf_progs
.lock
);
135 struct btf_node
*__perf_env__find_btf(struct perf_env
*env
, __u32 btf_id
)
137 struct btf_node
*node
= NULL
;
140 n
= env
->bpf_progs
.btfs
.rb_node
;
143 node
= rb_entry(n
, struct btf_node
, rb_node
);
144 if (btf_id
< node
->id
)
146 else if (btf_id
> node
->id
)
154 /* purge data in bpf_progs.infos tree */
155 static void perf_env__purge_bpf(struct perf_env
*env
)
157 struct rb_root
*root
;
158 struct rb_node
*next
;
160 down_write(&env
->bpf_progs
.lock
);
162 root
= &env
->bpf_progs
.infos
;
163 next
= rb_first(root
);
166 struct bpf_prog_info_node
*node
;
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
);
175 env
->bpf_progs
.infos_cnt
= 0;
177 root
= &env
->bpf_progs
.btfs
;
178 next
= rb_first(root
);
181 struct btf_node
*node
;
183 node
= rb_entry(next
, struct btf_node
, rb_node
);
184 next
= rb_next(&node
->rb_node
);
185 rb_erase(&node
->rb_node
, root
);
189 env
->bpf_progs
.btfs_cnt
= 0;
191 up_write(&env
->bpf_progs
.lock
);
193 #else // HAVE_LIBBPF_SUPPORT
194 static void perf_env__purge_bpf(struct perf_env
*env __maybe_unused
)
197 #endif // HAVE_LIBBPF_SUPPORT
199 void perf_env__exit(struct perf_env
*env
)
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
);
209 zfree(&env
->cpu_desc
);
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
);
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
);
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
);
227 for (i
= 0; i
< env
->caches_cnt
; i
++)
228 cpu_cache_level__free(&env
->caches
[i
]);
231 for (i
= 0; i
< env
->nr_memory_nodes
; i
++)
232 zfree(&env
->memory_nodes
[i
].set
);
233 zfree(&env
->memory_nodes
);
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
);
239 zfree(&env
->hybrid_nodes
);
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
);
247 zfree(&env
->pmu_caps
);
250 void perf_env__init(struct perf_env
*env
)
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
);
257 env
->kernel_is_64_bit
= -1;
260 static void perf_env__init_kernel_mode(struct perf_env
*env
)
262 const char *arch
= perf_env__raw_arch(env
);
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;
270 env
->kernel_is_64_bit
= 0;
273 int perf_env__kernel_is_64_bit(struct perf_env
*env
)
275 if (env
->kernel_is_64_bit
== -1)
276 perf_env__init_kernel_mode(env
);
278 return env
->kernel_is_64_bit
;
281 int perf_env__set_cmdline(struct perf_env
*env
, int argc
, const char *argv
[])
285 /* do not include NULL termination */
286 env
->cmdline_argv
= calloc(argc
, sizeof(char *));
287 if (env
->cmdline_argv
== NULL
)
291 * Must copy argv contents because it gets moved around during option
294 for (i
= 0; i
< argc
; i
++) {
295 env
->cmdline_argv
[i
] = argv
[i
];
296 if (env
->cmdline_argv
[i
] == NULL
)
300 env
->nr_cmdline
= argc
;
304 zfree(&env
->cmdline_argv
);
309 int perf_env__read_cpu_topology_map(struct perf_env
*env
)
313 if (env
->cpu
!= NULL
)
316 if (env
->nr_cpus_avail
== 0)
317 env
->nr_cpus_avail
= cpu__max_present_cpu().cpu
;
319 nr_cpus
= env
->nr_cpus_avail
;
323 env
->cpu
= calloc(nr_cpus
, sizeof(env
->cpu
[0]));
324 if (env
->cpu
== NULL
)
327 for (idx
= 0; idx
< nr_cpus
; ++idx
) {
328 struct perf_cpu cpu
= { .cpu
= idx
};
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
);
335 env
->nr_cpus_avail
= nr_cpus
;
339 int perf_env__read_pmu_mappings(struct perf_env
*env
)
341 struct perf_pmu
*pmu
= NULL
;
345 while ((pmu
= perf_pmus__scan(pmu
)))
349 pr_debug("pmu mappings not available\n");
352 env
->nr_pmu_mappings
= pmu_num
;
354 if (strbuf_init(&sb
, 128 * pmu_num
) < 0)
357 while ((pmu
= perf_pmus__scan(pmu
))) {
358 if (strbuf_addf(&sb
, "%u:%s", pmu
->type
, pmu
->name
) < 0)
360 /* include a NULL character at the end */
361 if (strbuf_add(&sb
, "", 1) < 0)
365 env
->pmu_mappings
= strbuf_detach(&sb
, NULL
);
374 int perf_env__read_cpuid(struct perf_env
*env
)
377 struct perf_cpu cpu
= {-1};
378 int err
= get_cpuid(cpuid
, sizeof(cpuid
), cpu
);
384 env
->cpuid
= strdup(cpuid
);
385 if (env
->cpuid
== NULL
)
390 static int perf_env__read_arch(struct perf_env
*env
)
398 env
->arch
= strdup(uts
.machine
);
400 return env
->arch
? 0 : -ENOMEM
;
403 static int perf_env__read_nr_cpus_avail(struct perf_env
*env
)
405 if (env
->nr_cpus_avail
== 0)
406 env
->nr_cpus_avail
= cpu__max_present_cpu().cpu
;
408 return env
->nr_cpus_avail
? 0 : -ENOENT
;
411 const char *perf_env__raw_arch(struct perf_env
*env
)
413 return env
&& !perf_env__read_arch(env
) ? env
->arch
: "unknown";
416 int perf_env__nr_cpus_avail(struct perf_env
*env
)
418 return env
&& !perf_env__read_nr_cpus_avail(env
) ? env
->nr_cpus_avail
: 0;
421 void cpu_cache_level__free(struct cpu_cache_level
*cache
)
429 * Return architecture name in a normalized form.
430 * The conversion logic comes from the Makefile.
432 static const char *normalize_arch(char *arch
)
434 if (!strcmp(arch
, "x86_64"))
436 if (arch
[0] == 'i' && arch
[2] == '8' && arch
[3] == '6')
438 if (!strcmp(arch
, "sun4u") || !strncmp(arch
, "sparc", 5))
440 if (!strncmp(arch
, "aarch64", 7) || !strncmp(arch
, "arm64", 5))
442 if (!strncmp(arch
, "arm", 3) || !strcmp(arch
, "sa110"))
444 if (!strncmp(arch
, "s390", 4))
446 if (!strncmp(arch
, "parisc", 6))
448 if (!strncmp(arch
, "powerpc", 7) || !strncmp(arch
, "ppc", 3))
450 if (!strncmp(arch
, "mips", 4))
452 if (!strncmp(arch
, "sh", 2) && isdigit(arch
[2]))
454 if (!strncmp(arch
, "loongarch", 9))
460 const char *perf_env__arch(struct perf_env
*env
)
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)
468 arch_name
= uts
.machine
;
470 arch_name
= env
->arch
;
472 return normalize_arch(arch_name
);
475 const char *perf_env__arch_strerrno(struct perf_env
*env __maybe_unused
, int err __maybe_unused
)
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
));
481 return env
->arch_strerrno
? env
->arch_strerrno(err
) : "no arch specific strerrno function";
483 return "!(HAVE_SYSCALL_TABLE_SUPPORT && HAVE_LIBTRACEEVENT)";
487 const char *perf_env__cpuid(struct perf_env
*env
)
491 if (!env
->cpuid
) { /* Assume local operation */
492 status
= perf_env__read_cpuid(env
);
500 int perf_env__nr_pmu_mappings(struct perf_env
*env
)
504 if (!env
->nr_pmu_mappings
) { /* Assume local operation */
505 status
= perf_env__read_pmu_mappings(env
);
510 return env
->nr_pmu_mappings
;
513 const char *perf_env__pmu_mappings(struct perf_env
*env
)
517 if (!env
->pmu_mappings
) { /* Assume local operation */
518 status
= perf_env__read_pmu_mappings(env
);
523 return env
->pmu_mappings
;
526 int perf_env__numa_node(struct perf_env
*env
, struct perf_cpu cpu
)
528 if (!env
->nr_numa_map
) {
529 struct numa_node
*nn
;
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
);
540 * We initialize the numa_map array to prepare
541 * it for missing cpus, which return node -1
543 env
->numa_map
= malloc(nr
* sizeof(int));
547 for (i
= 0; i
< nr
; i
++)
548 env
->numa_map
[i
] = -1;
550 env
->nr_numa_map
= nr
;
552 for (i
= 0; i
< env
->nr_numa_nodes
; i
++) {
556 nn
= &env
->numa_nodes
[i
];
557 perf_cpu_map__for_each_cpu(tmp
, j
, nn
->map
)
558 env
->numa_map
[tmp
.cpu
] = i
;
562 return cpu
.cpu
>= 0 && cpu
.cpu
< env
->nr_numa_map
? env
->numa_map
[cpu
.cpu
] : -1;
565 bool perf_env__has_pmu_mapping(struct perf_env
*env
, const char *pmu_name
)
567 char *pmu_mapping
= env
->pmu_mappings
, *colon
;
569 for (int i
= 0; i
< env
->nr_pmu_mappings
; ++i
) {
570 if (strtoul(pmu_mapping
, &colon
, 0) == ULONG_MAX
|| *colon
!= ':')
573 pmu_mapping
= colon
+ 1;
574 if (strcmp(pmu_mapping
, pmu_name
) == 0)
577 pmu_mapping
+= strlen(pmu_mapping
) + 1;
583 char *perf_env__find_pmu_cap(struct perf_env
*env
, const char *pmu_name
,
591 if (!pmu_name
|| !cap
)
594 cap_size
= strlen(cap
);
595 cap_eq
= zalloc(cap_size
+ 2);
599 memcpy(cap_eq
, cap
, cap_size
);
600 cap_eq
[cap_size
] = '=';
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)) {
606 return &env
->cpu_pmu_caps
[i
][cap_size
+ 1];
612 for (i
= 0; i
< env
->nr_pmus_with_caps
; i
++) {
613 if (strcmp(env
->pmu_caps
[i
].pmu_name
, pmu_name
))
616 ptr
= env
->pmu_caps
[i
].caps
;
618 for (j
= 0; j
< env
->pmu_caps
[i
].nr_caps
; j
++) {
619 if (!strncmp(ptr
[j
], cap_eq
, cap_size
+ 1)) {
621 return &ptr
[j
][cap_size
+ 1];
631 void perf_env__find_br_cntr_info(struct perf_env
*env
,
636 *nr
= env
->cpu_pmu_caps
? env
->br_cntr_nr
:
637 env
->pmu_caps
->br_cntr_nr
;
641 *width
= env
->cpu_pmu_caps
? env
->br_cntr_width
:
642 env
->pmu_caps
->br_cntr_width
;
646 bool perf_env__is_x86_amd_cpu(struct perf_env
*env
)
648 static int is_amd
; /* 0: Uninitialized, 1: Yes, -1: No */
651 is_amd
= env
->cpuid
&& strstarts(env
->cpuid
, "AuthenticAMD") ? 1 : -1;
653 return is_amd
>= 1 ? true : false;
656 bool x86__is_amd_cpu(void)
658 struct perf_env env
= { .total_mem
= 0, };
661 perf_env__cpuid(&env
);
662 is_amd
= perf_env__is_x86_amd_cpu(&env
);
663 perf_env__exit(&env
);