brintos

brintos / linux-shallow public Read only

0
0
Text · 13.9 KiB · 1edbccf Raw
642 lines · c
1// SPDX-License-Identifier: GPL-2.02#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 18struct perf_env perf_env;19 20#ifdef HAVE_LIBBPF_SUPPORT21#include "bpf-event.h"22#include "bpf-utils.h"23#include <bpf/libbpf.h>24 25void 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 33void __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 60struct 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		else76			goto out;77	}78	node = NULL;79 80out:81	up_read(&env->bpf_progs.lock);82	return node;83}84 85bool 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 95bool __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 123struct 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 133struct 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		else147			return node;148	}149	return NULL;150}151 152/* purge data in bpf_progs.infos tree */153static 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_SUPPORT192static void perf_env__purge_bpf(struct perf_env *env __maybe_unused)193{194}195#endif // HAVE_LIBBPF_SUPPORT196 197void 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 248void perf_env__init(struct perf_env *env)249{250#ifdef HAVE_LIBBPF_SUPPORT251	env->bpf_progs.infos = RB_ROOT;252	env->bpf_progs.btfs = RB_ROOT;253	init_rwsem(&env->bpf_progs.lock);254#endif255	env->kernel_is_64_bit = -1;256}257 258static 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	else268		env->kernel_is_64_bit = 0;269}270 271int 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 279int 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 option290	 * 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;301out_free:302	zfree(&env->cmdline_argv);303out_enomem:304	return -ENOMEM;305}306 307int 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 337int 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 367error:368	strbuf_release(&sb);369	return -1;370}371 372int 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 387static 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 400static 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 408const char *perf_env__raw_arch(struct perf_env *env)409{410	return env && !perf_env__read_arch(env) ? env->arch : "unknown";411}412 413int 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 418void 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 */429static 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 457const 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	} else467		arch_name = env->arch;468 469	return normalize_arch(arch_name);470}471 472const 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#else480	return "!(HAVE_SYSCALL_TABLE_SUPPORT && HAVE_LIBTRACEEVENT)";481#endif482}483 484const 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 497int 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 510const 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 523int 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 prepare538		 * it for missing cpus, which return node -1539		 */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 562bool 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	}576out_error:577	return false;578}579 580char *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 623out:624	free(cap_eq);625	return NULL;626}627 628void 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