Skip to content

Commit 638e2b9

Browse files
ahunter6acmel
authored andcommitted
perf script: Add option to list dlfilters
Add option --list-dlfilters to list dlfilters in the current directory or the exec-path e.g. ~/libexec/perf-core/dlfilters. Use with option -v (must come before option --list-dlfilters) to show long descriptions. 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-4-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
1 parent 9bde93a commit 638e2b9

6 files changed

Lines changed: 134 additions & 1 deletion

File tree

tools/perf/Documentation/perf-dlfilter.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ int start(void **data, void *ctx);
3737
int stop(void *data, void *ctx);
3838
int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ctx);
3939
int filter_event_early(void *data, const struct perf_dlfilter_sample *sample, void *ctx);
40+
const char *filter_description(const char **long_description);
4041
----
4142

4243
If implemented, 'start' will be called at the beginning, before any
@@ -59,6 +60,9 @@ error code. 'data' is set by 'start'. 'ctx' is needed for calls to
5960
'filter_event_early' is the same as 'filter_event' except it is called before
6061
internal filtering.
6162

63+
If implemented, 'filter_description' should return a one-line description
64+
of the filter, and optionally a longer description.
65+
6266
The perf_dlfilter_sample structure
6367
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6468

tools/perf/Documentation/perf-script.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ OPTIONS
102102
Filter sample events using the given shared object file.
103103
Refer linkperf:perf-dlfilter[1]
104104

105+
--list-dlfilters=::
106+
Display a list of available dlfilters. Use with option -v (must come
107+
before option --list-dlfilters) to show long descriptions.
108+
105109
-a::
106110
Force system-wide collection. Scripts run without a <command>
107111
normally use -a by default, while scripts run with a <command>

tools/perf/builtin-script.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3631,6 +3631,8 @@ int cmd_script(int argc, const char **argv)
36313631
"show latency attributes (irqs/preemption disabled, etc)"),
36323632
OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
36333633
list_available_scripts),
3634+
OPT_CALLBACK_NOOPT(0, "list-dlfilters", NULL, NULL, "list available dlfilters",
3635+
list_available_dlfilters),
36343636
OPT_CALLBACK('s', "script", NULL, "name",
36353637
"script file name (lang:script name, script name, or *)",
36363638
parse_scriptname),

tools/perf/util/dlfilter.c

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#include <dlfcn.h>
77
#include <stdlib.h>
88
#include <string.h>
9+
#include <dirent.h>
10+
#include <subcmd/exec-cmd.h>
911
#include <linux/zalloc.h>
1012
#include <linux/build_bug.h>
1113

@@ -136,6 +138,35 @@ static const struct perf_dlfilter_fns perf_dlfilter_fns = {
136138
.resolve_addr = dlfilter__resolve_addr,
137139
};
138140

141+
static char *find_dlfilter(const char *file)
142+
{
143+
char path[PATH_MAX];
144+
char *exec_path;
145+
146+
if (strchr(file, '/'))
147+
goto out;
148+
149+
if (!access(file, R_OK)) {
150+
/*
151+
* Prepend "./" so that dlopen will find the file in the
152+
* current directory.
153+
*/
154+
snprintf(path, sizeof(path), "./%s", file);
155+
file = path;
156+
goto out;
157+
}
158+
159+
exec_path = get_argv_exec_path();
160+
if (!exec_path)
161+
goto out;
162+
snprintf(path, sizeof(path), "%s/dlfilters/%s", exec_path, file);
163+
free(exec_path);
164+
if (!access(path, R_OK))
165+
file = path;
166+
out:
167+
return strdup(file);
168+
}
169+
139170
#define CHECK_FLAG(x) BUILD_BUG_ON((u64)PERF_DLFILTER_FLAG_ ## x != (u64)PERF_IP_FLAG_ ## x)
140171

