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
perf_env__insert_bpf_prog_info(struct perf_env * env,struct bpf_prog_info_node * info_node)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
__perf_env__insert_bpf_prog_info(struct perf_env * env,struct bpf_prog_info_node * info_node)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
perf_env__find_bpf_prog_info(struct perf_env * env,__u32 prog_id)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
perf_env__insert_btf(struct perf_env * env,struct btf_node * btf_node)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
__perf_env__insert_btf(struct perf_env * env,struct btf_node * btf_node)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
perf_env__find_btf(struct perf_env * env,__u32 btf_id)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
__perf_env__find_btf(struct perf_env * env,__u32 btf_id)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 */
perf_env__purge_bpf(struct perf_env * env)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
perf_env__purge_bpf(struct perf_env * env __maybe_unused)195 static void perf_env__purge_bpf(struct perf_env *env __maybe_unused)
196 {
197 }
198 #endif // HAVE_LIBBPF_SUPPORT
199
perf_env__exit(struct perf_env * env)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
perf_env__init(struct perf_env * env)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
perf_env__init_kernel_mode(struct perf_env * env)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
perf_env__kernel_is_64_bit(struct perf_env * env)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
perf_env__set_cmdline(struct perf_env * env,int argc,const char * argv[])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
perf_env__read_cpu_topology_map(struct perf_env * env)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
perf_env__read_pmu_mappings(struct perf_env * env)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
perf_env__read_cpuid(struct perf_env * env)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
perf_env__read_arch(struct perf_env * env)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
perf_env__read_nr_cpus_avail(struct perf_env * env)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
perf_env__raw_arch(struct perf_env * env)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
perf_env__nr_cpus_avail(struct perf_env * env)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
cpu_cache_level__free(struct cpu_cache_level * cache)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 */
normalize_arch(char * arch)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
perf_env__arch(struct perf_env * env)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
perf_env__cpuid(struct perf_env * env)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
perf_env__nr_pmu_mappings(struct perf_env * env)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
perf_env__pmu_mappings(struct perf_env * env)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
perf_env__numa_node(struct perf_env * env,struct perf_cpu cpu)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
perf_env__find_pmu_cap(struct perf_env * env,const char * pmu_name,const char * cap)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