perf script: Add dlfilter__filter_event_early()

filter_event_early() can be more than 30% faster than filter_event()
because it is called before internal filtering. In other respects it
is the same as filter_event(), except that it will be passed events
that have yet to be filtered out.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210627131818.810-3-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Adrian Hunter 2021-06-27 16:18:10 +03:00 committed by Arnaldo Carvalho de Melo
parent 291961fc3c
commit 9bde93a79a
5 changed files with 59 additions and 16 deletions

View File

@ -36,16 +36,17 @@ const struct perf_dlfilter_fns perf_dlfilter_fns;
int start(void **data, void *ctx); int start(void **data, void *ctx);
int stop(void *data, void *ctx); int stop(void *data, void *ctx);
int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ctx); int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ctx);
int filter_event_early(void *data, const struct perf_dlfilter_sample *sample, void *ctx);
---- ----
If implemented, 'start' will be called at the beginning, before any If implemented, 'start' will be called at the beginning, before any
calls to 'filter_event' . Return 0 to indicate success, calls to 'filter_event' or 'filter_event_early'. Return 0 to indicate success,
or return a negative error code. '*data' can be assigned for use by other or return a negative error code. '*data' can be assigned for use by other
functions. 'ctx' is needed for calls to perf_dlfilter_fns, but most functions. 'ctx' is needed for calls to perf_dlfilter_fns, but most
perf_dlfilter_fns are not valid when called from 'start'. perf_dlfilter_fns are not valid when called from 'start'.
If implemented, 'stop' will be called at the end, after any calls to If implemented, 'stop' will be called at the end, after any calls to
'filter_event'. Return 0 to indicate success, or 'filter_event' or 'filter_event_early'. Return 0 to indicate success, or
return a negative error code. 'data' is set by 'start'. 'ctx' is needed return a negative error code. 'data' is set by 'start'. 'ctx' is needed
for calls to perf_dlfilter_fns, but most perf_dlfilter_fns are not valid for calls to perf_dlfilter_fns, but most perf_dlfilter_fns are not valid
when called from 'stop'. when called from 'stop'.
@ -55,10 +56,13 @@ Return 0 to keep the sample event, 1 to filter it out, or return a negative
error code. 'data' is set by 'start'. 'ctx' is needed for calls to error code. 'data' is set by 'start'. 'ctx' is needed for calls to
'perf_dlfilter_fns'. 'perf_dlfilter_fns'.
'filter_event_early' is the same as 'filter_event' except it is called before
internal filtering.
The perf_dlfilter_sample structure The perf_dlfilter_sample structure
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'filter_event' is passed a perf_dlfilter_sample 'filter_event' and 'filter_event_early' are passed a perf_dlfilter_sample
structure, which contains the following fields: structure, which contains the following fields:
[source,c] [source,c]
---- ----
@ -105,7 +109,8 @@ The perf_dlfilter_fns structure
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 'perf_dlfilter_fns' structure is populated with function pointers when the The 'perf_dlfilter_fns' structure is populated with function pointers when the
file is loaded. The functions can be called by 'filter_event'. file is loaded. The functions can be called by 'filter_event' or
'filter_event_early'.
[source,c] [source,c]
---- ----

View File

@ -2179,9 +2179,20 @@ static int process_sample_event(struct perf_tool *tool,
struct addr_location addr_al; struct addr_location addr_al;
int ret = 0; int ret = 0;
/* Set thread to NULL to indicate addr_al and al are not initialized */
addr_al.thread = NULL;
al.thread = NULL;
ret = dlfilter__filter_event_early(dlfilter, event, sample, evsel, machine, &al, &addr_al);
if (ret) {
if (ret > 0)
ret = 0;
goto out_put;
}
if (perf_time__ranges_skip_sample(scr->ptime_range, scr->range_num, if (perf_time__ranges_skip_sample(scr->ptime_range, scr->range_num,
sample->time)) { sample->time)) {
return 0; goto out_put;
} }
if (debug_mode) { if (debug_mode) {
@ -2192,24 +2203,22 @@ static int process_sample_event(struct perf_tool *tool,
nr_unordered++; nr_unordered++;
} }
last_timestamp = sample->time; last_timestamp = sample->time;
return 0; goto out_put;
} }
if (filter_cpu(sample)) if (filter_cpu(sample))
return 0; goto out_put;
if (machine__resolve(machine, &al, sample) < 0) { if (machine__resolve(machine, &al, sample) < 0) {
pr_err("problem processing %d event, skipping it.\n", pr_err("problem processing %d event, skipping it.\n",
event->header.type); event->header.type);
return -1; ret = -1;
goto out_put;
} }
if (al.filtered) if (al.filtered)
goto out_put; goto out_put;
/* Set thread to NULL to indicate addr_al is not initialized */
addr_al.thread = NULL;
if (!show_event(sample, evsel, al.thread, &al, &addr_al)) if (!show_event(sample, evsel, al.thread, &al, &addr_al))
goto out_put; goto out_put;
@ -2238,7 +2247,8 @@ static int process_sample_event(struct perf_tool *tool,
} }
out_put: out_put:
addr_location__put(&al); if (al.thread)
addr_location__put(&al);
return ret; return ret;
} }

