Commit 638e2b99 authored by Adrian Hunter's avatar Adrian Hunter Committed by Arnaldo Carvalho de Melo

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: 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-4-adrian.hunter@intel.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 9bde93a7
...@@ -37,6 +37,7 @@ int start(void **data, void *ctx); ...@@ -37,6 +37,7 @@ 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); int filter_event_early(void *data, const struct perf_dlfilter_sample *sample, void *ctx);
const char *filter_description(const char **long_description);
---- ----
If implemented, 'start' will be called at the beginning, before any 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 ...@@ -59,6 +60,9 @@ error code. 'data' is set by 'start'. 'ctx' is needed for calls to
'filter_event_early' is the same as 'filter_event' except it is called before 'filter_event_early' is the same as 'filter_event' except it is called before
internal filtering. internal filtering.
If implemented, 'filter_description' should return a one-line description
of the filter, and optionally a longer description.
The perf_dlfilter_sample structure The perf_dlfilter_sample structure
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......
...@@ -102,6 +102,10 @@ OPTIONS ...@@ -102,6 +102,10 @@ OPTIONS
Filter sample events using the given shared object file. Filter sample events using the given shared object file.
Refer linkperf:perf-dlfilter[1] Refer linkperf:perf-dlfilter[1]
--list-dlfilters=::
Display a list of available dlfilters. Use with option -v (must come
before option --list-dlfilters) to show long descriptions.
-a:: -a::
Force system-wide collection. Scripts run without a <command> Force system-wide collection. Scripts run without a <command>
normally use -a by default, while scripts run with a <command> normally use -a by default, while scripts run with a <command>
......
...@@ -3631,6 +3631,8 @@ int cmd_script(int argc, const char **argv) ...@@ -3631,6 +3631,8 @@ int cmd_script(int argc, const char **argv)
"show latency attributes (irqs/preemption disabled, etc)"), "show latency attributes (irqs/preemption disabled, etc)"),
OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts", OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
list_available_scripts), list_available_scripts),
OPT_CALLBACK_NOOPT(0, "list-dlfilters", NULL, NULL, "list available dlfilters",
list_available_dlfilters),
OPT_CALLBACK('s', "script", NULL, "name", OPT_CALLBACK('s', "script", NULL, "name",
"script file name (lang:script name, script name, or *)", "script file name (lang:script name, script name, or *)",
parse_scriptname), parse_scriptname),
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#include <dlfcn.h> #include <dlfcn.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <dirent.h>
#include <subcmd/exec-cmd.h>
#include <linux/zalloc.h> #include <linux/zalloc.h>
#include <linux/build_bug.h> #include <linux/build_bug.h>
...@@ -136,6 +138,35 @@ static const struct perf_dlfilter_fns perf_dlfilter_fns = { ...@@ -136,6 +138,35 @@ static const struct perf_dlfilter_fns perf_dlfilter_fns = {
.resolve_addr = dlfilter__resolve_addr, .resolve_addr = dlfilter__resolve_addr,
}; };
static char *find_dlfilter(const char *file)
{
char path[PATH_MAX];
char *exec_path;
if (strchr(file, '/'))
goto out;
if (!access(file, R_OK)) {
/*
* Prepend "./" so that dlopen will find the file in the
* current directory.
*/
snprintf(path, sizeof(path), "./%s", file);
file = path;
goto out;
}
exec_path = get_argv_exec_path();
if (!exec_path)
goto out;
snprintf(path, sizeof(path), "%s/dlfilters/%s", exec_path, file);
free(exec_path);
if (!access(path, R_OK))
file = path;
out:
return strdup(file);
}
#define CHECK_FLAG(x) BUILD_BUG_ON((u64)PERF_DLFILTER_FLAG_ ## x != (u64)PERF_IP_FLAG_ ## x) #define CHECK_FLAG(x) BUILD_BUG_ON((u64)PERF_DLFILTER_FLAG_ ## x != (u64)PERF_IP_FLAG_ ## x)
static int dlfilter__init(struct dlfilter *d, const char *file) static int dlfilter__init(struct dlfilter *d, const char *file)
...@@ -155,7 +186,7 @@ static int dlfilter__init(struct dlfilter *d, const char *file) ...@@ -155,7 +186,7 @@ static int dlfilter__init(struct dlfilter *d, const char *file)
CHECK_FLAG(VMEXIT); CHECK_FLAG(VMEXIT);
memset(d, 0, sizeof(*d)); memset(d, 0, sizeof(*d));
d->file = strdup(file); d->file = find_dlfilter(file);
if (!d->file) if (!d->file)
return -1; return -1;
return 0; return 0;
...@@ -333,3 +364,87 @@ int dlfilter__do_filter_event(struct dlfilter *d, ...@@ -333,3 +364,87 @@ int dlfilter__do_filter_event(struct dlfilter *d,
return ret; return ret;
} }
static bool get_filter_desc(const char *dirname, const char *name,
char **desc, char **long_desc)
{
char path[PATH_MAX];
void *handle;
const char *(*desc_fn)(const char **long_description);
snprintf(path, sizeof(path), "%s/%s", dirname, name);
handle = dlopen(path, RTLD_NOW);
if (!handle || !(dlsym(handle, "filter_event") || dlsym(handle, "filter_event_early")))
return false;
desc_fn = dlsym(handle, "filter_description");
if (desc_fn) {
const char *dsc;
const char *long_dsc;
dsc = desc_fn(&long_dsc);
if (dsc)
*desc = strdup(dsc);
if (long_dsc)
*long_desc = strdup(long_dsc);
}
dlclose(handle);
return true;
}
static void list_filters(const char *dirname)
{
struct dirent *entry;
DIR *dir;
dir = opendir(dirname);
if (!dir)
return;
while ((entry = readdir(dir)) != NULL)
{
size_t n = strlen(entry->d_name);
char *long_desc = NULL;
char *desc = NULL;
if (entry->d_type == DT_DIR || n < 4 ||
strcmp(".so", entry->d_name + n - 3))
continue;
if (!get_filter_desc(dirname, entry->d_name, &desc, &long_desc))
continue;
printf(" %-36s %s\n", entry->d_name, desc ? desc : "");
if (verbose) {
char *p = long_desc;
char *line;
while ((line = strsep(&p, "\n")) != NULL)
printf("%39s%s\n", "", line);
}
free(long_desc);
free(desc);
}
closedir(dir);
}
int list_available_dlfilters(const struct option *opt __maybe_unused,
const char *s __maybe_unused,
int unset __maybe_unused)
{
char path[PATH_MAX];
char *exec_path;
printf("List of available dlfilters:\n");
list_filters(".");
exec_path = get_argv_exec_path();
if (!exec_path)
goto out;
snprintf(path, sizeof(path), "%s/dlfilters", exec_path);
list_filters(path);
free(exec_path);
out:
exit(0);
}
...@@ -88,4 +88,6 @@ static inline int dlfilter__filter_event_early(struct dlfilter *d, ...@@ -88,4 +88,6 @@ static inline int dlfilter__filter_event_early(struct dlfilter *d,
return dlfilter__do_filter_event(d, event, sample, evsel, machine, al, addr_al, true); return dlfilter__do_filter_event(d, event, sample, evsel, machine, al, addr_al, true);
} }
int list_available_dlfilters(const struct option *opt, const char *s, int unset);
#endif #endif
...@@ -126,4 +126,10 @@ int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ct ...@@ -126,4 +126,10 @@ int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ct
*/ */
int filter_event_early(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, return a one-line description of the filter, and optionally
* a longer description.
*/
const char *filter_description(const char **long_description);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment