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/zalloc.h>
9  #include "cgroup.h"
10  #include <errno.h>
11  #include <sys/utsname.h>
12  #include <stdlib.h>
13  #include <string.h>
14  #include "pmus.h"
15  #include "strbuf.h"
16  #include "trace/beauty/beauty.h"
17  
18  struct perf_env perf_env;
19  
20  #ifdef HAVE_LIBBPF_SUPPORT
21  #include "bpf-event.h"
22  #include "bpf-utils.h"
23  #include <bpf/libbpf.h>
24  
perf_env__insert_bpf_prog_info(struct perf_env * env,struct bpf_prog_info_node * info_node)25  void perf_env__insert_bpf_prog_info(struct perf_env *env,
26  				    struct bpf_prog_info_node *info_node)
27  {
28  	down_write(&env->bpf_progs.lock);
29  	__perf_env__insert_bpf_prog_info(env, info_node);
30  	up_write(&env->bpf_progs.lock);
31  }
32  
__perf_env__insert_bpf_prog_info(struct perf_env * env,struct bpf_prog_info_node * info_node)33  void __perf_env__insert_bpf_prog_info(struct perf_env *env, struct bpf_prog_info_node *info_node)
34  {
35  	__u32 prog_id = info_node->info_linear->info.id;
36  	struct bpf_prog_info_node *node;
37  	struct rb_node *parent = NULL;
38  	struct rb_node **p;
39  
40  	p = &env->bpf_progs.infos.rb_node;
41  
42  	while (*p != NULL) {
43  		parent = *p;
44  		node = rb_entry(parent, struct bpf_prog_info_node, rb_node);
45  		if (prog_id < node->info_linear->info.id) {
46  			p = &(*p)->rb_left;
47  		} else if (prog_id > node->info_linear->info.id) {
48  			p = &(*p)->rb_right;
49  		} else {
50  			pr_debug("duplicated bpf prog info %u\n", prog_id);
51  			return;
52  		}
53  	}
54  
55  	rb_link_node(&info_node->rb_node, parent, p);
56  	rb_insert_color(&info_node->rb_node, &env->bpf_progs.infos);
57  	env->bpf_progs.infos_cnt++;
58  }
59  
perf_env__find_bpf_prog_info(struct perf_env * env,__u32 prog_id)60  struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
61  							__u32 prog_id)
62  {
63  	struct bpf_prog_info_node *node = NULL;
64  	struct rb_node *n;
65  
66  	down_read(&env->bpf_progs.lock);
67  	n = env->bpf_progs.infos.rb_node;
68  
69  	while (n) {
70  		node = rb_entry(n, struct bpf_prog_info_node, rb_node);
71  		if (prog_id < node->info_linear->info.id)
72  			n = n->rb_left;
73  		else if (prog_id > node->info_linear->info.id)
74  			n = n->rb_right;
75  		else
76  			goto out;
77  	}
78  	node = NULL;
79  
80  out:
81  	up_read(&env->bpf_progs.lock);
82  	return node;
83  }
84  
perf_env__insert_btf(struct perf_env * env,struct btf_node * btf_node)85  bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
86  {
87  	bool ret;
88  
89  	down_write(&env->bpf_progs.lock);
90  	ret = __perf_env__insert_btf(env, btf_node);
91  	up_write(&env->bpf_progs.lock);
92  	return ret;
93  }
94  
__perf_env__insert_btf(struct perf_env * env,struct btf_node * btf_node)95  bool __perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
96  {
97  	struct rb_node *parent = NULL;
98  	__u32 btf_id = btf_node->id;
99  	struct btf_node *node;
100  	struct rb_node **p;
101  
102  	p = &env->bpf_progs.btfs.rb_node;
103  
104  	while (*p != NULL) {
105  		parent = *p;
106  		node = rb_entry(parent, struct btf_node, rb_node);
107  		if (btf_id < node->id) {
108  			p = &(*p)->rb_left;
109  		} else if (btf_id > node->id) {
110  			p = &(*p)->rb_right;
111  		} else {
112  			pr_debug("duplicated btf %u\n", btf_id);
113  			return false;
114  		}
115  	}
116  
117  	rb_link_node(&btf_node->rb_node, parent, p);
118  	rb_insert_color(&btf_node->rb_node, &env->bpf_progs.btfs);
119  	env->bpf_progs.btfs_cnt++;
120  	return true;
121  }
122  
perf_env__find_btf(struct perf_env * env,__u32 btf_id)123  struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id)
124  {
125  	struct btf_node *res;
126  
127  	down_read(&env->bpf_progs.lock);
128  	res = __perf_env__find_btf(env, btf_id);
129  	up_read(&env->bpf_progs.lock);
130  	return res;
131  }
132  
__perf_env__find_btf(struct perf_env * env,__u32 btf_id)133  struct btf_node *__perf_env__find_btf(struct perf_env *env, __u32 btf_id)
134  {
135  	struct btf_node *node = NULL;
136  	struct rb_node *n;
137  
138  	n = env->bpf_progs.btfs.rb_node;
139  
140  	while (n) {
141  		node = rb_entry(n, struct btf_node, rb_node);
142  		if (btf_id < node->id)
143  			n = n->rb_left;
144  		else if (btf_id > node->id)
145  			n = n->rb_right;
146  		else
147  			return node;
148  	}
149  	return NULL;
150  }
151  
152  /* purge data in bpf_progs.infos tree */
perf_env__purge_bpf(struct perf_env * env)153  static void perf_env__purge_bpf(struct perf_env *env)
154  {
155  	struct rb_root *root;
156  	struct rb_node *next;
157  
158  	down_write(&env->bpf_progs.lock);
159  
160  	root = &env->bpf_progs.infos;
161  	next = rb_first(root);
162  
163  	while (next) {
164  		struct bpf_prog_info_node *node;
165  
166  		node = rb_entry(next, struct bpf_prog_info_node, rb_node);
167  		next = rb_next(&node->rb_node);
168  		rb_erase(&node->rb_node, root);
169  		zfree(&node->info_linear);
170  		free(node);
171  	}
172  
173  	env->bpf_progs.infos_cnt = 0;
174  
175  	root = &env->bpf_progs.btfs;
176  	next = rb_first(root);
177  
178  	while (next) {
179  		struct btf_node *node;
180  
181  		node = rb_entry(next, struct btf_node, rb_node);
182  		next = rb_next(&node->rb_node);
183  		rb_erase(&node->rb_node, root);
184  		free(node);
185  	}
186  
187  	env->bpf_progs.btfs_cnt = 0;
188  
189  	up_write(&env->bpf_progs.lock);
190  }
191  #else // HAVE_LIBBPF_SUPPORT
perf_env__purge_bpf(struct perf_env * env __maybe_unused)192  static void perf_env__purge_bpf(struct perf_env *env __maybe_unused)
193  {
194  }
195  #endif // HAVE_LIBBPF_SUPPORT
196  
perf_env__exit(struct perf_env * env)197  void perf_env__exit(struct perf_env *env)
198  {
199  	int i, j;
200  
201  	perf_env__purge_bpf(env);
202  	perf_env__purge_cgroups(env);
203  	zfree(&env->hostname);
204  	zfree(&env->os_release);
205  	zfree(&env->version);
206  	zfree(&env->arch);
207  	zfree(&env->cpu_desc);
208  	zfree(&env->cpuid);
209  	zfree(&env->cmdline);
210  	zfree(&env->cmdline_argv);
211  	zfree(&env->sibling_dies);
212  	zfree(&env->sibling_cores);
213  	zfree(&env->sibling_threads);
214  	zfree(&env->pmu_mappings);
215  	zfree(&env->cpu);
216  	for (i = 0; i < env->nr_cpu_pmu_caps; i++)
217  		zfree(&env->cpu_pmu_caps[i]);
218  	zfree(&env->cpu_pmu_caps);
219  	zfree(&env->numa_map);
220  
221  	for (i = 0; i < env->nr_numa_nodes; i++)
222  		perf_cpu_map__put(env->numa_nodes[i].map);
223  	zfree(&env->numa_nodes);
224  
225  	for (i = 0; i < env->caches_cnt; i++)
226  		cpu_cache_level__free(&env->caches[i]);
227  	zfree(&env->caches);
228  
229  	for (i = 0; i < env->nr_memory_nodes; i++)
230  		zfree(&env->memory_nodes[i].set);
231  	zfree(&env->memory_nodes);
232  
233  	for (i = 0; i < env->nr_hybrid_nodes; i++) {
234  		zfree(&env->hybrid_nodes[i].pmu_name);
235  		zfree(&env->hybrid_nodes[i].cpus);
236  	}
237  	zfree(&env->hybrid_nodes);
238  
239  	for (i = 0; i < env->nr_pmus_with_caps; i++) {
240  		for (j = 0; j < env->pmu_caps[i].nr_caps; j++)
241  			zfree(&env->pmu_caps[i].caps[j]);
242  		zfree(&env->pmu_caps[i].caps);
243  		zfree(&env->pmu_caps[i].pmu_name);
244  	}
245  	zfree(&env->pmu_caps);
246  }
247  
perf_env__init(struct perf_env * env)248  void perf_env__init(struct perf_env *env)
249  {
250  #ifdef HAVE_LIBBPF_SUPPORT
251  	env->bpf_progs.infos = RB_ROOT;
252  	env->bpf_progs.btfs = RB_ROOT;
253  	init_rwsem(&env->bpf_progs.lock);
254  #endif
255  	env->kernel_is_64_bit = -1;
256  }
257  
perf_env__init_kernel_mode(struct perf_env * env)258  static void perf_env__init_kernel_mode(struct perf_env *env)
259  {
260  	const char *arch = perf_env__raw_arch(env);
261  
262  	if (!strncmp(arch, "x86_64", 6) || !strncmp(arch, "aarch64", 7) ||
263  	    !strncmp(arch, "arm64", 5) || !strncmp(arch, "mips64", 6) ||
264  	    !strncmp(arch, "parisc64", 8) || !strncmp(arch, "riscv64", 7) ||
265  	    !strncmp(arch, "s390x", 5) || !strncmp(arch, "sparc64", 7))
266  		env->kernel_is_64_bit = 1;
267  	else
268  		env->kernel_is_64_bit = 0;
269  }
270  
perf_env__kernel_is_64_bit(struct perf_env * env)271  int perf_env__kernel_is_64_bit(struct perf_env *env)
272  {
273  	if (env->kernel_is_64_bit == -1)
274  		perf_env__init_kernel_mode(env);
275  
276  	return env->kernel_is_64_bit;
277  }
278  
perf_env__set_cmdline(struct perf_env * env,int argc,const char * argv[])279  int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
280  {
281  	int i;
282  
283  	/* do not include NULL termination */
284  	env->cmdline_argv = calloc(argc, sizeof(char *));
285  	if (env->cmdline_argv == NULL)
286  		goto out_enomem;
287  
288  	/*
289  	 * Must copy argv contents because it gets moved around during option
290  	 * parsing:
291  	 */
292  	for (i = 0; i < argc ; i++) {
293  		env->cmdline_argv[i] = argv[i];
294  		if (env->cmdline_argv[i] == NULL)
295  			goto out_free;
296  	}
297  
298  	env->nr_cmdline = argc;
299  
300  	return 0;
301  out_free:
302  	zfree(&env->cmdline_argv);
303  out_enomem:
304  	return -ENOMEM;
305  }
306  
perf_env__read_cpu_topology_map(struct perf_env * env)307  int perf_env__read_cpu_topology_map(struct perf_env *env)
308  {
309  	int idx, nr_cpus;
310  
311  	if (env->cpu != NULL)
312  		return 0;
313  
314  	if (env->nr_cpus_avail == 0)
315  		env->nr_cpus_avail = cpu__max_present_cpu().cpu;
316  
317  	nr_cpus = env->nr_cpus_avail;
318  	if (nr_cpus == -1)
319  		return -EINVAL;
320  
321  	env->cpu = calloc(nr_cpus, sizeof(env->cpu[0]));
322  	if (env->cpu == NULL)
323  		return -ENOMEM;
324  
325  	for (idx = 0; idx < nr_cpus; ++idx) {
326  		struct perf_cpu cpu = { .cpu = idx };
327  
328  		env->cpu[idx].core_id	= cpu__get_core_id(cpu);
329  		env->cpu[idx].socket_id	= cpu__get_socket_id(cpu);
330  		env->cpu[idx].die_id	= cpu__get_die_id(cpu);
331  	}
332  
333  	env->nr_cpus_avail = nr_cpus;
334  	return 0;
335  }
336  
perf_env__read_pmu_mappings(struct perf_env * env)337  int perf_env__read_pmu_mappings(struct perf_env *env)
338  {
339  	struct perf_pmu *pmu = NULL;
340  	u32 pmu_num = 0;
341  	struct strbuf sb;
342  
343  	while ((pmu = perf_pmus__scan(pmu)))
344  		pmu_num++;
345  
346  	if (!pmu_num) {
347  		pr_debug("pmu mappings not available\n");
348  		return -ENOENT;
349  	}
350  	env->nr_pmu_mappings = pmu_num;
351  
352  	if (strbuf_init(&sb, 128 * pmu_num) < 0)
353  		return -ENOMEM;
354  
355  	while ((pmu = perf_pmus__scan(pmu))) {
356  		if (strbuf_addf(&sb, "%u:%s", pmu->type, pmu->name) < 0)
357  			goto error;
358  		/* include a NULL character at the end */
359  		if (strbuf_add(&sb, "", 1) < 0)
360  			goto error;
361  	}
362  
363  	env->pmu_mappings = strbuf_detach(&sb, NULL);
364  
365  	return 0;
366  
367  error:
368  	strbuf_release(&sb);
369  	return -1;
370  }
371  
perf_env__read_cpuid(struct perf_env * env)372  int perf_env__read_cpuid(struct perf_env *env)
373  {
374  	char cpuid[128];
375  	int err = get_cpuid(cpuid, sizeof(cpuid));
376  
377  	if (err)
378  		return err;
379  
380  	free(env->cpuid);
381  	env->cpuid = strdup(cpuid);
382  	if (env->cpuid == NULL)
383  		return ENOMEM;
384  	return 0;
385  }
386  
perf_env__read_arch(struct perf_env * env)387  static int perf_env__read_arch(struct perf_env *env)
388  {
389  	struct utsname uts;
390  
391  	if (env->arch)
392  		return 0;
393  
394  	if (!uname(&uts))
395  		env->arch = strdup(uts.machine);
396  
397  	return env->arch ? 0 : -ENOMEM;
398  }
399  
perf_env__read_nr_cpus_avail(struct perf_env * env)400  static int perf_env__read_nr_cpus_avail(struct perf_env *env)
401  {
402  	if (env->nr_cpus_avail == 0)
403  		env->nr_cpus_avail = cpu__max_present_cpu().cpu;
404  
405  	return env->nr_cpus_avail ? 0 : -ENOENT;
406  }
407  
perf_env__raw_arch(struct perf_env * env)408  const char *perf_env__raw_arch(struct perf_env *env)
409  {
410  	return env && !perf_env__read_arch(env) ? env->arch : "unknown";
411  }
412  
perf_env__nr_cpus_avail(struct perf_env * env)413  int perf_env__nr_cpus_avail(struct perf_env *env)
414  {
415  	return env && !perf_env__read_nr_cpus_avail(env) ? env->nr_cpus_avail : 0;
416  }
417  
cpu_cache_level__free(struct cpu_cache_level * cache)418  void cpu_cache_level__free(struct cpu_cache_level *cache)
419  {
420  	zfree(&cache->type);
421  	zfree(&cache->map);
422  	zfree(&cache->size);
423  }
424  
425  /*
426   * Return architecture name in a normalized form.
427   * The conversion logic comes from the Makefile.
428   */
normalize_arch(char * arch)429  static const char *normalize_arch(char *arch)
430  {
431  	if (!strcmp(arch, "x86_64"))
432  		return "x86";
433  	if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6')
434  		return "x86";
435  	if (!strcmp(arch, "sun4u") || !strncmp(arch, "sparc", 5))
436  		return "sparc";
437  	if (!strncmp(arch, "aarch64", 7) || !strncmp(arch, "arm64", 5))
438  		return "arm64";
439  	if (!strncmp(arch, "arm", 3) || !strcmp(arch, "sa110"))
440  		return "arm";
441  	if (!strncmp(arch, "s390", 4))
442  		return "s390";
443  	if (!strncmp(arch, "parisc", 6))
444  		return "parisc";
445  	if (!strncmp(arch, "powerpc", 7) || !strncmp(arch, "ppc", 3))
446  		return "powerpc";
447  	if (!strncmp(arch, "mips", 4))
448  		return "mips";
449  	if (!strncmp(arch, "sh", 2) && isdigit(arch[2]))
450  		return "sh";
451  	if (!strncmp(arch, "loongarch", 9))
452  		return "loongarch";
453  
454  	return arch;
455  }
456  
perf_env__arch(struct perf_env * env)457  const char *perf_env__arch(struct perf_env *env)
458  {
459  	char *arch_name;
460  
461  	if (!env || !env->arch) { /* Assume local operation */
462  		static struct utsname uts = { .machine[0] = '\0', };
463  		if (uts.machine[0] == '\0' && uname(&uts) < 0)
464  			return NULL;
465  		arch_name = uts.machine;
466  	} else
467  		arch_name = env->arch;
468  
469  	return normalize_arch(arch_name);
470  }
471  
perf_env__arch_strerrno(struct perf_env * env __maybe_unused,int err __maybe_unused)472  const char *perf_env__arch_strerrno(struct perf_env *env __maybe_unused, int err __maybe_unused)
473  {
474  #if defined(HAVE_SYSCALL_TABLE_SUPPORT) && defined(HAVE_LIBTRACEEVENT)
475  	if (env->arch_strerrno == NULL)
476  		env->arch_strerrno = arch_syscalls__strerrno_function(perf_env__arch(env));
477  
478  	return env->arch_strerrno ? env->arch_strerrno(err) : "no arch specific strerrno function";
479  #else
480  	return "!(HAVE_SYSCALL_TABLE_SUPPORT && HAVE_LIBTRACEEVENT)";
481  #endif
482  }
483  
perf_env__cpuid(struct perf_env * env)484  const char *perf_env__cpuid(struct perf_env *env)
485  {
486  	int status;
487  
488  	if (!env->cpuid) { /* Assume local operation */
489  		status = perf_env__read_cpuid(env);
490  		if (status)
491  			return NULL;
492  	}
493  
494  	return env->cpuid;
495  }
496  
perf_env__nr_pmu_mappings(struct perf_env * env)497  int perf_env__nr_pmu_mappings(struct perf_env *env)
498  {
499  	int status;
500  
501  	if (!env->nr_pmu_mappings) { /* Assume local operation */
502  		status = perf_env__read_pmu_mappings(env);
503  		if (status)
504  			return 0;
505  	}
506  
507  	return env->nr_pmu_mappings;
508  }
509  
perf_env__pmu_mappings(struct perf_env * env)510  const char *perf_env__pmu_mappings(struct perf_env *env)
511  {
512  	int status;
513  
514  	if (!env->pmu_mappings) { /* Assume local operation */
515  		status = perf_env__read_pmu_mappings(env);
516  		if (status)
517  			return NULL;
518  	}
519  
520  	return env->pmu_mappings;
521  }
522  
perf_env__numa_node(struct perf_env * env,struct perf_cpu cpu)523  int perf_env__numa_node(struct perf_env *env, struct perf_cpu cpu)
524  {
525  	if (!env->nr_numa_map) {
526  		struct numa_node *nn;
527  		int i, nr = 0;
528  
529  		for (i = 0; i < env->nr_numa_nodes; i++) {
530  			nn = &env->numa_nodes[i];
531  			nr = max(nr, perf_cpu_map__max(nn->map).cpu);
532  		}
533  
534  		nr++;
535  
536  		/*
537  		 * We initialize the numa_map array to prepare
538  		 * it for missing cpus, which return node -1
539  		 */
540  		env->numa_map = malloc(nr * sizeof(int));
541  		if (!env->numa_map)
542  			return -1;
543  
544  		for (i = 0; i < nr; i++)
545  			env->numa_map[i] = -1;
546  
547  		env->nr_numa_map = nr;
548  
549  		for (i = 0; i < env->nr_numa_nodes; i++) {
550  			struct perf_cpu tmp;
551  			int j;
552  
553  			nn = &env->numa_nodes[i];
554  			perf_cpu_map__for_each_cpu(tmp, j, nn->map)
555  				env->numa_map[tmp.cpu] = i;
556  		}
557  	}
558  
559  	return cpu.cpu >= 0 && cpu.cpu < env->nr_numa_map ? env->numa_map[cpu.cpu] : -1;
560  }
561  
perf_env__has_pmu_mapping(struct perf_env * env,const char * pmu_name)562  bool perf_env__has_pmu_mapping(struct perf_env *env, const char *pmu_name)
563  {
564  	char *pmu_mapping = env->pmu_mappings, *colon;
565  
566  	for (int i = 0; i < env->nr_pmu_mappings; ++i) {
567  		if (strtoul(pmu_mapping, &colon, 0) == ULONG_MAX || *colon != ':')
568  			goto out_error;
569  
570  		pmu_mapping = colon + 1;
571  		if (strcmp(pmu_mapping, pmu_name) == 0)
572  			return true;
573  
574  		pmu_mapping += strlen(pmu_mapping) + 1;
575  	}
576  out_error:
577  	return false;
578  }
579  
perf_env__find_pmu_cap(struct perf_env * env,const char * pmu_name,const char * cap)580  char *perf_env__find_pmu_cap(struct perf_env *env, const char *pmu_name,
581  			     const char *cap)
582  {
583  	char *cap_eq;
584  	int cap_size;
585  	char **ptr;
586  	int i, j;
587  
588  	if (!pmu_name || !cap)
589  		return NULL;
590  
591  	cap_size = strlen(cap);
592  	cap_eq = zalloc(cap_size + 2);
593  	if (!cap_eq)
594  		return NULL;
595  
596  	memcpy(cap_eq, cap, cap_size);
597  	cap_eq[cap_size] = '=';
598  
599  	if (!strcmp(pmu_name, "cpu")) {
600  		for (i = 0; i < env->nr_cpu_pmu_caps; i++) {
601  			if (!strncmp(env->cpu_pmu_caps[i], cap_eq, cap_size + 1)) {
602  				free(cap_eq);
603  				return &env->cpu_pmu_caps[i][cap_size + 1];
604  			}
605  		}
606  		goto out;
607  	}
608  
609  	for (i = 0; i < env->nr_pmus_with_caps; i++) {
610  		if (strcmp(env->pmu_caps[i].pmu_name, pmu_name))
611  			continue;
612  
613  		ptr = env->pmu_caps[i].caps;
614  
615  		for (j = 0; j < env->pmu_caps[i].nr_caps; j++) {
616  			if (!strncmp(ptr[j], cap_eq, cap_size + 1)) {
617  				free(cap_eq);
618  				return &ptr[j][cap_size + 1];
619  			}
620  		}
621  	}
622  
623  out:
624  	free(cap_eq);
625  	return NULL;
626  }
627  
perf_env__find_br_cntr_info(struct perf_env * env,unsigned int * nr,unsigned int * width)628  void perf_env__find_br_cntr_info(struct perf_env *env,
629  				 unsigned int *nr,
630  				 unsigned int *width)
631  {
632  	if (nr) {
633  		*nr = env->cpu_pmu_caps ? env->br_cntr_nr :
634  					  env->pmu_caps->br_cntr_nr;
635  	}
636  
637  	if (width) {
638  		*width = env->cpu_pmu_caps ? env->br_cntr_width :
639  					     env->pmu_caps->br_cntr_width;
640  	}
641  }
642