projects/linux·blob master · refs

1087 lines · 24.3 KiB

1// SPDX-License-Identifier: GPL-2.0
2#include "cpumap.h"
3#include "dwarf-regs.h"
4#include "debug.h"
5#include "env.h"
6#include "util/header.h"
7#include "util/rwsem.h"
8#include <linux/compiler.h>
9#include <linux/kernel.h>
10#include <linux/ctype.h>
11#include <linux/rbtree.h>
12#include <linux/string.h>
13#include <linux/zalloc.h>
14#include "cgroup.h"
15#include <errno.h>
16#include <sys/utsname.h>
17#include <stdlib.h>
18#include <string.h>
19#include "pmu.h"
20#include "pmus.h"
21#include "strbuf.h"
22#include "trace/beauty/beauty.h"
23
24#ifdef HAVE_LIBBPF_SUPPORT
25#include "bpf-event.h"
26#include "bpf-utils.h"
27#include <bpf/libbpf.h>
28
29bool perf_env__insert_bpf_prog_info(struct perf_env *env,
30 struct bpf_prog_info_node *info_node)
31{
32 bool ret;
33
34 down_write(&env->bpf_progs.lock);
35 ret = __perf_env__insert_bpf_prog_info(env, info_node);
36 up_write(&env->bpf_progs.lock);
37
38 return ret;
39}
40
41bool __perf_env__insert_bpf_prog_info(struct perf_env *env, struct bpf_prog_info_node *info_node)
42{
43 __u32 prog_id = info_node->info_linear->info.id;
44 struct bpf_prog_info_node *node;
45 struct rb_node *parent = NULL;
46 struct rb_node **p;
47
48 p = &env->bpf_progs.infos.rb_node;
49
50 while (*p != NULL) {
51 parent = *p;
52 node = rb_entry(parent, struct bpf_prog_info_node, rb_node);
53 if (prog_id < node->info_linear->info.id) {
54 p = &(*p)->rb_left;
55 } else if (prog_id > node->info_linear->info.id) {
56 p = &(*p)->rb_right;
57 } else {
58 pr_debug("duplicated bpf prog info %u\n", prog_id);
59 return false;
60 }
61 }
62
63 rb_link_node(&info_node->rb_node, parent, p);
64 rb_insert_color(&info_node->rb_node, &env->bpf_progs.infos);
65 env->bpf_progs.infos_cnt++;
66 return true;
67}
68
69struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
70 __u32 prog_id)
71{
72 struct bpf_prog_info_node *node = NULL;
73 struct rb_node *n;
74
75 down_read(&env->bpf_progs.lock);
76 n = env->bpf_progs.infos.rb_node;
77
78 while (n) {
79 node = rb_entry(n, struct bpf_prog_info_node, rb_node);
80 if (prog_id < node->info_linear->info.id)
81 n = n->rb_left;
82 else if (prog_id > node->info_linear->info.id)
83 n = n->rb_right;
84 else
85 goto out;
86 }
87 node = NULL;
88
89out:
90 up_read(&env->bpf_progs.lock);
91 return node;
92}
93
94void perf_env__iterate_bpf_prog_info(struct perf_env *env,
95 void (*cb)(struct bpf_prog_info_node *node,
96 void *data),
97 void *data)
98{
99 struct rb_node *first;
100
101 down_read(&env->bpf_progs.lock);
102 first = rb_first(&env->bpf_progs.infos);
103 for (struct rb_node *node = first; node != NULL; node = rb_next(node))
104 (*cb)(rb_entry(node, struct bpf_prog_info_node, rb_node), data);
105 up_read(&env->bpf_progs.lock);
106}
107
108bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
109{
110 bool ret;
111
112 down_write(&env->bpf_progs.lock);
113 ret = __perf_env__insert_btf(env, btf_node);
114 up_write(&env->bpf_progs.lock);
115 return ret;
116}
117
118bool __perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
119{
120 struct rb_node *parent = NULL;
121 __u32 btf_id = btf_node->id;
122 struct btf_node *node;
123 struct rb_node **p;
124
125 p = &env->bpf_progs.btfs.rb_node;
126
127 while (*p != NULL) {
128 parent = *p;
129 node = rb_entry(parent, struct btf_node, rb_node);
130 if (btf_id < node->id) {
131 p = &(*p)->rb_left;
132 } else if (btf_id > node->id) {
133 p = &(*p)->rb_right;
134 } else {
135 pr_debug("duplicated btf %u\n", btf_id);
136 return false;
137 }
138 }
139
140 rb_link_node(&btf_node->rb_node, parent, p);
141 rb_insert_color(&btf_node->rb_node, &env->bpf_progs.btfs);
142 env->bpf_progs.btfs_cnt++;
143 return true;
144}
145
146struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id)
147{
148 struct btf_node *res;
149
150 down_read(&env->bpf_progs.lock);
151 res = __perf_env__find_btf(env, btf_id);
152 up_read(&env->bpf_progs.lock);
153 return res;
154}
155
156struct btf_node *__perf_env__find_btf(struct perf_env *env, __u32 btf_id)
157{
158 struct btf_node *node = NULL;
159 struct rb_node *n;
160
161 n = env->bpf_progs.btfs.rb_node;
162
163 while (n) {
164 node = rb_entry(n, struct btf_node, rb_node);
165 if (btf_id < node->id)
166 n = n->rb_left;
167 else if (btf_id > node->id)
168 n = n->rb_right;
169 else
170 return node;
171 }
172 return NULL;
173}
174
175/* purge data in bpf_progs.infos tree */
176static void perf_env__purge_bpf(struct perf_env *env)
177{
178 struct rb_root *root;
179 struct rb_node *next;
180
181 down_write(&env->bpf_progs.lock);
182
183 root = &env->bpf_progs.infos;
184 next = rb_first(root);
185
186 while (next) {
187 struct bpf_prog_info_node *node;
188
189 node = rb_entry(next, struct bpf_prog_info_node, rb_node);
190 next = rb_next(&node->rb_node);
191 rb_erase(&node->rb_node, root);
192 zfree(&node->info_linear);
193 bpf_metadata_free(node->metadata);
194 free(node);
195 }
196
197 env->bpf_progs.infos_cnt = 0;
198
199 root = &env->bpf_progs.btfs;
200 next = rb_first(root);
201
202 while (next) {
203 struct btf_node *node;
204
205 node = rb_entry(next, struct btf_node, rb_node);
206 next = rb_next(&node->rb_node);
207 rb_erase(&node->rb_node, root);
208 free(node);
209 }
210
211 env->bpf_progs.btfs_cnt = 0;
212
213 up_write(&env->bpf_progs.lock);
214}
215#else // HAVE_LIBBPF_SUPPORT
216static void perf_env__purge_bpf(struct perf_env *env __maybe_unused)
217{
218}
219#endif // HAVE_LIBBPF_SUPPORT
220
221void free_cpu_domain_info(struct cpu_domain_map **cd_map, u32 schedstat_version, u32 nr)
222{
223 if (!cd_map)
224 return;
225
226 for (u32 i = 0; i < nr; i++) {
227 if (!cd_map[i])
228 continue;
229
230 for (u32 j = 0; j < cd_map[i]->nr_domains; j++) {
231 struct domain_info *d_info = cd_map[i]->domains[j];
232
233 if (!d_info)
234 continue;
235
236 if (schedstat_version >= 17)
237 zfree(&d_info->dname);
238
239 zfree(&d_info->cpumask);
240 zfree(&d_info->cpulist);
241 zfree(&d_info);
242 }
243 zfree(&cd_map[i]->domains);
244 zfree(&cd_map[i]);
245 }
246 zfree(&cd_map);
247}
248
249void perf_env__exit(struct perf_env *env)
250{
251 int i, j;
252
253 mutex_destroy(&env->lock);
254
255 perf_env__purge_bpf(env);
256 perf_env__purge_cgroups(env);
257 zfree(&env->hostname);
258 zfree(&env->os_release);
259 zfree(&env->version);
260 zfree(&env->arch);
261 zfree(&env->cpu_desc);
262 zfree(&env->cpuid);
263 zfree(&env->cmdline);
264 zfree(&env->cmdline_argv);
265 zfree(&env->sibling_dies);
266 zfree(&env->sibling_cores);
267 zfree(&env->sibling_threads);
268 zfree(&env->pmu_mappings);
269 zfree(&env->cpu);
270 for (i = 0; i < env->nr_cpu_pmu_caps; i++)
271 zfree(&env->cpu_pmu_caps[i]);
272 zfree(&env->cpu_pmu_caps);
273 zfree(&env->numa_map);
274
275 for (i = 0; i < env->nr_numa_nodes; i++)
276 perf_cpu_map__put(env->numa_nodes[i].map);
277 zfree(&env->numa_nodes);
278
279 for (i = 0; i < env->caches_cnt; i++)
280 cpu_cache_level__free(&env->caches[i]);
281 zfree(&env->caches);
282
283 for (i = 0; i < env->nr_memory_nodes; i++)
284 zfree(&env->memory_nodes[i].set);
285 zfree(&env->memory_nodes);
286
287 for (i = 0; i < env->nr_hybrid_nodes; i++) {
288 zfree(&env->hybrid_nodes[i].pmu_name);
289 zfree(&env->hybrid_nodes[i].cpus);
290 }
291 zfree(&env->hybrid_nodes);
292
293 for (i = 0; i < env->nr_pmus_with_caps; i++) {
294 for (j = 0; j < env->pmu_caps[i].nr_caps; j++)
295 zfree(&env->pmu_caps[i].caps[j]);
296 zfree(&env->pmu_caps[i].caps);
297 zfree(&env->pmu_caps[i].pmu_name);
298 }
299 zfree(&env->pmu_caps);
300 free_cpu_domain_info(env->cpu_domain, env->schedstat_version, env->nr_cpus_avail);
301}
302
303void perf_env__init(struct perf_env *env)
304{
305 memset(env, 0, sizeof(*env));
306#ifdef HAVE_LIBBPF_SUPPORT
307 env->bpf_progs.infos = RB_ROOT;
308 env->bpf_progs.btfs = RB_ROOT;
309 init_rwsem(&env->bpf_progs.lock);
310#endif
311 env->kernel_is_64_bit = -1;
312 mutex_init(&env->lock);
313}
314
315static void perf_env__init_kernel_mode(struct perf_env *env)
316{
317 const char *arch = env->arch;
318
319 if (!arch) {
320 static struct utsname uts = { .machine[0] = '\0', };
321
322 if (uts.machine[0] == '\0')
323 uname(&uts);
324 if (uts.machine[0] != '\0')
325 arch = uts.machine;
326 }
327
328 if (arch) {
329 if (strstr(arch, "64") || strstr(arch, "s390x"))
330 env->kernel_is_64_bit = 1;
331 else
332 env->kernel_is_64_bit = 0;
333 return;
334 }
335
336 /* Fallback if completely unresolvable (assume host-bitness) */
337 env->kernel_is_64_bit = (sizeof(void *) == 8) ? 1 : 0;
338}
339
340int perf_env__kernel_is_64_bit(struct perf_env *env)
341{
342 if (env->kernel_is_64_bit == -1)
343 perf_env__init_kernel_mode(env);
344
345 return env->kernel_is_64_bit;
346}
347
348bool perf_arch_is_big_endian(const char *arch)
349{
350 if (!arch)
351 return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__;
352
353 if (str_ends_with(arch, "_be") || !strcmp(arch, "sparc") || !strcmp(arch, "sparc64") ||
354 !strcmp(arch, "s390") || !strcmp(arch, "s390x") || !strcmp(arch, "powerpc") ||
355 !strcmp(arch, "ppc") || !strcmp(arch, "ppc64") ||
356 !strcmp(arch, "mips") || !strcmp(arch, "mips64") || !strcmp(arch, "parisc") ||
357 !strcmp(arch, "parisc64") || !strcmp(arch, "m68k") ||
358 !strcmp(arch, "armeb") || !strcmp(arch, "mipseb") || !strcmp(arch, "mips64eb"))
359 return true;
360
361 return false;
362}
363
364const char *perf_env__os_release(struct perf_env *env)
365{
366 struct utsname uts;
367 int ret;
368 const char *release;
369
370 if (!env)
371 return perf_version_string;
372
373 mutex_lock(&env->lock);
374 if (env->os_release) {
375 release = env->os_release;
376 goto out;
377 }
378
379 /*
380 * If env->arch is set, this is an offline target environment.
381 * If the os_release is not populated in the file, we do not want
382 * to poison it with the host's release which would break guest checks.
383 */
384 if (env->arch) {
385 release = NULL;
386 goto out;
387 }
388
389 /*
390 * The os_release is being accessed but wasn't initialized from a data
391 * file, assume this is 'live' mode and use the release from uname. If
392 * uname or strdup fails then use the current perf tool version.
393 */
394 ret = uname(&uts);
395 env->os_release = strdup(ret < 0 ? perf_version_string : uts.release);
396 release = env->os_release ?: perf_version_string;
397out:
398 mutex_unlock(&env->lock);
399 return release;
400}
401
402int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
403{
404 int i;
405
406 /* do not include NULL termination */
407 env->cmdline_argv = calloc(argc, sizeof(char *));
408 if (env->cmdline_argv == NULL)
409 goto out_enomem;
410
411 /*
412 * Must copy argv contents because it gets moved around during option
413 * parsing:
414 */
415 for (i = 0; i < argc ; i++) {
416 env->cmdline_argv[i] = argv[i];
417 if (env->cmdline_argv[i] == NULL)
418 goto out_free;
419 }
420
421 env->nr_cmdline = argc;
422
423 return 0;
424out_free:
425 zfree(&env->cmdline_argv);
426out_enomem:
427 return -ENOMEM;
428}
429
430int perf_env__read_cpu_topology_map(struct perf_env *env)
431{
432 int idx, nr_cpus;
433
434 if (env->cpu != NULL)
435 return 0;
436
437 if (env->nr_cpus_avail == 0)
438 env->nr_cpus_avail = cpu__max_present_cpu().cpu;
439
440 nr_cpus = env->nr_cpus_avail;
441 if (nr_cpus == -1)
442 return -EINVAL;
443
444 env->cpu = calloc(nr_cpus, sizeof(env->cpu[0]));
445 if (env->cpu == NULL)
446 return -ENOMEM;
447
448 for (idx = 0; idx < nr_cpus; ++idx) {
449 struct perf_cpu cpu = { .cpu = idx };
450 int core_id = cpu__get_core_id(cpu);
451 int socket_id = cpu__get_socket_id(cpu);
452 int die_id = cpu__get_die_id(cpu);
453
454 env->cpu[idx].core_id = core_id >= 0 ? core_id : -1;
455 env->cpu[idx].socket_id = socket_id >= 0 ? socket_id : -1;
456 env->cpu[idx].die_id = die_id >= 0 ? die_id : -1;
457 }
458
459 env->nr_cpus_avail = nr_cpus;
460 return 0;
461}
462
463int perf_env__read_pmu_mappings(struct perf_env *env)
464{
465 struct perf_pmu *pmu = NULL;
466 u32 pmu_num = 0;
467 struct strbuf sb;
468
469 while ((pmu = perf_pmus__scan(pmu)))
470 pmu_num++;
471
472 if (!pmu_num) {
473 pr_debug("pmu mappings not available\n");
474 return -ENOENT;
475 }
476 env->nr_pmu_mappings = pmu_num;
477
478 if (strbuf_init(&sb, 128 * pmu_num) < 0)
479 return -ENOMEM;
480
481 while ((pmu = perf_pmus__scan(pmu))) {
482 if (strbuf_addf(&sb, "%u:%s", pmu->type, pmu->name) < 0)
483 goto error;
484 /* include a NULL character at the end */
485 if (strbuf_add(&sb, "", 1) < 0)
486 goto error;
487 }
488
489 env->pmu_mappings = strbuf_detach(&sb, NULL);
490
491 return 0;
492
493error:
494 strbuf_release(&sb);
495 return -1;
496}
497
498int perf_env__read_cpuid(struct perf_env *env)
499{
500 char cpuid[128];
501 struct perf_cpu cpu = {-1};
502 int err = get_cpuid(cpuid, sizeof(cpuid), cpu);
503
504 if (err)
505 return err;
506
507 free(env->cpuid);
508 env->cpuid = strdup(cpuid);
509 if (env->cpuid == NULL)
510 return ENOMEM;
511 return 0;
512}
513
514static int perf_env__read_nr_cpus_avail(struct perf_env *env)
515{
516 if (env->nr_cpus_avail == 0)
517 env->nr_cpus_avail = cpu__max_present_cpu().cpu;
518
519 return env->nr_cpus_avail ? 0 : -ENOENT;
520}
521
522static int __perf_env__read_core_pmu_caps(const struct perf_pmu *pmu,
523 int *nr_caps, char ***caps,
524 unsigned int *max_branches,
525 unsigned int *br_cntr_nr,
526 unsigned int *br_cntr_width)
527{
528 struct perf_pmu_caps *pcaps = NULL;
529 char *ptr, **tmp;
530 int ret = 0;
531
532 *nr_caps = 0;
533 *caps = NULL;
534
535 if (!pmu->nr_caps)
536 return 0;
537
538 *caps = calloc(pmu->nr_caps, sizeof(char *));
539 if (!*caps)
540 return -ENOMEM;
541
542 tmp = *caps;
543 list_for_each_entry(pcaps, &pmu->caps, list) {
544 if (asprintf(&ptr, "%s=%s", pcaps->name, pcaps->value) < 0) {
545 ret = -ENOMEM;
546 goto error;
547 }
548
549 *tmp++ = ptr;
550
551 if (!strcmp(pcaps->name, "branches"))
552 *max_branches = atoi(pcaps->value);
553 else if (!strcmp(pcaps->name, "branch_counter_nr"))
554 *br_cntr_nr = atoi(pcaps->value);
555 else if (!strcmp(pcaps->name, "branch_counter_width"))
556 *br_cntr_width = atoi(pcaps->value);
557 }
558 *nr_caps = pmu->nr_caps;
559 return 0;
560error:
561 while (tmp-- != *caps)
562 zfree(tmp);
563 zfree(caps);
564 *nr_caps = 0;
565 return ret;
566}
567
568int perf_env__read_core_pmu_caps(struct perf_env *env)
569{
570 struct pmu_caps *pmu_caps;
571 struct perf_pmu *pmu = NULL;
572 int nr_pmu, i = 0, j;
573 int ret;
574
575 nr_pmu = perf_pmus__num_core_pmus();
576
577 if (!nr_pmu)
578 return -ENODEV;
579
580 if (nr_pmu == 1) {
581 pmu = perf_pmus__find_core_pmu();
582 if (!pmu)
583 return -ENODEV;
584 ret = perf_pmu__caps_parse(pmu);
585 if (ret < 0)
586 return ret;
587 return __perf_env__read_core_pmu_caps(pmu, &env->nr_cpu_pmu_caps,
588 &env->cpu_pmu_caps,
589 &env->max_branches,
590 &env->br_cntr_nr,
591 &env->br_cntr_width);
592 }
593
594 pmu_caps = calloc(nr_pmu, sizeof(*pmu_caps));
595 if (!pmu_caps)
596 return -ENOMEM;
597
598 while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
599 if (perf_pmu__caps_parse(pmu) <= 0)
600 continue;
601 ret = __perf_env__read_core_pmu_caps(pmu, &pmu_caps[i].nr_caps,
602 &pmu_caps[i].caps,
603 &pmu_caps[i].max_branches,
604 &pmu_caps[i].br_cntr_nr,
605 &pmu_caps[i].br_cntr_width);
606 if (ret)
607 goto error;
608
609 pmu_caps[i].pmu_name = strdup(pmu->name);
610 if (!pmu_caps[i].pmu_name) {
611 ret = -ENOMEM;
612 goto error;
613 }
614 i++;
615 }
616
617 env->nr_pmus_with_caps = nr_pmu;
618 env->pmu_caps = pmu_caps;
619
620 return 0;
621error:
622 for (i = 0; i < nr_pmu; i++) {
623 for (j = 0; j < pmu_caps[i].nr_caps; j++)
624 zfree(&pmu_caps[i].caps[j]);
625 zfree(&pmu_caps[i].caps);
626 zfree(&pmu_caps[i].pmu_name);
627 }
628 zfree(&pmu_caps);
629 return ret;
630}
631
632int perf_env__nr_cpus_avail(struct perf_env *env)
633{
634 return env && !perf_env__read_nr_cpus_avail(env) ? env->nr_cpus_avail : 0;
635}
636
637void cpu_cache_level__free(struct cpu_cache_level *cache)
638{
639 zfree(&cache->type);
640 zfree(&cache->map);
641 zfree(&cache->size);
642}
643
644struct arch_to_e_machine {
645 const char *prefix;
646 uint16_t e_machine;
647};
648
649/*
650 * A mapping from an arch prefix string to an ELF machine that can be used in a
651 * bsearch. Some arch prefixes are shared an need additional processing as
652 * marked next to the architecture. The prefixes handle both perf's architecture
653 * naming and those from uname.
654 */
655static const struct arch_to_e_machine prefix_to_e_machine[] = {
656 {"aarch64", EM_AARCH64},
657 {"alpha", EM_ALPHA},
658 {"arc", EM_ARC},
659 {"arm", EM_ARM}, /* Check also for EM_AARCH64. */
660 {"avr", EM_AVR}, /* Check also for EM_AVR32. */
661 {"bfin", EM_BLACKFIN},
662 {"blackfin", EM_BLACKFIN},
663 {"cris", EM_CRIS},
664 {"csky", EM_CSKY},
665 {"hppa", EM_PARISC},
666 {"i386", EM_386},
667 {"i486", EM_386},
668 {"i586", EM_386},
669 {"i686", EM_386},
670 {"loongarch", EM_LOONGARCH},
671 {"m32r", EM_M32R},
672 {"m68k", EM_68K},
673 {"microblaze", EM_MICROBLAZE},
674 {"mips", EM_MIPS},
675 {"msp430", EM_MSP430},
676 {"parisc", EM_PARISC},
677 {"powerpc", EM_PPC}, /* Check also for EM_PPC64. */
678 {"ppc", EM_PPC}, /* Check also for EM_PPC64. */
679 {"riscv", EM_RISCV},
680 {"s390", EM_S390},
681 {"sa110", EM_ARM},
682 {"sh", EM_SH},
683 {"sparc", EM_SPARC}, /* Check also for EM_SPARCV9. */
684 {"sun4u", EM_SPARC},
685 {"x86", EM_X86_64}, /* Check also for EM_386. */
686 {"xtensa", EM_XTENSA},
687};
688
689static int compare_prefix(const void *key, const void *element)
690{
691 const char *search_key = key;
692 const struct arch_to_e_machine *map_element = element;
693 size_t prefix_len = strlen(map_element->prefix);
694
695 return strncmp(search_key, map_element->prefix, prefix_len);
696}
697
698static uint16_t perf_arch_to_e_machine(const char *perf_arch, int is_64_bit)
699{
700 /* Binary search for a matching prefix. */
701 const struct arch_to_e_machine *result;
702
703 if (!perf_arch)
704 return EM_HOST;
705
706 result = bsearch(perf_arch,
707 prefix_to_e_machine, ARRAY_SIZE(prefix_to_e_machine),
708 sizeof(prefix_to_e_machine[0]),
709 compare_prefix);
710
711 if (!result) {
712 pr_debug("Unknown perf arch for ELF machine mapping: %s\n", perf_arch);
713 return EM_NONE;
714 }
715
716 /*
717 * Handle conflicting prefixes. If the is_64_bit is unknown (-1) then
718 * assume 64-bit. We can't use perf_env__kernel_is_64_bit as that
719 * depends on the arch string.
720 */
721 switch (result->e_machine) {
722 case EM_ARM:
723 return !strcmp(perf_arch, "arm64") || !strcmp(perf_arch, "aarch64")
724 ? EM_AARCH64 : EM_ARM;
725 case EM_AVR:
726 return !strcmp(perf_arch, "avr32") ? EM_AVR32 : EM_AVR;
727 case EM_PPC:
728 if (is_64_bit == 1)
729 return EM_PPC64;
730 if (is_64_bit == 0)
731 return EM_PPC;
732 return strstarts(perf_arch, "ppc64") ? EM_PPC64 : EM_PPC;
733 case EM_SPARC:
734 if (is_64_bit == 1)
735 return EM_SPARCV9;
736 if (is_64_bit == 0)
737 return EM_SPARC;
738 return !strcmp(perf_arch, "sparc64") || !strcmp(perf_arch, "sun4u")
739 ? EM_SPARCV9 : EM_SPARC;
740 case EM_X86_64:
741 if (is_64_bit == 1)
742 return EM_X86_64;
743 if (is_64_bit == 0)
744 return EM_386;
745 return !strcmp(perf_arch, "x86_64") || !strcmp(perf_arch, "x86")
746 ? EM_X86_64 : EM_386;
747 default:
748 return result->e_machine;
749 }
750}
751
752static const char *e_machine_to_perf_arch(uint16_t e_machine)
753{
754 /*
755 * Table for if either the perf arch string differs from uname or there
756 * are >1 ELF machine with the prefix.
757 */
758 static const struct arch_to_e_machine extras[] = {
759 {"arm64", EM_AARCH64},
760 {"avr32", EM_AVR32},
761 {"powerpc", EM_PPC},
762 {"powerpc", EM_PPC64},
763 {"sparc", EM_SPARCV9},
764 {"x86", EM_386},
765 {"x86", EM_X86_64},
766 {"none", EM_NONE},
767 };
768
769 for (size_t i = 0; i < ARRAY_SIZE(extras); i++) {
770 if (extras[i].e_machine == e_machine)
771 return extras[i].prefix;
772 }
773
774 for (size_t i = 0; i < ARRAY_SIZE(prefix_to_e_machine); i++) {
775 if (prefix_to_e_machine[i].e_machine == e_machine)
776 return prefix_to_e_machine[i].prefix;
777
778 }
779 return "unknown";
780}
781
782uint16_t perf_env__e_machine_nocache(struct perf_env *env, uint32_t *e_flags)
783{
784 uint16_t e_machine = EM_NONE;
785 const char *arch = NULL;
786 int is_64_bit = -1;
787
788 if (e_flags)
789 *e_flags = 0;
790
791 if (env) {
792 arch = env->arch;
793 is_64_bit = env->kernel_is_64_bit;
794 }
795
796 if (!arch) {
797 static struct utsname uts = { .machine[0] = '\0', };
798
799 if (uts.machine[0] == '\0')
800 uname(&uts);
801 if (uts.machine[0] != '\0')
802 arch = uts.machine;
803 }
804
805 e_machine = perf_arch_to_e_machine(arch, is_64_bit);
806
807 if (e_flags)
808 *e_flags = (e_machine == EM_HOST) ? EF_HOST : 0;
809
810 return e_machine;
811}
812
813uint16_t perf_env__e_machine(struct perf_env *env, uint32_t *e_flags)
814{
815 uint16_t e_machine;
816 uint32_t local_e_flags = 0;
817
818 if (env && env->e_machine != EM_NONE) {
819 if (e_flags)
820 *e_flags = env->e_flags;
821
822 return env->e_machine;
823 }
824 e_machine = perf_env__e_machine_nocache(env, &local_e_flags);
825 /*
826 * Only cache the e_machine in perf_env if env->arch is not NULL.
827 * If env->arch is NULL, the e_machine is just a fallback to EM_HOST.
828 * Caching it permanently would prevent dynamic, more accurate
829 * thread-based session e_machine scanning later in
830 * perf_session__e_machine().
831 */
832 if (env && env->arch) {
833 env->e_machine = e_machine;
834 env->e_flags = local_e_flags;
835 }
836 if (e_flags)
837 *e_flags = local_e_flags;
838
839 return e_machine;
840}
841
842const char *perf_env__arch(struct perf_env *env)
843{
844 uint16_t e_machine;
845 const char *arch;
846
847 if (!env) {
848 static struct utsname uts = { .machine[0] = '\0', };
849 uint16_t host_e_machine;
850
851 if (uts.machine[0] == '\0')
852 uname(&uts);
853 if (uts.machine[0] != '\0') {
854 host_e_machine = perf_arch_to_e_machine(uts.machine, -1);
855 return e_machine_to_perf_arch(host_e_machine);
856 }
857 return e_machine_to_perf_arch(EM_HOST);
858 }
859
860 /*
861 * Lazily compute/allocate arch. The e_machine may have been
862 * read from a data file and so may not be EM_HOST.
863 */
864 e_machine = perf_env__e_machine(env, /*e_flags=*/NULL);
865 arch = e_machine_to_perf_arch(e_machine);
866
867 if (e_machine == EM_RISCV && perf_env__kernel_is_64_bit(env) == 1)
868 arch = "riscv64";
869 else if (e_machine == EM_MIPS && perf_env__kernel_is_64_bit(env) == 1)
870 arch = "mips64";
871 else if (e_machine == EM_PARISC && perf_env__kernel_is_64_bit(env) == 1)
872 arch = "parisc64";
873
874 return arch;
875}
876
877const char *arch_syscalls__strerrno(uint16_t e_machine, int err);
878
879const char *perf_env__arch_strerrno(uint16_t e_machine, int err)
880{
881 return arch_syscalls__strerrno(e_machine, err);
882}
883
884const char *perf_env__cpuid(struct perf_env *env)
885{
886 int status;
887
888 if (!env->cpuid) { /* Assume local operation */
889 status = perf_env__read_cpuid(env);
890 if (status)
891 return NULL;
892 }
893
894 return env->cpuid;
895}
896
897int perf_env__nr_pmu_mappings(struct perf_env *env)
898{
899 int status;
900
901 if (!env->nr_pmu_mappings) { /* Assume local operation */
902 status = perf_env__read_pmu_mappings(env);
903 if (status)
904 return 0;
905 }
906
907 return env->nr_pmu_mappings;
908}
909
910const char *perf_env__pmu_mappings(struct perf_env *env)
911{
912 int status;
913
914 if (!env->pmu_mappings) { /* Assume local operation */
915 status = perf_env__read_pmu_mappings(env);
916 if (status)
917 return NULL;
918 }
919
920 return env->pmu_mappings;
921}
922
923int perf_env__numa_node(struct perf_env *env, struct perf_cpu cpu)
924{
925 if (!env->nr_numa_map) {
926 struct numa_node *nn;
927 int i, nr = 0;
928
929 for (i = 0; i < env->nr_numa_nodes; i++) {
930 nn = &env->numa_nodes[i];
931 nr = max(nr, (int)perf_cpu_map__max(nn->map).cpu);
932 }
933
934 nr++;
935
936 /*
937 * We initialize the numa_map array to prepare
938 * it for missing cpus, which return node -1
939 */
940 env->numa_map = malloc(nr * sizeof(int));
941 if (!env->numa_map)
942 return -1;
943
944 for (i = 0; i < nr; i++)
945 env->numa_map[i] = -1;
946
947 env->nr_numa_map = nr;
948
949 for (i = 0; i < env->nr_numa_nodes; i++) {
950 struct perf_cpu tmp;
951 unsigned int j;
952
953 nn = &env->numa_nodes[i];
954 perf_cpu_map__for_each_cpu(tmp, j, nn->map)
955 env->numa_map[tmp.cpu] = i;
956 }
957 }
958
959 return cpu.cpu >= 0 && cpu.cpu < env->nr_numa_map ? env->numa_map[cpu.cpu] : -1;
960}
961
962bool perf_env__has_pmu_mapping(struct perf_env *env, const char *pmu_name)
963{
964 char *pmu_mapping = env->pmu_mappings, *colon;
965
966 for (int i = 0; i < env->nr_pmu_mappings; ++i) {
967 if (strtoul(pmu_mapping, &colon, 0) == ULONG_MAX || *colon != ':')
968 goto out_error;
969
970 pmu_mapping = colon + 1;
971 if (strcmp(pmu_mapping, pmu_name) == 0)
972 return true;
973
974 pmu_mapping += strlen(pmu_mapping) + 1;
975 }
976out_error:
977 return false;
978}
979
980char *perf_env__find_pmu_cap(struct perf_env *env, const char *pmu_name,
981 const char *cap)
982{
983 char *cap_eq;
984 int cap_size;
985 char **ptr;
986 int i, j;
987
988 if (!pmu_name || !cap)
989 return NULL;
990
991 cap_size = strlen(cap);
992 cap_eq = zalloc(cap_size + 2);
993 if (!cap_eq)
994 return NULL;
995
996 memcpy(cap_eq, cap, cap_size);
997 cap_eq[cap_size] = '=';
998
999 if (!strcmp(pmu_name, "cpu")) {
1000 for (i = 0; i < env->nr_cpu_pmu_caps; i++) {
1001 if (!strncmp(env->cpu_pmu_caps[i], cap_eq, cap_size + 1)) {
1002 free(cap_eq);
1003 return &env->cpu_pmu_caps[i][cap_size + 1];
1004 }
1005 }
1006 goto out;
1007 }
1008
1009 for (i = 0; i < env->nr_pmus_with_caps; i++) {
1010 if (strcmp(env->pmu_caps[i].pmu_name, pmu_name))
1011 continue;
1012
1013 ptr = env->pmu_caps[i].caps;
1014
1015 for (j = 0; j < env->pmu_caps[i].nr_caps; j++) {
1016 if (!strncmp(ptr[j], cap_eq, cap_size + 1)) {
1017 free(cap_eq);
1018 return &ptr[j][cap_size + 1];
1019 }
1020 }
1021 }
1022
1023out:
1024 free(cap_eq);
1025 return NULL;
1026}
1027
1028void perf_env__find_br_cntr_info(struct perf_env *env,
1029 unsigned int *nr,
1030 unsigned int *width)
1031{
1032 if (nr) {
1033 *nr = env->cpu_pmu_caps ? env->br_cntr_nr :
1034 env->pmu_caps->br_cntr_nr;
1035 }
1036
1037 if (width) {
1038 *width = env->cpu_pmu_caps ? env->br_cntr_width :
1039 env->pmu_caps->br_cntr_width;
1040 }
1041}
1042
1043bool perf_env__is_x86_amd_cpu(struct perf_env *env)
1044{
1045 static int is_amd; /* 0: Uninitialized, 1: Yes, -1: No */
1046
1047 if (is_amd == 0)
1048 is_amd = env->cpuid && strstarts(env->cpuid, "AuthenticAMD") ? 1 : -1;
1049
1050 return is_amd >= 1 ? true : false;
1051}
1052
1053bool x86__is_amd_cpu(void)
1054{
1055 struct perf_env env = { .total_mem = 0, };
1056 bool is_amd;
1057
1058 perf_env__init(&env);
1059 perf_env__cpuid(&env);
1060 is_amd = perf_env__is_x86_amd_cpu(&env);
1061 perf_env__exit(&env);
1062
1063 return is_amd;
1064}
1065
1066bool perf_env__is_x86_intel_cpu(struct perf_env *env)
1067{
1068 static int is_intel; /* 0: Uninitialized, 1: Yes, -1: No */
1069
1070 if (is_intel == 0)
1071 is_intel = env->cpuid && strstarts(env->cpuid, "GenuineIntel") ? 1 : -1;
1072
1073 return is_intel >= 1 ? true : false;
1074}
1075
1076bool x86__is_intel_cpu(void)
1077{
1078 struct perf_env env = { .total_mem = 0, };
1079 bool is_intel;
1080
1081 perf_env__init(&env);
1082 perf_env__cpuid(&env);
1083 is_intel = perf_env__is_x86_intel_cpu(&env);
1084 perf_env__exit(&env);
1085
1086 return is_intel;
1087}