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

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.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 9bde93a7
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+4 −0
Original line number Diff line number Diff line
@@ -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>
+2 −0
Original line number Diff line number Diff line
@@ -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),
+116 −1
Original line number Diff line number Diff line
@@ -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);
}
+2 −0
Original line number Diff line number Diff line
@@ -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
Loading