[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250416045117.876775-4-irogers@google.com>
Date: Tue, 15 Apr 2025 21:51:16 -0700
From: Ian Rogers <irogers@...gle.com>
To: Peter Zijlstra <peterz@...radead.org>, Ingo Molnar <mingo@...hat.com>,
Arnaldo Carvalho de Melo <acme@...nel.org>, Namhyung Kim <namhyung@...nel.org>,
Mark Rutland <mark.rutland@....com>,
Alexander Shishkin <alexander.shishkin@...ux.intel.com>, Jiri Olsa <jolsa@...nel.org>,
Ian Rogers <irogers@...gle.com>, Adrian Hunter <adrian.hunter@...el.com>,
Kan Liang <kan.liang@...ux.intel.com>, James Clark <james.clark@...aro.org>,
Ze Gao <zegao2021@...il.com>, Weilin Wang <weilin.wang@...el.com>,
Dominique Martinet <asmadeus@...ewreck.org>,
Jean-Philippe Romain <jean-philippe.romain@...s.st.com>, Junhao He <hejunhao3@...wei.com>,
linux-perf-users@...r.kernel.org, linux-kernel@...r.kernel.org,
Aditya Bodkhe <Aditya.Bodkhe1@....com>, Leo Yan <leo.yan@....com>,
Thomas Falcon <thomas.falcon@...el.com>, Atish Patra <atishp@...osinc.com>
Subject: [PATCH v8 3/4] perf parse-events: Allow software events to be terms
Allow legacy software events to be specified as, for example,
software/cpu-clock/u for consistency in parsing with hardware
events. Rename the type for hardware_event to legacy_event given its
new dual role.
Signed-off-by: Ian Rogers <irogers@...gle.com>
---
tools/perf/util/parse-events.c | 20 +++++++++++---
tools/perf/util/parse-events.h | 3 ++-
tools/perf/util/parse-events.l | 48 ++++++++++++++++++++++------------
tools/perf/util/parse-events.y | 43 ++++++++++++++++++++++--------
tools/perf/util/pmu.c | 9 ++++---
5 files changed, 86 insertions(+), 37 deletions(-)
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index f4236570aa4c..21506fcf0bfa 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -805,6 +805,7 @@ const char *parse_events__term_type_str(enum parse_events__term_type term_type)
[PARSE_EVENTS__TERM_TYPE_RAW] = "raw",
[PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE] = "legacy-cache",
[PARSE_EVENTS__TERM_TYPE_HARDWARE] = "hardware",
+ [PARSE_EVENTS__TERM_TYPE_SOFTWARE] = "software",
};
if ((unsigned int)term_type >= __PARSE_EVENTS__TERM_TYPE_NR)
return "unknown term";
@@ -854,6 +855,7 @@ config_term_avail(enum parse_events__term_type term_type, struct parse_events_er
case PARSE_EVENTS__TERM_TYPE_RAW:
case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE:
case PARSE_EVENTS__TERM_TYPE_HARDWARE:
+ case PARSE_EVENTS__TERM_TYPE_SOFTWARE:
default:
if (!err)
return false;
@@ -985,6 +987,7 @@ do { \
case PARSE_EVENTS__TERM_TYPE_USER:
case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE:
case PARSE_EVENTS__TERM_TYPE_HARDWARE:
+ case PARSE_EVENTS__TERM_TYPE_SOFTWARE:
default:
parse_events_error__handle(err, term->err_term,
strdup(parse_events__term_type_str(term->type_term)),
@@ -1037,7 +1040,8 @@ static int config_term_pmu(struct perf_event_attr *attr,
term->no_value = true;
}
}
- if (term->type_term == PARSE_EVENTS__TERM_TYPE_HARDWARE) {
+ if (term->type_term == PARSE_EVENTS__TERM_TYPE_HARDWARE ||
+ term->type_term == PARSE_EVENTS__TERM_TYPE_SOFTWARE) {
struct perf_pmu *pmu = perf_pmus__find_by_type(attr->type);
if (!pmu) {
@@ -1057,10 +1061,15 @@ static int config_term_pmu(struct perf_event_attr *attr,
term->no_value = true;
term->alternate_hw_config = true;
} else {
- attr->type = PERF_TYPE_HARDWARE;
attr->config = term->val.num;
- if (perf_pmus__supports_extended_type())
- attr->config |= (__u64)pmu->type << PERF_PMU_TYPE_SHIFT;
+ if (term->type_term == PARSE_EVENTS__TERM_TYPE_HARDWARE) {
+ attr->type = PERF_TYPE_HARDWARE;
+ if (perf_pmus__supports_extended_type())
+ attr->config |= (__u64)pmu->type << PERF_PMU_TYPE_SHIFT;
+
+ } else {
+ attr->type = PERF_TYPE_SOFTWARE;
+ }
}
return 0;
}
@@ -1108,6 +1117,7 @@ static int config_term_tracepoint(struct perf_event_attr *attr,
case PARSE_EVENTS__TERM_TYPE_RAW:
case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE:
case PARSE_EVENTS__TERM_TYPE_HARDWARE:
+ case PARSE_EVENTS__TERM_TYPE_SOFTWARE:
default:
if (err) {
parse_events_error__handle(err, term->err_term,
@@ -1242,6 +1252,7 @@ do { \
case PARSE_EVENTS__TERM_TYPE_RAW:
case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE:
case PARSE_EVENTS__TERM_TYPE_HARDWARE:
+ case PARSE_EVENTS__TERM_TYPE_SOFTWARE:
default:
break;
}
@@ -1296,6 +1307,7 @@ static int get_config_chgs(struct perf_pmu *pmu, struct parse_events_terms *head
case PARSE_EVENTS__TERM_TYPE_RAW:
case PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE:
case PARSE_EVENTS__TERM_TYPE_HARDWARE:
+ case PARSE_EVENTS__TERM_TYPE_SOFTWARE:
default:
break;
}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index e176a34ab088..c0a594827f4f 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -80,7 +80,8 @@ enum parse_events__term_type {
PARSE_EVENTS__TERM_TYPE_RAW,
PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE,
PARSE_EVENTS__TERM_TYPE_HARDWARE,
-#define __PARSE_EVENTS__TERM_TYPE_NR (PARSE_EVENTS__TERM_TYPE_HARDWARE + 1)
+ PARSE_EVENTS__TERM_TYPE_SOFTWARE,
+#define __PARSE_EVENTS__TERM_TYPE_NR (PARSE_EVENTS__TERM_TYPE_SOFTWARE + 1)
};
struct parse_events_term {
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 324b7dc8a0d3..a670d23ea9cc 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -117,12 +117,14 @@ do { \
yyless(0); \
} while (0)
-static int sym(yyscan_t scanner, int config)
+static int sw(yyscan_t scanner, int config)
{
YYSTYPE *yylval = parse_events_get_lval(scanner);
+ char *text = parse_events_get_text(scanner);
- yylval->num = config;
- return PE_VALUE_SYM_SW;
+ yylval->legacy_event.str = strdup(text);
+ yylval->legacy_event.num = config;
+ return PE_TERM_SW;
}
static int term(yyscan_t scanner, enum parse_events__term_type type)
@@ -138,8 +140,8 @@ static int hw(yyscan_t scanner, int config)
YYSTYPE *yylval = parse_events_get_lval(scanner);
char *text = parse_events_get_text(scanner);
- yylval->hardware_event.str = strdup(text);
- yylval->hardware_event.num = config;
+ yylval->legacy_event.str = strdup(text);
+ yylval->legacy_event.num = config;
return PE_TERM_HW;
}
@@ -345,6 +347,18 @@ branch-instructions|branches { return hw(yyscanner, PERF_COUNT_HW_BRANCH_INSTR
branch-misses { return hw(yyscanner, PERF_COUNT_HW_BRANCH_MISSES); }
bus-cycles { return hw(yyscanner, PERF_COUNT_HW_BUS_CYCLES); }
ref-cycles { return hw(yyscanner, PERF_COUNT_HW_REF_CPU_CYCLES); }
+cpu-clock { return sw(yyscanner, PERF_COUNT_SW_CPU_CLOCK); }
+task-clock { return sw(yyscanner, PERF_COUNT_SW_TASK_CLOCK); }
+page-faults|faults { return sw(yyscanner, PERF_COUNT_SW_PAGE_FAULTS); }
+minor-faults { return sw(yyscanner, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
+major-faults { return sw(yyscanner, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
+context-switches|cs { return sw(yyscanner, PERF_COUNT_SW_CONTEXT_SWITCHES); }
+cpu-migrations|migrations { return sw(yyscanner, PERF_COUNT_SW_CPU_MIGRATIONS); }
+alignment-faults { return sw(yyscanner, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
+emulation-faults { return sw(yyscanner, PERF_COUNT_SW_EMULATION_FAULTS); }
+dummy { return sw(yyscanner, PERF_COUNT_SW_DUMMY); }
+bpf-output { return sw(yyscanner, PERF_COUNT_SW_BPF_OUTPUT); }
+cgroup-switches { return sw(yyscanner, PERF_COUNT_SW_CGROUP_SWITCHES); }
r{num_raw_hex} { return str(yyscanner, PE_RAW); }
r0x{num_raw_hex} { return str(yyscanner, PE_RAW); }
, { return ','; }
@@ -400,18 +414,18 @@ branch-instructions|branches { return hw(yyscanner, PERF_COUNT_HW_BRANCH_INSTR
branch-misses { return hw(yyscanner, PERF_COUNT_HW_BRANCH_MISSES); }
bus-cycles { return hw(yyscanner, PERF_COUNT_HW_BUS_CYCLES); }
ref-cycles { return hw(yyscanner, PERF_COUNT_HW_REF_CPU_CYCLES); }
-cpu-clock { return sym(yyscanner, PERF_COUNT_SW_CPU_CLOCK); }
-task-clock { return sym(yyscanner, PERF_COUNT_SW_TASK_CLOCK); }
-page-faults|faults { return sym(yyscanner, PERF_COUNT_SW_PAGE_FAULTS); }
-minor-faults { return sym(yyscanner, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
-major-faults { return sym(yyscanner, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
-context-switches|cs { return sym(yyscanner, PERF_COUNT_SW_CONTEXT_SWITCHES); }
-cpu-migrations|migrations { return sym(yyscanner, PERF_COUNT_SW_CPU_MIGRATIONS); }
-alignment-faults { return sym(yyscanner, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
-emulation-faults { return sym(yyscanner, PERF_COUNT_SW_EMULATION_FAULTS); }
-dummy { return sym(yyscanner, PERF_COUNT_SW_DUMMY); }
-bpf-output { return sym(yyscanner, PERF_COUNT_SW_BPF_OUTPUT); }
-cgroup-switches { return sym(yyscanner, PERF_COUNT_SW_CGROUP_SWITCHES); }
+cpu-clock { return sw(yyscanner, PERF_COUNT_SW_CPU_CLOCK); }
+task-clock { return sw(yyscanner, PERF_COUNT_SW_TASK_CLOCK); }
+page-faults|faults { return sw(yyscanner, PERF_COUNT_SW_PAGE_FAULTS); }
+minor-faults { return sw(yyscanner, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
+major-faults { return sw(yyscanner, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
+context-switches|cs { return sw(yyscanner, PERF_COUNT_SW_CONTEXT_SWITCHES); }
+cpu-migrations|migrations { return sw(yyscanner, PERF_COUNT_SW_CPU_MIGRATIONS); }
+alignment-faults { return sw(yyscanner, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
+emulation-faults { return sw(yyscanner, PERF_COUNT_SW_EMULATION_FAULTS); }
+dummy { return sw(yyscanner, PERF_COUNT_SW_DUMMY); }
+bpf-output { return sw(yyscanner, PERF_COUNT_SW_BPF_OUTPUT); }
+cgroup-switches { return sw(yyscanner, PERF_COUNT_SW_CGROUP_SWITCHES); }
{lc_type} { return str(yyscanner, PE_LEGACY_CACHE); }
{lc_type}-{lc_op_result} { return str(yyscanner, PE_LEGACY_CACHE); }
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index d2ef1890007e..4992a5bf3c44 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -55,7 +55,7 @@ static void free_list_evsel(struct list_head* list_evsel)
%}
%token PE_START_EVENTS PE_START_TERMS
-%token PE_VALUE PE_VALUE_SYM_SW PE_TERM
+%token PE_VALUE PE_TERM
%token PE_EVENT_NAME
%token PE_RAW PE_NAME
%token PE_MODIFIER_EVENT PE_MODIFIER_BP PE_BP_COLON PE_BP_SLASH
@@ -63,9 +63,8 @@ static void free_list_evsel(struct list_head* list_evsel)
%token PE_PREFIX_MEM
%token PE_ERROR
%token PE_DRV_CFG_TERM
-%token PE_TERM_HW
+%token PE_TERM_HW PE_TERM_SW
%type <num> PE_VALUE
-%type <num> PE_VALUE_SYM_SW
%type <mod> PE_MODIFIER_EVENT
%type <term_type> PE_TERM
%type <str> PE_RAW
@@ -101,8 +100,9 @@ static void free_list_evsel(struct list_head* list_evsel)
%destructor { free_list_evsel ($$); } <list_evsel>
%type <tracepoint_name> tracepoint_name
%destructor { free ($$.sys); free ($$.event); } <tracepoint_name>
-%type <hardware_event> PE_TERM_HW
-%destructor { free ($$.str); } <hardware_event>
+%type <legacy_event> PE_TERM_HW
+%type <legacy_event> PE_TERM_SW
+%destructor { free ($$.str); } <legacy_event>
%union
{
@@ -117,10 +117,10 @@ static void free_list_evsel(struct list_head* list_evsel)
char *sys;
char *event;
} tracepoint_name;
- struct hardware_event {
+ struct legacy_event {
char *str;
u64 num;
- } hardware_event;
+ } legacy_event;
}
%%
@@ -334,16 +334,17 @@ PE_TERM_HW sep_dc
}
event_legacy_symbol:
-PE_VALUE_SYM_SW '/' event_config '/'
+PE_TERM_SW '/' event_config '/'
{
struct list_head *list;
int err;
+ free($1.str);
list = alloc_list();
if (!list)
YYNOMEM;
err = parse_events_add_numeric(_parse_state, list,
- /*type=*/PERF_TYPE_SOFTWARE, /*config=*/$1,
+ /*type=*/PERF_TYPE_SOFTWARE, /*config=*/$1.num,
$3, /*wildcard=*/false);
parse_events_terms__delete($3);
if (err) {
@@ -353,16 +354,17 @@ PE_VALUE_SYM_SW '/' event_config '/'
$$ = list;
}
|
-PE_VALUE_SYM_SW sep_slash_slash_dc
+PE_TERM_SW sep_slash_slash_dc
{
struct list_head *list;
int err;
+ free($1.str);
list = alloc_list();
if (!list)
YYNOMEM;
err = parse_events_add_numeric(_parse_state, list,
- /*type=*/PERF_TYPE_SOFTWARE, /*config=*/$1,
+ /*type=*/PERF_TYPE_SOFTWARE, /*config=*/$1.num,
/*head_config=*/NULL, /*wildcard=*/false);
if (err)
PE_ABORT(err);
@@ -615,6 +617,11 @@ PE_TERM_HW
{
$$ = $1.str;
}
+|
+PE_TERM_SW
+{
+ $$ = $1.str;
+}
event_term:
PE_RAW
@@ -696,6 +703,20 @@ PE_TERM_HW
$$ = term;
}
|
+PE_TERM_SW
+{
+ struct parse_events_term *term;
+ int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_SOFTWARE,
+ $1.str, $1.num & 255, /*novalue=*/false,
+ &@1, /*loc_val=*/NULL);
+
+ if (err) {
+ free($1.str);
+ PE_ABORT(err);
+ }
+ $$ = term;
+}
+|
PE_TERM '=' name_or_raw
{
struct parse_events_term *term;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index b7ebac5ab1d1..ac1149658d9b 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1429,7 +1429,7 @@ static int pmu_config_term(const struct perf_pmu *pmu,
break;
case PARSE_EVENTS__TERM_TYPE_USER: /* Not hardcoded. */
return -EINVAL;
- case PARSE_EVENTS__TERM_TYPE_NAME ... PARSE_EVENTS__TERM_TYPE_HARDWARE:
+ case PARSE_EVENTS__TERM_TYPE_NAME ... PARSE_EVENTS__TERM_TYPE_SOFTWARE:
/* Skip non-config terms. */
break;
default:
@@ -1810,10 +1810,11 @@ int perf_pmu__for_each_format(struct perf_pmu *pmu, void *state, pmu_format_call
/*
* max-events and driver-config are missing above as are the internal
- * types user, metric-id, raw, legacy cache and hardware. Assert against
- * the enum parse_events__term_type so they are kept in sync.
+ * types user, metric-id, raw, legacy cache, hardware and
+ * software. Assert against the enum parse_events__term_type so they are
+ * kept in sync.
*/
- _Static_assert(ARRAY_SIZE(terms) == __PARSE_EVENTS__TERM_TYPE_NR - 6,
+ _Static_assert(ARRAY_SIZE(terms) == __PARSE_EVENTS__TERM_TYPE_NR - 7,
"perf_pmu__for_each_format()'s terms must be kept in sync with enum parse_events__term_type");
list_for_each_entry(format, &pmu->format, list) {
perf_pmu_format__load(pmu, format);
--
2.49.0.777.g153de2bbd5-goog
Powered by blists - more mailing lists