mirror of
https://github.com/torvalds/linux.git
synced 2024-12-03 01:21:28 +00:00
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>
This commit is contained in:
parent
9bde93a79a
commit
638e2b9984
@ -37,6 +37,7 @@ 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);
|
||||
const char *filter_description(const char **long_description);
|
||||
----
|
||||
|
||||
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
|
||||
'filter_event_early' is the same as 'filter_event' except it is called before
|
||||
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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -102,6 +102,10 @@ OPTIONS
|
||||
Filter sample events using the given shared object file.
|
||||
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::
|
||||
Force system-wide collection. Scripts run without 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)
|
||||
"show latency attributes (irqs/preemption disabled, etc)"),
|
||||
OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "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",
|
||||
"script file name (lang:script name, script name, or *)",
|
||||
parse_scriptname),
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <subcmd/exec-cmd.h>
|
||||
#include <linux/zalloc.h>
|
||||
#include <linux/build_bug.h>
|
||||
|
||||
@ -136,6 +138,35 @@ static const struct perf_dlfilter_fns perf_dlfilter_fns = {
|
||||
.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)
|
||||
|
||||
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);
|
||||
|
||||
memset(d, 0, sizeof(*d));
|
||||
d->file = strdup(file);
|
||||
d->file = find_dlfilter(file);
|
||||
if (!d->file)
|
||||
return -1;
|
||||
return 0;
|
||||
@ -333,3 +364,87 @@ int dlfilter__do_filter_event(struct dlfilter *d,
|
||||
|
||||
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,
|
||||
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
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
* If implemented, return a one-line description of the filter, and optionally
|
||||
* a longer description.
|
||||
*/
|
||||
const char *filter_description(const char **long_description);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user