Commit 9bde93a7 authored by Adrian Hunter's avatar Adrian Hunter Committed by Arnaldo Carvalho de Melo
Browse files

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: default avatarAdrian 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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 291961fc
Loading
Loading
Loading
Loading
+9 −4
Original line number Diff line number Diff line
@@ -36,16 +36,17 @@ const struct perf_dlfilter_fns perf_dlfilter_fns;
int start(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_early(void *data, const struct perf_dlfilter_sample *sample, void *ctx);
----

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
functions. 'ctx' is needed for calls to perf_dlfilter_fns, but most
perf_dlfilter_fns are not valid when called from 'start'.

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
for calls to perf_dlfilter_fns, but most perf_dlfilter_fns are not valid
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
'perf_dlfilter_fns'.

'filter_event_early' is the same as 'filter_event' except it is called before
internal filtering.

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:
[source,c]
----
@@ -105,7 +109,8 @@ The perf_dlfilter_fns structure
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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]
----
+18 −8
Original line number Diff line number Diff line
@@ -2179,9 +2179,20 @@ static int process_sample_event(struct perf_tool *tool,
	struct addr_location addr_al;
	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,
					  sample->time)) {
		return 0;
		goto out_put;
	}

	if (debug_mode) {
@@ -2192,24 +2203,22 @@ static int process_sample_event(struct perf_tool *tool,
			nr_unordered++;
		}
		last_timestamp = sample->time;
		return 0;
		goto out_put;
	}

	if (filter_cpu(sample))
		return 0;
		goto out_put;

	if (machine__resolve(machine, &al, sample) < 0) {
		pr_err("problem processing %d event, skipping it.\n",
		       event->header.type);
		return -1;
		ret = -1;
		goto out_put;
	}

	if (al.filtered)
		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))
		goto out_put;

@@ -2238,6 +2247,7 @@ static int process_sample_event(struct perf_tool *tool,
	}

out_put:
	if (al.thread)
		addr_location__put(&al);
	return ret;
}
+7 −2
Original line number Diff line number Diff line
@@ -175,6 +175,7 @@ static int dlfilter__open(struct dlfilter *d)
	}
	d->start = dlsym(d->handle, "start");
	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->fns = dlsym(d->handle, "perf_dlfilter_fns");
	if (d->fns)
@@ -251,7 +252,8 @@ int dlfilter__do_filter_event(struct dlfilter *d,
			      struct evsel *evsel,
			      struct machine *machine,
			      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_al d_ip_al;
@@ -322,6 +324,9 @@ int dlfilter__do_filter_event(struct dlfilter *d,

	d->ctx_valid = true;

	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;
+19 −2
Original line number Diff line number Diff line
@@ -40,6 +40,9 @@ struct dlfilter {
	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);

	struct perf_dlfilter_fns *fns;
};
@@ -54,7 +57,8 @@ int dlfilter__do_filter_event(struct dlfilter *d,
			      struct evsel *evsel,
			      struct machine *machine,
			      struct addr_location *al,
			      struct addr_location *addr_al);
			      struct addr_location *addr_al,
			      bool early);

void dlfilter__cleanup(struct dlfilter *d);

@@ -68,7 +72,20 @@ static inline int dlfilter__filter_event(struct dlfilter *d,
{
	if (!d || !d->filter_event)
		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
+6 −0
Original line number Diff line number Diff line
@@ -120,4 +120,10 @@ int stop(void *data, 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