aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2017-08-31 10:50:04 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2017-09-01 13:45:58 -0400
commit27702bcfe8a125a1feeeb5f07526d63b20cac47f (patch)
tree7ea5f8ea7a27dd431e638c887086aacb21ef4b05 /tools/perf
parent89be3f8ab701180fc0329eff1b076528d64ac56b (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.txt2
-rw-r--r--tools/perf/builtin-trace.c39
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)
1261static int trace__validate_ev_qualifier(struct trace *trace) 1261static 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 1299matches:
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);
1329out_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);