Skip to content

Commit 6f91ea2

Browse files
Kan Liangacmel
authored andcommitted
perf header: Support CPU PMU capabilities
To stitch LBR call stack, the max LBR information is required. So the CPU PMU capabilities information has to be stored in perf header. Add a new feature HEADER_CPU_PMU_CAPS for CPU PMU capabilities. Retrieve all CPU PMU capabilities, not just max LBR information. Add variable max_branches to facilitate future usage. Committer testing: # ls -la /sys/devices/cpu/caps/ total 0 drwxr-xr-x. 2 root root 0 Apr 17 10:53 . drwxr-xr-x. 6 root root 0 Apr 17 07:02 .. -r--r--r--. 1 root root 4096 Apr 17 10:53 max_precise # # cat /sys/devices/cpu/caps/max_precise 0 # perf record sleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.033 MB perf.data (7 samples) ] # # perf report --header-only | egrep 'cpu(desc|.*capabilities)' # cpudesc : AMD Ryzen 5 3600X 6-Core Processor # cpu pmu capabilities: max_precise=0 # And then on an Intel machine: $ ls -la /sys/devices/cpu/caps/ total 0 drwxr-xr-x. 2 root root 0 Apr 17 10:51 . drwxr-xr-x. 6 root root 0 Apr 17 10:04 .. -r--r--r--. 1 root root 4096 Apr 17 11:37 branches -r--r--r--. 1 root root 4096 Apr 17 10:51 max_precise -r--r--r--. 1 root root 4096 Apr 17 11:37 pmu_name $ cat /sys/devices/cpu/caps/max_precise 3 $ cat /sys/devices/cpu/caps/branches 32 $ cat /sys/devices/cpu/caps/pmu_name skylake $ perf record sleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.001 MB perf.data (8 samples) ] $ perf report --header-only | egrep 'cpu(desc|.*capabilities)' # cpudesc : Intel(R) Core(TM) i5-7500 CPU @ 3.40GHz # cpu pmu capabilities: branches=32, max_precise=3, pmu_name=skylake $ Signed-off-by: Kan Liang <[email protected]> Reviewed-by: Andi Kleen <[email protected]> Acked-by: Jiri Olsa <[email protected]> Tested-by: Arnaldo Carvalho de Melo <[email protected]> Cc: Adrian Hunter <[email protected]> Cc: Alexey Budankov <[email protected]> Cc: Mathieu Poirier <[email protected]> Cc: Michael Ellerman <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Pavel Gerasimov <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Ravi Bangoria <[email protected]> Cc: Stephane Eranian <[email protected]> Cc: Vitaly Slobodskoy <[email protected]> Link: http://lore.kernel.org/lkml/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 3a6c51e commit 6f91ea2

File tree

4 files changed

+128
-0
lines changed

4 files changed

+128
-0
lines changed

