Commit bd09d7b5 authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Arnaldo Carvalho de Melo

perf probe: Add variable filter support

Add filters support for available variable list.

Default filter is "!__k???tab_*&!__crc_*" for filtering out
automatically generated symbols.

The format of filter rule is "[!]GLOBPATTERN", so you can use wild
cards. If the filter rule starts with '!', matched variables are filter
out.

e.g.:
 # perf probe -V schedule --externs --filter=cpu*
Available variables at schedule
        @<schedule+0>
                cpumask_var_t   cpu_callout_mask
                cpumask_var_t   cpu_core_map
                cpumask_var_t   cpu_isolated_map
                cpumask_var_t   cpu_sibling_map
                int     cpu_number
                long unsigned int*      cpu_bit_bitmap
		...

Cc: 2nddept-manager@sdl.hitachi.co.jp
Cc: Chase Douglas <chase.douglas@canonical.com>
Cc: Franck Bui-Huu <fbuihuu@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
LKML-Reference: <20110120141539.25915.43401.stgit@ltc236.sdl.hitachi.co.jp>
Signed-off-by: default avatarMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
[ committer note: Removed the elf.h include as it was fixed up in e80711ca]
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 68baa431
......@@ -77,6 +77,12 @@ OPTIONS
--funcs::
Show available functions in given module or kernel.
--filter=FILTER::
(Only for --vars) Set filter for variables. FILTER is a combination of
glob pattern, see FILTER PATTERN for details.
Default FILTER is "!__k???tab_* & !__crc_*".
If several filters are specified, only the last filter is valid.
-f::
--force::
Forcibly add events with existing name.
......@@ -139,6 +145,14 @@ e.g.
This provides some sort of flexibility and robustness to probe point definitions against minor code changes. For example, actual 10th line of schedule() can be moved easily by modifying schedule(), but the same line matching 'rq=cpu_rq*' may still exist in the function.)
FILTER PATTERN
--------------
The filter pattern is a glob matching pattern(s) to filter variables.
In addition, you can use "!" for specifying filter-out rule. You also can give several rules combined with "&" or "|", and fold those rules as one rule by using "(" ")".
e.g.
With --filter "foo* | bar*", perf probe -V shows variables which start with "foo" or "bar".
With --filter "!foo* & *bar", perf probe -V shows variables which don't start with "foo" and end with "bar", like "fizzbar". But "foobar" is filtered out.
EXAMPLES
--------
......
......@@ -36,6 +36,7 @@
#include "builtin.h"
#include "util/util.h"
#include "util/strlist.h"
#include "util/strfilter.h"
#include "util/symbol.h"
#include "util/debug.h"
#include "util/debugfs.h"
......@@ -43,6 +44,7 @@
#include "util/probe-finder.h"
#include "util/probe-event.h"
#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
#define MAX_PATH_LEN 256
/* Session management structure */
......@@ -60,6 +62,7 @@ static struct {
struct line_range line_range;
const char *target_module;
int max_probe_points;
struct strfilter *filter;
} params;
/* Parse an event definition. Note that any error must die. */
......@@ -156,6 +159,27 @@ static int opt_show_vars(const struct option *opt __used,
return ret;
}
static int opt_set_filter(const struct option *opt __used,
const char *str, int unset __used)
{
const char *err;
if (str) {
pr_debug2("Set filter: %s\n", str);
if (params.filter)
strfilter__delete(params.filter);
params.filter = strfilter__new(str, &err);
if (!params.filter) {
pr_err("Filter parse error at %ld.\n", err - str + 1);
pr_err("Source: \"%s\"\n", str);
pr_err(" %*c\n", (int)(err - str + 1), '^');
return -EINVAL;
}
}
return 0;
}
#endif
static const char * const probe_usage[] = {
......@@ -212,6 +236,10 @@ static const struct option options[] = {
"Show accessible variables on PROBEDEF", opt_show_vars),
OPT_BOOLEAN('\0', "externs", &params.show_ext_vars,
"Show external variables too (with --vars only)"),
OPT_CALLBACK('\0', "filter", NULL,
"[!]FILTER", "Set a variable filter (with --vars only)\n"
"\t\t\t(default: \"" DEFAULT_VAR_FILTER "\")",
opt_set_filter),
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
"file", "vmlinux pathname"),
OPT_STRING('s', "source", &symbol_conf.source_prefix,
......@@ -324,10 +352,16 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
" --add/--del.\n");
usage_with_options(probe_usage, options);
}
if (!params.filter)
params.filter = strfilter__new(DEFAULT_VAR_FILTER,
NULL);
ret = show_available_vars(params.events, params.nevents,
params.max_probe_points,
params.target_module,
params.filter,
params.show_ext_vars);
strfilter__delete(params.filter);
if (ret < 0)
pr_err(" Error: Failed to show vars. (%d)\n", ret);
return ret;
......
......@@ -451,12 +451,14 @@ int show_line_range(struct line_range *lr, const char *module)
}
static int show_available_vars_at(int fd, struct perf_probe_event *pev,
int max_vls, bool externs)
int max_vls, struct strfilter *_filter,
bool externs)
{
char *buf;
int ret, i;
int ret, i, nvars;
struct str_node *node;
struct variable_list *vls = NULL, *vl;
const char *var;
buf = synthesize_perf_probe_point(&pev->point);
if (!buf)
......@@ -464,8 +466,11 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev,
pr_debug("Searching variables at %s\n", buf);
ret = find_available_vars_at(fd, pev, &vls, max_vls, externs);
if (ret > 0) {
/* Some variables were found */
if (ret <= 0) {
pr_err("Failed to find variables at %s (%d)\n", buf, ret);
goto end;
}
/* Some variables are found */
fprintf(stdout, "Available variables at %s\n", buf);
for (i = 0; i < ret; i++) {
vl = &vls[i];
......@@ -476,24 +481,30 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev,
fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
vl->point.offset);
free(vl->point.symbol);
nvars = 0;
if (vl->vars) {
strlist__for_each(node, vl->vars)
strlist__for_each(node, vl->vars) {
var = strchr(node->s, '\t') + 1;
if (strfilter__compare(_filter, var)) {
fprintf(stdout, "\t\t%s\n", node->s);
nvars++;
}
}
strlist__delete(vl->vars);
} else
fprintf(stdout, "(No variables)\n");
}
if (nvars == 0)
fprintf(stdout, "\t\t(No matched variables)\n");
}
free(vls);
} else
pr_err("Failed to find variables at %s (%d)\n", buf, ret);
end:
free(buf);
return ret;
}
/* Show available variables on given probe point */
int show_available_vars(struct perf_probe_event *pevs, int npevs,
int max_vls, const char *module, bool externs)
int max_vls, const char *module,
struct strfilter *_filter, bool externs)
{
int i, fd, ret = 0;
......@@ -510,7 +521,8 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
setup_pager();
for (i = 0; i < npevs && ret >= 0; i++)
ret = show_available_vars_at(fd, &pevs[i], max_vls, externs);
ret = show_available_vars_at(fd, &pevs[i], max_vls, _filter,
externs);
close(fd);
return ret;
......@@ -556,7 +568,9 @@ int show_line_range(struct line_range *lr __unused, const char *module __unused)
int show_available_vars(struct perf_probe_event *pevs __unused,
int npevs __unused, int max_vls __unused,
const char *module __unused, bool externs __unused)
const char *module __unused,
struct strfilter *filter __unused,
bool externs __unused)
{
pr_warning("Debuginfo-analysis is not supported.\n");
return -ENOSYS;
......
......@@ -3,6 +3,7 @@
#include <stdbool.h>
#include "strlist.h"
#include "strfilter.h"
extern bool probe_event_dry_run;
......@@ -126,7 +127,7 @@ extern int show_perf_probe_events(void);
extern int show_line_range(struct line_range *lr, const char *module);
extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
int max_probe_points, const char *module,
bool externs);
struct strfilter *filter, bool externs);
extern int show_available_funcs(const char *module);
......
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