| 1 | |
| 2 | #include "cpumap.h"
|
| 3 | #include "dwarf-regs.h"
|
| 4 | #include "debug.h"
|
| 5 | #include "env.h"
|
| 6 | #include "util/header.h"
|
| 7 | #include "util/rwsem.h"
|
| 8 | #include <linux/compiler.h>
|
| 9 | #include <linux/kernel.h>
|
| 10 | #include <linux/ctype.h>
|
| 11 | #include <linux/rbtree.h>
|
| 12 | #include <linux/string.h>
|
| 13 | #include <linux/zalloc.h>
|
| 14 | #include "cgroup.h"
|
| 15 | #include <errno.h>
|
| 16 | #include <sys/utsname.h>
|
| 17 | #include <stdlib.h>
|
| 18 | #include <string.h>
|
| 19 | #include "pmu.h"
|
| 20 | #include "pmus.h"
|
| 21 | #include "strbuf.h"
|
| 22 | #include "trace/beauty/beauty.h"
|
| 23 |
|
| 24 | #ifdef HAVE_LIBBPF_SUPPORT
|
| 25 | #include "bpf-event.h"
|
| 26 | #include "bpf-utils.h"
|
| 27 | #include <bpf/libbpf.h>
|
| 28 |
|
| 29 | bool perf_env__insert_bpf_prog_info(struct perf_env *env,
|
| 30 | struct bpf_prog_info_node *info_node)
|
| 31 | {
|
| 32 | bool ret;
|
| 33 |
|
| 34 | down_write(&env->bpf_progs.lock);
|
| 35 | ret = __perf_env__insert_bpf_prog_info(env, info_node);
|
| 36 | up_write(&env->bpf_progs.lock);
|
| 37 |
|
| 38 | return ret;
|
| 39 | }
|
| 40 |
|
| 41 | bool __perf_env__insert_bpf_prog_info(struct perf_env *env, struct bpf_prog_info_node *info_node)
|
| 42 | {
|
| 43 | __u32 prog_id = info_node->info_linear->info.id;
|
| 44 | struct bpf_prog_info_node *node;
|
| 45 | struct rb_node *parent = NULL;
|
| 46 | struct rb_node **p;
|
| 47 |
|
| 48 | p = &env->bpf_progs.infos.rb_node;
|
| 49 |
|
| 50 | while (*p != NULL) {
|
| 51 | parent = *p;
|
| 52 | node = rb_entry(parent, struct bpf_prog_info_node, rb_node);
|
| 53 | if (prog_id < node->info_linear->info.id) {
|
| 54 | p = &(*p)->rb_left;
|
| 55 | } else if (prog_id > node->info_linear->info.id) {
|
| 56 | p = &(*p)->rb_right;
|
| 57 | } else {
|
| 58 | pr_debug("duplicated bpf prog info %u\n", prog_id);
|
| 59 | return false;
|
| 60 | }
|
| 61 | }
|
| 62 |
|
| 63 | rb_link_node(&info_node->rb_node, parent, p);
|
| 64 | rb_insert_color(&info_node->rb_node, &env->bpf_progs.infos);
|
| 65 | env->bpf_progs.infos_cnt++;
|
| 66 | return true;
|
| 67 | }
|
| 68 |
|
| 69 | struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
|
| 70 | __u32 prog_id)
|
| 71 | {
|
| 72 | struct bpf_prog_info_node *node = NULL;
|
| 73 | struct rb_node *n;
|
| 74 |
|
| 75 | down_read(&env->bpf_progs.lock);
|
| 76 | n = env->bpf_progs.infos.rb_node;
|
| 77 |
|
| 78 | while (n) {
|
| 79 | node = rb_entry(n, struct bpf_prog_info_node, rb_node);
|
| 80 | if (prog_id < node->info_linear->info.id)
|
| 81 | n = n->rb_left;
|
| 82 | else if (prog_id > node->info_linear->info.id)
|
| 83 | n = n->rb_right;
|
| 84 | else
|
| 85 | goto out;
|
| 86 | }
|
| 87 | node = NULL;
|
| 88 |
|
| 89 | out:
|
| 90 | up_read(&env->bpf_progs.lock);
|
| 91 | return node;
|
| 92 | }
|
| 93 |
|
| 94 | void perf_env__iterate_bpf_prog_info(struct perf_env *env,
|
| 95 | void (*cb)(struct bpf_prog_info_node *node,
|
| 96 | void *data),
|
| 97 | void *data)
|
| 98 | {
|
| 99 | struct rb_node *first;
|
| 100 |
|
| 101 | down_read(&env->bpf_progs.lock);
|
| 102 | first = rb_first(&env->bpf_progs.infos);
|
| 103 | for (struct rb_node *node = first; node != NULL; node = rb_next(node))
|
| 104 | (*cb)(rb_entry(node, struct bpf_prog_info_node, rb_node), data);
|
| 105 | up_read(&env->bpf_progs.lock);
|
| 106 | }
|
| 107 |
|
| 108 | bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
|
| 109 | {
|
| 110 | bool ret;
|
| 111 |
|
| 112 | down_write(&env->bpf_progs.lock);
|
| 113 | ret = __perf_env__insert_btf(env, btf_node);
|
| 114 | up_write(&env->bpf_progs.lock);
|
| 115 | return ret;
|
| 116 | }
|
| 117 |
|
| 118 | bool __perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
|
| 119 | {
|
| 120 | struct rb_node *parent = NULL;
|
| 121 | __u32 btf_id = btf_node->id;
|
| 122 | struct btf_node *node;
|
| 123 | struct rb_node **p;
|
| 124 |
|
| 125 | p = &env->bpf_progs.btfs.rb_node;
|
| 126 |
|
| 127 | while (*p != NULL) {
|
| 128 | parent = *p;
|
| 129 | node = rb_entry(parent, struct btf_node, rb_node);
|
| 130 | if (btf_id < node->id) {
|
| 131 | p = &(*p)->rb_left;
|
| 132 | } else if (btf_id > node->id) {
|
| 133 | p = &(*p)->rb_right;
|
| 134 | } else {
|
| 135 | pr_debug("duplicated btf %u\n", btf_id);
|
| 136 | return false;
|
| 137 | }
|
| 138 | }
|
| 139 |
|
| 140 | rb_link_node(&btf_node->rb_node, parent, p);
|
| 141 | rb_insert_color(&btf_node->rb_node, &env->bpf_progs.btfs);
|
| 142 | env->bpf_progs.btfs_cnt++;
|
| 143 | return true;
|
| 144 | }
|
| 145 |
|
| 146 | struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id)
|
| 147 | {
|
| 148 | struct btf_node *res;
|
| 149 |
|
| 150 | down_read(&env->bpf_progs.lock);
|
| 151 | res = __perf_env__find_btf(env, btf_id);
|
| 152 | up_read(&env->bpf_progs.lock);
|
| 153 | return res;
|
| 154 | }
|
| 155 |
|
| 156 | struct btf_node *__perf_env__find_btf(struct perf_env *env, __u32 btf_id)
|
| 157 | {
|
| 158 | struct btf_node *node = NULL;
|
| 159 | struct rb_node *n;
|
| 160 |
|
| 161 | n = env->bpf_progs.btfs.rb_node;
|
| 162 |
|
| 163 | while (n) {
|
| 164 | node = rb_entry(n, struct btf_node, rb_node);
|
| 165 | if (btf_id < node->id)
|
| 166 | n = n->rb_left;
|
| 167 | else if (btf_id > node->id)
|
| 168 | n = n->rb_right;
|
| 169 | else
|
| 170 | return node;
|
| 171 | }
|
| 172 | return NULL;
|
| 173 | }
|
| 174 |
|
| 175 |
|
| 176 | static void perf_env__purge_bpf(struct perf_env *env)
|
| 177 | {
|
| 178 | struct rb_root *root;
|
| 179 | struct rb_node *next;
|
| 180 |
|
| 181 | down_write(&env->bpf_progs.lock);
|
| 182 |
|
| 183 | root = &env->bpf_progs.infos;
|
| 184 | next = rb_first(root);
|
| 185 |
|
| 186 | while (next) {
|
| 187 | struct bpf_prog_info_node *node;
|
| 188 |
|
| 189 | node = rb_entry(next, struct bpf_prog_info_node, rb_node);
|
| 190 | next = rb_next(&node->rb_node);
|
| 191 | rb_erase(&node->rb_node, root);
|
| 192 | zfree(&node->info_linear);
|
| 193 | bpf_metadata_free(node->metadata);
|
| 194 | free(node);
|
| 195 | }
|
| 196 |
|
| 197 | env->bpf_progs.infos_cnt = 0;
|
| 198 |
|
| 199 | root = &env->bpf_progs.btfs;
|
| 200 | next = rb_first(root);
|
| 201 |
|
| 202 | while (next) {
|
| 203 | struct btf_node *node;
|
| 204 |
|
| 205 | node = rb_entry(next, struct btf_node, rb_node);
|
| 206 | next = rb_next(&node->rb_node);
|
| 207 | rb_erase(&node->rb_node, root);
|
| 208 | free(node);
|
| 209 | }
|
| 210 |
|
| 211 | env->bpf_progs.btfs_cnt = 0;
|
| 212 |
|
| 213 | up_write(&env->bpf_progs.lock);
|
| 214 | }
|
| 215 | #else
|
| 216 | static void perf_env__purge_bpf(struct perf_env *env __maybe_unused)
|
| 217 | {
|
| 218 | }
|
| 219 | #endif |
| 220 |
|
| 221 | void free_cpu_domain_info(struct cpu_domain_map **cd_map, u32 schedstat_version, u32 nr)
|
| 222 | {
|
| 223 | if (!cd_map)
|
| 224 | return;
|
| 225 |
|
| 226 | for (u32 i = 0; i < nr; i++) {
|
| 227 | if (!cd_map[i])
|
| 228 | continue;
|
| 229 |
|
| 230 | for (u32 j = 0; j < cd_map[i]->nr_domains; j++) {
|
| 231 | struct domain_info *d_info = cd_map[i]->domains[j];
|
| 232 |
|
| 233 | if (!d_info)
|
| 234 | continue;
|
| 235 |
|
| 236 | if (schedstat_version >= 17)
|
| 237 | zfree(&d_info->dname);
|
| 238 |
|
| 239 | zfree(&d_info->cpumask);
|
| 240 | zfree(&d_info->cpulist);
|
| 241 | zfree(&d_info);
|
| 242 | }
|
| 243 | zfree(&cd_map[i]->domains);
|
| 244 | zfree(&cd_map[i]);
|
| 245 | }
|
| 246 | zfree(&cd_map);
|
| 247 | }
|
| 248 |
|
| 249 | void perf_env__exit(struct perf_env *env)
|
| 250 | {
|
| 251 | int i, j;
|
| 252 |
|
| 253 | mutex_destroy(&env->lock);
|
| 254 |
|
| 255 | perf_env__purge_bpf(env);
|
| 256 | perf_env__purge_cgroups(env);
|
| 257 | zfree(&env->hostname);
|
| 258 | zfree(&env->os_release);
|
| 259 | zfree(&env->version);
|
| 260 | zfree(&env->arch);
|
| 261 | zfree(&env->cpu_desc);
|
| 262 | zfree(&env->cpuid);
|
| 263 | zfree(&env->cmdline);
|
| 264 | zfree(&env->cmdline_argv);
|
| 265 | zfree(&env->sibling_dies);
|
| 266 | zfree(&env->sibling_cores);
|
| 267 | zfree(&env->sibling_threads);
|
| 268 | zfree(&env->pmu_mappings);
|
| 269 | zfree(&env->cpu);
|
| 270 | for (i = 0; i < env->nr_cpu_pmu_caps; i++)
|
| 271 | zfree(&env->cpu_pmu_caps[i]);
|
| 272 | zfree(&env->cpu_pmu_caps);
|
| 273 | zfree(&env->numa_map);
|
| 274 |
|
| 275 | for (i = 0; i < env->nr_numa_nodes; i++)
|
| 276 | perf_cpu_map__put(env->numa_nodes[i].map);
|
| 277 | zfree(&env->numa_nodes);
|
| 278 |
|
| 279 | for (i = 0; i < env->caches_cnt; i++)
|
| 280 | cpu_cache_level__free(&env->caches[i]);
|
| 281 | zfree(&env->caches);
|
| 282 |
|
| 283 | for (i = 0; i < env->nr_memory_nodes; i++)
|
| 284 | zfree(&env->memory_nodes[i].set);
|
| 285 | zfree(&env->memory_nodes);
|
| 286 |
|
| 287 | for (i = 0; i < env->nr_hybrid_nodes; i++) {
|
| 288 | zfree(&env->hybrid_nodes[i].pmu_name);
|
| 289 | zfree(&env->hybrid_nodes[i].cpus);
|
| 290 | }
|
| 291 | zfree(&env->hybrid_nodes);
|
| 292 |
|
| 293 | for (i = 0; i < env->nr_pmus_with_caps; i++) {
|
| 294 | for (j = 0; j < env->pmu_caps[i].nr_caps; j++)
|
| 295 | zfree(&env->pmu_caps[i].caps[j]);
|
| 296 | zfree(&env->pmu_caps[i].caps);
|
| 297 | zfree(&env->pmu_caps[i].pmu_name);
|
| 298 | }
|
| 299 | zfree(&env->pmu_caps);
|
| 300 | free_cpu_domain_info(env->cpu_domain, env->schedstat_version, env->nr_cpus_avail);
|
| 301 | }
|
| 302 |
|
| 303 | void perf_env__init(struct perf_env *env)
|
| 304 | {
|
| 305 | memset(env, 0, sizeof(*env));
|
| 306 | #ifdef HAVE_LIBBPF_SUPPORT
|
| 307 | env->bpf_progs.infos = RB_ROOT;
|
| 308 | env->bpf_progs.btfs = RB_ROOT;
|
| 309 | init_rwsem(&env->bpf_progs.lock);
|
| 310 | #endif
|
| 311 | env->kernel_is_64_bit = -1;
|
| 312 | mutex_init(&env->lock);
|
| 313 | }
|
| 314 |
|
| 315 | static void perf_env__init_kernel_mode(struct perf_env *env)
|
| 316 | {
|
| 317 | const char *arch = env->arch;
|
| 318 |
|
| 319 | if (!arch) {
|
| 320 | static struct utsname uts = { .machine[0] = '\0', };
|
| 321 |
|
| 322 | if (uts.machine[0] == '\0')
|
| 323 | uname(&uts);
|
| 324 | if (uts.machine[0] != '\0')
|
| 325 | arch = uts.machine;
|
| 326 | }
|
| 327 |
|
| 328 | if (arch) {
|
| 329 | if (strstr(arch, "64") || strstr(arch, "s390x"))
|
| 330 | env->kernel_is_64_bit = 1;
|
| 331 | else
|
| 332 | env->kernel_is_64_bit = 0;
|
| 333 | return;
|
| 334 | }
|
| 335 |
|
| 336 |
|
| 337 | env->kernel_is_64_bit = (sizeof(void *) == 8) ? 1 : 0;
|
| 338 | }
|
| 339 |
|
| 340 | int perf_env__kernel_is_64_bit(struct perf_env *env)
|
| 341 | {
|
| 342 | if (env->kernel_is_64_bit == -1)
|
| 343 | perf_env__init_kernel_mode(env);
|
| 344 |
|
| 345 | return env->kernel_is_64_bit;
|
| 346 | }
|
| 347 |
|
| 348 | bool perf_arch_is_big_endian(const char *arch)
|
| 349 | {
|
| 350 | if (!arch)
|
| 351 | return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__;
|
| 352 |
|
| 353 | if (str_ends_with(arch, "_be") || !strcmp(arch, "sparc") || !strcmp(arch, "sparc64") ||
|
| 354 | !strcmp(arch, "s390") || !strcmp(arch, "s390x") || !strcmp(arch, "powerpc") ||
|
| 355 | !strcmp(arch, "ppc") || !strcmp(arch, "ppc64") ||
|
| 356 | !strcmp(arch, "mips") || !strcmp(arch, "mips64") || !strcmp(arch, "parisc") ||
|
| 357 | !strcmp(arch, "parisc64") || !strcmp(arch, "m68k") ||
|
| 358 | !strcmp(arch, "armeb") || !strcmp(arch, "mipseb") || !strcmp(arch, "mips64eb"))
|
| 359 | return true;
|
| 360 |
|
| 361 | return false;
|
| 362 | }
|
| 363 |
|
| 364 | const char *perf_env__os_release(struct perf_env *env)
|
| 365 | {
|
| 366 | struct utsname uts;
|
| 367 | int ret;
|
| 368 | const char *release;
|
| 369 |
|
| 370 | if (!env)
|
| 371 | return perf_version_string;
|
| 372 |
|
| 373 | mutex_lock(&env->lock);
|
| 374 | if (env->os_release) {
|
| 375 | release = env->os_release;
|
| 376 | goto out;
|
| 377 | }
|
| 378 |
|
| 379 | |
| 380 | * If env->arch is set, this is an offline target environment.
|
| 381 | * If the os_release is not populated in the file, we do not want
|
| 382 | * to poison it with the host's release which would break guest checks.
|
| 383 |
|
| 384 | if (env->arch) {
|
| 385 | release = NULL;
|
| 386 | goto out;
|
| 387 | }
|
| 388 |
|
| 389 | |
| 390 | * The os_release is being accessed but wasn't initialized from a data
|
| 391 | * file, assume this is 'live' mode and use the release from uname. If
|
| 392 | * uname or strdup fails then use the current perf tool version.
|
| 393 |
|
| 394 | ret = uname(&uts);
|
| 395 | env->os_release = strdup(ret < 0 ? perf_version_string : uts.release);
|
| 396 | release = env->os_release ?: perf_version_string;
|
| 397 | out:
|
| 398 | mutex_unlock(&env->lock);
|
| 399 | return release;
|
| 400 | }
|
| 401 |
|
| 402 | int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
|
| 403 | {
|
| 404 | int i;
|
| 405 |
|
| 406 |
|
| 407 | env->cmdline_argv = calloc(argc, sizeof(char *));
|
| 408 | if (env->cmdline_argv == NULL)
|
| 409 | goto out_enomem;
|
| 410 |
|
| 411 | |
| 412 | * Must copy argv contents because it gets moved around during option
|
| 413 | * parsing:
|
| 414 |
|
| 415 | for (i = 0; i < argc ; i++) {
|
| 416 | env->cmdline_argv[i] = argv[i];
|
| 417 | if (env->cmdline_argv[i] == NULL)
|
| 418 | goto out_free;
|
| 419 | }
|
| 420 |
|
| 421 | env->nr_cmdline = argc;
|
| 422 |
|
| 423 | return 0;
|
| 424 | out_free:
|
| 425 | zfree(&env->cmdline_argv);
|
| 426 | out_enomem:
|
| 427 | return -ENOMEM;
|
| 428 | }
|
| 429 |
|
| 430 | int perf_env__read_cpu_topology_map(struct perf_env *env)
|
| 431 | {
|
| 432 | int idx, nr_cpus;
|
| 433 |
|
| 434 | if (env->cpu != NULL)
|
| 435 | return 0;
|
| 436 |
|
| 437 | if (env->nr_cpus_avail == 0)
|
| 438 | env->nr_cpus_avail = cpu__max_present_cpu().cpu;
|
| 439 |
|
| 440 | nr_cpus = env->nr_cpus_avail;
|
| 441 | if (nr_cpus == -1)
|
| 442 | return -EINVAL;
|
| 443 |
|
| 444 | env->cpu = calloc(nr_cpus, sizeof(env->cpu[0]));
|
| 445 | if (env->cpu == NULL)
|
| 446 | return -ENOMEM;
|
| 447 |
|
| 448 | for (idx = 0; idx < nr_cpus; ++idx) {
|
| 449 | struct perf_cpu cpu = { .cpu = idx };
|
| 450 | int core_id = cpu__get_core_id(cpu);
|
| 451 | int socket_id = cpu__get_socket_id(cpu);
|
| 452 | int die_id = cpu__get_die_id(cpu);
|
| 453 |
|
| 454 | env->cpu[idx].core_id = core_id >= 0 ? core_id : -1;
|
| 455 | env->cpu[idx].socket_id = socket_id >= 0 ? socket_id : -1;
|
| 456 | env->cpu[idx].die_id = die_id >= 0 ? die_id : -1;
|
| 457 | }
|
| 458 |
|
| 459 | env->nr_cpus_avail = nr_cpus;
|
| 460 | return 0;
|
| 461 | }
|
| 462 |
|
| 463 | int perf_env__read_pmu_mappings(struct perf_env *env)
|
| 464 | {
|
| 465 | struct perf_pmu *pmu = NULL;
|
| 466 | u32 pmu_num = 0;
|
| 467 | struct strbuf sb;
|
| 468 |
|
| 469 | while ((pmu = perf_pmus__scan(pmu)))
|
| 470 | pmu_num++;
|
| 471 |
|
| 472 | if (!pmu_num) {
|
| 473 | pr_debug("pmu mappings not available\n");
|
| 474 | return -ENOENT;
|
| 475 | }
|
| 476 | env->nr_pmu_mappings = pmu_num;
|
| 477 |
|
| 478 | if (strbuf_init(&sb, 128 * pmu_num) < 0)
|
| 479 | return -ENOMEM;
|
| 480 |
|
| 481 | while ((pmu = perf_pmus__scan(pmu))) {
|
| 482 | if (strbuf_addf(&sb, "%u:%s", pmu->type, pmu->name) < 0)
|
| 483 | goto error;
|
| 484 |
|
| 485 | if (strbuf_add(&sb, "", 1) < 0)
|
| 486 | goto error;
|
| 487 | }
|
| 488 |
|
| 489 | env->pmu_mappings = strbuf_detach(&sb, NULL);
|
| 490 |
|
| 491 | return 0;
|
| 492 |
|
| 493 | error:
|
| 494 | strbuf_release(&sb);
|
| 495 | return -1;
|
| 496 | }
|
| 497 |
|
| 498 | int perf_env__read_cpuid(struct perf_env *env)
|
| 499 | {
|
| 500 | char cpuid[128];
|
| 501 | struct perf_cpu cpu = {-1};
|
| 502 | int err = get_cpuid(cpuid, sizeof(cpuid), cpu);
|
| 503 |
|
| 504 | if (err)
|
| 505 | return err;
|
| 506 |
|
| 507 | free(env->cpuid);
|
| 508 | env->cpuid = strdup(cpuid);
|
| 509 | if (env->cpuid == NULL)
|
| 510 | return ENOMEM;
|
| 511 | return 0;
|
| 512 | }
|
| 513 |
|
| 514 | static int perf_env__read_nr_cpus_avail(struct perf_env *env)
|
| 515 | {
|
| 516 | if (env->nr_cpus_avail == 0)
|
| 517 | env->nr_cpus_avail = cpu__max_present_cpu().cpu;
|
| 518 |
|
| 519 | return env->nr_cpus_avail ? 0 : -ENOENT;
|
| 520 | }
|
| 521 |
|
| 522 | static int __perf_env__read_core_pmu_caps(const struct perf_pmu *pmu,
|
| 523 | int *nr_caps, char ***caps,
|
| 524 | unsigned int *max_branches,
|
| 525 | unsigned int *br_cntr_nr,
|
| 526 | unsigned int *br_cntr_width)
|
| 527 | {
|
| 528 | struct perf_pmu_caps *pcaps = NULL;
|
| 529 | char *ptr, **tmp;
|
| 530 | int ret = 0;
|
| 531 |
|
| 532 | *nr_caps = 0;
|
| 533 | *caps = NULL;
|
| 534 |
|
| 535 | if (!pmu->nr_caps)
|
| 536 | return 0;
|
| 537 |
|
| 538 | *caps = calloc(pmu->nr_caps, sizeof(char *));
|
| 539 | if (!*caps)
|
| 540 | return -ENOMEM;
|
| 541 |
|
| 542 | tmp = *caps;
|
| 543 | list_for_each_entry(pcaps, &pmu->caps, list) {
|
| 544 | if (asprintf(&ptr, "%s=%s", pcaps->name, pcaps->value) < 0) {
|
| 545 | ret = -ENOMEM;
|
| 546 | goto error;
|
| 547 | }
|
| 548 |
|
| 549 | *tmp++ = ptr;
|
| 550 |
|
| 551 | if (!strcmp(pcaps->name, "branches"))
|
| 552 | *max_branches = atoi(pcaps->value);
|
| 553 | else if (!strcmp(pcaps->name, "branch_counter_nr"))
|
| 554 | *br_cntr_nr = atoi(pcaps->value);
|
| 555 | else if (!strcmp(pcaps->name, "branch_counter_width"))
|
| 556 | *br_cntr_width = atoi(pcaps->value);
|
| 557 | }
|
| 558 | *nr_caps = pmu->nr_caps;
|
| 559 | return 0;
|
| 560 | error:
|
| 561 | while (tmp-- != *caps)
|
| 562 | zfree(tmp);
|
| 563 | zfree(caps);
|
| 564 | *nr_caps = 0;
|
| 565 | return ret;
|
| 566 | }
|
| 567 |
|
| 568 | int perf_env__read_core_pmu_caps(struct perf_env *env)
|
| 569 | {
|
| 570 | struct pmu_caps *pmu_caps;
|
| 571 | struct perf_pmu *pmu = NULL;
|
| 572 | int nr_pmu, i = 0, j;
|
| 573 | int ret;
|
| 574 |
|
| 575 | nr_pmu = perf_pmus__num_core_pmus();
|
| 576 |
|
| 577 | if (!nr_pmu)
|
| 578 | return -ENODEV;
|
| 579 |
|
| 580 | if (nr_pmu == 1) {
|
| 581 | pmu = perf_pmus__find_core_pmu();
|
| 582 | if (!pmu)
|
| 583 | return -ENODEV;
|
| 584 | ret = perf_pmu__caps_parse(pmu);
|
| 585 | if (ret < 0)
|
| 586 | return ret;
|
| 587 | return __perf_env__read_core_pmu_caps(pmu, &env->nr_cpu_pmu_caps,
|
| 588 | &env->cpu_pmu_caps,
|
| 589 | &env->max_branches,
|
| 590 | &env->br_cntr_nr,
|
| 591 | &env->br_cntr_width);
|
| 592 | }
|
| 593 |
|
| 594 | pmu_caps = calloc(nr_pmu, sizeof(*pmu_caps));
|
| 595 | if (!pmu_caps)
|
| 596 | return -ENOMEM;
|
| 597 |
|
| 598 | while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
|
| 599 | if (perf_pmu__caps_parse(pmu) <= 0)
|
| 600 | continue;
|
| 601 | ret = __perf_env__read_core_pmu_caps(pmu, &pmu_caps[i].nr_caps,
|
| 602 | &pmu_caps[i].caps,
|
| 603 | &pmu_caps[i].max_branches,
|
| 604 | &pmu_caps[i].br_cntr_nr,
|
| 605 | &pmu_caps[i].br_cntr_width);
|
| 606 | if (ret)
|
| 607 | goto error;
|
| 608 |
|
| 609 | pmu_caps[i].pmu_name = strdup(pmu->name);
|
| 610 | if (!pmu_caps[i].pmu_name) {
|
| 611 | ret = -ENOMEM;
|
| 612 | goto error;
|
| 613 | }
|
| 614 | i++;
|
| 615 | }
|
| 616 |
|
| 617 | env->nr_pmus_with_caps = nr_pmu;
|
| 618 | env->pmu_caps = pmu_caps;
|
| 619 |
|
| 620 | return 0;
|
| 621 | error:
|
| 622 | for (i = 0; i < nr_pmu; i++) {
|
| 623 | for (j = 0; j < pmu_caps[i].nr_caps; j++)
|
| 624 | zfree(&pmu_caps[i].caps[j]);
|
| 625 | zfree(&pmu_caps[i].caps);
|
| 626 | zfree(&pmu_caps[i].pmu_name);
|
| 627 | }
|
| 628 | zfree(&pmu_caps);
|
| 629 | return ret;
|
| 630 | }
|
| 631 |
|
| 632 | int perf_env__nr_cpus_avail(struct perf_env *env)
|
| 633 | {
|
| 634 | return env && !perf_env__read_nr_cpus_avail(env) ? env->nr_cpus_avail : 0;
|
| 635 | }
|
| 636 |
|
| 637 | void cpu_cache_level__free(struct cpu_cache_level *cache)
|
| 638 | {
|
| 639 | zfree(&cache->type);
|
| 640 | zfree(&cache->map);
|
| 641 | zfree(&cache->size);
|
| 642 | }
|
| 643 |
|
| 644 | struct arch_to_e_machine {
|
| 645 | const char *prefix;
|
| 646 | uint16_t e_machine;
|
| 647 | };
|
| 648 |
|
| 649 | |
| 650 | * A mapping from an arch prefix string to an ELF machine that can be used in a
|
| 651 | * bsearch. Some arch prefixes are shared an need additional processing as
|
| 652 | * marked next to the architecture. The prefixes handle both perf's architecture
|
| 653 | * naming and those from uname.
|
| 654 |
|
| 655 | static const struct arch_to_e_machine prefix_to_e_machine[] = {
|
| 656 | {"aarch64", EM_AARCH64},
|
| 657 | {"alpha", EM_ALPHA},
|
| 658 | {"arc", EM_ARC},
|
| 659 | {"arm", EM_ARM},
|
| 660 | {"avr", EM_AVR},
|
| 661 | {"bfin", EM_BLACKFIN},
|
| 662 | {"blackfin", EM_BLACKFIN},
|
| 663 | {"cris", EM_CRIS},
|
| 664 | {"csky", EM_CSKY},
|
| 665 | {"hppa", EM_PARISC},
|
| 666 | {"i386", EM_386},
|
| 667 | {"i486", EM_386},
|
| 668 | {"i586", EM_386},
|
| 669 | {"i686", EM_386},
|
| 670 | {"loongarch", EM_LOONGARCH},
|
| 671 | {"m32r", EM_M32R},
|
| 672 | {"m68k", EM_68K},
|
| 673 | {"microblaze", EM_MICROBLAZE},
|
| 674 | {"mips", EM_MIPS},
|
| 675 | {"msp430", EM_MSP430},
|
| 676 | {"parisc", EM_PARISC},
|
| 677 | {"powerpc", EM_PPC},
|
| 678 | {"ppc", EM_PPC},
|
| 679 | {"riscv", EM_RISCV},
|
| 680 | {"s390", EM_S390},
|
| 681 | {"sa110", EM_ARM},
|
| 682 | {"sh", EM_SH},
|
| 683 | {"sparc", EM_SPARC},
|
| 684 | {"sun4u", EM_SPARC},
|
| 685 | {"x86", EM_X86_64},
|
| 686 | {"xtensa", EM_XTENSA},
|
| 687 | };
|
| 688 |
|
| 689 | static int compare_prefix(const void *key, const void *element)
|
| 690 | {
|
| 691 | const char *search_key = key;
|
| 692 | const struct arch_to_e_machine *map_element = element;
|
| 693 | size_t prefix_len = strlen(map_element->prefix);
|
| 694 |
|
| 695 | return strncmp(search_key, map_element->prefix, prefix_len);
|
| 696 | }
|
| 697 |
|
| 698 | static uint16_t perf_arch_to_e_machine(const char *perf_arch, int is_64_bit)
|
| 699 | {
|
| 700 |
|
| 701 | const struct arch_to_e_machine *result;
|
| 702 |
|
| 703 | if (!perf_arch)
|
| 704 | return EM_HOST;
|
| 705 |
|
| 706 | result = bsearch(perf_arch,
|
| 707 | prefix_to_e_machine, ARRAY_SIZE(prefix_to_e_machine),
|
| 708 | sizeof(prefix_to_e_machine[0]),
|
| 709 | compare_prefix);
|
| 710 |
|
| 711 | if (!result) {
|
| 712 | pr_debug("Unknown perf arch for ELF machine mapping: %s\n", perf_arch);
|
| 713 | return EM_NONE;
|
| 714 | }
|
| 715 |
|
| 716 | |
| 717 | * Handle conflicting prefixes. If the is_64_bit is unknown (-1) then
|
| 718 | * assume 64-bit. We can't use perf_env__kernel_is_64_bit as that
|
| 719 | * depends on the arch string.
|
| 720 |
|
| 721 | switch (result->e_machine) {
|
| 722 | case EM_ARM:
|
| 723 | return !strcmp(perf_arch, "arm64") || !strcmp(perf_arch, "aarch64")
|
| 724 | ? EM_AARCH64 : EM_ARM;
|
| 725 | case EM_AVR:
|
| 726 | return !strcmp(perf_arch, "avr32") ? EM_AVR32 : EM_AVR;
|
| 727 | case EM_PPC:
|
| 728 | if (is_64_bit == 1)
|
| 729 | return EM_PPC64;
|
| 730 | if (is_64_bit == 0)
|
| 731 | return EM_PPC;
|
| 732 | return strstarts(perf_arch, "ppc64") ? EM_PPC64 : EM_PPC;
|
| 733 | case EM_SPARC:
|
| 734 | if (is_64_bit == 1)
|
| 735 | return EM_SPARCV9;
|
| 736 | if (is_64_bit == 0)
|
| 737 | return EM_SPARC;
|
| 738 | return !strcmp(perf_arch, "sparc64") || !strcmp(perf_arch, "sun4u")
|
| 739 | ? EM_SPARCV9 : EM_SPARC;
|
| 740 | case EM_X86_64:
|
| 741 | if (is_64_bit == 1)
|
| 742 | return EM_X86_64;
|
| 743 | if (is_64_bit == 0)
|
| 744 | return EM_386;
|
| 745 | return !strcmp(perf_arch, "x86_64") || !strcmp(perf_arch, "x86")
|
| 746 | ? EM_X86_64 : EM_386;
|
| 747 | default:
|
| 748 | return result->e_machine;
|
| 749 | }
|
| 750 | }
|
| 751 |
|
| 752 | static const char *e_machine_to_perf_arch(uint16_t e_machine)
|
| 753 | {
|
| 754 | |
| 755 | * Table for if either the perf arch string differs from uname or there
|
| 756 | * are >1 ELF machine with the prefix.
|
| 757 |
|
| 758 | static const struct arch_to_e_machine extras[] = {
|
| 759 | {"arm64", EM_AARCH64},
|
| 760 | {"avr32", EM_AVR32},
|
| 761 | {"powerpc", EM_PPC},
|
| 762 | {"powerpc", EM_PPC64},
|
| 763 | {"sparc", EM_SPARCV9},
|
| 764 | {"x86", EM_386},
|
| 765 | {"x86", EM_X86_64},
|
| 766 | {"none", EM_NONE},
|
| 767 | };
|
| 768 |
|
| 769 | for (size_t i = 0; i < ARRAY_SIZE(extras); i++) {
|
| 770 | if (extras[i].e_machine == e_machine)
|
| 771 | return extras[i].prefix;
|
| 772 | }
|
| 773 |
|
| 774 | for (size_t i = 0; i < ARRAY_SIZE(prefix_to_e_machine); i++) {
|
| 775 | if (prefix_to_e_machine[i].e_machine == e_machine)
|
| 776 | return prefix_to_e_machine[i].prefix;
|
| 777 |
|
| 778 | }
|
| 779 | return "unknown";
|
| 780 | }
|
| 781 |
|
| 782 | uint16_t perf_env__e_machine_nocache(struct perf_env *env, uint32_t *e_flags)
|
| 783 | {
|
| 784 | uint16_t e_machine = EM_NONE;
|
| 785 | const char *arch = NULL;
|
| 786 | int is_64_bit = -1;
|
| 787 |
|
| 788 | if (e_flags)
|
| 789 | *e_flags = 0;
|
| 790 |
|
| 791 | if (env) {
|
| 792 | arch = env->arch;
|
| 793 | is_64_bit = env->kernel_is_64_bit;
|
| 794 | }
|
| 795 |
|
| 796 | if (!arch) {
|
| 797 | static struct utsname uts = { .machine[0] = '\0', };
|
| 798 |
|
| 799 | if (uts.machine[0] == '\0')
|
| 800 | uname(&uts);
|
| 801 | if (uts.machine[0] != '\0')
|
| 802 | arch = uts.machine;
|
| 803 | }
|
| 804 |
|
| 805 | e_machine = perf_arch_to_e_machine(arch, is_64_bit);
|
| 806 |
|
| 807 | if (e_flags)
|
| 808 | *e_flags = (e_machine == EM_HOST) ? EF_HOST : 0;
|
| 809 |
|
| 810 | return e_machine;
|
| 811 | }
|
| 812 |
|
| 813 | uint16_t perf_env__e_machine(struct perf_env *env, uint32_t *e_flags)
|
| 814 | {
|
| 815 | uint16_t e_machine;
|
| 816 | uint32_t local_e_flags = 0;
|
| 817 |
|
| 818 | if (env && env->e_machine != EM_NONE) {
|
| 819 | if (e_flags)
|
| 820 | *e_flags = env->e_flags;
|
| 821 |
|
| 822 | return env->e_machine;
|
| 823 | }
|
| 824 | e_machine = perf_env__e_machine_nocache(env, &local_e_flags);
|
| 825 | |
| 826 | * Only cache the e_machine in perf_env if env->arch is not NULL.
|
| 827 | * If env->arch is NULL, the e_machine is just a fallback to EM_HOST.
|
| 828 | * Caching it permanently would prevent dynamic, more accurate
|
| 829 | * thread-based session e_machine scanning later in
|
| 830 | * perf_session__e_machine().
|
| 831 |
|
| 832 | if (env && env->arch) {
|
| 833 | env->e_machine = e_machine;
|
| 834 | env->e_flags = local_e_flags;
|
| 835 | }
|
| 836 | if (e_flags)
|
| 837 | *e_flags = local_e_flags;
|
| 838 |
|
| 839 | return e_machine;
|
| 840 | }
|
| 841 |
|
| 842 | const char *perf_env__arch(struct perf_env *env)
|
| 843 | {
|
| 844 | uint16_t e_machine;
|
| 845 | const char *arch;
|
| 846 |
|
| 847 | if (!env) {
|
| 848 | static struct utsname uts = { .machine[0] = '\0', };
|
| 849 | uint16_t host_e_machine;
|
| 850 |
|
| 851 | if (uts.machine[0] == '\0')
|
| 852 | uname(&uts);
|
| 853 | if (uts.machine[0] != '\0') {
|
| 854 | host_e_machine = perf_arch_to_e_machine(uts.machine, -1);
|
| 855 | return e_machine_to_perf_arch(host_e_machine);
|
| 856 | }
|
| 857 | return e_machine_to_perf_arch(EM_HOST);
|
| 858 | }
|
| 859 |
|
| 860 | |
| 861 | * Lazily compute/allocate arch. The e_machine may have been
|
| 862 | * read from a data file and so may not be EM_HOST.
|
| 863 |
|
| 864 | e_machine = perf_env__e_machine(env, NULL);
|
| 865 | arch = e_machine_to_perf_arch(e_machine);
|
| 866 |
|
| 867 | if (e_machine == EM_RISCV && perf_env__kernel_is_64_bit(env) == 1)
|
| 868 | arch = "riscv64";
|
| 869 | else if (e_machine == EM_MIPS && perf_env__kernel_is_64_bit(env) == 1)
|
| 870 | arch = "mips64";
|
| 871 | else if (e_machine == EM_PARISC && perf_env__kernel_is_64_bit(env) == 1)
|
| 872 | arch = "parisc64";
|
| 873 |
|
| 874 | return arch;
|
| 875 | }
|
| 876 |
|
| 877 | const char *arch_syscalls__strerrno(uint16_t e_machine, int err);
|
| 878 |
|
| 879 | const char *perf_env__arch_strerrno(uint16_t e_machine, int err)
|
| 880 | {
|
| 881 | return arch_syscalls__strerrno(e_machine, err);
|
| 882 | }
|
| 883 |
|
| 884 | const char *perf_env__cpuid(struct perf_env *env)
|
| 885 | {
|
| 886 | int status;
|
| 887 |
|
| 888 | if (!env->cpuid) {
|
| 889 | status = perf_env__read_cpuid(env);
|
| 890 | if (status)
|
| 891 | return NULL;
|
| 892 | }
|
| 893 |
|
| 894 | return env->cpuid;
|
| 895 | }
|
| 896 |
|
| 897 | int perf_env__nr_pmu_mappings(struct perf_env *env)
|
| 898 | {
|
| 899 | int status;
|
| 900 |
|
| 901 | if (!env->nr_pmu_mappings) {
|
| 902 | status = perf_env__read_pmu_mappings(env);
|
| 903 | if (status)
|
| 904 | return 0;
|
| 905 | }
|
| 906 |
|
| 907 | return env->nr_pmu_mappings;
|
| 908 | }
|
| 909 |
|
| 910 | const char *perf_env__pmu_mappings(struct perf_env *env)
|
| 911 | {
|
| 912 | int status;
|
| 913 |
|
| 914 | if (!env->pmu_mappings) {
|
| 915 | status = perf_env__read_pmu_mappings(env);
|
| 916 | if (status)
|
| 917 | return NULL;
|
| 918 | }
|
| 919 |
|
| 920 | return env->pmu_mappings;
|
| 921 | }
|
| 922 |
|
| 923 | int perf_env__numa_node(struct perf_env *env, struct perf_cpu cpu)
|
| 924 | {
|
| 925 | if (!env->nr_numa_map) {
|
| 926 | struct numa_node *nn;
|
| 927 | int i, nr = 0;
|
| 928 |
|
| 929 | for (i = 0; i < env->nr_numa_nodes; i++) {
|
| 930 | nn = &env->numa_nodes[i];
|
| 931 | nr = max(nr, (int)perf_cpu_map__max(nn->map).cpu);
|
| 932 | }
|
| 933 |
|
| 934 | nr++;
|
| 935 |
|
| 936 | |
| 937 | * We initialize the numa_map array to prepare
|
| 938 | * it for missing cpus, which return node -1
|
| 939 |
|
| 940 | env->numa_map = malloc(nr * sizeof(int));
|
| 941 | if (!env->numa_map)
|
| 942 | return -1;
|
| 943 |
|
| 944 | for (i = 0; i < nr; i++)
|
| 945 | env->numa_map[i] = -1;
|
| 946 |
|
| 947 | env->nr_numa_map = nr;
|
| 948 |
|
| 949 | for (i = 0; i < env->nr_numa_nodes; i++) {
|
| 950 | struct perf_cpu tmp;
|
| 951 | unsigned int j;
|
| 952 |
|
| 953 | nn = &env->numa_nodes[i];
|
| 954 | perf_cpu_map__for_each_cpu(tmp, j, nn->map)
|
| 955 | env->numa_map[tmp.cpu] = i;
|
| 956 | }
|
| 957 | }
|
| 958 |
|
| 959 | return cpu.cpu >= 0 && cpu.cpu < env->nr_numa_map ? env->numa_map[cpu.cpu] : -1;
|
| 960 | }
|
| 961 |
|
| 962 | bool perf_env__has_pmu_mapping(struct perf_env *env, const char *pmu_name)
|
| 963 | {
|
| 964 | char *pmu_mapping = env->pmu_mappings, *colon;
|
| 965 |
|
| 966 | for (int i = 0; i < env->nr_pmu_mappings; ++i) {
|
| 967 | if (strtoul(pmu_mapping, &colon, 0) == ULONG_MAX || *colon != ':')
|
| 968 | goto out_error;
|
| 969 |
|
| 970 | pmu_mapping = colon + 1;
|
| 971 | if (strcmp(pmu_mapping, pmu_name) == 0)
|
| 972 | return true;
|
| 973 |
|
| 974 | pmu_mapping += strlen(pmu_mapping) + 1;
|
| 975 | }
|
| 976 | out_error:
|
| 977 | return false;
|
| 978 | }
|
| 979 |
|
| 980 | char *perf_env__find_pmu_cap(struct perf_env *env, const char *pmu_name,
|
| 981 | const char *cap)
|
| 982 | {
|
| 983 | char *cap_eq;
|
| 984 | int cap_size;
|
| 985 | char **ptr;
|
| 986 | int i, j;
|
| 987 |
|
| 988 | if (!pmu_name || !cap)
|
| 989 | return NULL;
|
| 990 |
|
| 991 | cap_size = strlen(cap);
|
| 992 | cap_eq = zalloc(cap_size + 2);
|
| 993 | if (!cap_eq)
|
| 994 | return NULL;
|
| 995 |
|
| 996 | memcpy(cap_eq, cap, cap_size);
|
| 997 | cap_eq[cap_size] = '=';
|
| 998 |
|
| 999 | if (!strcmp(pmu_name, "cpu")) {
|
| 1000 | for (i = 0; i < env->nr_cpu_pmu_caps; i++) {
|
| 1001 | if (!strncmp(env->cpu_pmu_caps[i], cap_eq, cap_size + 1)) {
|
| 1002 | free(cap_eq);
|
| 1003 | return &env->cpu_pmu_caps[i][cap_size + 1];
|
| 1004 | }
|
| 1005 | }
|
| 1006 | goto out;
|
| 1007 | }
|
| 1008 |
|
| 1009 | for (i = 0; i < env->nr_pmus_with_caps; i++) {
|
| 1010 | if (strcmp(env->pmu_caps[i].pmu_name, pmu_name))
|
| 1011 | continue;
|
| 1012 |
|
| 1013 | ptr = env->pmu_caps[i].caps;
|
| 1014 |
|
| 1015 | for (j = 0; j < env->pmu_caps[i].nr_caps; j++) {
|
| 1016 | if (!strncmp(ptr[j], cap_eq, cap_size + 1)) {
|
| 1017 | free(cap_eq);
|
| 1018 | return &ptr[j][cap_size + 1];
|
| 1019 | }
|
| 1020 | }
|
| 1021 | }
|
| 1022 |
|
| 1023 | out:
|
| 1024 | free(cap_eq);
|
| 1025 | return NULL;
|
| 1026 | }
|
| 1027 |
|
| 1028 | void perf_env__find_br_cntr_info(struct perf_env *env,
|
| 1029 | unsigned int *nr,
|
| 1030 | unsigned int *width)
|
| 1031 | {
|
| 1032 | if (nr) {
|
| 1033 | *nr = env->cpu_pmu_caps ? env->br_cntr_nr :
|
| 1034 | env->pmu_caps->br_cntr_nr;
|
| 1035 | }
|
| 1036 |
|
| 1037 | if (width) {
|
| 1038 | *width = env->cpu_pmu_caps ? env->br_cntr_width :
|
| 1039 | env->pmu_caps->br_cntr_width;
|
| 1040 | }
|
| 1041 | }
|
| 1042 |
|
| 1043 | bool perf_env__is_x86_amd_cpu(struct perf_env *env)
|
| 1044 | {
|
| 1045 | static int is_amd;
|
| 1046 |
|
| 1047 | if (is_amd == 0)
|
| 1048 | is_amd = env->cpuid && strstarts(env->cpuid, "AuthenticAMD") ? 1 : -1;
|
| 1049 |
|
| 1050 | return is_amd >= 1 ? true : false;
|
| 1051 | }
|
| 1052 |
|
| 1053 | bool x86__is_amd_cpu(void)
|
| 1054 | {
|
| 1055 | struct perf_env env = { .total_mem = 0, };
|
| 1056 | bool is_amd;
|
| 1057 |
|
| 1058 | perf_env__init(&env);
|
| 1059 | perf_env__cpuid(&env);
|
| 1060 | is_amd = perf_env__is_x86_amd_cpu(&env);
|
| 1061 | perf_env__exit(&env);
|
| 1062 |
|
| 1063 | return is_amd;
|
| 1064 | }
|
| 1065 |
|
| 1066 | bool perf_env__is_x86_intel_cpu(struct perf_env *env)
|
| 1067 | {
|
| 1068 | static int is_intel;
|
| 1069 |
|
| 1070 | if (is_intel == 0)
|
| 1071 | is_intel = env->cpuid && strstarts(env->cpuid, "GenuineIntel") ? 1 : -1;
|
| 1072 |
|
| 1073 | return is_intel >= 1 ? true : false;
|
| 1074 | }
|
| 1075 |
|
| 1076 | bool x86__is_intel_cpu(void)
|
| 1077 | {
|
| 1078 | struct perf_env env = { .total_mem = 0, };
|
| 1079 | bool is_intel;
|
| 1080 |
|
| 1081 | perf_env__init(&env);
|
| 1082 | perf_env__cpuid(&env);
|
| 1083 | is_intel = perf_env__is_x86_intel_cpu(&env);
|
| 1084 | perf_env__exit(&env);
|
| 1085 |
|
| 1086 | return is_intel;
|
| 1087 | }
|