Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf evsel: Introduce per event max_events property

This simply adds the field to 'struct perf_evsel' and allows setting
it via the event parser, to test it lets trace trace:

First look at where in a function that receives an evsel we can put a probe
to read how evsel->max_events was setup:

# perf probe -x ~/bin/perf -L trace__event_handler
<trace__event_handler@/home/acme/git/perf/tools/perf/builtin-trace.c:0>
0 static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
union perf_event *event __maybe_unused,
struct perf_sample *sample)
3 {
4 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
5 int callchain_ret = 0;

7 if (sample->callchain) {
8 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
9 if (callchain_ret == 0) {
10 if (callchain_cursor.nr < trace->min_stack)
11 goto out;
12 callchain_ret = 1;
}
}

See what variables we can probe at line 7:

# perf probe -x ~/bin/perf -V trace__event_handler:7
Available variables at trace__event_handler:7
@<trace__event_handler+89>
int callchain_ret
struct perf_evsel* evsel
struct perf_sample* sample
struct thread* thread
struct trace* trace
union perf_event* event

Add a probe at that line asking for evsel->max_events to be collected and named
as "max_events":

# perf probe -x ~/bin/perf trace__event_handler:7 'max_events=evsel->max_events'
Added new event:
probe_perf:trace__event_handler (on trace__event_handler:7 in /home/acme/bin/perf with max_events=evsel->max_events)

You can now use it in all perf tools, such as:

perf record -e probe_perf:trace__event_handler -aR sleep 1

Now use 'perf trace', here aliased to just 'trace' and trace trace, i.e.
the first 'trace' is tracing just that 'probe_perf:trace__event_handler' event,
while the traced trace is tracing all scheduler tracepoints, will stop at two
events (--max-events 2) and will just set evsel->max_events for all the sched
tracepoints to 9, we will see the output of both traces intermixed:

# trace -e *perf:*event_handler trace --max-events 2 -e sched:*/nr=9/
0.000 :0/0 sched:sched_waking:comm=rcu_sched pid=10 prio=120 target_cpu=000
0.009 :0/0 sched:sched_wakeup:comm=rcu_sched pid=10 prio=120 target_cpu=000
0.000 trace/23949 probe_perf:trace__event_handler:(48c34a) max_events=0x9
0.046 trace/23949 probe_perf:trace__event_handler:(48c34a) max_events=0x9
#

Now, if the traced trace sends its output to /dev/null, we'll see just
what the first level trace outputs: that evsel->max_events is indeed
being set to 9:

# trace -e *perf:*event_handler trace -o /dev/null --max-events 2 -e sched:*/nr=9/
0.000 trace/23961 probe_perf:trace__event_handler:(48c34a) max_events=0x9
0.030 trace/23961 probe_perf:trace__event_handler:(48c34a) max_events=0x9
#

Now that we can set evsel->max_events, we can go to the next step, honour that
per-event property in 'perf trace'.

Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Milian Wolff <milian.wolff@kdab.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Wang Nan <wangnan0@huawei.com>
Link: https://lkml.kernel.org/n/tip-og00yasj276joem6e14l1eas@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

+17
+4
tools/perf/util/evsel.c
··· 232 232 evsel->leader = evsel; 233 233 evsel->unit = ""; 234 234 evsel->scale = 1.0; 235 + evsel->max_events = ULONG_MAX; 235 236 evsel->evlist = NULL; 236 237 evsel->bpf_fd = -1; 237 238 INIT_LIST_HEAD(&evsel->node); ··· 793 792 break; 794 793 case PERF_EVSEL__CONFIG_TERM_MAX_STACK: 795 794 max_stack = term->val.max_stack; 795 + break; 796 + case PERF_EVSEL__CONFIG_TERM_MAX_EVENTS: 797 + evsel->max_events = term->val.max_events; 796 798 break; 797 799 case PERF_EVSEL__CONFIG_TERM_INHERIT: 798 800 /*
+3
tools/perf/util/evsel.h
··· 46 46 PERF_EVSEL__CONFIG_TERM_STACK_USER, 47 47 PERF_EVSEL__CONFIG_TERM_INHERIT, 48 48 PERF_EVSEL__CONFIG_TERM_MAX_STACK, 49 + PERF_EVSEL__CONFIG_TERM_MAX_EVENTS, 49 50 PERF_EVSEL__CONFIG_TERM_OVERWRITE, 50 51 PERF_EVSEL__CONFIG_TERM_DRV_CFG, 51 52 PERF_EVSEL__CONFIG_TERM_BRANCH, ··· 66 65 bool inherit; 67 66 bool overwrite; 68 67 char *branch; 68 + unsigned long max_events; 69 69 } val; 70 70 bool weak; 71 71 }; ··· 101 99 struct perf_counts *prev_raw_counts; 102 100 int idx; 103 101 u32 ids; 102 + unsigned long max_events; 104 103 char *name; 105 104 double scale; 106 105 const char *unit;
+8
tools/perf/util/parse-events.c
··· 926 926 [PARSE_EVENTS__TERM_TYPE_NOINHERIT] = "no-inherit", 927 927 [PARSE_EVENTS__TERM_TYPE_INHERIT] = "inherit", 928 928 [PARSE_EVENTS__TERM_TYPE_MAX_STACK] = "max-stack", 929 + [PARSE_EVENTS__TERM_TYPE_MAX_EVENTS] = "nr", 929 930 [PARSE_EVENTS__TERM_TYPE_OVERWRITE] = "overwrite", 930 931 [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE] = "no-overwrite", 931 932 [PARSE_EVENTS__TERM_TYPE_DRV_CFG] = "driver-config", ··· 1038 1037 case PARSE_EVENTS__TERM_TYPE_MAX_STACK: 1039 1038 CHECK_TYPE_VAL(NUM); 1040 1039 break; 1040 + case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: 1041 + CHECK_TYPE_VAL(NUM); 1042 + break; 1041 1043 default: 1042 1044 err->str = strdup("unknown term"); 1043 1045 err->idx = term->err_term; ··· 1088 1084 case PARSE_EVENTS__TERM_TYPE_INHERIT: 1089 1085 case PARSE_EVENTS__TERM_TYPE_NOINHERIT: 1090 1086 case PARSE_EVENTS__TERM_TYPE_MAX_STACK: 1087 + case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: 1091 1088 case PARSE_EVENTS__TERM_TYPE_OVERWRITE: 1092 1089 case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: 1093 1090 return config_term_common(attr, term, err); ··· 1166 1161 break; 1167 1162 case PARSE_EVENTS__TERM_TYPE_MAX_STACK: 1168 1163 ADD_CONFIG_TERM(MAX_STACK, max_stack, term->val.num); 1164 + break; 1165 + case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: 1166 + ADD_CONFIG_TERM(MAX_EVENTS, max_events, term->val.num); 1169 1167 break; 1170 1168 case PARSE_EVENTS__TERM_TYPE_OVERWRITE: 1171 1169 ADD_CONFIG_TERM(OVERWRITE, overwrite, term->val.num ? 1 : 0);
+1
tools/perf/util/parse-events.h
··· 71 71 PARSE_EVENTS__TERM_TYPE_NOINHERIT, 72 72 PARSE_EVENTS__TERM_TYPE_INHERIT, 73 73 PARSE_EVENTS__TERM_TYPE_MAX_STACK, 74 + PARSE_EVENTS__TERM_TYPE_MAX_EVENTS, 74 75 PARSE_EVENTS__TERM_TYPE_NOOVERWRITE, 75 76 PARSE_EVENTS__TERM_TYPE_OVERWRITE, 76 77 PARSE_EVENTS__TERM_TYPE_DRV_CFG,
+1
tools/perf/util/parse-events.l
··· 269 269 call-graph { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CALLGRAPH); } 270 270 stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); } 271 271 max-stack { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_STACK); } 272 + nr { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_EVENTS); } 272 273 inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); } 273 274 no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } 274 275 overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_OVERWRITE); }