Received: by 2002:a25:e7d8:0:0:0:0:0 with SMTP id e207csp969799ybh; Tue, 10 Mar 2020 11:52:04 -0700 (PDT) X-Google-Smtp-Source: ADFU+vtrNzfK9PhQHvPaHls+YbSymcsbr447gqyo85dFYNLBN9Ue01qL2NWMSiZcgnRDT25ZdfqD X-Received: by 2002:aca:4843:: with SMTP id v64mr2157314oia.13.1583866324783; Tue, 10 Mar 2020 11:52:04 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1583866324; cv=none; d=google.com; s=arc-20160816; b=Q1D1KXaoGsH37XMQKYRGj4Tq4pu8J++bkEmv0af3fWZ5jaJWqU2O0RUw5wqr9NpMZD 6t3bFLMXJsImGC9vlsaKKgJpXJTQYh73/IfZXb1F8ET524oQawG7AIIBrFgVVNZpaFjp Qq/uUP1nxWD0jp39w/vKDGFqCmWydYayn0VYsqGNCEMiWlmo9ocWFQQJnKwBBpbQhUsz yKVrCb/ytRpp8g8Sb/61b1n8r4Dmrwz4Mgg5zHHEZS3zHv3kr+2TLqzLKNeo7FoBVlL9 ri9sqrEDbz3sWiQrJZsFu9s0JXrZwuo+4p5OgBYyZsudvCKLE7XWsMJOi/mt4GxM691G v2gQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:from:subject:mime-version :message-id:date:dkim-signature; bh=I1CSJFz81fTNKggDkChPEp4UnR5kldR5cwnH1hbOS98=; b=gUyyappDh7ZGZoIUTCNKn9l/tgUz7Vzi1x5Dl+9pmQg9LzOFXejiUOQgCMEsiGk5Ww QiSemF7NWteimwrHMalUwmvNPjrcKmSGS7ohusMIYa8mbCJknmfmBzIPYk1UvF6LX6HX q8hy41OHeATAxrBYOWWyUrNXWIcS/0PD4N7MjmHlXVwuzN5ixFZKTWlOREYYN1owCCBk P2yyL/i/7ZbE2910Rccf2/E2wFsU5JeJVJnMx4h0ZzYwy5jiwezXeecZD3bP2Wb9wODW KJ3iunp8qf1eT9++EpDclCOJQYEF/QIkULAVKTPsA1LmvCTNn0Pm/HqV6UeBevsDeEJ8 Ag7Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=Vv0dPj13; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id h7si8837733otk.84.2020.03.10.11.51.51; Tue, 10 Mar 2020 11:52:04 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=Vv0dPj13; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727124AbgCJSuW (ORCPT + 99 others); Tue, 10 Mar 2020 14:50:22 -0400 Received: from mail-qv1-f73.google.com ([209.85.219.73]:48050 "EHLO mail-qv1-f73.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726403AbgCJSuV (ORCPT ); Tue, 10 Mar 2020 14:50:21 -0400 Received: by mail-qv1-f73.google.com with SMTP id dr18so9727421qvb.14 for ; Tue, 10 Mar 2020 11:50:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:message-id:mime-version:subject:from:to:cc; bh=I1CSJFz81fTNKggDkChPEp4UnR5kldR5cwnH1hbOS98=; b=Vv0dPj138pDg0j4YPlHE/emzMqYhP8LaO0sYounrbNCuZle0tU7gwPndoHrwlkt+Am c1HM96MJCcnSIqEVIpHqcvts55mis5iCSiWkJfQWFZAVpCrT2R5W76aSB8+YR7j5xXOF DhWPGs5e0tE+sBZ6w9Nhsx12fx+SlLM41MBr/0jd8v6BQF2pjD2K2DN8TufW6H/pM2mo DxOMKoj+LbYMJnYzszoweIzIqC8aK4u2G5IWTbvkUhlkZoT0hmg33hIBnnidDAvpmy1l 32F1yWHgZIUvZ1Q0sQ3jIk4wzLZCaSOEpVlofkFI65cD27j0IDBjeGs1nM7eG/S5O3bi euHw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:message-id:mime-version:subject:from:to:cc; bh=I1CSJFz81fTNKggDkChPEp4UnR5kldR5cwnH1hbOS98=; b=OSSwciH2ixCrzDK49utxCeGmjatBFzCqZeRWIV9VoXKOVUY1yaj0dwllMlyt9F0ShN 0yVetZv7bfLd2vZpvMhuZXZ+6qi2ZqioG8hdlx4gcdHVnhRxRtxoTMLwPDhc6VJyBzub ycJK2u7xKiPzs2B4UU1I1qxWP9ZL4cxfVyMUBkdT6AcN8lQxsrOKL7CkYZF56FUfby51 /sQB54FqFuszj0AxWoNPSR7e3beHsYS5lNNrIboSxA5ZLXhKL/BbGjJQKFsFGkgTNVuF tKX6bUlY7H3kGAR0xghRFOiune49kU6F9avwMYkYJAa+jatTIuJeEkS7PrXQgbyEMNfO 7p3Q== X-Gm-Message-State: ANhLgQ0UKPCnygJm4eahRPrhbhcKiZNV1rFRcMMxv5cERAHIJPCZymOK QnwR4Sw4WfebTojzunr6u0Y8D2u/VzZ8 X-Received: by 2002:a05:6214:907:: with SMTP id dj7mr19974595qvb.245.1583866219345; Tue, 10 Mar 2020 11:50:19 -0700 (PDT) Date: Tue, 10 Mar 2020 11:50:03 -0700 Message-Id: <20200310185003.57344-1-irogers@google.com> Mime-Version: 1.0 X-Mailer: git-send-email 2.25.1.481.gfbce0eb801-goog Subject: [PATCH] perf tools: add support for lipfm4 From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Alexei Starovoitov , Daniel Borkmann , Martin KaFai Lau , Yonghong Song , Andrii Nakryiko , Greg Kroah-Hartman , Thomas Gleixner , Igor Lubashev , Alexey Budankov , Florian Fainelli , Adrian Hunter , Andi Kleen , Jiwei Sun , yuzhoujian , Kan Liang , Jin Yao , Leo Yan , John Garry , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, bpf@vger.kernel.org, linux-perf-users@vger.kernel.org Cc: Stephane Eranian , Ian Rogers Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 Signed-off-by: Ian Rogers --- 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, 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=:: 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 #include +#ifdef HAVE_LIBPFM +#include +#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 #include +#ifdef HAVE_LIBPFM +#include +#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 #include +#ifdef HAVE_LIBPFM +#include +#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 #include +#ifdef HAVE_LIBPFM +#include +#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 +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