2020-03-10 18:52:04

by Ian Rogers

[permalink] [raw]
Subject: [PATCH] perf tools: add support for lipfm4

This patch links perf with the libpfm4 library.
This library contains all the hardware event tables for all
processors supported by perf_events. This is a helper library
that help convert from a symbolic event name to the event
encoding required by the underlying kernel interface. This
library is open-source and available from: http://perfmon2.sf.net.

With this patch, it is possible to specify full hardware event
by names. Hardware filters are also supported. Events must be
specified via the --pfm-events and not -e option. Both options
are active at the same time and it is possible to mix and match:

$ perf stat --pfm-events inst_retired:any_p:c=1:i -e cycles ....

You need to have libpfm4-dev package installed on your system.

Author: Stephane Eranian <[email protected]>
Signed-off-by: Ian Rogers <[email protected]>
---
tools/build/Makefile.feature | 6 +-
tools/build/feature/Makefile | 7 +-
tools/perf/Documentation/perf-record.txt | 10 +
tools/perf/Documentation/perf-stat.txt | 9 +
tools/perf/Documentation/perf-top.txt | 10 +
tools/perf/Makefile.config | 11 +
tools/perf/Makefile.perf | 2 +
tools/perf/builtin-list.c | 16 ++
tools/perf/builtin-record.c | 20 ++
tools/perf/builtin-stat.c | 21 ++
tools/perf/builtin-top.c | 20 ++
tools/perf/util/evsel.c | 2 +-
tools/perf/util/evsel.h | 1 +
tools/perf/util/parse-events.c | 246 +++++++++++++++++++++++
tools/perf/util/parse-events.h | 5 +
tools/perf/util/pmu.c | 11 +
tools/perf/util/pmu.h | 1 +
17 files changed, 394 insertions(+), 4 deletions(-)

diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index 574c2e0b9d20..08c6fe5aee2d 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -72,7 +72,8 @@ FEATURE_TESTS_BASIC := \
setns \
libaio \
libzstd \
- disassembler-four-args
+ disassembler-four-args \
+ libpfm4

# FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
# of all feature tests
@@ -127,7 +128,8 @@ FEATURE_DISPLAY ?= \
bpf \
libaio \
libzstd \
- disassembler-four-args
+ disassembler-four-args \
+ libpfm4

# Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features.
# If in the future we need per-feature checks/flags for features not
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index 7ac0d8088565..573072d32545 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -67,7 +67,9 @@ FILES= \
test-llvm.bin \
test-llvm-version.bin \
test-libaio.bin \
- test-libzstd.bin
+ test-libzstd.bin \
+ test-libpfm4.bin
+

FILES := $(addprefix $(OUTPUT),$(FILES))

@@ -321,6 +323,9 @@ $(OUTPUT)test-libaio.bin:
$(OUTPUT)test-libzstd.bin:
$(BUILD) -lzstd

+$(OUTPUT)test-libpfm4.bin:
+ $(BUILD) -lpfm
+
###############################

clean:
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index b23a4012a606..2a73e7910baa 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -587,6 +587,16 @@ Make a copy of /proc/kcore and place it into a directory with the perf data file
Limit the sample data max size, <size> is expected to be a number with
appended unit character - B/K/M/G