tools/perf/Documentation/perf.data-file-format.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,22 @@ struct {
373373
Indicates that trace contains records of PERF_RECORD_COMPRESSED type
374374
that have perf_events records in compressed form.
375375

376+
HEADER_CPU_PMU_CAPS = 28,
377+
378+
A list of cpu PMU capabilities. The format of data is as below.
379+
380+
struct {
381+
u32 nr_cpu_pmu_caps;
382+
{
383+
char name[];
384+
char value[];
385+
} [nr_cpu_pmu_caps]
386+
};
387+
388+
389+
Example:
390+
cpu pmu capabilities: branches=32, max_precise=3, pmu_name=icelake
391+
376392
other bits are reserved and should ignored for now
377393
HEADER_FEAT_BITS = 256,
378394

tools/perf/util/env.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ struct perf_env {
4848
char *cpuid;
4949
unsigned long long total_mem;
5050
unsigned int msr_pmu_type;
51+
unsigned int max_branches;
5152

5253
int nr_cmdline;
5354
int nr_sibling_cores;
@@ -57,12 +58,14 @@ struct perf_env {
5758
int nr_memory_nodes;
5859
int nr_pmu_mappings;
5960
int nr_groups;
61+
int nr_cpu_pmu_caps;
6062
char *cmdline;
6163
const char **cmdline_argv;
6264
char *sibling_cores;
6365
char *sibling_dies;
6466
char *sibling_threads;
6567
char *pmu_mappings;
68+
char *cpu_pmu_caps;
6669
struct cpu_topology_map *cpu;
6770
struct cpu_cache_level *caches;
6871
int caches_cnt;

tools/perf/util/header.c

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,6 +1395,38 @@ static int write_compressed(struct feat_fd *ff __maybe_unused,
13951395
return do_write(ff, &(ff->ph->env.comp_mmap_len), sizeof(ff->ph->env.comp_mmap_len));
13961396
}
13971397

1398+
static int write_cpu_pmu_caps(struct feat_fd *ff,
1399+
struct evlist *evlist __maybe_unused)
1400+
{
1401+
struct perf_pmu *cpu_pmu = perf_pmu__find("cpu");
1402+
struct perf_pmu_caps *caps = NULL;
1403+
int nr_caps;
1404+
int ret;
1405+
1406+
if (!cpu_pmu)
1407+
return -ENOENT;
1408+
1409+
nr_caps = perf_pmu__caps_parse(cpu_pmu);
1410+
if (nr_caps < 0)
1411+
return nr_caps;
1412+
1413+
ret = do_write(ff, &nr_caps, sizeof(nr_caps));
1414+
if (ret < 0)
1415+
return ret;
1416+
1417+
list_for_each_entry(caps, &cpu_pmu->caps, list) {
1418+
ret = do_write_string(ff, caps->name);
1419+
if (ret < 0)
1420+
return ret;
1421+
1422+
ret = do_write_string(ff, caps->value);
1423+
if (ret < 0)
1424+
return ret;
1425+
}
1426+
1427+
return ret;
1428+
}
1429+
13981430
static void print_hostname(struct feat_fd *ff, FILE *fp)
13991431
{
14001432
fprintf(fp, "# hostname : %s\n", ff->ph->env.hostname);
@@ -1809,6 +1841,27 @@ static void print_compressed(struct feat_fd *ff, FILE *fp)
18091841
ff->ph->env.comp_level, ff->ph->env.comp_ratio);
18101842
}
18111843

1844+
static void print_cpu_pmu_caps(struct feat_fd *ff, FILE *fp)
1845+
{
1846+
const char *delimiter = "# cpu pmu capabilities: ";
1847+
u32 nr_caps = ff->ph->env.nr_cpu_pmu_caps;
1848+
char *str;
1849+
1850+
if (!nr_caps) {
1851+
fprintf(fp, "# cpu pmu capabilities: not available\n");
1852+
return;
1853+
}
1854+
1855+
str = ff->ph->env.cpu_pmu_caps;
1856+
while (nr_caps--) {
1857+
fprintf(fp, "%s%s", delimiter, str);
1858+
delimiter = ", ";
1859+
str += strlen(str) + 1;
1860+
}
1861+
1862+
fprintf(fp, "\n");
1863+
}
1864+
18121865
static void print_pmu_mappings(struct feat_fd *ff, FILE *fp)
18131866
{
18141867
const char *delimiter = "# pmu mappings: ";
@@ -2846,6 +2899,60 @@ static int process_compressed(struct feat_fd *ff,
28462899
return 0;
28472900
}
28482901

2902+
static int process_cpu_pmu_caps(struct feat_fd *ff,
2903+
void *data __maybe_unused)
2904+
{
2905+
char *name, *value;
2906+
struct strbuf sb;
2907+
u32 nr_caps;
2908+
2909+
if (do_read_u32(ff, &nr_caps))
2910+
return -1;
2911+
2912+
if (!nr_caps) {
2913+
pr_debug("cpu pmu capabilities not available\n");
2914+
return 0;
2915+
}
2916+
2917+
ff->ph->env.nr_cpu_pmu_caps = nr_caps;
2918+
2919+
if (strbuf_init(&sb, 128) < 0)
2920+
return -1;
2921+
2922+
while (nr_caps--) {
2923+
name = do_read_string(ff);
2924+
if (!name)
2925+
goto error;
2926+
2927+
value = do_read_string(ff);
2928+
if (!value)
2929+
goto free_name;
2930+
2931+
if (strbuf_addf(&sb, "%s=%s", name, value) < 0)
2932+
goto free_value;
2933+
2934+
/* include a NULL character at the end */
2935+
if (strbuf_add(&sb, "", 1) < 0)
2936+
goto free_value;
2937+
2938+
if (!strcmp(name, "branches"))
2939+
ff->ph->env.max_branches = atoi(value);
2940+
2941+
free(value);
2942+
free(name);
2943+
}
2944+
ff->ph->env.cpu_pmu_caps = strbuf_detach(&sb, NULL);
2945+
return 0;
2946+
2947+
free_value:
2948+
free(value);
2949+
free_name:
2950+
free(name);
2951+
error:
2952+
strbuf_release(&sb);
2953+
return -1;
2954+
}
2955+
28492956
#define FEAT_OPR(n, func, __full_only) \
28502957
[HEADER_##n] = { \
28512958
.name = __stringify(n), \
@@ -2903,6 +3010,7 @@ const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE] = {
29033010
FEAT_OPR(BPF_PROG_INFO, bpf_prog_info, false),
29043011
FEAT_OPR(BPF_BTF, bpf_btf, false),
29053012
FEAT_OPR(COMPRESSED, compressed, false),
3013+
FEAT_OPR(CPU_PMU_CAPS, cpu_pmu_caps, false),
29063014
};
29073015

29083016
struct header_print_data {

tools/perf/util/header.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ enum {
4343
HEADER_BPF_PROG_INFO,
4444
HEADER_BPF_BTF,
4545
HEADER_COMPRESSED,
46+
HEADER_CPU_PMU_CAPS,
4647
HEADER_LAST_FEATURE,
4748
HEADER_FEAT_BITS = 256,
4849
};

0 commit comments

Comments
 (0)