Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
aa36ddd7 | 2 | #include "cpumap.h" |
5e51b0bb | 3 | #include "debug.h" |
f0ce888c | 4 | #include "env.h" |
f1cedfb8 | 5 | #include "util/header.h" |
54373b5d | 6 | #include "linux/compiler.h" |
3052ba56 | 7 | #include <linux/ctype.h> |
7f7c536f | 8 | #include <linux/zalloc.h> |
d1277aa3 | 9 | #include "cgroup.h" |
a43783ae | 10 | #include <errno.h> |
4e8fbc1c | 11 | #include <sys/utsname.h> |
215a0d30 | 12 | #include <stdlib.h> |
8520a98d | 13 | #include <string.h> |
1eaf496e | 14 | #include "pmus.h" |
9fe8895a | 15 | #include "strbuf.h" |
54373b5d | 16 | #include "trace/beauty/beauty.h" |
f0ce888c | 17 | |
b6998692 ACM |
18 | struct perf_env perf_env; |
19 | ||
ef0580ec ACM |
20 | #ifdef HAVE_LIBBPF_SUPPORT |
21 | #include "bpf-event.h" | |
6ac22d03 | 22 | #include "bpf-utils.h" |
ef0580ec ACM |
23 | #include <bpf/libbpf.h> |
24 | ||
e4378f0c SL |
25 | void perf_env__insert_bpf_prog_info(struct perf_env *env, |
26 | struct bpf_prog_info_node *info_node) | |
9c51f878 IR |
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 | ||
33 | void __perf_env__insert_bpf_prog_info(struct perf_env *env, struct bpf_prog_info_node *info_node) | |
e4378f0c SL |
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 | ||
e4378f0c SL |
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); | |
9c51f878 | 51 | return; |
e4378f0c SL |
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++; | |
e4378f0c SL |
58 | } |
59 | ||
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 | |
aa526602 | 76 | goto out; |
e4378f0c | 77 | } |
aa526602 | 78 | node = NULL; |
e4378f0c | 79 | |
aa526602 | 80 | out: |
e4378f0c SL |
81 | up_read(&env->bpf_progs.lock); |
82 | return node; | |
83 | } | |
84 | ||
4924b1f7 | 85 | bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node) |
9c51f878 IR |
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 | ||
95 | bool __perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node) | |
3792cb2f SL |
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 | ||
3792cb2f SL |
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); | |
9c51f878 | 113 | return false; |
3792cb2f SL |
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++; | |
9c51f878 | 120 | return true; |
3792cb2f SL |
121 | } |
122 | ||
123 | struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id) | |
9c51f878 IR |
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 | ||
133 | struct btf_node *__perf_env__find_btf(struct perf_env *env, __u32 btf_id) | |
3792cb2f SL |
134 | { |
135 | struct btf_node *node = NULL; | |
136 | struct rb_node *n; | |
137 | ||
3792cb2f SL |
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 | |
9c51f878 | 147 | return node; |
3792cb2f | 148 | } |
9c51f878 | 149 | return NULL; |
3792cb2f SL |
150 | } |
151 | ||
e4378f0c SL |
152 | /* purge data in bpf_progs.infos tree */ |
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); | |
9fbde6c8 | 169 | zfree(&node->info_linear); |
e4378f0c SL |
170 | free(node); |
171 | } | |
172 | ||
173 | env->bpf_progs.infos_cnt = 0; | |
174 | ||
3792cb2f SL |
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 | ||
e4378f0c SL |
189 | up_write(&env->bpf_progs.lock); |
190 | } | |
ef0580ec ACM |
191 | #else // HAVE_LIBBPF_SUPPORT |
192 | static void perf_env__purge_bpf(struct perf_env *env __maybe_unused) | |
193 | { | |
194 | } | |
195 | #endif // HAVE_LIBBPF_SUPPORT | |
e4378f0c | 196 | |
f0ce888c ACM |
197 | void perf_env__exit(struct perf_env *env) |
198 | { | |
ff34eaa8 | 199 | int i, j; |
720e98b5 | 200 | |
e4378f0c | 201 | perf_env__purge_bpf(env); |
d1277aa3 | 202 | perf_env__purge_cgroups(env); |
f0ce888c ACM |
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); | |
42db3d9d | 211 | zfree(&env->sibling_dies); |
f0ce888c ACM |
212 | zfree(&env->sibling_cores); |
213 | zfree(&env->sibling_threads); | |
f0ce888c ACM |
214 | zfree(&env->pmu_mappings); |
215 | zfree(&env->cpu); | |
ff34eaa8 RB |
216 | for (i = 0; i < env->nr_cpu_pmu_caps; i++) |
217 | zfree(&env->cpu_pmu_caps[i]); | |
da6b7c6c | 218 | zfree(&env->cpu_pmu_caps); |
389799a7 | 219 | zfree(&env->numa_map); |
720e98b5 | 220 | |
c60da22a | 221 | for (i = 0; i < env->nr_numa_nodes; i++) |
38f01d8d | 222 | perf_cpu_map__put(env->numa_nodes[i].map); |
c60da22a JO |
223 | zfree(&env->numa_nodes); |
224 | ||
720e98b5 JO |
225 | for (i = 0; i < env->caches_cnt; i++) |
226 | cpu_cache_level__free(&env->caches[i]); | |
227 | zfree(&env->caches); | |
e725920c JO |
228 | |
229 | for (i = 0; i < env->nr_memory_nodes; i++) | |
d8f9da24 | 230 | zfree(&env->memory_nodes[i].set); |
e725920c | 231 | zfree(&env->memory_nodes); |
f7d74ce3 JY |
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); | |
e119083b | 238 | |
2139f742 RB |
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); | |
e119083b | 244 | } |
2139f742 | 245 | zfree(&env->pmu_caps); |
f0ce888c | 246 | } |
b6998692 | 247 | |
7c0223e1 | 248 | void perf_env__init(struct perf_env *env) |
e4378f0c | 249 | { |
ef0580ec | 250 | #ifdef HAVE_LIBBPF_SUPPORT |
e4378f0c | 251 | env->bpf_progs.infos = RB_ROOT; |
3792cb2f | 252 | env->bpf_progs.btfs = RB_ROOT; |
e4378f0c | 253 | init_rwsem(&env->bpf_progs.lock); |
ef0580ec | 254 | #endif |
7c0223e1 LY |
255 | env->kernel_is_64_bit = -1; |
256 | } | |
257 | ||
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 | ||
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; | |
e4378f0c SL |
277 | } |
278 | ||
b6998692 ACM |
279 | int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]) |
280 | { | |
281 | int i; | |
282 | ||
b6998692 ACM |
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 | } | |
aa36ddd7 ACM |
306 | |
307 | int perf_env__read_cpu_topology_map(struct perf_env *env) | |
308 | { | |
6d18804b | 309 | int idx, nr_cpus; |
aa36ddd7 ACM |
310 | |
311 | if (env->cpu != NULL) | |
312 | return 0; | |
313 | ||
314 | if (env->nr_cpus_avail == 0) | |
6d18804b | 315 | env->nr_cpus_avail = cpu__max_present_cpu().cpu; |
aa36ddd7 ACM |
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 | ||
6d18804b IR |
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); | |
aa36ddd7 ACM |
331 | } |
332 | ||
333 | env->nr_cpus_avail = nr_cpus; | |
334 | return 0; | |
335 | } | |
720e98b5 | 336 | |
9fe8895a KP |
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 | ||
c091ee90 | 343 | while ((pmu = perf_pmus__scan(pmu))) |
9fe8895a | 344 | pmu_num++; |
c091ee90 | 345 | |
9fe8895a KP |
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 | ||
1eaf496e | 355 | while ((pmu = perf_pmus__scan(pmu))) { |
9fe8895a KP |
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 | ||
f1cedfb8 ACM |
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 | ||
dbbd34a6 AH |
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 | ||
9cecca32 AH |
400 | static int perf_env__read_nr_cpus_avail(struct perf_env *env) |
401 | { | |
402 | if (env->nr_cpus_avail == 0) | |
6d18804b | 403 | env->nr_cpus_avail = cpu__max_present_cpu().cpu; |
9cecca32 AH |
404 | |
405 | return env->nr_cpus_avail ? 0 : -ENOENT; | |
406 | } | |
407 | ||
dbbd34a6 AH |
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 | ||
9cecca32 AH |
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 | ||
720e98b5 JO |
418 | void cpu_cache_level__free(struct cpu_cache_level *cache) |
419 | { | |
d8f9da24 ACM |
420 | zfree(&cache->type); |
421 | zfree(&cache->map); | |
422 | zfree(&cache->size); | |
720e98b5 | 423 | } |
4e8fbc1c ACM |
424 | |
425 | /* | |
426 | * Return architecture name in a normalized form. | |
427 | * The conversion logic comes from the Makefile. | |
428 | */ | |
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"; | |
4502da0e | 437 | if (!strncmp(arch, "aarch64", 7) || !strncmp(arch, "arm64", 5)) |
4e8fbc1c ACM |
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"; | |
2fa5ebe3 HC |
451 | if (!strncmp(arch, "loongarch", 9)) |
452 | return "loongarch"; | |
4e8fbc1c ACM |
453 | |
454 | return arch; | |
455 | } | |
456 | ||
457 | const char *perf_env__arch(struct perf_env *env) | |
458 | { | |
4e8fbc1c ACM |
459 | char *arch_name; |
460 | ||
804234f2 | 461 | if (!env || !env->arch) { /* Assume local operation */ |
ebcb9464 ACM |
462 | static struct utsname uts = { .machine[0] = '\0', }; |
463 | if (uts.machine[0] == '\0' && uname(&uts) < 0) | |
4e8fbc1c ACM |
464 | return NULL; |
465 | arch_name = uts.machine; | |
466 | } else | |
467 | arch_name = env->arch; | |
468 | ||
469 | return normalize_arch(arch_name); | |
470 | } | |
389799a7 | 471 | |
54373b5d ACM |
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) | |
4acef676 ACM |
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"; | |
54373b5d ACM |
479 | #else |
480 | return "!(HAVE_SYSCALL_TABLE_SUPPORT && HAVE_LIBTRACEEVENT)"; | |
481 | #endif | |
482 | } | |
483 | ||
9fe8895a KP |
484 | const char *perf_env__cpuid(struct perf_env *env) |
485 | { | |
486 | int status; | |
487 | ||
e2372136 | 488 | if (!env->cpuid) { /* Assume local operation */ |
9fe8895a KP |
489 | status = perf_env__read_cpuid(env); |
490 | if (status) | |
491 | return NULL; | |
492 | } | |
493 | ||
494 | return env->cpuid; | |
495 | } | |
496 | ||
497 | int perf_env__nr_pmu_mappings(struct perf_env *env) | |
498 | { | |
499 | int status; | |
500 | ||
e2372136 | 501 | if (!env->nr_pmu_mappings) { /* Assume local operation */ |
9fe8895a KP |
502 | status = perf_env__read_pmu_mappings(env); |
503 | if (status) | |
504 | return 0; | |
505 | } | |
506 | ||
507 | return env->nr_pmu_mappings; | |
508 | } | |
509 | ||
510 | const char *perf_env__pmu_mappings(struct perf_env *env) | |
511 | { | |
512 | int status; | |
513 | ||
e2372136 | 514 | if (!env->pmu_mappings) { /* Assume local operation */ |
9fe8895a KP |
515 | status = perf_env__read_pmu_mappings(env); |
516 | if (status) | |
517 | return NULL; | |
518 | } | |
519 | ||
520 | return env->pmu_mappings; | |
521 | } | |
389799a7 | 522 | |
6d18804b | 523 | int perf_env__numa_node(struct perf_env *env, struct perf_cpu cpu) |
389799a7 JO |
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]; | |
6d18804b | 531 | nr = max(nr, perf_cpu_map__max(nn->map).cpu); |
389799a7 JO |
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++) { | |
6d18804b IR |
550 | struct perf_cpu tmp; |
551 | int j; | |
389799a7 JO |
552 | |
553 | nn = &env->numa_nodes[i]; | |
6d18804b IR |
554 | perf_cpu_map__for_each_cpu(tmp, j, nn->map) |
555 | env->numa_map[tmp.cpu] = i; | |
389799a7 JO |
556 | } |
557 | } | |
558 | ||
6d18804b | 559 | return cpu.cpu >= 0 && cpu.cpu < env->nr_numa_map ? env->numa_map[cpu.cpu] : -1; |
389799a7 | 560 | } |
2139f742 | 561 | |
dd678532 ACM |
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 | ||
2139f742 RB |
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 | } |