141172
static int dlfilter__init(struct dlfilter *d, const char *file)
@@ -155,7 +186,7 @@ static int dlfilter__init(struct dlfilter *d, const char *file)
155186
CHECK_FLAG(VMEXIT);
156187

157188
memset(d, 0, sizeof(*d));
158-
d->file = strdup(file);
189+
d->file = find_dlfilter(file);
159190
if (!d->file)
160191
return -1;
161192
return 0;
@@ -333,3 +364,87 @@ int dlfilter__do_filter_event(struct dlfilter *d,
333364

334365
return ret;
335366
}
367+
368+
static bool get_filter_desc(const char *dirname, const char *name,
369+
char **desc, char **long_desc)
370+
{
371+
char path[PATH_MAX];
372+
void *handle;
373+
const char *(*desc_fn)(const char **long_description);
374+
375+
snprintf(path, sizeof(path), "%s/%s", dirname, name);
376+
handle = dlopen(path, RTLD_NOW);
377+
if (!handle || !(dlsym(handle, "filter_event") || dlsym(handle, "filter_event_early")))
378+
return false;
379+
desc_fn = dlsym(handle, "filter_description");
380+
if (desc_fn) {
381+
const char *dsc;
382+
const char *long_dsc;
383+
384+
dsc = desc_fn(&long_dsc);
385+
if (dsc)
386+
*desc = strdup(dsc);
387+
if (long_dsc)
388+
*long_desc = strdup(long_dsc);
389+
}
390+
dlclose(handle);
391+
return true;
392+
}
393+
394+
static void list_filters(const char *dirname)
395+
{
396+
struct dirent *entry;
397+
DIR *dir;
398+
399+
dir = opendir(dirname);
400+
if (!dir)
401+
return;
402+
403+
while ((entry = readdir(dir)) != NULL)
404+
{
405+
size_t n = strlen(entry->d_name);
406+
char *long_desc = NULL;
407+
char *desc = NULL;
408+
409+
if (entry->d_type == DT_DIR || n < 4 ||
410+
strcmp(".so", entry->d_name + n - 3))
411+
continue;
412+
if (!get_filter_desc(dirname, entry->d_name, &desc, &long_desc))
413+
continue;
414+
printf(" %-36s %s\n", entry->d_name, desc ? desc : "");
415+
if (verbose) {
416+
char *p = long_desc;
417+
char *line;
418+
419+
while ((line = strsep(&p, "\n")) != NULL)
420+
printf("%39s%s\n", "", line);
421+
}
422+
free(long_desc);
423+
free(desc);
424+
}
425+
426+
closedir(dir);
427+
}
428+
429+
int list_available_dlfilters(const struct option *opt __maybe_unused,
430+
const char *s __maybe_unused,
431+
int unset __maybe_unused)
432+
{
433+
char path[PATH_MAX];
434+
char *exec_path;
435+
436+
printf("List of available dlfilters:\n");
437+
438+
list_filters(".");
439+
440+
exec_path = get_argv_exec_path();
441+
if (!exec_path)
442+
goto out;
443+
snprintf(path, sizeof(path), "%s/dlfilters", exec_path);
444+
445+
list_filters(path);
446+
447+
free(exec_path);
448+
out:
449+
exit(0);
450+
}

tools/perf/util/dlfilter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,6 @@ static inline int dlfilter__filter_event_early(struct dlfilter *d,
8888
return dlfilter__do_filter_event(d, event, sample, evsel, machine, al, addr_al, true);
8989
}
9090

91+
int list_available_dlfilters(const struct option *opt, const char *s, int unset);
92+
9193
#endif

tools/perf/util/perf_dlfilter.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,10 @@ int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ct
126126
*/
127127
int filter_event_early(void *data, const struct perf_dlfilter_sample *sample, void *ctx);
128128

129+
/*
130+
* If implemented, return a one-line description of the filter, and optionally
131+
* a longer description.
132+
*/
133+
const char *filter_description(const char **long_description);
134+
129135
#endif

0 commit comments

Comments
 (0)