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); |
