]> Git Repo - J-linux.git/blob - tools/perf/util/env.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / tools / perf / util / env.c
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 }
This page took 0.0613899999999999 seconds and 4 git commands to generate.