View File

@ -175,6 +175,7 @@ static int dlfilter__open(struct dlfilter *d)
} }
d->start = dlsym(d->handle, "start"); d->start = dlsym(d->handle, "start");
d->filter_event = dlsym(d->handle, "filter_event"); d->filter_event = dlsym(d->handle, "filter_event");
d->filter_event_early = dlsym(d->handle, "filter_event_early");
d->stop = dlsym(d->handle, "stop"); d->stop = dlsym(d->handle, "stop");
d->fns = dlsym(d->handle, "perf_dlfilter_fns"); d->fns = dlsym(d->handle, "perf_dlfilter_fns");
if (d->fns) if (d->fns)
@ -251,7 +252,8 @@ int dlfilter__do_filter_event(struct dlfilter *d,
struct evsel *evsel, struct evsel *evsel,
struct machine *machine, struct machine *machine,
struct addr_location *al, struct addr_location *al,
struct addr_location *addr_al) struct addr_location *addr_al,
bool early)
{ {
struct perf_dlfilter_sample d_sample; struct perf_dlfilter_sample d_sample;
struct perf_dlfilter_al d_ip_al; struct perf_dlfilter_al d_ip_al;
@ -322,7 +324,10 @@ int dlfilter__do_filter_event(struct dlfilter *d,
d->ctx_valid = true; d->ctx_valid = true;
ret = d->filter_event(d->data, &d_sample, d); if (early)
ret = d->filter_event_early(d->data, &d_sample, d);
else
ret = d->filter_event(d->data, &d_sample, d);
d->ctx_valid = false; d->ctx_valid = false;

View File

@ -40,6 +40,9 @@ struct dlfilter {
int (*filter_event)(void *data, int (*filter_event)(void *data,
const struct perf_dlfilter_sample *sample, const struct perf_dlfilter_sample *sample,
void *ctx); void *ctx);
int (*filter_event_early)(void *data,
const struct perf_dlfilter_sample *sample,
void *ctx);
struct perf_dlfilter_fns *fns; struct perf_dlfilter_fns *fns;
}; };
@ -54,7 +57,8 @@ int dlfilter__do_filter_event(struct dlfilter *d,
struct evsel *evsel, struct evsel *evsel,
struct machine *machine, struct machine *machine,
struct addr_location *al, struct addr_location *al,
struct addr_location *addr_al); struct addr_location *addr_al,
bool early);
void dlfilter__cleanup(struct dlfilter *d); void dlfilter__cleanup(struct dlfilter *d);
@ -68,7 +72,20 @@ static inline int dlfilter__filter_event(struct dlfilter *d,
{ {
if (!d || !d->filter_event) if (!d || !d->filter_event)
return 0; return 0;
return dlfilter__do_filter_event(d, event, sample, evsel, machine, al, addr_al); return dlfilter__do_filter_event(d, event, sample, evsel, machine, al, addr_al, false);
}
static inline int dlfilter__filter_event_early(struct dlfilter *d,
union perf_event *event,
struct perf_sample *sample,
struct evsel *evsel,
struct machine *machine,
struct addr_location *al,
struct addr_location *addr_al)
{
if (!d || !d->filter_event_early)
return 0;
return dlfilter__do_filter_event(d, event, sample, evsel, machine, al, addr_al, true);
} }
#endif #endif

View File

@ -120,4 +120,10 @@ int stop(void *data, void *ctx);
*/ */
int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ctx); int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ctx);
/*
* The same as 'filter_event' except it is called before internal
* filtering.
*/
int filter_event_early(void *data, const struct perf_dlfilter_sample *sample, void *ctx);
#endif #endif