]> git.baikalelectronics.ru Git - kernel.git/commitdiff
perf script: Add dlfilter__filter_event_early()
authorAdrian Hunter <adrian.hunter@intel.com>
Sun, 27 Jun 2021 13:18:10 +0000 (16:18 +0300)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 1 Jul 2021 19:14:37 +0000 (16:14 -0300)
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>
tools/perf/Documentation/perf-dlfilter.txt
tools/perf/builtin-script.c
tools/perf/util/dlfilter.c
tools/perf/util/dlfilter.h
tools/perf/util/perf_dlfilter.h

index 15d5f4b01c97ae2f2531ced06b4c0fa10cb4a6dd..aef1c32babd144dc31c137fbefc9978e69e3b04e 100644 (file)
@@ -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]
 ----
index aaf2922643a0d21f5562b9934829ba3a92150e9e..e47affe674a5508bb5ea0d7dd6506a152a21980d 100644 (file)
@@ -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,7 +2247,8 @@ static int process_sample_event(struct perf_tool *tool,
        }
 
 out_put:
-       addr_location__put(&al);
+       if (al.thread)
+               addr_location__put(&al);
        return ret;
 }
 
index 03c4bf1506566dabdfafdef6cb2f5a02612c16ef..e93c49c079991448ce0a944c3d4042c13deee442 100644 (file)
@@ -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,7 +324,10 @@ int dlfilter__do_filter_event(struct dlfilter *d,
 
        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;
 
index 22b7636028dd0500fe035ad47f3d490cc3b30bed..a994560e563da7d04c74f81705bc53e077ccf153 100644 (file)
@@ -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
index 82833ee8680d2a63c08a144eb7f074c752f1bab3..f7a847fdee593819dac60d98db345af30226043c 100644 (file)
@@ -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