1 // SPDX-License-Identifier: GPL-2.0
2 #include "cpumap.h"
3 #include "debug.h"
4 #include "env.h"
5 #include <linux/ctype.h>
6 #include <linux/zalloc.h>
7 #include "bpf-event.h"
8 #include <errno.h>
9 #include <sys/utsname.h>
10 #include <bpf/libbpf.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 struct perf_env perf_env;
15
perf_env__insert_bpf_prog_info(struct perf_env * env,struct bpf_prog_info_node * info_node)16 void perf_env__insert_bpf_prog_info(struct perf_env *env,
17 struct bpf_prog_info_node *info_node)
18 {
19 down_write(&env->bpf_progs.lock);
20 __perf_env__insert_bpf_prog_info(env, info_node);
21 up_write(&env->bpf_progs.lock);
22 }
23
__perf_env__insert_bpf_prog_info(struct perf_env * env,struct bpf_prog_info_node * info_node)24 void __perf_env__insert_bpf_prog_info(struct perf_env *env, struct bpf_prog_info_node *info_node)
25 {
26 __u32 prog_id = info_node->info_linear->info.id;
27 struct bpf_prog_info_node *node;
28 struct rb_node *parent = NULL;
29 struct rb_node **p;
30
31 p = &env->bpf_progs.infos.rb_node;
32
33 while (*p != NULL) {
34 parent = *p;
35 node = rb_entry(parent, struct bpf_prog_info_node, rb_node);
36 if (prog_id < node->info_linear->info.id) {
37 p = &(*p)->rb_left;
38 } else if (prog_id > node->info_linear->info.id) {
39 p = &(*p)->rb_right;
40 } else {
41 pr_debug("duplicated bpf prog info %u\n", prog_id);
42 return;
43 }
44 }
45
46 rb_link_node(&info_node->rb_node, parent, p);
47 rb_insert_color(&info_node->rb_node, &env->bpf_progs.infos);
48 env->bpf_progs.infos_cnt++;
49 }
50
perf_env__find_bpf_prog_info(struct perf_env * env,__u32 prog_id)51 struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
52 __u32 prog_id)
53 {
54 struct bpf_prog_info_node *node = NULL;
55 struct rb_node *n;
56
57 down_read(&env->bpf_progs.lock);
58 n = env->bpf_progs.infos.rb_node;
59
60 while (n) {
61 node = rb_entry(n, struct bpf_prog_info_node, rb_node);
62 if (prog_id < node->info_linear->info.id)
63 n = n->rb_left;
64 else if (prog_id > node->info_linear->info.id)
65 n = n->rb_right;
66 else
67 goto out;
68 }
69 node = NULL;
70
71 out:
72 up_read(&env->bpf_progs.lock);
73 return node;
74 }
75
perf_env__insert_btf(struct perf_env * env,struct btf_node * btf_node)76 bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
77 {
78 bool ret;
79
80 down_write(&env->bpf_progs.lock);
81 ret = __perf_env__insert_btf(env, btf_node);
82 up_write(&env->bpf_progs.lock);
83 return ret;
84 }
85
__perf_env__insert_btf(struct perf_env * env,struct btf_node * btf_node)86 bool __perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
87 {
88 struct rb_node *parent = NULL;
89 __u32 btf_id = btf_node->id;
90 struct btf_node *node;
91 struct rb_node **p;
92
93 p = &env->bpf_progs.btfs.rb_node;
94
95 while (*p != NULL) {
96 parent = *p;
97 node = rb_entry(parent, struct btf_node, rb_node);
98 if (btf_id < node->id) {
99 p = &(*p)->rb_left;
100 } else if (btf_id > node->id) {
101 p = &(*p)->rb_right;
102 } else {
103 pr_debug("duplicated btf %u\n", btf_id);
104 return false;
105 }
106 }
107
108 rb_link_node(&btf_node->rb_node, parent, p);
109 rb_insert_color(&btf_node->rb_node, &env->bpf_progs.btfs);
110 env->bpf_progs.btfs_cnt++;
111 return true;
112 }
113
perf_env__find_btf(struct perf_env * env,__u32 btf_id)114 struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id)
115 {
116 struct btf_node *res;
117
118 down_read(&env->bpf_progs.lock);
119 res = __perf_env__find_btf(env, btf_id);
120 up_read(&env->bpf_progs.lock);
121 return res;
122 }
123
__perf_env__find_btf(struct perf_env * env,__u32 btf_id)124 struct btf_node *__perf_env__find_btf(struct perf_env *env, __u32 btf_id)
125 {
126 struct btf_node *node = NULL;
127 struct rb_node *n;
128
129 n = env->bpf_progs.btfs.rb_node;
130
131 while (n) {
132 node = rb_entry(n, struct btf_node, rb_node);
133 if (btf_id < node->id)
134 n = n->rb_left;
135 else if (btf_id > node->id)
136 n = n->rb_right;
137 else
138 return node;
139 }
140 return NULL;
141 }
142
143 /* purge data in bpf_progs.infos tree */
perf_env__purge_bpf(struct perf_env * env)144 static void perf_env__purge_bpf(struct perf_env *env)
145 {
146 struct rb_root *root;
147 struct rb_node *next;
148
149 down_write(&env->bpf_progs.lock);
150
151 root = &env->bpf_progs.infos;
152 next = rb_first(root);
153
154 while (next) {
155 struct bpf_prog_info_node *node;
156
157 node = rb_entry(next, struct bpf_prog_info_node, rb_node);
158 next = rb_next(&node->rb_node);
159 rb_erase(&node->rb_node, root);
160 free(node);
161 }
162
163 env->bpf_progs.infos_cnt = 0;
164
165 root = &env->bpf_progs.btfs;
166 next = rb_first(root);
167
168 while (next) {
169 struct btf_node *node;
170
171 node = rb_entry(next, struct btf_node, rb_node);
172 next = rb_next(&node->rb_node);
173 rb_erase(&node->rb_node, root);
174 free(node);
175 }
176
177 env->bpf_progs.btfs_cnt = 0;
178
179 up_write(&env->bpf_progs.lock);
180 }
181
perf_env__exit(struct perf_env * env)182 void perf_env__exit(struct perf_env *env)
183 {
184 int i;
185
186 perf_env__purge_bpf(env);
187 zfree(&env->hostname);
188 zfree(&env->os_release);
189 zfree(&env->version);
190 zfree(&env->arch);
191 zfree(&env->cpu_desc);
192 zfree(&env->cpuid);
193 zfree(&env->cmdline);
194 zfree(&env->cmdline_argv);
195 zfree(&env->sibling_dies);
196 zfree(&env->sibling_cores);
197 zfree(&env->sibling_threads);
198 zfree(&env->pmu_mappings);
199 zfree(&env->cpu);
200 zfree(&env->numa_map);
201
202 for (i = 0; i < env->nr_numa_nodes; i++)
203 perf_cpu_map__put(env->numa_nodes[i].map);
204 zfree(&env->numa_nodes);
205
206 for (i = 0; i < env->caches_cnt; i++)
207 cpu_cache_level__free(&env->caches[i]);
208 zfree(&env->caches);
209
210 for (i = 0; i < env->nr_memory_nodes; i++)
211 zfree(&env->memory_nodes[i].set);
212 zfree(&env->memory_nodes);
213 }
214
perf_env__init(struct perf_env * env)215 void perf_env__init(struct perf_env *env)
216 {
217 env->bpf_progs.infos = RB_ROOT;
218 env->bpf_progs.btfs = RB_ROOT;
219 init_rwsem(&env->bpf_progs.lock);
220 }
221
perf_env__set_cmdline(struct perf_env * env,int argc,const char * argv[])222 int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
223 {
224 int i;
225
226 /* do not include NULL termination */
227 env->cmdline_argv = calloc(argc, sizeof(char *));
228 if (env->cmdline_argv == NULL)
229 goto out_enomem;
230
231 /*
232 * Must copy argv contents because it gets moved around during option
233 * parsing:
234 */
235 for (i = 0; i < argc ; i++) {
236 env->cmdline_argv[i] = argv[i];
237 if (env->cmdline_argv[i] == NULL)
238 goto out_free;
239 }
240
241 env->nr_cmdline = argc;
242
243 return 0;
244 out_free:
245 zfree(&env->cmdline_argv);
246 out_enomem:
247 return -ENOMEM;
248 }
249
perf_env__read_cpu_topology_map(struct perf_env * env)250 int perf_env__read_cpu_topology_map(struct perf_env *env)
251 {
252 int cpu, nr_cpus;
253
254 if (env->cpu != NULL)
255 return 0;
256
257 if (env->nr_cpus_avail == 0)
258 env->nr_cpus_avail = cpu__max_present_cpu();
259
260 nr_cpus = env->nr_cpus_avail;
261 if (nr_cpus == -1)
262 return -EINVAL;
263
264 env->cpu = calloc(nr_cpus, sizeof(env->cpu[0]));
265 if (env->cpu == NULL)
266 return -ENOMEM;
267
268 for (cpu = 0; cpu < nr_cpus; ++cpu) {
269 env->cpu[cpu].core_id = cpu_map__get_core_id(cpu);
270 env->cpu[cpu].socket_id = cpu_map__get_socket_id(cpu);
271 env->cpu[cpu].die_id = cpu_map__get_die_id(cpu);
272 }
273
274 env->nr_cpus_avail = nr_cpus;
275 return 0;
276 }
277
perf_env__read_arch(struct perf_env * env)278 static int perf_env__read_arch(struct perf_env *env)
279 {
280 struct utsname uts;
281
282 if (env->arch)
283 return 0;
284
285 if (!uname(&uts))
286 env->arch = strdup(uts.machine);
287
288 return env->arch ? 0 : -ENOMEM;
289 }
290
perf_env__read_nr_cpus_avail(struct perf_env * env)291 static int perf_env__read_nr_cpus_avail(struct perf_env *env)
292 {
293 if (env->nr_cpus_avail == 0)
294 env->nr_cpus_avail = cpu__max_present_cpu();
295
296 return env->nr_cpus_avail ? 0 : -ENOENT;
297 }
298
perf_env__raw_arch(struct perf_env * env)299 const char *perf_env__raw_arch(struct perf_env *env)
300 {
301 return env && !perf_env__read_arch(env) ? env->arch : "unknown";
302 }
303
perf_env__nr_cpus_avail(struct perf_env * env)304 int perf_env__nr_cpus_avail(struct perf_env *env)
305 {
306 return env && !perf_env__read_nr_cpus_avail(env) ? env->nr_cpus_avail : 0;
307 }
308
cpu_cache_level__free(struct cpu_cache_level * cache)309 void cpu_cache_level__free(struct cpu_cache_level *cache)
310 {
311 zfree(&cache->type);
312 zfree(&cache->map);
313 zfree(&cache->size);
314 }
315
316 /*
317 * Return architecture name in a normalized form.
318 * The conversion logic comes from the Makefile.
319 */
normalize_arch(char * arch)320 static const char *normalize_arch(char *arch)
321 {
322 if (!strcmp(arch, "x86_64"))
323 return "x86";
324 if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6')
325 return "x86";
326 if (!strcmp(arch, "sun4u") || !strncmp(arch, "sparc", 5))
327 return "sparc";
328 if (!strcmp(arch, "aarch64") || !strcmp(arch, "arm64"))
329 return "arm64";
330 if (!strncmp(arch, "arm", 3) || !strcmp(arch, "sa110"))
331 return "arm";
332 if (!strncmp(arch, "s390", 4))
333 return "s390";
334 if (!strncmp(arch, "parisc", 6))
335 return "parisc";
336 if (!strncmp(arch, "powerpc", 7) || !strncmp(arch, "ppc", 3))
337 return "powerpc";
338 if (!strncmp(arch, "mips", 4))
339 return "mips";
340 if (!strncmp(arch, "sh", 2) && isdigit(arch[2]))
341 return "sh";
342
343 return arch;
344 }
345
perf_env__arch(struct perf_env * env)346 const char *perf_env__arch(struct perf_env *env)
347 {
348 char *arch_name;
349
350 if (!env || !env->arch) { /* Assume local operation */
351 static struct utsname uts = { .machine[0] = '\0', };
352 if (uts.machine[0] == '\0' && uname(&uts) < 0)
353 return NULL;
354 arch_name = uts.machine;
355 } else
356 arch_name = env->arch;
357
358 return normalize_arch(arch_name);
359 }
360
361
perf_env__numa_node(struct perf_env * env,int cpu)362 int perf_env__numa_node(struct perf_env *env, int cpu)
363 {
364 if (!env->nr_numa_map) {
365 struct numa_node *nn;
366 int i, nr = 0;
367
368 for (i = 0; i < env->nr_numa_nodes; i++) {
369 nn = &env->numa_nodes[i];
370 nr = max(nr, perf_cpu_map__max(nn->map));
371 }
372
373 nr++;
374
375 /*
376 * We initialize the numa_map array to prepare
377 * it for missing cpus, which return node -1
378 */
379 env->numa_map = malloc(nr * sizeof(int));
380 if (!env->numa_map)
381 return -1;
382
383 for (i = 0; i < nr; i++)
384 env->numa_map[i] = -1;
385
386 env->nr_numa_map = nr;
387
388 for (i = 0; i < env->nr_numa_nodes; i++) {
389 int tmp, j;
390
391 nn = &env->numa_nodes[i];
392 perf_cpu_map__for_each_cpu(j, tmp, nn->map)
393 env->numa_map[j] = i;
394 }
395 }
396
397 return cpu >= 0 && cpu < env->nr_numa_map ? env->numa_map[cpu] : -1;
398 }
399