blob: 0fafcf264d235abcac353369237a43ab54ed9b73 [file] [log] [blame]
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001// SPDX-License-Identifier: GPL-2.0
2#include "cpumap.h"
David Brazdil0f672f62019-12-10 10:32:29 +00003#include "debug.h"
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004#include "env.h"
David Brazdil0f672f62019-12-10 10:32:29 +00005#include <linux/ctype.h>
6#include <linux/zalloc.h>
7#include "bpf-event.h"
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00008#include <errno.h>
9#include <sys/utsname.h>
David Brazdil0f672f62019-12-10 10:32:29 +000010#include <bpf/libbpf.h>
11#include <stdlib.h>
12#include <string.h>
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000013
14struct perf_env perf_env;
15
David Brazdil0f672f62019-12-10 10:32:29 +000016void perf_env__insert_bpf_prog_info(struct perf_env *env,
17 struct bpf_prog_info_node *info_node)
18{
19 __u32 prog_id = info_node->info_linear->info.id;
20 struct bpf_prog_info_node *node;
21 struct rb_node *parent = NULL;
22 struct rb_node **p;
23
24 down_write(&env->bpf_progs.lock);
25 p = &env->bpf_progs.infos.rb_node;
26
27 while (*p != NULL) {
28 parent = *p;
29 node = rb_entry(parent, struct bpf_prog_info_node, rb_node);
30 if (prog_id < node->info_linear->info.id) {
31 p = &(*p)->rb_left;
32 } else if (prog_id > node->info_linear->info.id) {
33 p = &(*p)->rb_right;
34 } else {
35 pr_debug("duplicated bpf prog info %u\n", prog_id);
36 goto out;
37 }
38 }
39
40 rb_link_node(&info_node->rb_node, parent, p);
41 rb_insert_color(&info_node->rb_node, &env->bpf_progs.infos);
42 env->bpf_progs.infos_cnt++;
43out:
44 up_write(&env->bpf_progs.lock);
45}
46
47struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
48 __u32 prog_id)
49{
50 struct bpf_prog_info_node *node = NULL;
51 struct rb_node *n;
52
53 down_read(&env->bpf_progs.lock);
54 n = env->bpf_progs.infos.rb_node;
55
56 while (n) {
57 node = rb_entry(n, struct bpf_prog_info_node, rb_node);
58 if (prog_id < node->info_linear->info.id)
59 n = n->rb_left;
60 else if (prog_id > node->info_linear->info.id)
61 n = n->rb_right;
62 else
63 goto out;
64 }
65 node = NULL;
66
67out:
68 up_read(&env->bpf_progs.lock);
69 return node;
70}
71
72void perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
73{
74 struct rb_node *parent = NULL;
75 __u32 btf_id = btf_node->id;
76 struct btf_node *node;
77 struct rb_node **p;
78
79 down_write(&env->bpf_progs.lock);
80 p = &env->bpf_progs.btfs.rb_node;
81
82 while (*p != NULL) {
83 parent = *p;
84 node = rb_entry(parent, struct btf_node, rb_node);
85 if (btf_id < node->id) {
86 p = &(*p)->rb_left;
87 } else if (btf_id > node->id) {
88 p = &(*p)->rb_right;
89 } else {
90 pr_debug("duplicated btf %u\n", btf_id);
91 goto out;
92 }
93 }
94
95 rb_link_node(&btf_node->rb_node, parent, p);
96 rb_insert_color(&btf_node->rb_node, &env->bpf_progs.btfs);
97 env->bpf_progs.btfs_cnt++;
98out:
99 up_write(&env->bpf_progs.lock);
100}
101
102struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id)
103{
104 struct btf_node *node = NULL;
105 struct rb_node *n;
106
107 down_read(&env->bpf_progs.lock);
108 n = env->bpf_progs.btfs.rb_node;
109
110 while (n) {
111 node = rb_entry(n, struct btf_node, rb_node);
112 if (btf_id < node->id)
113 n = n->rb_left;
114 else if (btf_id > node->id)
115 n = n->rb_right;
116 else
117 goto out;
118 }
119 node = NULL;
120
121out:
122 up_read(&env->bpf_progs.lock);
123 return node;
124}
125
126/* purge data in bpf_progs.infos tree */
127static void perf_env__purge_bpf(struct perf_env *env)
128{
129 struct rb_root *root;
130 struct rb_node *next;
131
132 down_write(&env->bpf_progs.lock);
133
134 root = &env->bpf_progs.infos;
135 next = rb_first(root);
136
137 while (next) {
138 struct bpf_prog_info_node *node;
139
140 node = rb_entry(next, struct bpf_prog_info_node, rb_node);
141 next = rb_next(&node->rb_node);
142 rb_erase(&node->rb_node, root);
143 free(node);
144 }
145
146 env->bpf_progs.infos_cnt = 0;
147
148 root = &env->bpf_progs.btfs;
149 next = rb_first(root);
150
151 while (next) {
152 struct btf_node *node;
153
154 node = rb_entry(next, struct btf_node, rb_node);
155 next = rb_next(&node->rb_node);
156 rb_erase(&node->rb_node, root);
157 free(node);
158 }
159
160 env->bpf_progs.btfs_cnt = 0;
161
162 up_write(&env->bpf_progs.lock);
163}
164
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000165void perf_env__exit(struct perf_env *env)
166{
167 int i;
168
David Brazdil0f672f62019-12-10 10:32:29 +0000169 perf_env__purge_bpf(env);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000170 zfree(&env->hostname);
171 zfree(&env->os_release);
172 zfree(&env->version);
173 zfree(&env->arch);
174 zfree(&env->cpu_desc);
175 zfree(&env->cpuid);
176 zfree(&env->cmdline);
177 zfree(&env->cmdline_argv);
Olivier Deprez0e641232021-09-23 10:07:05 +0200178 zfree(&env->sibling_dies);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000179 zfree(&env->sibling_cores);
180 zfree(&env->sibling_threads);
181 zfree(&env->pmu_mappings);
182 zfree(&env->cpu);
183
184 for (i = 0; i < env->nr_numa_nodes; i++)
David Brazdil0f672f62019-12-10 10:32:29 +0000185 perf_cpu_map__put(env->numa_nodes[i].map);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000186 zfree(&env->numa_nodes);
187
188 for (i = 0; i < env->caches_cnt; i++)
189 cpu_cache_level__free(&env->caches[i]);
190 zfree(&env->caches);
191
192 for (i = 0; i < env->nr_memory_nodes; i++)
David Brazdil0f672f62019-12-10 10:32:29 +0000193 zfree(&env->memory_nodes[i].set);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000194 zfree(&env->memory_nodes);
195}
196
David Brazdil0f672f62019-12-10 10:32:29 +0000197void perf_env__init(struct perf_env *env)
198{
199 env->bpf_progs.infos = RB_ROOT;
200 env->bpf_progs.btfs = RB_ROOT;
201 init_rwsem(&env->bpf_progs.lock);
202}
203
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000204int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
205{
206 int i;
207
208 /* do not include NULL termination */
209 env->cmdline_argv = calloc(argc, sizeof(char *));
210 if (env->cmdline_argv == NULL)
211 goto out_enomem;
212
213 /*
214 * Must copy argv contents because it gets moved around during option
215 * parsing:
216 */
217 for (i = 0; i < argc ; i++) {
218 env->cmdline_argv[i] = argv[i];
219 if (env->cmdline_argv[i] == NULL)
220 goto out_free;
221 }
222
223 env->nr_cmdline = argc;
224
225 return 0;
226out_free:
227 zfree(&env->cmdline_argv);
228out_enomem:
229 return -ENOMEM;
230}
231
232int perf_env__read_cpu_topology_map(struct perf_env *env)
233{
234 int cpu, nr_cpus;
235
236 if (env->cpu != NULL)
237 return 0;
238
239 if (env->nr_cpus_avail == 0)
240 env->nr_cpus_avail = cpu__max_present_cpu();
241
242 nr_cpus = env->nr_cpus_avail;
243 if (nr_cpus == -1)
244 return -EINVAL;
245
246 env->cpu = calloc(nr_cpus, sizeof(env->cpu[0]));
247 if (env->cpu == NULL)
248 return -ENOMEM;
249
250 for (cpu = 0; cpu < nr_cpus; ++cpu) {
251 env->cpu[cpu].core_id = cpu_map__get_core_id(cpu);
252 env->cpu[cpu].socket_id = cpu_map__get_socket_id(cpu);
David Brazdil0f672f62019-12-10 10:32:29 +0000253 env->cpu[cpu].die_id = cpu_map__get_die_id(cpu);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000254 }
255
256 env->nr_cpus_avail = nr_cpus;
257 return 0;
258}
259
260static int perf_env__read_arch(struct perf_env *env)
261{
262 struct utsname uts;
263
264 if (env->arch)
265 return 0;
266
267 if (!uname(&uts))
268 env->arch = strdup(uts.machine);
269
270 return env->arch ? 0 : -ENOMEM;
271}
272
273static int perf_env__read_nr_cpus_avail(struct perf_env *env)
274{
275 if (env->nr_cpus_avail == 0)
276 env->nr_cpus_avail = cpu__max_present_cpu();
277
278 return env->nr_cpus_avail ? 0 : -ENOENT;
279}
280
281const char *perf_env__raw_arch(struct perf_env *env)
282{
283 return env && !perf_env__read_arch(env) ? env->arch : "unknown";
284}
285
286int perf_env__nr_cpus_avail(struct perf_env *env)
287{
288 return env && !perf_env__read_nr_cpus_avail(env) ? env->nr_cpus_avail : 0;
289}
290
291void cpu_cache_level__free(struct cpu_cache_level *cache)
292{
David Brazdil0f672f62019-12-10 10:32:29 +0000293 zfree(&cache->type);
294 zfree(&cache->map);
295 zfree(&cache->size);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000296}
297
298/*
299 * Return architecture name in a normalized form.
300 * The conversion logic comes from the Makefile.
301 */
302static const char *normalize_arch(char *arch)
303{
304 if (!strcmp(arch, "x86_64"))
305 return "x86";
306 if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6')
307 return "x86";
308 if (!strcmp(arch, "sun4u") || !strncmp(arch, "sparc", 5))
309 return "sparc";
310 if (!strcmp(arch, "aarch64") || !strcmp(arch, "arm64"))
311 return "arm64";
312 if (!strncmp(arch, "arm", 3) || !strcmp(arch, "sa110"))
313 return "arm";
314 if (!strncmp(arch, "s390", 4))
315 return "s390";
316 if (!strncmp(arch, "parisc", 6))
317 return "parisc";
318 if (!strncmp(arch, "powerpc", 7) || !strncmp(arch, "ppc", 3))
319 return "powerpc";
320 if (!strncmp(arch, "mips", 4))
321 return "mips";
322 if (!strncmp(arch, "sh", 2) && isdigit(arch[2]))
323 return "sh";
324
325 return arch;
326}
327
328const char *perf_env__arch(struct perf_env *env)
329{
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000330 char *arch_name;
331
David Brazdil0f672f62019-12-10 10:32:29 +0000332 if (!env || !env->arch) { /* Assume local operation */
Olivier Deprez0e641232021-09-23 10:07:05 +0200333 static struct utsname uts = { .machine[0] = '\0', };
334 if (uts.machine[0] == '\0' && uname(&uts) < 0)
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000335 return NULL;
336 arch_name = uts.machine;
337 } else
338 arch_name = env->arch;
339
340 return normalize_arch(arch_name);
341}