diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2017-08-31 10:50:04 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2017-09-01 13:45:58 -0400 |
commit | 27702bcfe8a125a1feeeb5f07526d63b20cac47f (patch) | |
tree | 7ea5f8ea7a27dd431e638c887086aacb21ef4b05 /tools/perf | |
parent | 89be3f8ab701180fc0329eff1b076528d64ac56b (diff) |
perf trace: Support syscall name globbing
So now we can use:
# perf trace -e pkey_*
532.784 ( 0.006 ms): pkey/16018 pkey_alloc(init_val: DISABLE_WRITE) = -1 EINVAL Invalid argument
532.795 ( 0.004 ms): pkey/16018 pkey_mprotect(start: 0x7f380d0a6000, len: 4096, prot: READ|WRITE, pkey: -1) = 0
532.801 ( 0.002 ms): pkey/16018 pkey_free(pkey: -1 ) = -1 EINVAL Invalid argument
^C[root@jouet ~]#
Or '-e epoll*', '-e *msg*', etc.
Combining syscall names with perf events, tracepoints, etc, continues to
be valid, i.e. this is possible:
# perf probe -L sys_nanosleep
<SyS_nanosleep@/home/acme/git/linux/kernel/time/hrtimer.c:0>
0 SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp,
struct timespec __user *, rmtp)
{
struct timespec64 tu;
5 if (get_timespec64(&tu, rqtp))
6 return -EFAULT;
if (!timespec64_valid(&tu))
9 return -EINVAL;
11 current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
12 current->restart_block.nanosleep.rmtp = rmtp;
13 return hrtimer_nanosleep(&tu, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
}
# perf probe my_probe="sys_nanosleep:12 rmtp"
Added new event:
probe:my_probe (on sys_nanosleep:12 with rmtp)
You can now use it in all perf tools, such as:
perf record -e probe:my_probe -aR sleep 1
#
# perf trace -e probe:my_probe/max-stack=5/,*sleep sleep 1
0.427 ( 0.003 ms): sleep/16690 nanosleep(rqtp: 0x7ffefc245090) ...
0.430 ( ): probe:my_probe:(ffffffffbd112923) rmtp=0)
sys_nanosleep ([kernel.kallsyms])
do_syscall_64 ([kernel.kallsyms])
return_from_SYSCALL_64 ([kernel.kallsyms])
__nanosleep_nocancel (/usr/lib64/libc-2.25.so)
0.427 (1000.208 ms): sleep/16690 ... [continued]: nanosleep()) = 0
#
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/n/tip-elycoi8wy6y0w9dkj7ox1mzz@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/Documentation/perf-trace.txt | 2 | ||||
-rw-r--r-- | tools/perf/builtin-trace.c | 39 |
2 files changed, 36 insertions, 5 deletions
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index c1e3288a2dfb..d53bea6bd571 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt | |||
@@ -37,7 +37,7 @@ OPTIONS | |||
37 | --expr:: | 37 | --expr:: |
38 | --event:: | 38 | --event:: |
39 | List of syscalls and other perf events (tracepoints, HW cache events, | 39 | List of syscalls and other perf events (tracepoints, HW cache events, |
40 | etc) to show. | 40 | etc) to show. Globbing is supported, e.g.: "epoll_*", "*msg*", etc. |
41 | See 'perf list' for a complete list of events. | 41 | See 'perf list' for a complete list of events. |
42 | Prefixing with ! shows all syscalls but the ones specified. You may | 42 | Prefixing with ! shows all syscalls but the ones specified. You may |
43 | need to escape it. | 43 | need to escape it. |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index d59cdadf3a79..771ddab94bb0 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -1261,6 +1261,7 @@ static int trace__read_syscall_info(struct trace *trace, int id) | |||
1261 | static int trace__validate_ev_qualifier(struct trace *trace) | 1261 | static int trace__validate_ev_qualifier(struct trace *trace) |
1262 | { | 1262 | { |
1263 | int err = 0, i; | 1263 | int err = 0, i; |
1264 | size_t nr_allocated; | ||
1264 | struct str_node *pos; | 1265 | struct str_node *pos; |
1265 | 1266 | ||
1266 | trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier); | 1267 | trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier); |
@@ -1274,13 +1275,18 @@ static int trace__validate_ev_qualifier(struct trace *trace) | |||
1274 | goto out; | 1275 | goto out; |
1275 | } | 1276 | } |
1276 | 1277 | ||
1278 | nr_allocated = trace->ev_qualifier_ids.nr; | ||
1277 | i = 0; | 1279 | i = 0; |
1278 | 1280 | ||
1279 | strlist__for_each_entry(pos, trace->ev_qualifier) { | 1281 | strlist__for_each_entry(pos, trace->ev_qualifier) { |
1280 | const char *sc = pos->s; | 1282 | const char *sc = pos->s; |
1281 | int id = syscalltbl__id(trace->sctbl, sc); | 1283 | int id = syscalltbl__id(trace->sctbl, sc), match_next = -1; |
1282 | 1284 | ||
1283 | if (id < 0) { | 1285 | if (id < 0) { |
1286 | id = syscalltbl__strglobmatch_first(trace->sctbl, sc, &match_next); | ||
1287 | if (id >= 0) | ||
1288 | goto matches; | ||
1289 | |||
1284 | if (err == 0) { | 1290 | if (err == 0) { |
1285 | fputs("Error:\tInvalid syscall ", trace->output); | 1291 | fputs("Error:\tInvalid syscall ", trace->output); |
1286 | err = -EINVAL; | 1292 | err = -EINVAL; |
@@ -1290,13 +1296,37 @@ static int trace__validate_ev_qualifier(struct trace *trace) | |||
1290 | 1296 | ||
1291 | fputs(sc, trace->output); | 1297 | fputs(sc, trace->output); |
1292 | } | 1298 | } |
1293 | 1299 | matches: | |
1294 | trace->ev_qualifier_ids.entries[i++] = id; | 1300 | trace->ev_qualifier_ids.entries[i++] = id; |
1301 | if (match_next == -1) | ||
1302 | continue; | ||
1303 | |||
1304 | while (1) { | ||
1305 | id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next); | ||
1306 | if (id < 0) | ||
1307 | break; | ||
1308 | if (nr_allocated == trace->ev_qualifier_ids.nr) { | ||
1309 | void *entries; | ||
1310 | |||
1311 | nr_allocated += 8; | ||
1312 | entries = realloc(trace->ev_qualifier_ids.entries, | ||
1313 | nr_allocated * sizeof(trace->ev_qualifier_ids.entries[0])); | ||
1314 | if (entries == NULL) { | ||
1315 | err = -ENOMEM; | ||
1316 | fputs("\nError:\t Not enough memory for parsing\n", trace->output); | ||
1317 | goto out_free; | ||
1318 | } | ||
1319 | trace->ev_qualifier_ids.entries = entries; | ||
1320 | } | ||
1321 | trace->ev_qualifier_ids.nr++; | ||
1322 | trace->ev_qualifier_ids.entries[i++] = id; | ||
1323 | } | ||
1295 | } | 1324 | } |
1296 | 1325 | ||
1297 | if (err < 0) { | 1326 | if (err < 0) { |
1298 | fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'" | 1327 | fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'" |
1299 | "\nHint:\tand: 'man syscalls'\n", trace->output); | 1328 | "\nHint:\tand: 'man syscalls'\n", trace->output); |
1329 | out_free: | ||
1300 | zfree(&trace->ev_qualifier_ids.entries); | 1330 | zfree(&trace->ev_qualifier_ids.entries); |
1301 | trace->ev_qualifier_ids.nr = 0; | 1331 | trace->ev_qualifier_ids.nr = 0; |
1302 | } | 1332 | } |
@@ -2814,7 +2844,7 @@ static int trace__parse_events_option(const struct option *opt, const char *str, | |||
2814 | struct trace *trace = (struct trace *)opt->value; | 2844 | struct trace *trace = (struct trace *)opt->value; |
2815 | const char *s = str; | 2845 | const char *s = str; |
2816 | char *sep = NULL, *lists[2] = { NULL, NULL, }; | 2846 | char *sep = NULL, *lists[2] = { NULL, NULL, }; |
2817 | int len = strlen(str) + 1, err = -1, list; | 2847 | int len = strlen(str) + 1, err = -1, list, idx; |
2818 | char *strace_groups_dir = system_path(STRACE_GROUPS_DIR); | 2848 | char *strace_groups_dir = system_path(STRACE_GROUPS_DIR); |
2819 | char group_name[PATH_MAX]; | 2849 | char group_name[PATH_MAX]; |
2820 | 2850 | ||
@@ -2831,7 +2861,8 @@ static int trace__parse_events_option(const struct option *opt, const char *str, | |||
2831 | *sep = '\0'; | 2861 | *sep = '\0'; |
2832 | 2862 | ||
2833 | list = 0; | 2863 | list = 0; |
2834 | if (syscalltbl__id(trace->sctbl, s) >= 0) { | 2864 | if (syscalltbl__id(trace->sctbl, s) >= 0 || |
2865 | syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) { | ||
2835 | list = 1; | 2866 | list = 1; |
2836 | } else { | 2867 | } else { |
2837 | path__join(group_name, sizeof(group_name), strace_groups_dir, s); | 2868 | path__join(group_name, sizeof(group_name), strace_groups_dir, s); |