Received: by 2002:ac0:b7d5:0:0:0:0:0 with SMTP id v21csp115154ime; Thu, 28 Jul 2022 19:22:38 -0700 (PDT) X-Google-Smtp-Source: AGRyM1vR+B3d7hlRHKAGCXXJU5HJFWA4m67z06nCgr++9CellPQaAYcajQiv3QKfr+bwVXfLok2D X-Received: by 2002:a05:6a00:228e:b0:52b:13d2:2627 with SMTP id f14-20020a056a00228e00b0052b13d22627mr1626858pfe.42.1659061358677; Thu, 28 Jul 2022 19:22:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1659061358; cv=none; d=google.com; s=arc-20160816; b=lL4tY0NNEzyZHVmojJg82kDBVCQHWMLRQbx7VIGY5Qzc56Na2jm+5PWn0aAxi4qE1X QfX1oSw2UzGTqQAU0LDrYkylYlr1T9qn322DN1CXXNOW9brDEM7RWnpdXChZV+sYigMg SAeQD/ct2KdIs/WdH5VFU9UjQrejyeducmkP6zHOUIOC1CPErtGjqBDEvBK9mV3GWNO6 AzofCugg1F0bs1RDXBYWAkw/vLvK/9HgwjaRrzV5Gxx55tid2AB0ZYT8rG2guOUJL5Ze XEaQLTpIoCFXwvsTHOo0SXKJA1YTmD+t9LWGoOuTT5o64OBex4yVykaYsBr+xT9GUcJE ZjtQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:subject:message-id:date:from:in-reply-to :references:mime-version:dkim-signature; bh=2TsSloMo9X9JB2Zc2anTY5efE+VYUd6fzf6ONi9Vae8=; b=0R5LeXkBBkuLCJnmr1Njp/vk3KwrZB2937fImgE0GnZUhyEc0NZd8nOdWED4IzbD0i WThwVpqFW1PhP6QGt0EYfMBT+A5tv/eW2oV6YO57hWfQGL/hdLhIdUWOD78E3cmY8oV2 2frYovUGJbZlGdFR8BQ2fDadw+IAFBVoX99I5r48SpATcXfEA7htxHiO0x9uYHOzRNSb 4a8Xx5giifzcWUg2f5CvTrAbuxF1xc36NeqhB2FkF2vSN0Rxi0s4AkQAeTMkaxmJFVmX zhwG7GJzB5px+tGodwCdGJLVGE5i3bz57C9qJCeSxgypZGXrYzFsZIZib3Wl/Fmw6Db8 zw+A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=cuRJ4s2N; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 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 out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id mu18-20020a17090b389200b001e6820f720esi7553867pjb.125.2022.07.28.19.22.23; Thu, 28 Jul 2022 19:22:38 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=cuRJ4s2N; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 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 S231352AbiG2CIB (ORCPT + 99 others); Thu, 28 Jul 2022 22:08:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33482 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230239AbiG2CH4 (ORCPT ); Thu, 28 Jul 2022 22:07:56 -0400 Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A6C957A533 for ; Thu, 28 Jul 2022 19:07:52 -0700 (PDT) Received: by mail-wr1-x42b.google.com with SMTP id j7so4353498wrh.3 for ; Thu, 28 Jul 2022 19:07:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=2TsSloMo9X9JB2Zc2anTY5efE+VYUd6fzf6ONi9Vae8=; b=cuRJ4s2NXMRwMSFBA5JjISRMIdwewiJ5TQ9QK6QVbUF7pGjznfB9SnJhUVIvMYyxGm gBsOUeJqgE/JLD7EjRNArEBHHlovLN8mftzq052DQ6DssOJAA8JBqQ+7ficeg+5rRYiT QQ29ZplatGMNhHUZM+k8cjMDmJwm/RGdg/NP1/mtdiIm+OeRZzrAON55mC4O7K+KQt/Y /TKtobp+TvcHEVeQEyjQnWPCMOiI9i3ucvhtqguRZkl978M1QLpJp9wBIJ97Y2XSJB3N 3XGwGNGu+hKuDdDGei4yK5IE+t64ONpsIXISaK1T+7t0oBPsABrpsubRUHvdFN9CSea6 6KCA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=2TsSloMo9X9JB2Zc2anTY5efE+VYUd6fzf6ONi9Vae8=; b=rBbajIXFYJqpjE/ankkzXJMSYcapc4z8nsL4r/5CS4+aaHKIC8LwwYWefFS1RVx4oo n4VWIkZsfCMEnhNa4B4fNOze/ntfCcrC66Rd2cEd9+7od5SW9ScwhDPLPo0mwBlmIV4G BnQHjTRQJA/+QN5ZbhFmHVitblUgCDUuuLbQb7CzmxXBcfOAr3nmNbUC1QNL5hnisKJE E0M8/TeKA09tbDWDuMh480h5z6dptfN7EAkUPngNqywKCkYYm4eYB+en+6w8aqHU+sih 2obgyvOz7bE+rETYrRNT5sVjeKHTWLszGUw+rp2MAzs86uBEcnG/A6nAs0z1EEJP7lZb mT+A== X-Gm-Message-State: ACgBeo39nPkyVbRqibUZofZfL3v5WerC8Cs7tFFT+qzeblTXYor/zsyV IGFLqJO8+YKTVwsfM1fL4dx0KmkjEFmizRP2VFYnGg== X-Received: by 2002:a05:6000:1a8e:b0:21d:a7a8:54f4 with SMTP id f14-20020a0560001a8e00b0021da7a854f4mr887741wry.654.1659060470546; Thu, 28 Jul 2022 19:07:50 -0700 (PDT) MIME-Version: 1.0 References: <20220707191209.273065-1-irogers@google.com> In-Reply-To: <20220707191209.273065-1-irogers@google.com> From: Ian Rogers Date: Thu, 28 Jul 2022 19:07:38 -0700 Message-ID: Subject: Re: [PATCH v2] perf parse-events: Break out tracepoint and printing. To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org Cc: Stephane Eranian Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-17.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, ENV_AND_HDR_SPF_MATCH,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS, USER_IN_DEF_DKIM_WL,USER_IN_DEF_SPF_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Thu, Jul 7, 2022 at 12:12 PM Ian Rogers wrote: > > Move print_*_events functions out of parse-events.c into a new > print-events.c. Move tracepoint code into tracepoint.c or > trace-event-info.c (sole user). This reduces the dependencies of > parse-events.c and makes it more amenable to being a library in the > future. > Remove some unnecessary definitions from parse-events.h. Fix a > checkpatch.pl warning on using unsigned rather than unsigned int. > Fix some line length warnings too. > > v2. Rebase in particular after hybrid PMU changes. Ping. Feedback appreciated. Thanks, Ian > Signed-off-by: Ian Rogers > --- > tools/perf/builtin-list.c | 2 +- > tools/perf/builtin-lock.c | 1 + > tools/perf/builtin-timechart.c | 1 + > tools/perf/builtin-trace.c | 1 + > tools/perf/util/Build | 2 + > tools/perf/util/parse-events.c | 714 +---------------------------- > tools/perf/util/parse-events.h | 31 -- > tools/perf/util/print-events.c | 571 +++++++++++++++++++++++ > tools/perf/util/print-events.h | 22 + > tools/perf/util/trace-event-info.c | 96 ++++ > tools/perf/util/tracepoint.c | 63 +++ > tools/perf/util/tracepoint.h | 25 + > 12 files changed, 790 insertions(+), 739 deletions(-) > create mode 100644 tools/perf/util/print-events.c > create mode 100644 tools/perf/util/print-events.h > create mode 100644 tools/perf/util/tracepoint.c > create mode 100644 tools/perf/util/tracepoint.h > > diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c > index 468958154ed9..744dd3520584 100644 > --- a/tools/perf/builtin-list.c > +++ b/tools/perf/builtin-list.c > @@ -10,7 +10,7 @@ > */ > #include "builtin.h" > > -#include "util/parse-events.h" > +#include "util/print-events.h" > #include "util/pmu.h" > #include "util/pmu-hybrid.h" > #include "util/debug.h" > diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c > index 23a33ac15e68..dcc079a80585 100644 > --- a/tools/perf/builtin-lock.c > +++ b/tools/perf/builtin-lock.c > @@ -13,6 +13,7 @@ > #include > #include > #include "util/trace-event.h" > +#include "util/tracepoint.h" > > #include "util/debug.h" > #include "util/session.h" > diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c > index afce731cec16..e2e9ad929baf 100644 > --- a/tools/perf/builtin-timechart.c > +++ b/tools/perf/builtin-timechart.c > @@ -36,6 +36,7 @@ > #include "util/data.h" > #include "util/debug.h" > #include "util/string2.h" > +#include "util/tracepoint.h" > #include > > #ifdef LACKS_OPEN_MEMSTREAM_PROTOTYPE > diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c > index 897fc504918b..f031bb9c287b 100644 > --- a/tools/perf/builtin-trace.c > +++ b/tools/perf/builtin-trace.c > @@ -53,6 +53,7 @@ > #include "trace-event.h" > #include "util/parse-events.h" > #include "util/bpf-loader.h" > +#include "util/tracepoint.h" > #include "callchain.h" > #include "print_binary.h" > #include "string2.h" > diff --git a/tools/perf/util/Build b/tools/perf/util/Build > index a51267d88ca9..038e4cf8f488 100644 > --- a/tools/perf/util/Build > +++ b/tools/perf/util/Build > @@ -26,6 +26,8 @@ perf-y += mmap.o > perf-y += memswap.o > perf-y += parse-events.o > perf-y += parse-events-hybrid.o > +perf-y += print-events.o > +perf-y += tracepoint.o > perf-y += perf_regs.o > perf-y += path.o > perf-y += print_binary.o > diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c > index 7ed235740431..206c76623c06 100644 > --- a/tools/perf/util/parse-events.c > +++ b/tools/perf/util/parse-events.c > @@ -5,18 +5,12 @@ > #include > #include > #include > -#include > -#include > -#include > #include > #include "term.h" > -#include "build-id.h" > #include "evlist.h" > #include "evsel.h" > -#include > #include > #include "parse-events.h" > -#include > #include "string2.h" > #include "strlist.h" > #include "bpf-loader.h" > @@ -24,23 +18,24 @@ > #include > #include > #include "parse-events-bison.h" > -#define YY_EXTRA_TYPE void* > #include "parse-events-flex.h" > #include "pmu.h" > -#include "thread_map.h" > -#include "probe-file.h" > #include "asm/bug.h" > #include "util/parse-branch-options.h" > -#include "metricgroup.h" > #include "util/evsel_config.h" > #include "util/event.h" > -#include "util/pfm.h" > +#include "perf.h" > #include "util/parse-events-hybrid.h" > #include "util/pmu-hybrid.h" > -#include "perf.h" > +#include "tracepoint.h" > > #define MAX_NAME_LEN 100 > > +struct perf_pmu_event_symbol { > + char *symbol; > + enum perf_pmu_event_symbol_type type; > +}; > + > #ifdef PARSER_DEBUG > extern int parse_events_debug; > #endif > @@ -154,21 +149,6 @@ struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = { > }, > }; > > -struct event_symbol event_symbols_tool[PERF_TOOL_MAX] = { > - [PERF_TOOL_DURATION_TIME] = { > - .symbol = "duration_time", > - .alias = "", > - }, > - [PERF_TOOL_USER_TIME] = { > - .symbol = "user_time", > - .alias = "", > - }, > - [PERF_TOOL_SYSTEM_TIME] = { > - .symbol = "system_time", > - .alias = "", > - }, > -}; > - > #define __PERF_EVENT_FIELD(config, name) \ > ((config & PERF_EVENT_##name##_MASK) >> PERF_EVENT_##name##_SHIFT) > > @@ -177,121 +157,6 @@ struct event_symbol event_symbols_tool[PERF_TOOL_MAX] = { > #define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) > #define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) > > -#define for_each_subsystem(sys_dir, sys_dirent) \ > - while ((sys_dirent = readdir(sys_dir)) != NULL) \ > - if (sys_dirent->d_type == DT_DIR && \ > - (strcmp(sys_dirent->d_name, ".")) && \ > - (strcmp(sys_dirent->d_name, ".."))) > - > -static int tp_event_has_id(const char *dir_path, struct dirent *evt_dir) > -{ > - char evt_path[MAXPATHLEN]; > - int fd; > - > - snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, evt_dir->d_name); > - fd = open(evt_path, O_RDONLY); > - if (fd < 0) > - return -EINVAL; > - close(fd); > - > - return 0; > -} > - > -#define for_each_event(dir_path, evt_dir, evt_dirent) \ > - while ((evt_dirent = readdir(evt_dir)) != NULL) \ > - if (evt_dirent->d_type == DT_DIR && \ > - (strcmp(evt_dirent->d_name, ".")) && \ > - (strcmp(evt_dirent->d_name, "..")) && \ > - (!tp_event_has_id(dir_path, evt_dirent))) > - > -#define MAX_EVENT_LENGTH 512 > - > -struct tracepoint_path *tracepoint_id_to_path(u64 config) > -{ > - struct tracepoint_path *path = NULL; > - DIR *sys_dir, *evt_dir; > - struct dirent *sys_dirent, *evt_dirent; > - char id_buf[24]; > - int fd; > - u64 id; > - char evt_path[MAXPATHLEN]; > - char *dir_path; > - > - sys_dir = tracing_events__opendir(); > - if (!sys_dir) > - return NULL; > - > - for_each_subsystem(sys_dir, sys_dirent) { > - dir_path = get_events_file(sys_dirent->d_name); > - if (!dir_path) > - continue; > - evt_dir = opendir(dir_path); > - if (!evt_dir) > - goto next; > - > - for_each_event(dir_path, evt_dir, evt_dirent) { > - > - scnprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, > - evt_dirent->d_name); > - fd = open(evt_path, O_RDONLY); > - if (fd < 0) > - continue; > - if (read(fd, id_buf, sizeof(id_buf)) < 0) { > - close(fd); > - continue; > - } > - close(fd); > - id = atoll(id_buf); > - if (id == config) { > - put_events_file(dir_path); > - closedir(evt_dir); > - closedir(sys_dir); > - path = zalloc(sizeof(*path)); > - if (!path) > - return NULL; > - if (asprintf(&path->system, "%.*s", MAX_EVENT_LENGTH, sys_dirent->d_name) < 0) { > - free(path); > - return NULL; > - } > - if (asprintf(&path->name, "%.*s", MAX_EVENT_LENGTH, evt_dirent->d_name) < 0) { > - zfree(&path->system); > - free(path); > - return NULL; > - } > - return path; > - } > - } > - closedir(evt_dir); > -next: > - put_events_file(dir_path); > - } > - > - closedir(sys_dir); > - return NULL; > -} > - > -struct tracepoint_path *tracepoint_name_to_path(const char *name) > -{ > - struct tracepoint_path *path = zalloc(sizeof(*path)); > - char *str = strchr(name, ':'); > - > - if (path == NULL || str == NULL) { > - free(path); > - return NULL; > - } > - > - path->system = strndup(name, str - name); > - path->name = strdup(str+1); > - > - if (path->system == NULL || path->name == NULL) { > - zfree(&path->system); > - zfree(&path->name); > - zfree(&path); > - } > - > - return path; > -} > - > const char *event_type(int type) > { > switch (type) { > @@ -2666,571 +2531,6 @@ int exclude_perf(const struct option *opt, > NULL); > } > > -static const char * const event_type_descriptors[] = { > - "Hardware event", > - "Software event", > - "Tracepoint event", > - "Hardware cache event", > - "Raw hardware event descriptor", > - "Hardware breakpoint", > -}; > - > -static int cmp_string(const void *a, const void *b) > -{ > - const char * const *as = a; > - const char * const *bs = b; > - > - return strcmp(*as, *bs); > -} > - > -/* > - * Print the events from /tracing/events > - */ > - > -void print_tracepoint_events(const char *subsys_glob, const char *event_glob, > - bool name_only) > -{ > - DIR *sys_dir, *evt_dir; > - struct dirent *sys_dirent, *evt_dirent; > - char evt_path[MAXPATHLEN]; > - char *dir_path; > - char **evt_list = NULL; > - unsigned int evt_i = 0, evt_num = 0; > - bool evt_num_known = false; > - > -restart: > - sys_dir = tracing_events__opendir(); > - if (!sys_dir) > - return; > - > - if (evt_num_known) { > - evt_list = zalloc(sizeof(char *) * evt_num); > - if (!evt_list) > - goto out_close_sys_dir; > - } > - > - for_each_subsystem(sys_dir, sys_dirent) { > - if (subsys_glob != NULL && > - !strglobmatch(sys_dirent->d_name, subsys_glob)) > - continue; > - > - dir_path = get_events_file(sys_dirent->d_name); > - if (!dir_path) > - continue; > - evt_dir = opendir(dir_path); > - if (!evt_dir) > - goto next; > - > - for_each_event(dir_path, evt_dir, evt_dirent) { > - if (event_glob != NULL && > - !strglobmatch(evt_dirent->d_name, event_glob)) > - continue; > - > - if (!evt_num_known) { > - evt_num++; > - continue; > - } > - > - snprintf(evt_path, MAXPATHLEN, "%s:%s", > - sys_dirent->d_name, evt_dirent->d_name); > - > - evt_list[evt_i] = strdup(evt_path); > - if (evt_list[evt_i] == NULL) { > - put_events_file(dir_path); > - goto out_close_evt_dir; > - } > - evt_i++; > - } > - closedir(evt_dir); > -next: > - put_events_file(dir_path); > - } > - closedir(sys_dir); > - > - if (!evt_num_known) { > - evt_num_known = true; > - goto restart; > - } > - qsort(evt_list, evt_num, sizeof(char *), cmp_string); > - evt_i = 0; > - while (evt_i < evt_num) { > - if (name_only) { > - printf("%s ", evt_list[evt_i++]); > - continue; > - } > - printf(" %-50s [%s]\n", evt_list[evt_i++], > - event_type_descriptors[PERF_TYPE_TRACEPOINT]); > - } > - if (evt_num && pager_in_use()) > - printf("\n"); > - > -out_free: > - evt_num = evt_i; > - for (evt_i = 0; evt_i < evt_num; evt_i++) > - zfree(&evt_list[evt_i]); > - zfree(&evt_list); > - return; > - > -out_close_evt_dir: > - closedir(evt_dir); > -out_close_sys_dir: > - closedir(sys_dir); > - > - printf("FATAL: not enough memory to print %s\n", > - event_type_descriptors[PERF_TYPE_TRACEPOINT]); > - if (evt_list) > - goto out_free; > -} > - > -/* > - * Check whether event is in /tracing/events > - */ > - > -int is_valid_tracepoint(const char *event_string) > -{ > - DIR *sys_dir, *evt_dir; > - struct dirent *sys_dirent, *evt_dirent; > - char evt_path[MAXPATHLEN]; > - char *dir_path; > - > - sys_dir = tracing_events__opendir(); > - if (!sys_dir) > - return 0; > - > - for_each_subsystem(sys_dir, sys_dirent) { > - dir_path = get_events_file(sys_dirent->d_name); > - if (!dir_path) > - continue; > - evt_dir = opendir(dir_path); > - if (!evt_dir) > - goto next; > - > - for_each_event(dir_path, evt_dir, evt_dirent) { > - snprintf(evt_path, MAXPATHLEN, "%s:%s", > - sys_dirent->d_name, evt_dirent->d_name); > - if (!strcmp(evt_path, event_string)) { > - closedir(evt_dir); > - closedir(sys_dir); > - return 1; > - } > - } > - closedir(evt_dir); > -next: > - put_events_file(dir_path); > - } > - closedir(sys_dir); > - return 0; > -} > - > -static bool is_event_supported(u8 type, u64 config) > -{ > - bool ret = true; > - int open_return; > - struct evsel *evsel; > - struct perf_event_attr attr = { > - .type = type, > - .config = config, > - .disabled = 1, > - }; > - struct perf_thread_map *tmap = thread_map__new_by_tid(0); > - > - if (tmap == NULL) > - return false; > - > - evsel = evsel__new(&attr); > - if (evsel) { > - open_return = evsel__open(evsel, NULL, tmap); > - ret = open_return >= 0; > - > - if (open_return == -EACCES) { > - /* > - * This happens if the paranoid value > - * /proc/sys/kernel/perf_event_paranoid is set to 2 > - * Re-run with exclude_kernel set; we don't do that > - * by default as some ARM machines do not support it. > - * > - */ > - evsel->core.attr.exclude_kernel = 1; > - ret = evsel__open(evsel, NULL, tmap) >= 0; > - } > - evsel__delete(evsel); > - } > - > - perf_thread_map__put(tmap); > - return ret; > -} > - > -void print_sdt_events(const char *subsys_glob, const char *event_glob, > - bool name_only) > -{ > - struct probe_cache *pcache; > - struct probe_cache_entry *ent; > - struct strlist *bidlist, *sdtlist; > - struct strlist_config cfg = {.dont_dupstr = true}; > - struct str_node *nd, *nd2; > - char *buf, *path, *ptr = NULL; > - bool show_detail = false; > - int ret; > - > - sdtlist = strlist__new(NULL, &cfg); > - if (!sdtlist) { > - pr_debug("Failed to allocate new strlist for SDT\n"); > - return; > - } > - bidlist = build_id_cache__list_all(true); > - if (!bidlist) { > - pr_debug("Failed to get buildids: %d\n", errno); > - return; > - } > - strlist__for_each_entry(nd, bidlist) { > - pcache = probe_cache__new(nd->s, NULL); > - if (!pcache) > - continue; > - list_for_each_entry(ent, &pcache->entries, node) { > - if (!ent->sdt) > - continue; > - if (subsys_glob && > - !strglobmatch(ent->pev.group, subsys_glob)) > - continue; > - if (event_glob && > - !strglobmatch(ent->pev.event, event_glob)) > - continue; > - ret = asprintf(&buf, "%s:%s@%s", ent->pev.group, > - ent->pev.event, nd->s); > - if (ret > 0) > - strlist__add(sdtlist, buf); > - } > - probe_cache__delete(pcache); > - } > - strlist__delete(bidlist); > - > - strlist__for_each_entry(nd, sdtlist) { > - buf = strchr(nd->s, '@'); > - if (buf) > - *(buf++) = '\0'; > - if (name_only) { > - printf("%s ", nd->s); > - continue; > - } > - nd2 = strlist__next(nd); > - if (nd2) { > - ptr = strchr(nd2->s, '@'); > - if (ptr) > - *ptr = '\0'; > - if (strcmp(nd->s, nd2->s) == 0) > - show_detail = true; > - } > - if (show_detail) { > - path = build_id_cache__origname(buf); > - ret = asprintf(&buf, "%s@%s(%.12s)", nd->s, path, buf); > - if (ret > 0) { > - printf(" %-50s [%s]\n", buf, "SDT event"); > - free(buf); > - } > - free(path); > - } else > - printf(" %-50s [%s]\n", nd->s, "SDT event"); > - if (nd2) { > - if (strcmp(nd->s, nd2->s) != 0) > - show_detail = false; > - if (ptr) > - *ptr = '@'; > - } > - } > - strlist__delete(sdtlist); > -} > - > -int print_hwcache_events(const char *event_glob, bool name_only) > -{ > - unsigned int type, op, i, evt_i = 0, evt_num = 0, npmus = 0; > - char name[64], new_name[128]; > - char **evt_list = NULL, **evt_pmus = NULL; > - bool evt_num_known = false; > - struct perf_pmu *pmu = NULL; > - > - if (perf_pmu__has_hybrid()) { > - npmus = perf_pmu__hybrid_pmu_num(); > - evt_pmus = zalloc(sizeof(char *) * npmus); > - if (!evt_pmus) > - goto out_enomem; > - } > - > -restart: > - if (evt_num_known) { > - evt_list = zalloc(sizeof(char *) * evt_num); > - if (!evt_list) > - goto out_enomem; > - } > - > - for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { > - for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { > - /* skip invalid cache type */ > - if (!evsel__is_cache_op_valid(type, op)) > - continue; > - > - for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { > - unsigned int hybrid_supported = 0, j; > - bool supported; > - > - __evsel__hw_cache_type_op_res_name(type, op, i, name, sizeof(name)); > - if (event_glob != NULL && !strglobmatch(name, event_glob)) > - continue; > - > - if (!perf_pmu__has_hybrid()) { > - if (!is_event_supported(PERF_TYPE_HW_CACHE, > - type | (op << 8) | (i << 16))) { > - continue; > - } > - } else { > - perf_pmu__for_each_hybrid_pmu(pmu) { > - if (!evt_num_known) { > - evt_num++; > - continue; > - } > - > - supported = is_event_supported( > - PERF_TYPE_HW_CACHE, > - type | (op << 8) | (i << 16) | > - ((__u64)pmu->type << PERF_PMU_TYPE_SHIFT)); > - if (supported) { > - snprintf(new_name, sizeof(new_name), "%s/%s/", > - pmu->name, name); > - evt_pmus[hybrid_supported] = strdup(new_name); > - hybrid_supported++; > - } > - } > - > - if (hybrid_supported == 0) > - continue; > - } > - > - if (!evt_num_known) { > - evt_num++; > - continue; > - } > - > - if ((hybrid_supported == 0) || > - (hybrid_supported == npmus)) { > - evt_list[evt_i] = strdup(name); > - if (npmus > 0) { > - for (j = 0; j < npmus; j++) > - zfree(&evt_pmus[j]); > - } > - } else { > - for (j = 0; j < hybrid_supported; j++) { > - evt_list[evt_i++] = evt_pmus[j]; > - evt_pmus[j] = NULL; > - } > - continue; > - } > - > - if (evt_list[evt_i] == NULL) > - goto out_enomem; > - evt_i++; > - } > - } > - } > - > - if (!evt_num_known) { > - evt_num_known = true; > - goto restart; > - } > - > - for (evt_i = 0; evt_i < evt_num; evt_i++) { > - if (!evt_list[evt_i]) > - break; > - } > - > - evt_num = evt_i; > - qsort(evt_list, evt_num, sizeof(char *), cmp_string); > - evt_i = 0; > - while (evt_i < evt_num) { > - if (name_only) { > - printf("%s ", evt_list[evt_i++]); > - continue; > - } > - printf(" %-50s [%s]\n", evt_list[evt_i++], > - event_type_descriptors[PERF_TYPE_HW_CACHE]); > - } > - if (evt_num && pager_in_use()) > - printf("\n"); > - > -out_free: > - evt_num = evt_i; > - for (evt_i = 0; evt_i < evt_num; evt_i++) > - zfree(&evt_list[evt_i]); > - zfree(&evt_list); > - > - for (evt_i = 0; evt_i < npmus; evt_i++) > - zfree(&evt_pmus[evt_i]); > - zfree(&evt_pmus); > - return evt_num; > - > -out_enomem: > - printf("FATAL: not enough memory to print %s\n", event_type_descriptors[PERF_TYPE_HW_CACHE]); > - if (evt_list) > - goto out_free; > - return evt_num; > -} > - > -static void print_tool_event(const struct event_symbol *syms, const char *event_glob, > - bool name_only) > -{ > - if (syms->symbol == NULL) > - return; > - > - if (event_glob && !(strglobmatch(syms->symbol, event_glob) || > - (syms->alias && strglobmatch(syms->alias, event_glob)))) > - return; > - > - if (name_only) > - printf("%s ", syms->symbol); > - else { > - char name[MAX_NAME_LEN]; > - if (syms->alias && strlen(syms->alias)) > - snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); > - else > - strlcpy(name, syms->symbol, MAX_NAME_LEN); > - printf(" %-50s [%s]\n", name, "Tool event"); > - } > -} > - > -void print_tool_events(const char *event_glob, bool name_only) > -{ > - // Start at 1 because the first enum entry symbols no tool event > - for (int i = 1; i < PERF_TOOL_MAX; ++i) { > - print_tool_event(event_symbols_tool + i, event_glob, name_only); > - } > - if (pager_in_use()) > - printf("\n"); > -} > - > -void print_symbol_events(const char *event_glob, unsigned type, > - struct event_symbol *syms, unsigned max, > - bool name_only) > -{ > - unsigned int i, evt_i = 0, evt_num = 0; > - char name[MAX_NAME_LEN]; > - char **evt_list = NULL; > - bool evt_num_known = false; > - > -restart: > - if (evt_num_known) { > - evt_list = zalloc(sizeof(char *) * evt_num); > - if (!evt_list) > - goto out_enomem; > - syms -= max; > - } > - > - for (i = 0; i < max; i++, syms++) { > - /* > - * New attr.config still not supported here, the latest > - * example was PERF_COUNT_SW_CGROUP_SWITCHES > - */ > - if (syms->symbol == NULL) > - continue; > - > - if (event_glob != NULL && !(strglobmatch(syms->symbol, event_glob) || > - (syms->alias && strglobmatch(syms->alias, event_glob)))) > - continue; > - > - if (!is_event_supported(type, i)) > - continue; > - > - if (!evt_num_known) { > - evt_num++; > - continue; > - } > - > - if (!name_only && strlen(syms->alias)) > - snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); > - else > - strlcpy(name, syms->symbol, MAX_NAME_LEN); > - > - evt_list[evt_i] = strdup(name); > - if (evt_list[evt_i] == NULL) > - goto out_enomem; > - evt_i++; > - } > - > - if (!evt_num_known) { > - evt_num_known = true; > - goto restart; > - } > - qsort(evt_list, evt_num, sizeof(char *), cmp_string); > - evt_i = 0; > - while (evt_i < evt_num) { > - if (name_only) { > - printf("%s ", evt_list[evt_i++]); > - continue; > - } > - printf(" %-50s [%s]\n", evt_list[evt_i++], event_type_descriptors[type]); > - } > - if (evt_num && pager_in_use()) > - printf("\n"); > - > -out_free: > - evt_num = evt_i; > - for (evt_i = 0; evt_i < evt_num; evt_i++) > - zfree(&evt_list[evt_i]); > - zfree(&evt_list); > - return; > - > -out_enomem: > - printf("FATAL: not enough memory to print %s\n", event_type_descriptors[type]); > - if (evt_list) > - goto out_free; > -} > - > -/* > - * Print the help text for the event symbols: > - */ > -void print_events(const char *event_glob, bool name_only, bool quiet_flag, > - bool long_desc, bool details_flag, bool deprecated, > - const char *pmu_name) > -{ > - print_symbol_events(event_glob, PERF_TYPE_HARDWARE, > - event_symbols_hw, PERF_COUNT_HW_MAX, name_only); > - > - print_symbol_events(event_glob, PERF_TYPE_SOFTWARE, > - event_symbols_sw, PERF_COUNT_SW_MAX, name_only); > - print_tool_events(event_glob, name_only); > - > - print_hwcache_events(event_glob, name_only); > - > - print_pmu_events(event_glob, name_only, quiet_flag, long_desc, > - details_flag, deprecated, pmu_name); > - > - if (event_glob != NULL) > - return; > - > - if (!name_only) { > - printf(" %-50s [%s]\n", > - "rNNN", > - event_type_descriptors[PERF_TYPE_RAW]); > - printf(" %-50s [%s]\n", > - "cpu/t1=v1[,t2=v2,t3 ...]/modifier", > - event_type_descriptors[PERF_TYPE_RAW]); > - if (pager_in_use()) > - printf(" (see 'man perf-list' on how to encode it)\n\n"); > - > - printf(" %-50s [%s]\n", > - "mem:[/len][:access]", > - event_type_descriptors[PERF_TYPE_BREAKPOINT]); > - if (pager_in_use()) > - printf("\n"); > - } > - > - print_tracepoint_events(NULL, NULL, name_only); > - > - print_sdt_events(NULL, NULL, name_only); > - > - metricgroup__print(true, true, NULL, name_only, details_flag, > - pmu_name); > - > - print_libpfm_events(name_only, long_desc); > -} > - > int parse_events__is_hardcoded_term(struct parse_events_term *term) > { > return term->type_term != PARSE_EVENTS__TERM_TYPE_USER; > diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h > index a38b8b160e80..ba9fa3ddaf6e 100644 > --- a/tools/perf/util/parse-events.h > +++ b/tools/perf/util/parse-events.h > @@ -11,7 +11,6 @@ > #include > #include > > -struct list_head; > struct evsel; > struct evlist; > struct parse_events_error; > @@ -19,14 +18,6 @@ struct parse_events_error; > struct option; > struct perf_pmu; > > -struct tracepoint_path { > - char *system; > - char *name; > - struct tracepoint_path *next; > -}; > - > -struct tracepoint_path *tracepoint_id_to_path(u64 config); > -struct tracepoint_path *tracepoint_name_to_path(const char *name); > bool have_tracepoints(struct list_head *evlist); > > const char *event_type(int type); > @@ -46,8 +37,6 @@ 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); > > -#define EVENTS_HELP_MAX (128*1024) > - > enum perf_pmu_event_symbol_type { > PMU_EVENT_SYMBOL_ERR, /* not a PMU EVENT */ > PMU_EVENT_SYMBOL, /* normal style PMU event */ > @@ -56,11 +45,6 @@ enum perf_pmu_event_symbol_type { > PMU_EVENT_SYMBOL_SUFFIX2, /* suffix of pre-suf2 style event */ > }; > > -struct perf_pmu_event_symbol { > - char *symbol; > - enum perf_pmu_event_symbol_type type; > -}; > - > enum { > PARSE_EVENTS__TERM_TYPE_NUM, > PARSE_EVENTS__TERM_TYPE_STR, > @@ -219,28 +203,13 @@ void parse_events_update_lists(struct list_head *list_event, > void parse_events_evlist_error(struct parse_events_state *parse_state, > int idx, const char *str); > > -void print_events(const char *event_glob, bool name_only, bool quiet, > - bool long_desc, bool details_flag, bool deprecated, > - const char *pmu_name); > - > struct event_symbol { > const char *symbol; > const char *alias; > }; > extern struct event_symbol event_symbols_hw[]; > extern struct event_symbol event_symbols_sw[]; > -void print_symbol_events(const char *event_glob, unsigned type, > - struct event_symbol *syms, unsigned max, > - bool name_only); > -void print_tool_events(const char *event_glob, bool name_only); > -void print_tracepoint_events(const char *subsys_glob, const char *event_glob, > - bool name_only); > -int print_hwcache_events(const char *event_glob, bool name_only); > -void print_sdt_events(const char *subsys_glob, const char *event_glob, > - bool name_only); > -int is_valid_tracepoint(const char *event_string); > > -int valid_event_mount(const char *eventfs); > char *parse_events_formats_error_string(char *additional_terms); > > void parse_events_error__init(struct parse_events_error *err); > diff --git a/tools/perf/util/print-events.c b/tools/perf/util/print-events.c > new file mode 100644 > index 000000000000..3b071e57b4a0 > --- /dev/null > +++ b/tools/perf/util/print-events.c > @@ -0,0 +1,571 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > + > +#include "build-id.h" > +#include "debug.h" > +#include "evsel.h" > +#include "metricgroup.h" > +#include "parse-events.h" > +#include "pmu.h" > +#include "print-events.h" > +#include "probe-file.h" > +#include "string2.h" > +#include "strlist.h" > +#include "thread_map.h" > +#include "tracepoint.h" > +#include "pfm.h" > +#include "pmu-hybrid.h" > + > +#define MAX_NAME_LEN 100 > + > +static const char * const event_type_descriptors[] = { > + "Hardware event", > + "Software event", > + "Tracepoint event", > + "Hardware cache event", > + "Raw hardware event descriptor", > + "Hardware breakpoint", > +}; > + > +static const struct event_symbol event_symbols_tool[PERF_TOOL_MAX] = { > + [PERF_TOOL_DURATION_TIME] = { > + .symbol = "duration_time", > + .alias = "", > + }, > + [PERF_TOOL_USER_TIME] = { > + .symbol = "user_time", > + .alias = "", > + }, > + [PERF_TOOL_SYSTEM_TIME] = { > + .symbol = "system_time", > + .alias = "", > + }, > +}; > + > +static int cmp_string(const void *a, const void *b) > +{ > + const char * const *as = a; > + const char * const *bs = b; > + > + return strcmp(*as, *bs); > +} > + > +/* > + * Print the events from /tracing/events > + */ > +void print_tracepoint_events(const char *subsys_glob, > + const char *event_glob, bool name_only) > +{ > + DIR *sys_dir, *evt_dir; > + struct dirent *sys_dirent, *evt_dirent; > + char evt_path[MAXPATHLEN]; > + char *dir_path; > + char **evt_list = NULL; > + unsigned int evt_i = 0, evt_num = 0; > + bool evt_num_known = false; > + > +restart: > + sys_dir = tracing_events__opendir(); > + if (!sys_dir) > + return; > + > + if (evt_num_known) { > + evt_list = zalloc(sizeof(char *) * evt_num); > + if (!evt_list) > + goto out_close_sys_dir; > + } > + > + for_each_subsystem(sys_dir, sys_dirent) { > + if (subsys_glob != NULL && > + !strglobmatch(sys_dirent->d_name, subsys_glob)) > + continue; > + > + dir_path = get_events_file(sys_dirent->d_name); > + if (!dir_path) > + continue; > + evt_dir = opendir(dir_path); > + if (!evt_dir) > + goto next; > + > + for_each_event(dir_path, evt_dir, evt_dirent) { > + if (event_glob != NULL && > + !strglobmatch(evt_dirent->d_name, event_glob)) > + continue; > + > + if (!evt_num_known) { > + evt_num++; > + continue; > + } > + > + snprintf(evt_path, MAXPATHLEN, "%s:%s", > + sys_dirent->d_name, evt_dirent->d_name); > + > + evt_list[evt_i] = strdup(evt_path); > + if (evt_list[evt_i] == NULL) { > + put_events_file(dir_path); > + goto out_close_evt_dir; > + } > + evt_i++; > + } > + closedir(evt_dir); > +next: > + put_events_file(dir_path); > + } > + closedir(sys_dir); > + > + if (!evt_num_known) { > + evt_num_known = true; > + goto restart; > + } > + qsort(evt_list, evt_num, sizeof(char *), cmp_string); > + evt_i = 0; > + while (evt_i < evt_num) { > + if (name_only) { > + printf("%s ", evt_list[evt_i++]); > + continue; > + } > + printf(" %-50s [%s]\n", evt_list[evt_i++], > + event_type_descriptors[PERF_TYPE_TRACEPOINT]); > + } > + if (evt_num && pager_in_use()) > + printf("\n"); > + > +out_free: > + evt_num = evt_i; > + for (evt_i = 0; evt_i < evt_num; evt_i++) > + zfree(&evt_list[evt_i]); > + zfree(&evt_list); > + return; > + > +out_close_evt_dir: > + closedir(evt_dir); > +out_close_sys_dir: > + closedir(sys_dir); > + > + printf("FATAL: not enough memory to print %s\n", > + event_type_descriptors[PERF_TYPE_TRACEPOINT]); > + if (evt_list) > + goto out_free; > +} > + > +void print_sdt_events(const char *subsys_glob, const char *event_glob, > + bool name_only) > +{ > + struct probe_cache *pcache; > + struct probe_cache_entry *ent; > + struct strlist *bidlist, *sdtlist; > + struct strlist_config cfg = {.dont_dupstr = true}; > + struct str_node *nd, *nd2; > + char *buf, *path, *ptr = NULL; > + bool show_detail = false; > + int ret; > + > + sdtlist = strlist__new(NULL, &cfg); > + if (!sdtlist) { > + pr_debug("Failed to allocate new strlist for SDT\n"); > + return; > + } > + bidlist = build_id_cache__list_all(true); > + if (!bidlist) { > + pr_debug("Failed to get buildids: %d\n", errno); > + return; > + } > + strlist__for_each_entry(nd, bidlist) { > + pcache = probe_cache__new(nd->s, NULL); > + if (!pcache) > + continue; > + list_for_each_entry(ent, &pcache->entries, node) { > + if (!ent->sdt) > + continue; > + if (subsys_glob && > + !strglobmatch(ent->pev.group, subsys_glob)) > + continue; > + if (event_glob && > + !strglobmatch(ent->pev.event, event_glob)) > + continue; > + ret = asprintf(&buf, "%s:%s@%s", ent->pev.group, > + ent->pev.event, nd->s); > + if (ret > 0) > + strlist__add(sdtlist, buf); > + } > + probe_cache__delete(pcache); > + } > + strlist__delete(bidlist); > + > + strlist__for_each_entry(nd, sdtlist) { > + buf = strchr(nd->s, '@'); > + if (buf) > + *(buf++) = '\0'; > + if (name_only) { > + printf("%s ", nd->s); > + continue; > + } > + nd2 = strlist__next(nd); > + if (nd2) { > + ptr = strchr(nd2->s, '@'); > + if (ptr) > + *ptr = '\0'; > + if (strcmp(nd->s, nd2->s) == 0) > + show_detail = true; > + } > + if (show_detail) { > + path = build_id_cache__origname(buf); > + ret = asprintf(&buf, "%s@%s(%.12s)", nd->s, path, buf); > + if (ret > 0) { > + printf(" %-50s [%s]\n", buf, "SDT event"); > + free(buf); > + } > + free(path); > + } else > + printf(" %-50s [%s]\n", nd->s, "SDT event"); > + if (nd2) { > + if (strcmp(nd->s, nd2->s) != 0) > + show_detail = false; > + if (ptr) > + *ptr = '@'; > + } > + } > + strlist__delete(sdtlist); > +} > + > +static bool is_event_supported(u8 type, unsigned int config) > +{ > + bool ret = true; > + int open_return; > + struct evsel *evsel; > + struct perf_event_attr attr = { > + .type = type, > + .config = config, > + .disabled = 1, > + }; > + struct perf_thread_map *tmap = thread_map__new_by_tid(0); > + > + if (tmap == NULL) > + return false; > + > + evsel = evsel__new(&attr); > + if (evsel) { > + open_return = evsel__open(evsel, NULL, tmap); > + ret = open_return >= 0; > + > + if (open_return == -EACCES) { > + /* > + * This happens if the paranoid value > + * /proc/sys/kernel/perf_event_paranoid is set to 2 > + * Re-run with exclude_kernel set; we don't do that > + * by default as some ARM machines do not support it. > + * > + */ > + evsel->core.attr.exclude_kernel = 1; > + ret = evsel__open(evsel, NULL, tmap) >= 0; > + } > + evsel__delete(evsel); > + } > + > + perf_thread_map__put(tmap); > + return ret; > +} > + > +int print_hwcache_events(const char *event_glob, bool name_only) > +{ > + unsigned int type, op, i, evt_i = 0, evt_num = 0, npmus = 0; > + char name[64], new_name[128]; > + char **evt_list = NULL, **evt_pmus = NULL; > + bool evt_num_known = false; > + struct perf_pmu *pmu = NULL; > + > + if (perf_pmu__has_hybrid()) { > + npmus = perf_pmu__hybrid_pmu_num(); > + evt_pmus = zalloc(sizeof(char *) * npmus); > + if (!evt_pmus) > + goto out_enomem; > + } > + > +restart: > + if (evt_num_known) { > + evt_list = zalloc(sizeof(char *) * evt_num); > + if (!evt_list) > + goto out_enomem; > + } > + > + for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { > + for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { > + /* skip invalid cache type */ > + if (!evsel__is_cache_op_valid(type, op)) > + continue; > + > + for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { > + unsigned int hybrid_supported = 0, j; > + bool supported; > + > + __evsel__hw_cache_type_op_res_name(type, op, i, name, sizeof(name)); > + if (event_glob != NULL && !strglobmatch(name, event_glob)) > + continue; > + > + if (!perf_pmu__has_hybrid()) { > + if (!is_event_supported(PERF_TYPE_HW_CACHE, > + type | (op << 8) | (i << 16))) { > + continue; > + } > + } else { > + perf_pmu__for_each_hybrid_pmu(pmu) { > + if (!evt_num_known) { > + evt_num++; > + continue; > + } > + > + supported = is_event_supported( > + PERF_TYPE_HW_CACHE, > + type | (op << 8) | (i << 16) | > + ((__u64)pmu->type << PERF_PMU_TYPE_SHIFT)); > + if (supported) { > + snprintf(new_name, sizeof(new_name), > + "%s/%s/", pmu->name, name); > + evt_pmus[hybrid_supported] = > + strdup(new_name); > + hybrid_supported++; > + } > + } > + > + if (hybrid_supported == 0) > + continue; > + } > + > + if (!evt_num_known) { > + evt_num++; > + continue; > + } > + > + if ((hybrid_supported == 0) || > + (hybrid_supported == npmus)) { > + evt_list[evt_i] = strdup(name); > + if (npmus > 0) { > + for (j = 0; j < npmus; j++) > + zfree(&evt_pmus[j]); > + } > + } else { > + for (j = 0; j < hybrid_supported; j++) { > + evt_list[evt_i++] = evt_pmus[j]; > + evt_pmus[j] = NULL; > + } > + continue; > + } > + > + if (evt_list[evt_i] == NULL) > + goto out_enomem; > + evt_i++; > + } > + } > + } > + > + if (!evt_num_known) { > + evt_num_known = true; > + goto restart; > + } > + > + for (evt_i = 0; evt_i < evt_num; evt_i++) { > + if (!evt_list[evt_i]) > + break; > + } > + > + evt_num = evt_i; > + qsort(evt_list, evt_num, sizeof(char *), cmp_string); > + evt_i = 0; > + while (evt_i < evt_num) { > + if (name_only) { > + printf("%s ", evt_list[evt_i++]); > + continue; > + } > + printf(" %-50s [%s]\n", evt_list[evt_i++], > + event_type_descriptors[PERF_TYPE_HW_CACHE]); > + } > + if (evt_num && pager_in_use()) > + printf("\n"); > + > +out_free: > + evt_num = evt_i; > + for (evt_i = 0; evt_i < evt_num; evt_i++) > + zfree(&evt_list[evt_i]); > + zfree(&evt_list); > + > + for (evt_i = 0; evt_i < npmus; evt_i++) > + zfree(&evt_pmus[evt_i]); > + zfree(&evt_pmus); > + return evt_num; > + > +out_enomem: > + printf("FATAL: not enough memory to print %s\n", > + event_type_descriptors[PERF_TYPE_HW_CACHE]); > + if (evt_list) > + goto out_free; > + return evt_num; > +} > + > +static void print_tool_event(const struct event_symbol *syms, const char *event_glob, > + bool name_only) > +{ > + if (syms->symbol == NULL) > + return; > + > + if (event_glob && !(strglobmatch(syms->symbol, event_glob) || > + (syms->alias && strglobmatch(syms->alias, event_glob)))) > + return; > + > + if (name_only) > + printf("%s ", syms->symbol); > + else { > + char name[MAX_NAME_LEN]; > + > + if (syms->alias && strlen(syms->alias)) > + snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); > + else > + strlcpy(name, syms->symbol, MAX_NAME_LEN); > + printf(" %-50s [%s]\n", name, "Tool event"); > + } > +} > + > +void print_tool_events(const char *event_glob, bool name_only) > +{ > + // Start at 1 because the first enum entry means no tool event. > + for (int i = 1; i < PERF_TOOL_MAX; ++i) > + print_tool_event(event_symbols_tool + i, event_glob, name_only); > + > + if (pager_in_use()) > + printf("\n"); > +} > + > +void print_symbol_events(const char *event_glob, unsigned int type, > + struct event_symbol *syms, unsigned int max, > + bool name_only) > +{ > + unsigned int i, evt_i = 0, evt_num = 0; > + char name[MAX_NAME_LEN]; > + char **evt_list = NULL; > + bool evt_num_known = false; > + > +restart: > + if (evt_num_known) { > + evt_list = zalloc(sizeof(char *) * evt_num); > + if (!evt_list) > + goto out_enomem; > + syms -= max; > + } > + > + for (i = 0; i < max; i++, syms++) { > + /* > + * New attr.config still not supported here, the latest > + * example was PERF_COUNT_SW_CGROUP_SWITCHES > + */ > + if (syms->symbol == NULL) > + continue; > + > + if (event_glob != NULL && !(strglobmatch(syms->symbol, event_glob) || > + (syms->alias && strglobmatch(syms->alias, event_glob)))) > + continue; > + > + if (!is_event_supported(type, i)) > + continue; > + > + if (!evt_num_known) { > + evt_num++; > + continue; > + } > + > + if (!name_only && strlen(syms->alias)) > + snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); > + else > + strlcpy(name, syms->symbol, MAX_NAME_LEN); > + > + evt_list[evt_i] = strdup(name); > + if (evt_list[evt_i] == NULL) > + goto out_enomem; > + evt_i++; > + } > + > + if (!evt_num_known) { > + evt_num_known = true; > + goto restart; > + } > + qsort(evt_list, evt_num, sizeof(char *), cmp_string); > + evt_i = 0; > + while (evt_i < evt_num) { > + if (name_only) { > + printf("%s ", evt_list[evt_i++]); > + continue; > + } > + printf(" %-50s [%s]\n", evt_list[evt_i++], event_type_descriptors[type]); > + } > + if (evt_num && pager_in_use()) > + printf("\n"); > + > +out_free: > + evt_num = evt_i; > + for (evt_i = 0; evt_i < evt_num; evt_i++) > + zfree(&evt_list[evt_i]); > + zfree(&evt_list); > + return; > + > +out_enomem: > + printf("FATAL: not enough memory to print %s\n", event_type_descriptors[type]); > + if (evt_list) > + goto out_free; > +} > + > +/* > + * Print the help text for the event symbols: > + */ > +void print_events(const char *event_glob, bool name_only, bool quiet_flag, > + bool long_desc, bool details_flag, bool deprecated, > + const char *pmu_name) > +{ > + print_symbol_events(event_glob, PERF_TYPE_HARDWARE, > + event_symbols_hw, PERF_COUNT_HW_MAX, name_only); > + > + print_symbol_events(event_glob, PERF_TYPE_SOFTWARE, > + event_symbols_sw, PERF_COUNT_SW_MAX, name_only); > + print_tool_events(event_glob, name_only); > + > + print_hwcache_events(event_glob, name_only); > + > + print_pmu_events(event_glob, name_only, quiet_flag, long_desc, > + details_flag, deprecated, pmu_name); > + > + if (event_glob != NULL) > + return; > + > + if (!name_only) { > + printf(" %-50s [%s]\n", > + "rNNN", > + event_type_descriptors[PERF_TYPE_RAW]); > + printf(" %-50s [%s]\n", > + "cpu/t1=v1[,t2=v2,t3 ...]/modifier", > + event_type_descriptors[PERF_TYPE_RAW]); > + if (pager_in_use()) > + printf(" (see 'man perf-list' on how to encode it)\n\n"); > + > + printf(" %-50s [%s]\n", > + "mem:[/len][:access]", > + event_type_descriptors[PERF_TYPE_BREAKPOINT]); > + if (pager_in_use()) > + printf("\n"); > + } > + > + print_tracepoint_events(NULL, NULL, name_only); > + > + print_sdt_events(NULL, NULL, name_only); > + > + metricgroup__print(true, true, NULL, name_only, details_flag, > + pmu_name); > + > + print_libpfm_events(name_only, long_desc); > +} > diff --git a/tools/perf/util/print-events.h b/tools/perf/util/print-events.h > new file mode 100644 > index 000000000000..1da9910d83a6 > --- /dev/null > +++ b/tools/perf/util/print-events.h > @@ -0,0 +1,22 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +#ifndef __PERF_PRINT_EVENTS_H > +#define __PERF_PRINT_EVENTS_H > + > +#include > + > +struct event_symbol; > + > +void print_events(const char *event_glob, bool name_only, bool quiet_flag, > + bool long_desc, bool details_flag, bool deprecated, > + const char *pmu_name); > +int print_hwcache_events(const char *event_glob, bool name_only); > +void print_sdt_events(const char *subsys_glob, const char *event_glob, > + bool name_only); > +void print_symbol_events(const char *event_glob, unsigned int type, > + struct event_symbol *syms, unsigned int max, > + bool name_only); > +void print_tool_events(const char *event_glob, bool name_only); > +void print_tracepoint_events(const char *subsys_glob, const char *event_glob, > + bool name_only); > + > +#endif /* __PERF_PRINT_EVENTS_H */ > diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c > index a65f65d0857e..892c323b4ac9 100644 > --- a/tools/perf/util/trace-event-info.c > +++ b/tools/perf/util/trace-event-info.c > @@ -19,16 +19,24 @@ > #include > #include > #include // page_size > +#include > > #include "trace-event.h" > +#include "tracepoint.h" > #include > #include "evsel.h" > #include "debug.h" > > #define VERSION "0.6" > +#define MAX_EVENT_LENGTH 512 > > static int output_fd; > > +struct tracepoint_path { > + char *system; > + char *name; > + struct tracepoint_path *next; > +}; > > int bigendian(void) > { > @@ -400,6 +408,94 @@ put_tracepoints_path(struct tracepoint_path *tps) > } > } > > +static struct tracepoint_path *tracepoint_id_to_path(u64 config) > +{ > + struct tracepoint_path *path = NULL; > + DIR *sys_dir, *evt_dir; > + struct dirent *sys_dirent, *evt_dirent; > + char id_buf[24]; > + int fd; > + u64 id; > + char evt_path[MAXPATHLEN]; > + char *dir_path; > + > + sys_dir = tracing_events__opendir(); > + if (!sys_dir) > + return NULL; > + > + for_each_subsystem(sys_dir, sys_dirent) { > + dir_path = get_events_file(sys_dirent->d_name); > + if (!dir_path) > + continue; > + evt_dir = opendir(dir_path); > + if (!evt_dir) > + goto next; > + > + for_each_event(dir_path, evt_dir, evt_dirent) { > + > + scnprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, > + evt_dirent->d_name); > + fd = open(evt_path, O_RDONLY); > + if (fd < 0) > + continue; > + if (read(fd, id_buf, sizeof(id_buf)) < 0) { > + close(fd); > + continue; > + } > + close(fd); > + id = atoll(id_buf); > + if (id == config) { > + put_events_file(dir_path); > + closedir(evt_dir); > + closedir(sys_dir); > + path = zalloc(sizeof(*path)); > + if (!path) > + return NULL; > + if (asprintf(&path->system, "%.*s", > + MAX_EVENT_LENGTH, sys_dirent->d_name) < 0) { > + free(path); > + return NULL; > + } > + if (asprintf(&path->name, "%.*s", > + MAX_EVENT_LENGTH, evt_dirent->d_name) < 0) { > + zfree(&path->system); > + free(path); > + return NULL; > + } > + return path; > + } > + } > + closedir(evt_dir); > +next: > + put_events_file(dir_path); > + } > + > + closedir(sys_dir); > + return NULL; > +} > + > +static struct tracepoint_path *tracepoint_name_to_path(const char *name) > +{ > + struct tracepoint_path *path = zalloc(sizeof(*path)); > + char *str = strchr(name, ':'); > + > + if (path == NULL || str == NULL) { > + free(path); > + return NULL; > + } > + > + path->system = strndup(name, str - name); > + path->name = strdup(str+1); > + > + if (path->system == NULL || path->name == NULL) { > + zfree(&path->system); > + zfree(&path->name); > + zfree(&path); > + } > + > + return path; > +} > + > static struct tracepoint_path * > get_tracepoints_path(struct list_head *pattrs) > { > diff --git a/tools/perf/util/tracepoint.c b/tools/perf/util/tracepoint.c > new file mode 100644 > index 000000000000..89ef56c43311 > --- /dev/null > +++ b/tools/perf/util/tracepoint.c > @@ -0,0 +1,63 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include "tracepoint.h" > + > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +int tp_event_has_id(const char *dir_path, struct dirent *evt_dir) > +{ > + char evt_path[MAXPATHLEN]; > + int fd; > + > + snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, evt_dir->d_name); > + fd = open(evt_path, O_RDONLY); > + if (fd < 0) > + return -EINVAL; > + close(fd); > + > + return 0; > +} > + > +/* > + * Check whether event is in /tracing/events > + */ > +int is_valid_tracepoint(const char *event_string) > +{ > + DIR *sys_dir, *evt_dir; > + struct dirent *sys_dirent, *evt_dirent; > + char evt_path[MAXPATHLEN]; > + char *dir_path; > + > + sys_dir = tracing_events__opendir(); > + if (!sys_dir) > + return 0; > + > + for_each_subsystem(sys_dir, sys_dirent) { > + dir_path = get_events_file(sys_dirent->d_name); > + if (!dir_path) > + continue; > + evt_dir = opendir(dir_path); > + if (!evt_dir) > + goto next; > + > + for_each_event(dir_path, evt_dir, evt_dirent) { > + snprintf(evt_path, MAXPATHLEN, "%s:%s", > + sys_dirent->d_name, evt_dirent->d_name); > + if (!strcmp(evt_path, event_string)) { > + closedir(evt_dir); > + closedir(sys_dir); > + return 1; > + } > + } > + closedir(evt_dir); > +next: > + put_events_file(dir_path); > + } > + closedir(sys_dir); > + return 0; > +} > diff --git a/tools/perf/util/tracepoint.h b/tools/perf/util/tracepoint.h > new file mode 100644 > index 000000000000..c4a110fe87d7 > --- /dev/null > +++ b/tools/perf/util/tracepoint.h > @@ -0,0 +1,25 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +#ifndef __PERF_TRACEPOINT_H > +#define __PERF_TRACEPOINT_H > + > +#include > +#include > + > +int tp_event_has_id(const char *dir_path, struct dirent *evt_dir); > + > +#define for_each_event(dir_path, evt_dir, evt_dirent) \ > + while ((evt_dirent = readdir(evt_dir)) != NULL) \ > + if (evt_dirent->d_type == DT_DIR && \ > + (strcmp(evt_dirent->d_name, ".")) && \ > + (strcmp(evt_dirent->d_name, "..")) && \ > + (!tp_event_has_id(dir_path, evt_dirent))) > + > +#define for_each_subsystem(sys_dir, sys_dirent) \ > + while ((sys_dirent = readdir(sys_dir)) != NULL) \ > + if (sys_dirent->d_type == DT_DIR && \ > + (strcmp(sys_dirent->d_name, ".")) && \ > + (strcmp(sys_dirent->d_name, ".."))) > + > +int is_valid_tracepoint(const char *event_string); > + > +#endif /* __PERF_TRACEPOINT_H */ > -- > 2.37.0.rc0.161.g10f37bed90-goog >