+--pfm-events events::
+this option is only available when perf is linked with the libpfm4 library
+(see http://perfmon2.sf.net). It allows passing hardware events as strings
+for all support processors. Event filters can also be used. As an example:
+perf stat --pfm-events inst_retired:any_p:u:c=1:i. More than one event can
+be passed to the option using the comma separator. Hardware events and
+generic hardware events cannot be mixed together. The latter must be used
+with the -e option. The -e option and this one can be mixed and matched.
+Events can be grouped using the {} notation.
+
SEE ALSO
--------
linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 9431b8066fb4..5cb99212a2fc 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -71,6 +71,15 @@ report::
--tid=<tid>::
stat events on existing thread id (comma separated list)

+--pfm-events events::
+this option is only available when perf is linked with the libpfm4 library
+(see http://perfmon2.sf.net). It allows passing hardware events as strings
+for all support processors. Event filters can also be used. As an example:
+perf stat --pfm-events inst_retired:any_p:u:c=1:i. More than one event can
+be passed to the option using the comma separator. Hardware events and
+generic hardware events cannot be mixed together. The latter must be used
+with the -e option. The -e option and this one can be mixed and matched.
+Events can be grouped using the {} notation.

-a::
--all-cpus::
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 324b6b53c86b..23b05f849ca2 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -310,6 +310,16 @@ Default is to monitor all CPUS.
go straight to the histogram browser, just like 'perf top' with no events
explicitely specified does.

+--pfm-events events::
+this option is only available when perf is linked with the libpfm4 library
+(see http://perfmon2.sf.net). It allows passing hardware events as strings
+for all support processors. Event filters can also be used. As an example:
+perf stat --pfm-events inst_retired:any_p:u:c=1:i. More than one event can
+be passed to the option using the comma separator. Hardware events and
+generic hardware events cannot be mixed together. The latter must be used
+with the -e option. The -e option and this one can be mixed and matched.
+Events can be grouped using the {} notation.
+

INTERACTIVE PROMPTING KEYS
--------------------------
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 80e55e796be9..0579f008241d 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -999,6 +999,17 @@ ifdef LIBCLANGLLVM
endif
endif

+ifndef NO_LIBPFM4
+ ifeq ($(feature-libpfm4), 1)
+ CFLAGS += -DHAVE_LIBPFM
+ EXTLIBS += -lpfm
+ $(call detected,CONFIG_LIBPFM4)
+ else
+ msg := $(warning libpfm4 not found, disables libpfm4 support. Please install libpfm4-dev);
+ NO_LIBPFM4 := 1
+ endif
+endif
+
# Among the variables below, these:
# perfexecdir
# perf_include_dir
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 3eda9d4b88e7..56829bee4dc8 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -118,6 +118,8 @@ include ../scripts/utilities.mak
#
# Define LIBBPF_DYNAMIC to enable libbpf dynamic linking.
#
+# Define NO_LIBPFM4 to disable libpfm4 extension.
+#

# As per kernel Makefile, avoid funny character set dependencies
unexport LC_ALL
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index 965ef017496f..5edeb428168a 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -18,6 +18,10 @@
#include <subcmd/parse-options.h>
#include <stdio.h>

+#ifdef HAVE_LIBPFM
+#include <perfmon/pfmlib.h>
+#endif
+
static bool desc_flag = true;
static bool details_flag;

@@ -56,6 +60,18 @@ int cmd_list(int argc, const char **argv)
if (!raw_dump && pager_in_use())
printf("\nList of pre-defined events (to be used in -e):\n\n");

+#ifdef HAVE_LIBPFM
+ {
+ int ret;
+ ret = pfm_initialize();
+ if (ret != PFM_SUCCESS) {
+ fprintf(stderr,
+ "warning libpfm failed to initialize: %s\n",
+ pfm_strerror(ret));
+ }
+ }
+#endif
+
if (argc == 0) {
print_events(NULL, raw_dump, !desc_flag, long_desc_flag,
details_flag, deprecated);
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 4c301466101b..10b31f5f5fc1 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -64,6 +64,10 @@
#include <linux/zalloc.h>
#include <linux/bitmap.h>

+#ifdef HAVE_LIBPFM
+#include <perfmon/pfmlib.h>
+#endif
+
struct switch_output {
bool enabled;
bool signal;
@@ -2405,6 +2409,11 @@ static struct option __record_options[] = {
#endif
OPT_CALLBACK(0, "max-size", &record.output_max_size,
"size", "Limit the maximum size of the output file", parse_output_max_size),
+#ifdef HAVE_LIBPFM
+ OPT_CALLBACK(0, "pfm-events", &record.evlist, "event",
+ "libpfm4 event selector. use 'perf list' to list available events",
+ parse_libpfm_events_option),
+#endif
OPT_END()
};

@@ -2445,6 +2454,17 @@ int cmd_record(int argc, const char **argv)
if (rec->evlist == NULL)
return -ENOMEM;

+#ifdef HAVE_LIBPFM
+ {
+ int ret;
+ ret = pfm_initialize();
+ if (ret != PFM_SUCCESS) {
+ ui__warning("warning libpfm failed to initialize: %s\n",
+ pfm_strerror(ret));
+ }
+ }
+#endif
+
err = perf_config(perf_record_config, rec);
if (err)
return err;
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index a098c2ebf4ea..08ed4eaddd4a 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -89,6 +89,10 @@
#include <linux/ctype.h>
#include <perf/evlist.h>

+#ifdef HAVE_LIBPFM
+#include <perfmon/pfmlib.h>
+#endif
+
#define DEFAULT_SEPARATOR " "
#define FREEZE_ON_SMI_PATH "devices/cpu/freeze_on_smi"

@@ -929,6 +933,11 @@ static struct option stat_options[] = {
OPT_BOOLEAN_FLAG(0, "all-user", &stat_config.all_user,
"Configure all used events to run in user space.",
PARSE_OPT_EXCLUSIVE),
+#ifdef HAVE_LIBPFM
+ OPT_CALLBACK(0, "pfm-events", &evsel_list, "event",
+ "libpfm4 event selector. use 'perf list' to list available events",
+ parse_libpfm_events_option),
+#endif
OPT_END()
};

@@ -1867,6 +1876,18 @@ int cmd_stat(int argc, const char **argv)
unsigned int interval, timeout;
const char * const stat_subcommands[] = { "record", "report" };

+#ifdef HAVE_LIBPFM
+ {
+ int ret;
+ ret = pfm_initialize();
+ if (ret != PFM_SUCCESS) {
+ fprintf(stderr,
+ "warning libpfm failed to initialize: %s\n",
+ pfm_strerror(ret));
+ }
+ }
+#endif
+
setlocale(LC_ALL, "");

evsel_list = evlist__new();
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index d2539b793f9d..db6da472499b 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -84,6 +84,10 @@
#include <linux/ctype.h>
#include <perf/mmap.h>

+#ifdef HAVE_LIBPFM
+#include <perfmon/pfmlib.h>
+#endif
+
static volatile int done;
static volatile int resize;

@@ -1545,6 +1549,11 @@ int cmd_top(int argc, const char **argv)
"number of thread to run event synthesize"),
OPT_BOOLEAN(0, "namespaces", &opts->record_namespaces,
"Record namespaces events"),
+#ifdef HAVE_LIBPFM
+ OPT_CALLBACK(0, "pfm-events", &top.evlist, "event",
+ "libpfm4 event selector. use 'perf list' to list available events",
+ parse_libpfm_events_option),
+#endif
OPTS_EVSWITCH(&top.evswitch),
OPT_END()
};
@@ -1558,6 +1567,17 @@ int cmd_top(int argc, const char **argv)
if (status < 0)
return status;

+#ifdef HAVE_LIBPFM
+ {
+ int ret;
+ ret = pfm_initialize();
+ if (ret != PFM_SUCCESS) {
+ ui__warning("warning libpfm failed to initialize: %s\n",
+ pfm_strerror(ret));
+ }
+ }
+#endif
+
top.annotation_opts.min_pcnt = 5;
top.annotation_opts.context = 4;

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index c8dc4450884c..fea7bbf0682c 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -2418,7 +2418,7 @@ bool perf_evsel__fallback(struct evsel *evsel, int err,

/* Is there already the separator in the name. */
if (strchr(name, '/') ||
- strchr(name, ':'))
+ (strchr(name, ':') && !evsel->is_libpfm_event))
sep = "";

if (asprintf(&new_name, "%s%su", name, sep) < 0)
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index dc14f4a823cd..8dcbe34e9442 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -76,6 +76,7 @@ struct evsel {
bool ignore_missing_thread;
bool forced_leader;
bool use_uncore_alias;
+ bool is_libpfm_event;
/* parse modifier helper */
int exclude_GH;
int sample_read;
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index a14995835d85..266453445c5c 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -37,6 +37,11 @@
#include "util/evsel_config.h"
#include "util/event.h"

+#ifdef HAVE_LIBPFM
+#include <perfmon/pfmlib_perf_event.h>
+static void print_libpfm_events(bool name_only);
+#endif
+
#define MAX_NAME_LEN 100

#ifdef PARSER_DEBUG
@@ -2794,6 +2799,10 @@ void print_events(const char *event_glob, bool name_only, bool quiet_flag,
print_sdt_events(NULL, NULL, name_only);

metricgroup__print(true, true, NULL, name_only, details_flag);
+
+#ifdef HAVE_LIBPFM
+ print_libpfm_events(name_only);
+#endif
}

int parse_events__is_hardcoded_term(struct parse_events_term *term)
@@ -3042,3 +3051,240 @@ char *parse_events_formats_error_string(char *additional_terms)
fail:
return NULL;
}
+
+#ifdef HAVE_LIBPFM
+static int
+parse_libpfm_event(char *strp, struct perf_event_attr *attr)
+{
+ int ret;
+
+ ret = pfm_get_perf_event_encoding(strp, PFM_PLM0|PFM_PLM3,
+ attr, NULL, NULL);
+ return ret;
+}
+
+int parse_libpfm_events_option(const struct option *opt, const char *str,
+ int unset __maybe_unused)
+{
+ struct evlist *evlist = *(struct evlist **)opt->value;
+ struct perf_event_attr attr;
+ struct perf_pmu *pmu;
+ struct evsel *evsel, *grp_leader = NULL;
+ char *p, *q, *p_orig;
+ const char *sep;
+ int grp_evt = -1;
+ int ret;
+
+ p_orig = p = strdup(str);
+ if (!p)
+ return -1;
+ /*
+ * force loading of the PMU list
+ */
+ perf_pmu__scan(NULL);
+
+ for (q = p; strsep(&p, ",{}"); q = p) {
+ sep = p ? str + (p - p_orig - 1) : "";
+ if (*sep == '{') {
+ if (grp_evt > -1) {
+ fprintf(stderr, "nested event groups not supported\n");
+ goto error;
+ }
+ grp_evt++;
+ }
+
+ /* no event */
+ if (*q == '\0')
+ continue;
+
+ memset(&attr, 0, sizeof(attr));
+ event_attr_init(&attr);
+
+ ret = parse_libpfm_event(q, &attr);
+ if (ret != PFM_SUCCESS) {
+ fprintf(stderr, "failed to parse event %s : %s\n", str, pfm_strerror(ret));
+ goto error;
+ }
+
+ evsel = perf_evsel__new_idx(&attr, evlist->core.nr_entries);
+ if (evsel == NULL)
+ goto error;
+
+ evsel->name = strdup(q);
+ if (!evsel->name) {
+ evsel__delete(evsel);
+ goto error;
+ }
+ evsel->is_libpfm_event = true;
+
+ pmu = perf_pmu__find_by_type((unsigned)attr.type);
+ if (pmu)
+ evsel->core.own_cpus = perf_cpu_map__get(pmu->cpus);
+
+ evlist__add(evlist, evsel);
+
+ if (grp_evt == 0)
+ grp_leader = evsel;
+
+ if (grp_evt > -1) {
+ evsel->leader = grp_leader;
+ grp_leader->core.nr_members++;
+ grp_evt++;
+ }
+
+ if (*sep == '}') {
+ if (grp_evt < 0) {
+ fprintf(stderr, "cannot close a non-existing event group\n");
+ goto error;
+ }
+ evlist->nr_groups++;
+ grp_leader = NULL;
+ grp_evt = -1;
+ }
+ }
+ return 0;
+error:
+ free(p_orig);
+ return -1;
+}
+
+static const char *srcs[PFM_ATTR_CTRL_MAX]={
+ [PFM_ATTR_CTRL_UNKNOWN] = "???",
+ [PFM_ATTR_CTRL_PMU] = "PMU",
+ [PFM_ATTR_CTRL_PERF_EVENT] = "perf_event",
+};
+
+static void
+print_attr_flags(pfm_event_attr_info_t *info)
+{
+ int n = 0;
+
+ if (info->is_dfl) {
+ printf("[default] ");
+ n++;
+ }
+
+ if (info->is_precise) {
+ printf("[precise] ");
+ n++;
+ }
+
+ if (!n)
+ printf("- ");
+}
+
+static void
+print_libpfm_detailed_events(pfm_pmu_info_t *pinfo, pfm_event_info_t *info)
+{
+ pfm_event_attr_info_t ainfo;
+ const char *src;
+ int j, ret;
+
+ ainfo.size = sizeof(ainfo);
+
+ printf("\nName : %s\n", info->name);
+ printf("PMU : %s\n", pinfo->name);
+ printf("Desc : %s\n", info->desc);
+ printf("Equiv : %s\n", info->equiv ? info->equiv : "None");
+ printf("Code : 0x%"PRIx64"\n", info->code);
+
+ pfm_for_each_event_attr(j, info) {
+ ret = pfm_get_event_attr_info(info->idx, j, PFM_OS_PERF_EVENT_EXT, &ainfo);
+ if (ret != PFM_SUCCESS)
+ continue;
+
+ if (ainfo.ctrl >= PFM_ATTR_CTRL_MAX)
+ ainfo.ctrl = PFM_ATTR_CTRL_UNKNOWN;
+
+ src = srcs[ainfo.ctrl];
+ switch(ainfo.type) {
+ case PFM_ATTR_UMASK:
+ printf("Umask : 0x%02"PRIx64" : %s: [%s] : ", ainfo.code, src, ainfo.name);
+ print_attr_flags(&ainfo);
+ printf(": %s\n", ainfo.desc);
+ break;
+ case PFM_ATTR_MOD_BOOL:
+ printf("Modif : %s: [%s] : %s (boolean)\n", src, ainfo.name, ainfo.desc);
+ break;
+ case PFM_ATTR_MOD_INTEGER:
+ printf("Modif : %s: [%s] : %s (integer)\n", src, ainfo.name, ainfo.desc);
+ break;
+ case PFM_ATTR_NONE:
+ case PFM_ATTR_RAW_UMASK:
+ case PFM_ATTR_MAX:
+ default:
+ printf("Attr : %s: [%s] : %s\n", src, ainfo.name, ainfo.desc);
+ }
+ }
+}
+
+/*
+ * list all pmu::event:umask, pmu::event
+ * printed events may not be all valid combinations of umask for an event
+ */
+static void
+print_libpfm_simplified_events(pfm_pmu_info_t *pinfo, pfm_event_info_t *info)
+{
+ pfm_event_attr_info_t ainfo;
+ int j, ret;
+ int um = 0;
+
+ ainfo.size = sizeof(ainfo);
+
+ pfm_for_each_event_attr(j, info) {
+ ret = pfm_get_event_attr_info(info->idx, j, PFM_OS_PERF_EVENT_EXT, &ainfo);
+ if (ret != PFM_SUCCESS)
+ continue;
+
+ if (ainfo.type != PFM_ATTR_UMASK)
+ continue;
+
+ printf("%s::%s:%s\n", pinfo->name, info->name, ainfo.name);
+ um++;
+ }
+ if (um == 0)
+ printf("%s::%s\n", pinfo->name, info->name);
+}
+
+static void
+print_libpfm_events(bool name_only)
+{
+ pfm_event_info_t info;
+ pfm_pmu_info_t pinfo;
+ pfm_event_attr_info_t ainfo;
+ int i, p, ret;
+
+ /* initialize to zero to indicate ABI version */
+ info.size = sizeof(info);
+ pinfo.size = sizeof(pinfo);
+ ainfo.size = sizeof(ainfo);
+
+ putchar('\n');
+
+ pfm_for_all_pmus(p) {
+ ret = pfm_get_pmu_info(p, &pinfo);
+ if (ret != PFM_SUCCESS)
+ continue;
+
+ /* ony print events that are supported by host HW */
+ if (!pinfo.is_present)
+ continue;
+
+ /* handled by perf directly */
+ if (pinfo.pmu == PFM_PMU_PERF_EVENT)
+ continue;
+
+ for (i = pinfo.first_event; i != -1; i = pfm_get_event_next(i)) {
+
+ ret = pfm_get_event_info(i, PFM_OS_PERF_EVENT_EXT, &info);
+ if (ret != PFM_SUCCESS)
+ continue;
+
+ if (!name_only)
+ print_libpfm_detailed_events(&pinfo, &info);
+ else
+ print_libpfm_simplified_events(&pinfo, &info);
+ }
+ }
+}
+#endif
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 27596cbd0ba0..84d4799c9a31 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -37,6 +37,11 @@ int parse_events_terms(struct list_head *terms, const char *str);
int parse_filter(const struct option *opt, const char *str, int unset);
int exclude_perf(const struct option *opt, const char *arg, int unset);

+#ifdef HAVE_LIBPFM
+extern int parse_libpfm_events_option(const struct option *opt, const char *str,
+ int unset);
+#endif
+
#define EVENTS_HELP_MAX (128*1024)

enum perf_pmu_event_symbol_type {
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 8b99fd312aae..9e4a70c7204a 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -864,6 +864,17 @@ static struct perf_pmu *pmu_find(const char *name)
return NULL;
}

+struct perf_pmu *perf_pmu__find_by_type(unsigned int type)
+{
+ struct perf_pmu *pmu;
+
+ list_for_each_entry(pmu, &pmus, list)
+ if (pmu->type == type)
+ return pmu;
+
+ return NULL;
+}
+
struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
{
/*
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 6737e3d5d568..15a3253f1719 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -64,6 +64,7 @@ struct perf_pmu_alias {
};

struct perf_pmu *perf_pmu__find(const char *name);
+struct perf_pmu *perf_pmu__find_by_type(unsigned int type);
int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
struct list_head *head_terms,
struct parse_events_error *error);
--
2.25.1.481.gfbce0eb801-goog


2020-03-10 20:00:05

by Andi Kleen

[permalink] [raw]
Subject: Re: [PATCH] perf tools: add support for lipfm4

On Tue, Mar 10, 2020 at 11:50:03AM -0700, Ian Rogers wrote:
> This patch links perf with the libpfm4 library.
> This library contains all the hardware event tables for all
> processors supported by perf_events. This is a helper library
> that help convert from a symbolic event name to the event
> encoding required by the underlying kernel interface. This
> library is open-source and available from: http://perfmon2.sf.net.

For most CPUs the builtin perf JSON event support should make
this redundant.

Perhaps you could list what CPUs it actually supports over
the existing JSON tables.

If it's only a few it would be likely better to add
appropiate json files.

If it's a massive number it might be useful, although
JSON support would be better for those too.

-Andi

2020-03-10 21:09:54

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH] perf tools: add support for lipfm4

Em Tue, Mar 10, 2020 at 11:50:03AM -0700, Ian Rogers escreveu:
> This patch links perf with the libpfm4 library.
> This library contains all the hardware event tables for all
> processors supported by perf_events. This is a helper library
> that help convert from a symbolic event name to the event
> encoding required by the underlying kernel interface. This
> library is open-source and available from: http://perfmon2.sf.net.
>
> With this patch, it is possible to specify full hardware event
> by names. Hardware filters are also supported. Events must be
> specified via the --pfm-events and not -e option. Both options
> are active at the same time and it is possible to mix and match:
>
> $ perf stat --pfm-events inst_retired:any_p:c=1:i -e cycles ....
>
> You need to have libpfm4-dev package installed on your system.

Isn't that what we have already with the json files?

- Arnaldo

> Author: Stephane Eranian <[email protected]>
> Signed-off-by: Ian Rogers <[email protected]>
> ---
> tools/build/Makefile.feature | 6 +-
> tools/build/feature/Makefile | 7 +-
> tools/perf/Documentation/perf-record.txt | 10 +
> tools/perf/Documentation/perf-stat.txt | 9 +
> tools/perf/Documentation/perf-top.txt | 10 +
> tools/perf/Makefile.config | 11 +
> tools/perf/Makefile.perf | 2 +
> tools/perf/builtin-list.c | 16 ++
> tools/perf/builtin-record.c | 20 ++
> tools/perf/builtin-stat.c | 21 ++
> tools/perf/builtin-top.c | 20 ++
> tools/perf/util/evsel.c | 2 +-
> tools/perf/util/evsel.h | 1 +
> tools/perf/util/parse-events.c | 246 +++++++++++++++++++++++
> tools/perf/util/parse-events.h | 5 +
> tools/perf/util/pmu.c | 11 +
> tools/perf/util/pmu.h | 1 +
> 17 files changed, 394 insertions(+), 4 deletions(-)
>
> diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
> index 574c2e0b9d20..08c6fe5aee2d 100644
> --- a/tools/build/Makefile.feature
> +++ b/tools/build/Makefile.feature
> @@ -72,7 +72,8 @@ FEATURE_TESTS_BASIC := \
> setns \
> libaio \
> libzstd \
> - disassembler-four-args
> + disassembler-four-args \
> + libpfm4
>
> # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
> # of all feature tests
> @@ -127,7 +128,8 @@ FEATURE_DISPLAY ?= \
> bpf \
> libaio \
> libzstd \
> - disassembler-four-args
> + disassembler-four-args \
> + libpfm4
>
> # Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features.
> # If in the future we need per-feature checks/flags for features not
> diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
> index 7ac0d8088565..573072d32545 100644
> --- a/tools/build/feature/Makefile
> +++ b/tools/build/feature/Makefile
> @@ -67,7 +67,9 @@ FILES= \
> test-llvm.bin \
> test-llvm-version.bin \
> test-libaio.bin \
> - test-libzstd.bin
> + test-libzstd.bin \
> + test-libpfm4.bin
> +
>
> FILES := $(addprefix $(OUTPUT),$(FILES))
>
> @@ -321,6 +323,9 @@ $(OUTPUT)test-libaio.bin:
> $(OUTPUT)test-libzstd.bin:
> $(BUILD) -lzstd
>
> +$(OUTPUT)test-libpfm4.bin:
> + $(BUILD) -lpfm
> +
> ###############################
>
> clean:
> diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
> index b23a4012a606..2a73e7910baa 100644
> --- a/tools/perf/Documentation/perf-record.txt
> +++ b/tools/perf/Documentation/perf-record.txt
> @@ -587,6 +587,16 @@ Make a copy of /proc/kcore and place it into a directory with the perf data file
> Limit the sample data max size, <size> is expected to be a number with
> appended unit character - B/K/M/G
>
> +--pfm-events events::
> +this option is only available when perf is linked with the libpfm4 library
> +(see http://perfmon2.sf.net). It allows passing hardware events as strings
> +for all support processors. Event filters can also be used. As an example:
> +perf stat --pfm-events inst_retired:any_p:u:c=1:i. More than one event can
> +be passed to the option using the comma separator. Hardware events and
> +generic hardware events cannot be mixed together. The latter must be used
> +with the -e option. The -e option and this one can be mixed and matched.
> +Events can be grouped using the {} notation.
> +
> SEE ALSO
> --------
> linkperf:perf-stat[1], linkperf:perf-list[1]
> diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
> index 9431b8066fb4..5cb99212a2fc 100644
> --- a/tools/perf/Documentation/perf-stat.txt
> +++ b/tools/perf/Documentation/perf-stat.txt
> @@ -71,6 +71,15 @@ report::
> --tid=<tid>::
> stat events on existing thread id (comma separated list)
>
> +--pfm-events events::
> +this option is only available when perf is linked with the libpfm4 library
> +(see http://perfmon2.sf.net). It allows passing hardware events as strings
> +for all support processors. Event filters can also be used. As an example:
> +perf stat --pfm-events inst_retired:any_p:u:c=1:i. More than one event can
> +be passed to the option using the comma separator. Hardware events and
> +generic hardware events cannot be mixed together. The latter must be used
> +with the -e option. The -e option and this one can be mixed and matched.
> +Events can be grouped using the {} notation.
>
> -a::
> --all-cpus::
> diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
> index 324b6b53c86b..23b05f849ca2 100644
> --- a/tools/perf/Documentation/perf-top.txt
> +++ b/tools/perf/Documentation/perf-top.txt
> @@ -310,6 +310,16 @@ Default is to monitor all CPUS.
> go straight to the histogram browser, just like 'perf top' with no events
> explicitely specified does.
>
> +--pfm-events events::
> +this option is only available when perf is linked with the libpfm4 library
> +(see http://perfmon2.sf.net). It allows passing hardware events as strings
> +for all support processors. Event filters can also be used. As an example:
> +perf stat --pfm-events inst_retired:any_p:u:c=1:i. More than one event can
> +be passed to the option using the comma separator. Hardware events and
> +generic hardware events cannot be mixed together. The latter must be used
> +with the -e option. The -e option and this one can be mixed and matched.
> +Events can be grouped using the {} notation.
> +
>
> INTERACTIVE PROMPTING KEYS
> --------------------------
> diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
> index 80e55e796be9..0579f008241d 100644
> --- a/tools/perf/Makefile.config
> +++ b/tools/perf/Makefile.config
> @@ -999,6 +999,17 @@ ifdef LIBCLANGLLVM
> endif
> endif
>
> +ifndef NO_LIBPFM4
> + ifeq ($(feature-libpfm4), 1)
> + CFLAGS += -DHAVE_LIBPFM
> + EXTLIBS += -lpfm
> + $(call detected,CONFIG_LIBPFM4)
> + else
> + msg := $(warning libpfm4 not found, disables libpfm4 support. Please install libpfm4-dev);
> + NO_LIBPFM4 := 1
> + endif
> +endif
> +
> # Among the variables below, these:
> # perfexecdir
> # perf_include_dir
> diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
> index 3eda9d4b88e7..56829bee4dc8 100644
> --- a/tools/perf/Makefile.perf
> +++ b/tools/perf/Makefile.perf
> @@ -118,6 +118,8 @@ include ../scripts/utilities.mak
> #
> # Define LIBBPF_DYNAMIC to enable libbpf dynamic linking.
> #
> +# Define NO_LIBPFM4 to disable libpfm4 extension.
> +#
>
> # As per kernel Makefile, avoid funny character set dependencies
> unexport LC_ALL
> diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
> index 965ef017496f..5edeb428168a 100644
> --- a/tools/perf/builtin-list.c
> +++ b/tools/perf/builtin-list.c
> @@ -18,6 +18,10 @@
> #include <subcmd/parse-options.h>
> #include <stdio.h>
>
> +#ifdef HAVE_LIBPFM
> +#include <perfmon/pfmlib.h>
> +#endif
> +
> static bool desc_flag = true;
> static bool details_flag;
>
> @@ -56,6 +60,18 @@ int cmd_list(int argc, const char **argv)
> if (!raw_dump && pager_in_use())
> printf("\nList of pre-defined events (to be used in -e):\n\n");
>
> +#ifdef HAVE_LIBPFM
> + {
> + int ret;
> + ret = pfm_initialize();
> + if (ret != PFM_SUCCESS) {
> + fprintf(stderr,
> + "warning libpfm failed to initialize: %s\n",
> + pfm_strerror(ret));
> + }
> + }
> +#endif
> +
> if (argc == 0) {
> print_events(NULL, raw_dump, !desc_flag, long_desc_flag,
> details_flag, deprecated);
> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
> index 4c301466101b..10b31f5f5fc1 100644
> --- a/tools/perf/builtin-record.c
> +++ b/tools/perf/builtin-record.c
> @@ -64,6 +64,10 @@
> #include <linux/zalloc.h>
> #include <linux/bitmap.h>
>
> +#ifdef HAVE_LIBPFM
> +#include <perfmon/pfmlib.h>
> +#endif
> +
> struct switch_output {
> bool enabled;
> bool signal;
> @@ -2405,6 +2409,11 @@ static struct option __record_options[] = {
> #endif
> OPT_CALLBACK(0, "max-size", &record.output_max_size,
> "size", "Limit the maximum size of the output file", parse_output_max_size),
> +#ifdef HAVE_LIBPFM
> + OPT_CALLBACK(0, "pfm-events", &record.evlist, "event",
> + "libpfm4 event selector. use 'perf list' to list available events",
> + parse_libpfm_events_option),
> +#endif
> OPT_END()
> };
>
> @@ -2445,6 +2454,17 @@ int cmd_record(int argc, const char **argv)
> if (rec->evlist == NULL)
> return -ENOMEM;
>
> +#ifdef HAVE_LIBPFM
> + {
> + int ret;
> + ret = pfm_initialize();
> + if (ret != PFM_SUCCESS) {
> + ui__warning("warning libpfm failed to initialize: %s\n",
> + pfm_strerror(ret));
> + }
> + }
> +#endif
> +
> err = perf_config(perf_record_config, rec);
> if (err)
> return err;
> diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
> index a098c2ebf4ea..08ed4eaddd4a 100644
> --- a/tools/perf/builtin-stat.c
> +++ b/tools/perf/builtin-stat.c
> @@ -89,6 +89,10 @@
> #include <linux/ctype.h>
> #include <perf/evlist.h>
>
> +#ifdef HAVE_LIBPFM
> +#include <perfmon/pfmlib.h>
> +#endif
> +
> #define DEFAULT_SEPARATOR " "
> #define FREEZE_ON_SMI_PATH "devices/cpu/freeze_on_smi"
>
> @@ -929,6 +933,11 @@ static struct option stat_options[] = {
> OPT_BOOLEAN_FLAG(0, "all-user", &stat_config.all_user,
> "Configure all used events to run in user space.",
> PARSE_OPT_EXCLUSIVE),
> +#ifdef HAVE_LIBPFM
> + OPT_CALLBACK(0, "pfm-events", &evsel_list, "event",
> + "libpfm4 event selector. use 'perf list' to list available events",
> + parse_libpfm_events_option),
> +#endif
> OPT_END()
> };
>
> @@ -1867,6 +1876,18 @@ int cmd_stat(int argc, const char **argv)
> unsigned int interval, timeout;
> const char * const stat_subcommands[] = { "record", "report" };
>
> +#ifdef HAVE_LIBPFM
> + {
> + int ret;
> + ret = pfm_initialize();
> + if (ret != PFM_SUCCESS) {
> + fprintf(stderr,
> + "warning libpfm failed to initialize: %s\n",
> + pfm_strerror(ret));
> + }
> + }
> +#endif
> +
> setlocale(LC_ALL, "");
>
> evsel_list = evlist__new();
> diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
> index d2539b793f9d..db6da472499b 100644
> --- a/tools/perf/builtin-top.c
> +++ b/tools/perf/builtin-top.c
> @@ -84,6 +84,10 @@
> #include <linux/ctype.h>
> #include <perf/mmap.h>
>
> +#ifdef HAVE_LIBPFM
> +#include <perfmon/pfmlib.h>
> +#endif
> +
> static volatile int done;
> static volatile int resize;
>
> @@ -1545,6 +1549,11 @@ int cmd_top(int argc, const char **argv)
> "number of thread to run event synthesize"),
> OPT_BOOLEAN(0, "namespaces", &opts->record_namespaces,
> "Record namespaces events"),
> +#ifdef HAVE_LIBPFM
> + OPT_CALLBACK(0, "pfm-events", &top.evlist, "event",
> + "libpfm4 event selector. use 'perf list' to list available events",
> + parse_libpfm_events_option),
> +#endif
> OPTS_EVSWITCH(&top.evswitch),
> OPT_END()
> };
> @@ -1558,6 +1567,17 @@ int cmd_top(int argc, const char **argv)
> if (status < 0)
> return status;
>
> +#ifdef HAVE_LIBPFM
> + {
> + int ret;
> + ret = pfm_initialize();
> + if (ret != PFM_SUCCESS) {
> + ui__warning("warning libpfm failed to initialize: %s\n",
> + pfm_strerror(ret));
> + }
> + }
> +#endif
> +
> top.annotation_opts.min_pcnt = 5;
> top.annotation_opts.context = 4;
>
> diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
> index c8dc4450884c..fea7bbf0682c 100644
> --- a/tools/perf/util/evsel.c
> +++ b/tools/perf/util/evsel.c
> @@ -2418,7 +2418,7 @@ bool perf_evsel__fallback(struct evsel *evsel, int err,
>
> /* Is there already the separator in the name. */
> if (strchr(name, '/') ||
> - strchr(name, ':'))
> + (strchr(name, ':') && !evsel->is_libpfm_event))
> sep = "";
>
> if (asprintf(&new_name, "%s%su", name, sep) < 0)
> diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
> index dc14f4a823cd..8dcbe34e9442 100644
> --- a/tools/perf/util/evsel.h
> +++ b/tools/perf/util/evsel.h
> @@ -76,6 +76,7 @@ struct evsel {
> bool ignore_missing_thread;
> bool forced_leader;
> bool use_uncore_alias;
> + bool is_libpfm_event;
> /* parse modifier helper */
> int exclude_GH;
> int sample_read;
> diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
> index a14995835d85..266453445c5c 100644
> --- a/tools/perf/util/parse-events.c
> +++ b/tools/perf/util/parse-events.c
> @@ -37,6 +37,11 @@
> #include "util/evsel_config.h"
> #include "util/event.h"
>
> +#ifdef HAVE_LIBPFM
> +#include <perfmon/pfmlib_perf_event.h>
> +static void print_libpfm_events(bool name_only);
> +#endif
> +
> #define MAX_NAME_LEN 100
>
> #ifdef PARSER_DEBUG
> @@ -2794,6 +2799,10 @@ void print_events(const char *event_glob, bool name_only, bool quiet_flag,
> print_sdt_events(NULL, NULL, name_only);
>
> metricgroup__print(true, true, NULL, name_only, details_flag);
> +
> +#ifdef HAVE_LIBPFM
> + print_libpfm_events(name_only);
> +#endif
> }
>
> int parse_events__is_hardcoded_term(struct parse_events_term *term)
> @@ -3042,3 +3051,240 @@ char *parse_events_formats_error_string(char *additional_terms)
> fail:
> return NULL;
> }
> +
> +#ifdef HAVE_LIBPFM
> +static int
> +parse_libpfm_event(char *strp, struct perf_event_attr *attr)
> +{
> + int ret;
> +
> + ret = pfm_get_perf_event_encoding(strp, PFM_PLM0|PFM_PLM3,
> + attr, NULL, NULL);
> + return ret;
> +}
> +
> +int parse_libpfm_events_option(const struct option *opt, const char *str,
> + int unset __maybe_unused)
> +{
> + struct evlist *evlist = *(struct evlist **)opt->value;
> + struct perf_event_attr attr;
> + struct perf_pmu *pmu;
> + struct evsel *evsel, *grp_leader = NULL;
> + char *p, *q, *p_orig;
> + const char *sep;
> + int grp_evt = -1;
> + int ret;
> +
> + p_orig = p = strdup(str);
> + if (!p)
> + return -1;
> + /*
> + * force loading of the PMU list
> + */
> + perf_pmu__scan(NULL);
> +
> + for (q = p; strsep(&p, ",{}"); q = p) {
> + sep = p ? str + (p - p_orig - 1) : "";
> + if (*sep == '{') {
> + if (grp_evt > -1) {
> + fprintf(stderr, "nested event groups not supported\n");
> + goto error;
> + }
> + grp_evt++;
> + }
> +
> + /* no event */
> + if (*q == '\0')
> + continue;
> +
> + memset(&attr, 0, sizeof(attr));
> + event_attr_init(&attr);
> +
> + ret = parse_libpfm_event(q, &attr);
> + if (ret != PFM_SUCCESS) {
> + fprintf(stderr, "failed to parse event %s : %s\n", str, pfm_strerror(ret));
> + goto error;
> + }
> +
> + evsel = perf_evsel__new_idx(&attr, evlist->core.nr_entries);
> + if (evsel == NULL)
> + goto error;
> +
> + evsel->name = strdup(q);
> + if (!evsel->name) {
> + evsel__delete(evsel);
> + goto error;
> + }
> + evsel->is_libpfm_event = true;
> +
> + pmu = perf_pmu__find_by_type((unsigned)attr.type);
> + if (pmu)
> + evsel->core.own_cpus = perf_cpu_map__get(pmu->cpus);
> +
> + evlist__add(evlist, evsel);
> +
> + if (grp_evt == 0)
> + grp_leader = evsel;
> +
> + if (grp_evt > -1) {
> + evsel->leader = grp_leader;
> + grp_leader->core.nr_members++;
> + grp_evt++;
> + }
> +
> + if (*sep == '}') {
> + if (grp_evt < 0) {
> + fprintf(stderr, "cannot close a non-existing event group\n");
> + goto error;
> + }
> + evlist->nr_groups++;
> + grp_leader = NULL;
> + grp_evt = -1;
> + }
> + }
> + return 0;
> +error:
> + free(p_orig);
> + return -1;
> +}
> +
> +static const char *srcs[PFM_ATTR_CTRL_MAX]={
> + [PFM_ATTR_CTRL_UNKNOWN] = "???",
> + [PFM_ATTR_CTRL_PMU] = "PMU",
> + [PFM_ATTR_CTRL_PERF_EVENT] = "perf_event",
> +};
> +
> +static void
> +print_attr_flags(pfm_event_attr_info_t *info)
> +{
> + int n = 0;
> +
> + if (info->is_dfl) {
> + printf("[default] ");
> + n++;
> + }
> +
> + if (info->is_precise) {
> + printf("[precise] ");
> + n++;
> + }
> +
> + if (!n)
> + printf("- ");
> +}
> +
> +static void
> +print_libpfm_detailed_events(pfm_pmu_info_t *pinfo, pfm_event_info_t *info)
> +{
> + pfm_event_attr_info_t ainfo;
> + const char *src;
> + int j, ret;
> +
> + ainfo.size = sizeof(ainfo);
> +
> + printf("\nName : %s\n", info->name);
> + printf("PMU : %s\n", pinfo->name);
> + printf("Desc : %s\n", info->desc);
> + printf("Equiv : %s\n", info->equiv ? info->equiv : "None");
> + printf("Code : 0x%"PRIx64"\n", info->code);
> +
> + pfm_for_each_event_attr(j, info) {
> + ret = pfm_get_event_attr_info(info->idx, j, PFM_OS_PERF_EVENT_EXT, &ainfo);
> + if (ret != PFM_SUCCESS)
> + continue;
> +
> + if (ainfo.ctrl >= PFM_ATTR_CTRL_MAX)
> + ainfo.ctrl = PFM_ATTR_CTRL_UNKNOWN;
> +
> + src = srcs[ainfo.ctrl];
> + switch(ainfo.type) {
> + case PFM_ATTR_UMASK:
> + printf("Umask : 0x%02"PRIx64" : %s: [%s] : ", ainfo.code, src, ainfo.name);
> + print_attr_flags(&ainfo);
> + printf(": %s\n", ainfo.desc);
> + break;
> + case PFM_ATTR_MOD_BOOL:
> + printf("Modif : %s: [%s] : %s (boolean)\n", src, ainfo.name, ainfo.desc);
> + break;
> + case PFM_ATTR_MOD_INTEGER:
> + printf("Modif : %s: [%s] : %s (integer)\n", src, ainfo.name, ainfo.desc);
> + break;
> + case PFM_ATTR_NONE:
> + case PFM_ATTR_RAW_UMASK:
> + case PFM_ATTR_MAX:
> + default:
> + printf("Attr : %s: [%s] : %s\n", src, ainfo.name, ainfo.desc);
> + }
> + }
> +}
> +
> +/*
> + * list all pmu::event:umask, pmu::event
> + * printed events may not be all valid combinations of umask for an event
> + */
> +static void
> +print_libpfm_simplified_events(pfm_pmu_info_t *pinfo, pfm_event_info_t *info)
> +{
> + pfm_event_attr_info_t ainfo;
> + int j, ret;
> + int um = 0;
> +
> + ainfo.size = sizeof(ainfo);
> +
> + pfm_for_each_event_attr(j, info) {
> + ret = pfm_get_event_attr_info(info->idx, j, PFM_OS_PERF_EVENT_EXT, &ainfo);
> + if (ret != PFM_SUCCESS)
> + continue;
> +
> + if (ainfo.type != PFM_ATTR_UMASK)
> + continue;
> +
> + printf("%s::%s:%s\n", pinfo->name, info->name, ainfo.name);
> + um++;
> + }
> + if (um == 0)
> + printf("%s::%s\n", pinfo->name, info->name);
> +}
> +
> +static void
> +print_libpfm_events(bool name_only)
> +{
> + pfm_event_info_t info;
> + pfm_pmu_info_t pinfo;
> + pfm_event_attr_info_t ainfo;
> + int i, p, ret;
> +
> + /* initialize to zero to indicate ABI version */
> + info.size = sizeof(info);
> + pinfo.size = sizeof(pinfo);
> + ainfo.size = sizeof(ainfo);
> +
> + putchar('\n');
> +
> + pfm_for_all_pmus(p) {
> + ret = pfm_get_pmu_info(p, &pinfo);
> + if (ret != PFM_SUCCESS)
> + continue;
> +
> + /* ony print events that are supported by host HW */
> + if (!pinfo.is_present)
> + continue;
> +
> + /* handled by perf directly */
> + if (pinfo.pmu == PFM_PMU_PERF_EVENT)
> + continue;
> +
> + for (i = pinfo.first_event; i != -1; i = pfm_get_event_next(i)) {
> +
> + ret = pfm_get_event_info(i, PFM_OS_PERF_EVENT_EXT, &info);
> + if (ret != PFM_SUCCESS)
> + continue;
> +
> + if (!name_only)
> + print_libpfm_detailed_events(&pinfo, &info);
> + else
> + print_libpfm_simplified_events(&pinfo, &info);
> + }
> + }
> +}
> +#endif
> diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
> index 27596cbd0ba0..84d4799c9a31 100644
> --- a/tools/perf/util/parse-events.h
> +++ b/tools/perf/util/parse-events.h
> @@ -37,6 +37,11 @@ int parse_events_terms(struct list_head *terms, const char *str);
> int parse_filter(const struct option *opt, const char *str, int unset);
> int exclude_perf(const struct option *opt, const char *arg, int unset);
>
> +#ifdef HAVE_LIBPFM
> +extern int parse_libpfm_events_option(const struct option *opt, const char *str,
> + int unset);
> +#endif
> +
> #define EVENTS_HELP_MAX (128*1024)
>
> enum perf_pmu_event_symbol_type {
> diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
> index 8b99fd312aae..9e4a70c7204a 100644
> --- a/tools/perf/util/pmu.c
> +++ b/tools/perf/util/pmu.c
> @@ -864,6 +864,17 @@ static struct perf_pmu *pmu_find(const char *name)
> return NULL;
> }
>
> +struct perf_pmu *perf_pmu__find_by_type(unsigned int type)
> +{
> + struct perf_pmu *pmu;
> +
> + list_for_each_entry(pmu, &pmus, list)
> + if (pmu->type == type)
> + return pmu;
> +
> + return NULL;
> +}
> +
> struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
> {
> /*
> diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
> index 6737e3d5d568..15a3253f1719 100644
> --- a/tools/perf/util/pmu.h
> +++ b/tools/perf/util/pmu.h
> @@ -64,6 +64,7 @@ struct perf_pmu_alias {
> };
>
> struct perf_pmu *perf_pmu__find(const char *name);
> +struct perf_pmu *perf_pmu__find_by_type(unsigned int type);
> int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
> struct list_head *head_terms,
> struct parse_events_error *error);
> --
> 2.25.1.481.gfbce0eb801-goog
>

--

- Arnaldo

2020-03-10 21:40:21

by Stephane Eranian

[permalink] [raw]
Subject: Re: [PATCH] perf tools: add support for lipfm4

On Tue, Mar 10, 2020 at 12:59 PM Andi Kleen <[email protected]> wrote:
>
> On Tue, Mar 10, 2020 at 11:50:03AM -0700, Ian Rogers wrote:
> > This patch links perf with the libpfm4 library.
> > This library contains all the hardware event tables for all
> > processors supported by perf_events. This is a helper library
> > that help convert from a symbolic event name to the event
> > encoding required by the underlying kernel interface. This
> > library is open-source and available from: http://perfmon2.sf.net.
>
> For most CPUs the builtin perf JSON event support should make
> this redundant.
>
We decided to post this patch to propose an alternative to the JSON
file approach. It could be an option during the build.
The libpfm4 library has been around for 15 years now. Therefore, it
supports a lot of processors core and uncore and it is very portable.
The key value add I see is that this is a library that can be, and has
been, used by tool developers directly in their apps. It can
work with more than Linux perf_events interface. It is not tied to the
interface. It has well defined and documented entry points.
We do use libpfm4 extensively at Google in both the perf tool and
applications. The PAPI toolkit also relies on this library.

I don't see this as competing with the JSON approach. It is just an
option I'd like to offer to users especially those familiar
with it in their apps.

> Perhaps you could list what CPUs it actually supports over
> the existing JSON tables.
>
> If it's only a few it would be likely better to add
> appropiate json files.
>
> If it's a massive number it might be useful, although
> JSON support would be better for those too.
>
> -Andi

2020-03-11 16:14:38

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH] perf tools: add support for lipfm4

On Tue, Mar 10, 2020 at 02:39:23PM -0700, Stephane Eranian wrote:
> On Tue, Mar 10, 2020 at 12:59 PM Andi Kleen <[email protected]> wrote:
> >
> > On Tue, Mar 10, 2020 at 11:50:03AM -0700, Ian Rogers wrote:
> > > This patch links perf with the libpfm4 library.
> > > This library contains all the hardware event tables for all
> > > processors supported by perf_events. This is a helper library
> > > that help convert from a symbolic event name to the event
> > > encoding required by the underlying kernel interface. This
> > > library is open-source and available from: http://perfmon2.sf.net.
> >
> > For most CPUs the builtin perf JSON event support should make
> > this redundant.
> >
> We decided to post this patch to propose an alternative to the JSON
> file approach. It could be an option during the build.
> The libpfm4 library has been around for 15 years now. Therefore, it
> supports a lot of processors core and uncore and it is very portable.
> The key value add I see is that this is a library that can be, and has
> been, used by tool developers directly in their apps. It can
> work with more than Linux perf_events interface. It is not tied to the
> interface. It has well defined and documented entry points.
> We do use libpfm4 extensively at Google in both the perf tool and
> applications. The PAPI toolkit also relies on this library.
>
> I don't see this as competing with the JSON approach. It is just an
> option I'd like to offer to users especially those familiar
> with it in their apps.

I dont mind having it, in fact I found really old email where I'm
asking Peter about that ;-) and he wasn't very keen about that:
https://lore.kernel.org/lkml/1312806326.10488.30.camel@twins/

not sure what was the actual reason at that time and if anything
changed since.. Peter?

btw I can't apply even that v2 on latest Arnaldo's branch

jirka

2020-03-11 19:33:28

by Ian Rogers

[permalink] [raw]
Subject: Re: [PATCH] perf tools: add support for lipfm4

On Wed, Mar 11, 2020 at 9:13 AM Jiri Olsa <[email protected]> wrote:
>
> On Tue, Mar 10, 2020 at 02:39:23PM -0700, Stephane Eranian wrote:
> > On Tue, Mar 10, 2020 at 12:59 PM Andi Kleen <[email protected]> wrote:
> > >
> > > On Tue, Mar 10, 2020 at 11:50:03AM -0700, Ian Rogers wrote:
> > > > This patch links perf with the libpfm4 library.
> > > > This library contains all the hardware event tables for all
> > > > processors supported by perf_events. This is a helper library
> > > > that help convert from a symbolic event name to the event
> > > > encoding required by the underlying kernel interface. This
> > > > library is open-source and available from: http://perfmon2.sf.net.
> > >
> > > For most CPUs the builtin perf JSON event support should make
> > > this redundant.
> > >
> > We decided to post this patch to propose an alternative to the JSON
> > file approach. It could be an option during the build.
> > The libpfm4 library has been around for 15 years now. Therefore, it
> > supports a lot of processors core and uncore and it is very portable.
> > The key value add I see is that this is a library that can be, and has
> > been, used by tool developers directly in their apps. It can
> > work with more than Linux perf_events interface. It is not tied to the
> > interface. It has well defined and documented entry points.
> > We do use libpfm4 extensively at Google in both the perf tool and
> > applications. The PAPI toolkit also relies on this library.
> >
> > I don't see this as competing with the JSON approach. It is just an
> > option I'd like to offer to users especially those familiar
> > with it in their apps.
>
> I dont mind having it, in fact I found really old email where I'm
> asking Peter about that ;-) and he wasn't very keen about that:
> https://lore.kernel.org/lkml/1312806326.10488.30.camel@twins/
>
> not sure what was the actual reason at that time and if anything
> changed since.. Peter?
>
> btw I can't apply even that v2 on latest Arnaldo's branch
>
> jirka

Thanks Jiri,

the patches were done on tip.git/master, perhaps there is a conflict
with the Documents Makefile due to adding better man page dates? I'll
try to repro building on
https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/ on the
perf/core branch unless you have a different suggestion? I also
noticed a warning crept into the Makefile.config in the v2 patch set
that should be removed.

Ian

2020-03-12 10:05:08

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH] perf tools: add support for lipfm4

On Wed, Mar 11, 2020 at 12:32:26PM -0700, Ian Rogers wrote:
> On Wed, Mar 11, 2020 at 9:13 AM Jiri Olsa <[email protected]> wrote:
> >
> > On Tue, Mar 10, 2020 at 02:39:23PM -0700, Stephane Eranian wrote:
> > > On Tue, Mar 10, 2020 at 12:59 PM Andi Kleen <[email protected]> wrote:
> > > >
> > > > On Tue, Mar 10, 2020 at 11:50:03AM -0700, Ian Rogers wrote:
> > > > > This patch links perf with the libpfm4 library.
> > > > > This library contains all the hardware event tables for all
> > > > > processors supported by perf_events. This is a helper library
> > > > > that help convert from a symbolic event name to the event
> > > > > encoding required by the underlying kernel interface. This
> > > > > library is open-source and available from: http://perfmon2.sf.net.
> > > >
> > > > For most CPUs the builtin perf JSON event support should make
> > > > this redundant.
> > > >
> > > We decided to post this patch to propose an alternative to the JSON
> > > file approach. It could be an option during the build.
> > > The libpfm4 library has been around for 15 years now. Therefore, it
> > > supports a lot of processors core and uncore and it is very portable.
> > > The key value add I see is that this is a library that can be, and has
> > > been, used by tool developers directly in their apps. It can
> > > work with more than Linux perf_events interface. It is not tied to the
> > > interface. It has well defined and documented entry points.
> > > We do use libpfm4 extensively at Google in both the perf tool and
> > > applications. The PAPI toolkit also relies on this library.
> > >
> > > I don't see this as competing with the JSON approach. It is just an
> > > option I'd like to offer to users especially those familiar
> > > with it in their apps.
> >
> > I dont mind having it, in fact I found really old email where I'm
> > asking Peter about that ;-) and he wasn't very keen about that:
> > https://lore.kernel.org/lkml/1312806326.10488.30.camel@twins/
> >
> > not sure what was the actual reason at that time and if anything
> > changed since.. Peter?
> >
> > btw I can't apply even that v2 on latest Arnaldo's branch
> >
> > jirka
>
> Thanks Jiri,
>
> the patches were done on tip.git/master, perhaps there is a conflict
> with the Documents Makefile due to adding better man page dates? I'll
> try to repro building on
> https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/ on the
> perf/core branch unless you have a different suggestion? I also

yes, it's perf/core

jirka