diff options
author | Wang Nan <wangnan0@huawei.com> | 2015-07-10 03:36:10 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2015-07-20 16:49:17 -0400 |
commit | 4ba1faa19fa5f415bd69b1d7c366028332468bca (patch) | |
tree | 95a83aa5383a812da74eb3cc6abf33ab97236da1 /tools/perf/util/parse-events.c | |
parent | 15bfd2cc107a9971ac8aeb4b7724ced581a2ed30 (diff) |
perf record: Allow filtering perf's pid via --exclude-perf
This patch allows 'perf record' to exclude events issued by perf itself
by '--exclude-perf' option.
Before this patch, when doing something like:
# perf record -a -e syscalls:sys_enter_write <cmd>
One could easily get result like this:
# /tmp/perf report --stdio
...
# Overhead Command Shared Object Symbol
# ........ ....... .................. ....................
#
99.99% perf libpthread-2.18.so [.] __write_nocancel
0.01% ls libc-2.18.so [.] write
0.01% sshd libc-2.18.so [.] write
...
Where most events are generated by perf itself.
A shell trick can be done to filter perf itself out:
# cat << EOF > ./tmp
> #!/bin/sh
> exec perf record -e ... --filter="common_pid != \$\$" -a sleep 10
> EOF
# chmod a+x ./tmp
# ./tmp
However, doing so is user unfriendly.
This patch extracts evsel iteration framework introduced by patch 'perf
record: Apply filter to all events in a glob matching' into
foreach_evsel_in_last_glob(), and makes exclude_perf() function append
new filter expression to each evsel selected by a '-e' selector.
To avoid losing filters if user pass '--filter' after '--exclude-perf',
this patch uses perf_evsel__append_filter() in both case, instead of
perf_evsel__set_filter() which removes old filter. As a side effect, now
it is possible to use multiple '--filter' option for one selector. They
are combinded with '&&'.
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1436513770-8896-2-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util/parse-events.c')
-rw-r--r-- | tools/perf/util/parse-events.c | 83 |
1 files changed, 70 insertions, 13 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index bbb7fbc2857e..4f807fc1b14a 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -1167,27 +1167,24 @@ int parse_events_option(const struct option *opt, const char *str, | |||
1167 | return ret; | 1167 | return ret; |
1168 | } | 1168 | } |
1169 | 1169 | ||
1170 | int parse_filter(const struct option *opt, const char *str, | 1170 | static int |
1171 | int unset __maybe_unused) | 1171 | foreach_evsel_in_last_glob(struct perf_evlist *evlist, |
1172 | int (*func)(struct perf_evsel *evsel, | ||
1173 | const void *arg), | ||
1174 | const void *arg) | ||
1172 | { | 1175 | { |
1173 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; | ||
1174 | struct perf_evsel *last = NULL; | 1176 | struct perf_evsel *last = NULL; |
1177 | int err; | ||
1175 | 1178 | ||
1176 | if (evlist->nr_entries > 0) | 1179 | if (evlist->nr_entries > 0) |
1177 | last = perf_evlist__last(evlist); | 1180 | last = perf_evlist__last(evlist); |
1178 | 1181 | ||
1179 | do { | 1182 | do { |
1180 | if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { | 1183 | err = (*func)(last, arg); |
1181 | fprintf(stderr, | 1184 | if (err) |
1182 | "--filter option should follow a -e tracepoint option\n"); | ||
1183 | return -1; | ||
1184 | } | ||
1185 | |||
1186 | if (perf_evsel__set_filter(last, str) < 0) { | ||
1187 | fprintf(stderr, | ||
1188 | "not enough memory to hold filter string\n"); | ||
1189 | return -1; | 1185 | return -1; |
1190 | } | 1186 | if (!last) |
1187 | return 0; | ||
1191 | 1188 | ||
1192 | if (last->node.prev == &evlist->entries) | 1189 | if (last->node.prev == &evlist->entries) |
1193 | return 0; | 1190 | return 0; |
@@ -1197,6 +1194,66 @@ int parse_filter(const struct option *opt, const char *str, | |||
1197 | return 0; | 1194 | return 0; |
1198 | } | 1195 | } |
1199 | 1196 | ||
1197 | static int set_filter(struct perf_evsel *evsel, const void *arg) | ||
1198 | { | ||
1199 | const char *str = arg; | ||
1200 | |||
1201 | if (evsel == NULL || evsel->attr.type != PERF_TYPE_TRACEPOINT) { | ||
1202 | fprintf(stderr, | ||
1203 | "--filter option should follow a -e tracepoint option\n"); | ||
1204 | return -1; | ||
1205 | } | ||
1206 | |||
1207 | if (perf_evsel__append_filter(evsel, "&&", str) < 0) { | ||
1208 | fprintf(stderr, | ||
1209 | "not enough memory to hold filter string\n"); | ||
1210 | return -1; | ||
1211 | } | ||
1212 | |||
1213 | return 0; | ||
1214 | } | ||
1215 | |||
1216 | int parse_filter(const struct option *opt, const char *str, | ||
1217 | int unset __maybe_unused) | ||
1218 | { | ||
1219 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; | ||
1220 | |||
1221 | return foreach_evsel_in_last_glob(evlist, set_filter, | ||
1222 | (const void *)str); | ||
1223 | } | ||
1224 | |||
1225 | static int add_exclude_perf_filter(struct perf_evsel *evsel, | ||
1226 | const void *arg __maybe_unused) | ||
1227 | { | ||
1228 | char new_filter[64]; | ||
1229 | |||
1230 | if (evsel == NULL || evsel->attr.type != PERF_TYPE_TRACEPOINT) { | ||
1231 | fprintf(stderr, | ||
1232 | "--exclude-perf option should follow a -e tracepoint option\n"); | ||
1233 | return -1; | ||
1234 | } | ||
1235 | |||
1236 | snprintf(new_filter, sizeof(new_filter), "common_pid != %d", getpid()); | ||
1237 | |||
1238 | if (perf_evsel__append_filter(evsel, "&&", new_filter) < 0) { | ||
1239 | fprintf(stderr, | ||
1240 | "not enough memory to hold filter string\n"); | ||
1241 | return -1; | ||
1242 | } | ||
1243 | |||
1244 | return 0; | ||
1245 | } | ||
1246 | |||
1247 | int exclude_perf(const struct option *opt, | ||
1248 | const char *arg __maybe_unused, | ||
1249 | int unset __maybe_unused) | ||
1250 | { | ||
1251 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; | ||
1252 | |||
1253 | return foreach_evsel_in_last_glob(evlist, add_exclude_perf_filter, | ||
1254 | NULL); | ||
1255 | } | ||
1256 | |||
1200 | static const char * const event_type_descriptors[] = { | 1257 | static const char * const event_type_descriptors[] = { |
1201 | "Hardware event", | 1258 | "Hardware event", |
1202 | "Software event", | 1259 | "Software event", |