diff options
Diffstat (limited to 'tools/perf/util/header.c')
-rw-r--r-- | tools/perf/util/header.c | 140 |
1 files changed, 87 insertions, 53 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 276870221ce0..52fbf526fe74 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -24,6 +24,7 @@ #include <bpf/libbpf.h> #endif #include <perf/cpumap.h> +#include <tools/libc_compat.h> // reallocarray #include "dso.h" #include "evlist.h" @@ -37,6 +38,7 @@ #include "debug.h" #include "cpumap.h" #include "pmu.h" +#include "pmus.h" #include "vdso.h" #include "strbuf.h" #include "build-id.h" @@ -51,7 +53,6 @@ #include "bpf-event.h" #include "bpf-utils.h" #include "clockid.h" -#include "pmu-hybrid.h" #include <linux/ctype.h> #include <internal/lib.h> @@ -745,7 +746,7 @@ static int write_pmu_mappings(struct feat_fd *ff, * Do a first pass to count number of pmu to avoid lseek so this * works in pipe mode as well. */ - while ((pmu = perf_pmu__scan(pmu))) { + while ((pmu = perf_pmus__scan(pmu))) { if (!pmu->name) continue; pmu_num++; @@ -755,7 +756,7 @@ static int write_pmu_mappings(struct feat_fd *ff, if (ret < 0) return ret; - while ((pmu = perf_pmu__scan(pmu))) { + while ((pmu = perf_pmus__scan(pmu))) { if (!pmu->name) continue; @@ -1213,38 +1214,54 @@ static void cpu_cache_level__fprintf(FILE *out, struct cpu_cache_level *c) fprintf(out, "L%d %-15s %8s [%s]\n", c->level, c->type, c->size, c->map); } -#define MAX_CACHE_LVL 4 - -static int build_caches(struct cpu_cache_level caches[], u32 *cntp) +/* + * Build caches levels for a particular CPU from the data in + * /sys/devices/system/cpu/cpu<cpu>/cache/ + * The cache level data is stored in caches[] from index at + * *cntp. + */ +int build_caches_for_cpu(u32 cpu, struct cpu_cache_level caches[], u32 *cntp) { - u32 i, cnt = 0; - u32 nr, cpu; u16 level; - nr = cpu__max_cpu().cpu; + for (level = 0; level < MAX_CACHE_LVL; level++) { + struct cpu_cache_level c; + int err; + u32 i; - for (cpu = 0; cpu < nr; cpu++) { - for (level = 0; level < MAX_CACHE_LVL; level++) { - struct cpu_cache_level c; - int err; + err = cpu_cache_level__read(&c, cpu, level); + if (err < 0) + return err; - err = cpu_cache_level__read(&c, cpu, level); - if (err < 0) - return err; + if (err == 1) + break; - if (err == 1) + for (i = 0; i < *cntp; i++) { + if (cpu_cache_level__cmp(&c, &caches[i])) break; + } - for (i = 0; i < cnt; i++) { - if (cpu_cache_level__cmp(&c, &caches[i])) - break; - } + if (i == *cntp) { + caches[*cntp] = c; + *cntp = *cntp + 1; + } else + cpu_cache_level__free(&c); + } - if (i == cnt) - caches[cnt++] = c; - else - cpu_cache_level__free(&c); - } + return 0; +} + +static int build_caches(struct cpu_cache_level caches[], u32 *cntp) +{ + u32 nr, cpu, cnt = 0; + + nr = cpu__max_cpu().cpu; + + for (cpu = 0; cpu < nr; cpu++) { + int ret = build_caches_for_cpu(cpu, caches, &cnt); + + if (ret) + return ret; } *cntp = cnt; return 0; @@ -1372,6 +1389,14 @@ static int memory_node__read(struct memory_node *n, unsigned long idx) return 0; } +static void memory_node__delete_nodes(struct memory_node *nodesp, u64 cnt) +{ + for (u64 i = 0; i < cnt; i++) + bitmap_free(nodesp[i].set); + + free(nodesp); +} + static int memory_node__sort(const void *a, const void *b) { const struct memory_node *na = a; @@ -1380,13 +1405,14 @@ static int memory_node__sort(const void *a, const void *b) return na->node - nb->node; } -static int build_mem_topology(struct memory_node *nodes, u64 size, u64 *cntp) +static int build_mem_topology(struct memory_node **nodesp, u64 *cntp) { char path[PATH_MAX]; struct dirent *ent; DIR *dir; - u64 cnt = 0; int ret = 0; + size_t cnt = 0, size = 0; + struct memory_node *nodes = NULL; scnprintf(path, PATH_MAX, "%s/devices/system/node/", sysfs__mountpoint()); @@ -1410,26 +1436,32 @@ static int build_mem_topology(struct memory_node *nodes, u64 size, u64 *cntp) if (r != 1) continue; - if (WARN_ONCE(cnt >= size, - "failed to write MEM_TOPOLOGY, way too many nodes\n")) { - closedir(dir); - return -1; - } + if (cnt >= size) { + struct memory_node *new_nodes = + reallocarray(nodes, cnt + 4, sizeof(*nodes)); + if (!new_nodes) { + pr_err("Failed to write MEM_TOPOLOGY, size %zd nodes\n", size); + ret = -ENOMEM; + goto out; + } + nodes = new_nodes; + size += 4; + } ret = memory_node__read(&nodes[cnt++], idx); } - - *cntp = cnt; +out: closedir(dir); - - if (!ret) + if (!ret) { + *cntp = cnt; + *nodesp = nodes; qsort(nodes, cnt, sizeof(nodes[0]), memory_node__sort); + } else + memory_node__delete_nodes(nodes, cnt); return ret; } -#define MAX_MEMORY_NODES 2000 - /* * The MEM_TOPOLOGY holds physical memory map for every * node in system. The format of data is as follows: @@ -1448,8 +1480,8 @@ static int build_mem_topology(struct memory_node *nodes, u64 size, u64 *cntp) static int write_mem_topology(struct feat_fd *ff __maybe_unused, struct evlist *evlist __maybe_unused) { - static struct memory_node nodes[MAX_MEMORY_NODES]; - u64 bsize, version = 1, i, nr; + struct memory_node *nodes = NULL; + u64 bsize, version = 1, i, nr = 0; int ret; ret = sysfs__read_xll("devices/system/memory/block_size_bytes", @@ -1457,7 +1489,7 @@ static int write_mem_topology(struct feat_fd *ff __maybe_unused, if (ret) return ret; - ret = build_mem_topology(&nodes[0], MAX_MEMORY_NODES, &nr); + ret = build_mem_topology(&nodes, &nr); if (ret) return ret; @@ -1492,6 +1524,7 @@ static int write_mem_topology(struct feat_fd *ff __maybe_unused, } out: + memory_node__delete_nodes(nodes, nr); return ret; } @@ -1551,7 +1584,7 @@ static int __write_pmu_caps(struct feat_fd *ff, struct perf_pmu *pmu, static int write_cpu_pmu_caps(struct feat_fd *ff, struct evlist *evlist __maybe_unused) { - struct perf_pmu *cpu_pmu = perf_pmu__find("cpu"); + struct perf_pmu *cpu_pmu = perf_pmus__find("cpu"); int ret; if (!cpu_pmu) @@ -1571,7 +1604,7 @@ static int write_pmu_caps(struct feat_fd *ff, int nr_pmu = 0; int ret; - while ((pmu = perf_pmu__scan(pmu))) { + while ((pmu = perf_pmus__scan(pmu))) { if (!pmu->name || !strcmp(pmu->name, "cpu") || perf_pmu__caps_parse(pmu) <= 0) continue; @@ -1589,17 +1622,18 @@ static int write_pmu_caps(struct feat_fd *ff, * Write hybrid pmu caps first to maintain compatibility with * older perf tool. */ - pmu = NULL; - perf_pmu__for_each_hybrid_pmu(pmu) { - ret = __write_pmu_caps(ff, pmu, true); - if (ret < 0) - return ret; + if (perf_pmus__num_core_pmus() > 1) { + pmu = NULL; + while ((pmu = perf_pmus__scan_core(pmu))) { + ret = __write_pmu_caps(ff, pmu, true); + if (ret < 0) + return ret; + } } pmu = NULL; - while ((pmu = perf_pmu__scan(pmu))) { - if (!pmu->name || !strcmp(pmu->name, "cpu") || - !pmu->nr_caps || perf_pmu__is_hybrid(pmu->name)) + while ((pmu = perf_pmus__scan(pmu))) { + if (pmu->is_core || !pmu->nr_caps) continue; ret = __write_pmu_caps(ff, pmu, true); @@ -2810,7 +2844,7 @@ static int process_group_desc(struct feat_fd *ff, void *data __maybe_unused) i = nr = 0; evlist__for_each_entry(session->evlist, evsel) { - if (evsel->core.idx == (int) desc[i].leader_idx) { + if (i < nr_groups && evsel->core.idx == (int) desc[i].leader_idx) { evsel__set_leader(evsel, evsel); /* {anon_group} is a dummy name */ if (strcmp(desc[i].name, "{anon_group}")) { |