perf probe: Allow to use filter on --del command
This makes perf-probe --del option to accept filter rules not only simple glob pattern. This simplifies the code and improve the flexibility. E.g. if we remove 2 different pattern events, we need 2 -d options. ---- # ./perf probe -d vfs\* -d malloc Removed event: probe_libc:malloc Removed event: probe:vfs_read ---- This allows you to joint the 2 patterns with '|'. ---- # ./perf probe -d 'vfs*|malloc' Removed event: probe:vfs_read Removed event: probe_libc:malloc ---- Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: David Ahern <dsahern@gmail.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/20150505022948.23399.4197.stgit@localhost.localdomain Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
2dd6d8a10a
commit
307a464b23
|
@ -55,12 +55,12 @@ static struct {
|
|||
bool show_ext_vars;
|
||||
bool show_funcs;
|
||||
bool mod_events;
|
||||
bool del_events;
|
||||
bool uprobes;
|
||||
bool quiet;
|
||||
bool target_used;
|
||||
int nevents;
|
||||
struct perf_probe_event events[MAX_PROBES];
|
||||
struct strlist *dellist;
|
||||
struct line_range line_range;
|
||||
char *target;
|
||||
int max_probe_points;
|
||||
|
@ -195,10 +195,8 @@ static int opt_del_probe_event(const struct option *opt __maybe_unused,
|
|||
const char *str, int unset __maybe_unused)
|
||||
{
|
||||
if (str) {
|
||||
params.mod_events = true;
|
||||
if (!params.dellist)
|
||||
params.dellist = strlist__new(true, NULL);
|
||||
strlist__add(params.dellist, str);
|
||||
params.del_events = true;
|
||||
return params_add_filter(str);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -313,8 +311,6 @@ static void cleanup_params(void)
|
|||
|
||||
for (i = 0; i < params.nevents; i++)
|
||||
clear_perf_probe_event(params.events + i);
|
||||
if (params.dellist)
|
||||
strlist__delete(params.dellist);
|
||||
line_range__clear(¶ms.line_range);
|
||||
free(params.target);
|
||||
if (params.filter)
|
||||
|
@ -454,7 +450,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
if (params.max_probe_points == 0)
|
||||
params.max_probe_points = MAX_PROBES;
|
||||
|
||||
if ((!params.nevents && !params.dellist && !params.list_events &&
|
||||
if ((!params.nevents && !params.del_events && !params.list_events &&
|
||||
!params.show_lines && !params.show_funcs))
|
||||
usage_with_options(probe_usage, options);
|
||||
|
||||
|
@ -514,8 +510,8 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (params.dellist) {
|
||||
ret = del_perf_probe_events(params.dellist);
|
||||
if (params.del_events) {
|
||||
ret = del_perf_probe_events(params.filter);
|
||||
if (ret < 0) {
|
||||
pr_err_with_code(" Error: Failed to delete events.", ret);
|
||||
return ret;
|
||||
|
|
|
@ -2734,40 +2734,39 @@ error:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int del_trace_probe_event(int fd, const char *buf,
|
||||
static int del_trace_probe_events(int fd, struct strfilter *filter,
|
||||
struct strlist *namelist)
|
||||
{
|
||||
struct str_node *ent, *n;
|
||||
struct str_node *ent;
|
||||
const char *p;
|
||||
int ret = -ENOENT;
|
||||
|
||||
if (strpbrk(buf, "*?")) { /* Glob-exp */
|
||||
strlist__for_each_safe(ent, n, namelist)
|
||||
if (strglobmatch(ent->s, buf)) {
|
||||
if (!namelist)
|
||||
return -ENOENT;
|
||||
|
||||
strlist__for_each(ent, namelist) {
|
||||
p = strchr(ent->s, ':');
|
||||
if ((p && strfilter__compare(filter, p + 1)) ||
|
||||
strfilter__compare(filter, ent->s)) {
|
||||
ret = __del_trace_probe_event(fd, ent);
|
||||
if (ret < 0)
|
||||
break;
|
||||
strlist__remove(namelist, ent);
|
||||
}
|
||||
} else {
|
||||
ent = strlist__find(namelist, buf);
|
||||
if (ent) {
|
||||
ret = __del_trace_probe_event(fd, ent);
|
||||
if (ret >= 0)
|
||||
strlist__remove(namelist, ent);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int del_perf_probe_events(struct strlist *dellist)
|
||||
int del_perf_probe_events(struct strfilter *filter)
|
||||
{
|
||||
int ret = -1, ret2, ufd = -1, kfd = -1;
|
||||
char buf[128];
|
||||
const char *group, *event;
|
||||
char *p, *str;
|
||||
struct str_node *ent;
|
||||
int ret, ret2, ufd = -1, kfd = -1;
|
||||
struct strlist *namelist = NULL, *unamelist = NULL;
|
||||
char *str = strfilter__string(filter);
|
||||
|
||||
if (!str)
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("Delete filter: \'%s\'\n", str);
|
||||
|
||||
/* Get current event names */
|
||||
kfd = open_kprobe_events(true);
|
||||
|
@ -2780,59 +2779,21 @@ int del_perf_probe_events(struct strlist *dellist)
|
|||
|
||||
if (kfd < 0 && ufd < 0) {
|
||||
print_both_open_warning(kfd, ufd);
|
||||
ret = kfd;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (namelist == NULL && unamelist == NULL) {
|
||||
ret = -ENOENT;
|
||||
ret = del_trace_probe_events(kfd, filter, namelist);
|
||||
if (ret < 0 && ret != -ENOENT)
|
||||
goto error;
|
||||
}
|
||||
|
||||
strlist__for_each(ent, dellist) {
|
||||
str = strdup(ent->s);
|
||||
if (str == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
pr_debug("Parsing: %s\n", str);
|
||||
p = strchr(str, ':');
|
||||
if (p) {
|
||||
group = str;
|
||||
*p = '\0';
|
||||
event = p + 1;
|
||||
} else {
|
||||
group = "*";
|
||||
event = str;
|
||||
}
|
||||
|
||||
if (event && *event == '.')
|
||||
event++;
|
||||
|
||||
ret = e_snprintf(buf, 128, "%s:%s", group, event);
|
||||
if (ret < 0) {
|
||||
pr_err("Failed to copy event.");
|
||||
free(str);
|
||||
goto error;
|
||||
}
|
||||
|
||||
pr_debug("Group: %s, Event: %s\n", group, event);
|
||||
free(str);
|
||||
|
||||
ret = ret2 = -ENOENT;
|
||||
if (namelist)
|
||||
ret = del_trace_probe_event(kfd, buf, namelist);
|
||||
|
||||
if ((ret >= 0 || ret == -ENOENT) && unamelist)
|
||||
ret2 = del_trace_probe_event(ufd, buf, unamelist);
|
||||
|
||||
/* Since we can remove probes which already removed, don't check it */
|
||||
if (ret == -ENOENT && ret2 == -ENOENT)
|
||||
pr_debug("Event \"%s\" does not exist.\n", buf);
|
||||
else if (ret < 0 || ret2 < 0) {
|
||||
if (ret >= 0)
|
||||
ret2 = del_trace_probe_events(ufd, filter, unamelist);
|
||||
if (ret2 < 0 && ret2 != -ENOENT)
|
||||
ret = ret2;
|
||||
break;
|
||||
}
|
||||
else if (ret == -ENOENT && ret2 == -ENOENT) {
|
||||
pr_debug("\"%s\" does not hit any event.\n", str);
|
||||
/* Note that this is silently ignored */
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
error:
|
||||
|
@ -2845,6 +2806,7 @@ error:
|
|||
strlist__delete(unamelist);
|
||||
close(ufd);
|
||||
}
|
||||
free(str);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ extern const char *kernel_get_module_path(const char *module);
|
|||
|
||||
extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
|
||||
int max_probe_points, bool force_add);
|
||||
extern int del_perf_probe_events(struct strlist *dellist);
|
||||
extern int del_perf_probe_events(struct strfilter *filter);
|
||||
extern int show_perf_probe_events(struct strfilter *filter);
|
||||
extern int show_line_range(struct line_range *lr, const char *module,
|
||||
bool user);
|
||||
|
|
Loading…
Reference in New Issue