Skip to content

Commit

Permalink
perf header: Support CPU PMU capabilities
Browse files Browse the repository at this point in the history
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 <kan.liang@linux.intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexey Budankov <alexey.budankov@linux.intel.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Pavel Gerasimov <pavel.gerasimov@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Vitaly Slobodskoy <vitaly.slobodskoy@intel.com>
Link: http://lore.kernel.org/lkml/20200319202517.23423-3-kan.liang@linux.intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Kan Liang authored and Arnaldo Carvalho de Melo committed Apr 18, 2020
1 parent 3a6c51e commit 6f91ea2
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 0 deletions.
16 changes: 16 additions & 0 deletions tools/perf/Documentation/perf.data-file-format.txt
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,22 @@ struct {
Indicates that trace contains records of PERF_RECORD_COMPRESSED type
that have perf_events records in compressed form.

HEADER_CPU_PMU_CAPS = 28,

A list of cpu PMU capabilities. The format of data is as below.

struct {
u32 nr_cpu_pmu_caps;
{
char name[];
char value[];
} [nr_cpu_pmu_caps]
};


Example:
cpu pmu capabilities: branches=32, max_precise=3, pmu_name=icelake

other bits are reserved and should ignored for now
HEADER_FEAT_BITS = 256,

Expand Down
3 changes: 3 additions & 0 deletions tools/perf/util/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct perf_env {
char *cpuid;
unsigned long long total_mem;
unsigned int msr_pmu_type;
unsigned int max_branches;

int nr_cmdline;
int nr_sibling_cores;
Expand All @@ -57,12 +58,14 @@ struct perf_env {
int nr_memory_nodes;
int nr_pmu_mappings;
int nr_groups;
int nr_cpu_pmu_caps;
char *cmdline;
const char **cmdline_argv;
char *sibling_cores;
char *sibling_dies;
char *sibling_threads;
char *pmu_mappings;
char *cpu_pmu_caps;
struct cpu_topology_map *cpu;
struct cpu_cache_level *caches;
int caches_cnt;
Expand Down
108 changes: 108 additions & 0 deletions tools/perf/util/header.c
Original file line number Diff line number Diff line change
Expand Up @@ -1395,6 +1395,38 @@ static int write_compressed(struct feat_fd *ff __maybe_unused,
return do_write(ff, &(ff->ph->env.comp_mmap_len), sizeof(ff->ph->env.comp_mmap_len));
}

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_caps *caps = NULL;
int nr_caps;
int ret;

if (!cpu_pmu)
return -ENOENT;

nr_caps = perf_pmu__caps_parse(cpu_pmu);
if (nr_caps < 0)
return nr_caps;

ret = do_write(ff, &nr_caps, sizeof(nr_caps));
if (ret < 0)
return ret;

list_for_each_entry(caps, &cpu_pmu->caps, list) {
ret = do_write_string(ff, caps->name);
if (ret < 0)
return ret;

ret = do_write_string(ff, caps->value);
if (ret < 0)
return ret;
}

return ret;
}

static void print_hostname(struct feat_fd *ff, FILE *fp)
{
fprintf(fp, "# hostname : %s\n", ff->ph->env.hostname);
Expand Down Expand Up @@ -1809,6 +1841,27 @@ static void print_compressed(struct feat_fd *ff, FILE *fp)
ff->ph->env.comp_level, ff->ph->env.comp_ratio);
}

static void print_cpu_pmu_caps(struct feat_fd *ff, FILE *fp)
{
const char *delimiter = "# cpu pmu capabilities: ";
u32 nr_caps = ff->ph->env.nr_cpu_pmu_caps;
char *str;

if (!nr_caps) {
fprintf(fp, "# cpu pmu capabilities: not available\n");
return;
}

str = ff->ph->env.cpu_pmu_caps;
while (nr_caps--) {
fprintf(fp, "%s%s", delimiter, str);
delimiter = ", ";
str += strlen(str) + 1;
}

fprintf(fp, "\n");
}

static void print_pmu_mappings(struct feat_fd *ff, FILE *fp)
{
const char *delimiter = "# pmu mappings: ";
Expand Down Expand Up @@ -2846,6 +2899,60 @@ static int process_compressed(struct feat_fd *ff,
return 0;
}

static int process_cpu_pmu_caps(struct feat_fd *ff,
void *data __maybe_unused)
{
char *name, *value;
struct strbuf sb;
u32 nr_caps;

if (do_read_u32(ff, &nr_caps))
return -1;

if (!nr_caps) {
pr_debug("cpu pmu capabilities not available\n");
return 0;
}

ff->ph->env.nr_cpu_pmu_caps = nr_caps;

if (strbuf_init(&sb, 128) < 0)
return -1;

while (nr_caps--) {
name = do_read_string(ff);
if (!name)
goto error;

value = do_read_string(ff);
if (!value)
goto free_name;

if (strbuf_addf(&sb, "%s=%s", name, value) < 0)
goto free_value;

/* include a NULL character at the end */
if (strbuf_add(&sb, "", 1) < 0)
goto free_value;

if (!strcmp(name, "branches"))
ff->ph->env.max_branches = atoi(value);

free(value);
free(name);
}
ff->ph->env.cpu_pmu_caps = strbuf_detach(&sb, NULL);
return 0;

free_value:
free(value);
free_name:
free(name);
error:
strbuf_release(&sb);
return -1;
}

#define FEAT_OPR(n, func, __full_only) \
[HEADER_##n] = { \
.name = __stringify(n), \
Expand Down Expand Up @@ -2903,6 +3010,7 @@ const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE] = {
FEAT_OPR(BPF_PROG_INFO, bpf_prog_info, false),
FEAT_OPR(BPF_BTF, bpf_btf, false),
FEAT_OPR(COMPRESSED, compressed, false),
FEAT_OPR(CPU_PMU_CAPS, cpu_pmu_caps, false),
};

struct header_print_data {
Expand Down
1 change: 1 addition & 0 deletions tools/perf/util/header.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ enum {
HEADER_BPF_PROG_INFO,
HEADER_BPF_BTF,
HEADER_COMPRESSED,
HEADER_CPU_PMU_CAPS,
HEADER_LAST_FEATURE,
HEADER_FEAT_BITS = 256,
};
Expand Down

0 comments on commit 6f91ea2

Please sign in to comment.