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:
parent
291961fc3c
commit
9bde93a79a
|
@ -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]
|
||||||
----
|
----
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue