From 064b4e82aa1633c27c383cc686b87ced57e072d1 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Fri, 12 Apr 2019 21:59:47 +0800 Subject: [PATCH] perf tools: Add a 'percore' event qualifier Add a 'percore' event qualifier, like cpu/event=0,umask=0x3,percore=1/, that sums up the event counts for both hardware threads in a core. We can already do this with --per-core, but it's often useful to do this together with other metrics that are collected per hardware thread. So we need to support this per-core counting on a event level. This can be implemented in only the user tool, no kernel support needed. v4: --- 1. Add Arnaldo's patch which updates the documentation for this new qualifier. 2. Rebase to latest perf/core branch v3: --- Simplify the code according to Jiri's comments. Before: "return term->val.percore ? true : false;" Now: "return term->val.percore;" v2: --- Change the qualifier name from 'coresum' to 'percore' according to comments from Jiri and Andi. Signed-off-by: Jin Yao Tested-by: Ravi Bangoria Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jin Yao Cc: Kan Liang Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1555077590-27664-2-git-send-email-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-list.txt | 12 ++++++++++++ tools/perf/util/evsel.c | 2 ++ tools/perf/util/evsel.h | 3 +++ tools/perf/util/parse-events.c | 27 ++++++++++++++++++++++++++ tools/perf/util/parse-events.h | 1 + tools/perf/util/parse-events.l | 1 + 6 files changed, 46 insertions(+) diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index 138fb6e94b3c..18ed1b0fceb3 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt @@ -199,6 +199,18 @@ also be supplied. For example: perf stat -C 0 -e 'hv_gpci/dtbp_ptitc,phys_processor_idx=0x2/' ... +EVENT QUALIFIERS: + +It is also possible to add extra qualifiers to an event: + +percore: + +Sums up the event counts for all hardware threads in a core, e.g.: + + + perf stat -e cpu/event=0,umask=0x3,percore=1/ + + EVENT GROUPS ------------ diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index a10cf4cde920..a6f572a40deb 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -813,6 +813,8 @@ static void apply_config_terms(struct perf_evsel *evsel, break; case PERF_EVSEL__CONFIG_TERM_DRV_CFG: break; + case PERF_EVSEL__CONFIG_TERM_PERCORE: + break; default: break; } diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 6d190cbf1070..cad54e8ba522 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -50,6 +50,7 @@ enum term_type { PERF_EVSEL__CONFIG_TERM_OVERWRITE, PERF_EVSEL__CONFIG_TERM_DRV_CFG, PERF_EVSEL__CONFIG_TERM_BRANCH, + PERF_EVSEL__CONFIG_TERM_PERCORE, }; struct perf_evsel_config_term { @@ -67,6 +68,7 @@ struct perf_evsel_config_term { bool overwrite; char *branch; unsigned long max_events; + bool percore; } val; bool weak; }; @@ -158,6 +160,7 @@ struct perf_evsel { struct perf_evsel **metric_events; bool collect_stat; bool weak_group; + bool percore; const char *pmu_name; struct { perf_evsel__sb_cb_t *cb; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4432bfe039fd..cf0b9b81c5aa 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -950,6 +950,7 @@ static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = { [PARSE_EVENTS__TERM_TYPE_OVERWRITE] = "overwrite", [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE] = "no-overwrite", [PARSE_EVENTS__TERM_TYPE_DRV_CFG] = "driver-config", + [PARSE_EVENTS__TERM_TYPE_PERCORE] = "percore", }; static bool config_term_shrinked; @@ -970,6 +971,7 @@ config_term_avail(int term_type, struct parse_events_error *err) case PARSE_EVENTS__TERM_TYPE_CONFIG2: case PARSE_EVENTS__TERM_TYPE_NAME: case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: + case PARSE_EVENTS__TERM_TYPE_PERCORE: return true; default: if (!err) @@ -1061,6 +1063,14 @@ do { \ case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: CHECK_TYPE_VAL(NUM); break; + case PARSE_EVENTS__TERM_TYPE_PERCORE: + CHECK_TYPE_VAL(NUM); + if ((unsigned int)term->val.num > 1) { + err->str = strdup("expected 0 or 1"); + err->idx = term->err_val; + return -EINVAL; + } + break; default: err->str = strdup("unknown term"); err->idx = term->err_term; @@ -1199,6 +1209,10 @@ do { \ case PARSE_EVENTS__TERM_TYPE_DRV_CFG: ADD_CONFIG_TERM(DRV_CFG, drv_cfg, term->val.str); break; + case PARSE_EVENTS__TERM_TYPE_PERCORE: + ADD_CONFIG_TERM(PERCORE, percore, + term->val.num ? true : false); + break; default: break; } @@ -1260,6 +1274,18 @@ int parse_events_add_tool(struct parse_events_state *parse_state, return add_event_tool(list, &parse_state->idx, tool_event); } +static bool config_term_percore(struct list_head *config_terms) +{ + struct perf_evsel_config_term *term; + + list_for_each_entry(term, config_terms, list) { + if (term->type == PERF_EVSEL__CONFIG_TERM_PERCORE) + return term->val.percore; + } + + return false; +} + int parse_events_add_pmu(struct parse_events_state *parse_state, struct list_head *list, char *name, struct list_head *head_config, @@ -1333,6 +1359,7 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, evsel->metric_name = info.metric_name; evsel->pmu_name = name; evsel->use_uncore_alias = use_uncore_alias; + evsel->percore = config_term_percore(&evsel->config_terms); } return evsel ? 0 : -ENOMEM; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index a052cd6ac63e..f7139e1a2fd3 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -75,6 +75,7 @@ enum { PARSE_EVENTS__TERM_TYPE_NOOVERWRITE, PARSE_EVENTS__TERM_TYPE_OVERWRITE, PARSE_EVENTS__TERM_TYPE_DRV_CFG, + PARSE_EVENTS__TERM_TYPE_PERCORE, __PARSE_EVENTS__TERM_TYPE_NR, }; diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index c54bfe88626c..ca6098874fe2 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -283,6 +283,7 @@ inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); } no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_OVERWRITE); } no-overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOOVERWRITE); } +percore { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_PERCORE); } , { return ','; } "/" { BEGIN(INITIAL); return '/'; } {name_minus} { return str(yyscanner, PE_NAME); }