Skip to content

Commit 017037f

Browse files
committed
perf trace: Allow specifying list of syscalls and events in -e/--expr/--event
Makes it easier to specify both events and syscalls (to be formatter strace-like), i.e. previously one would have to do: # perf trace -e nanosleep --event sched:sched_switch usleep 1 Now it is possible to do: # perf trace -e nanosleep,sched:sched_switch usleep 1 0.000 ( 0.021 ms): usleep/17962 nanosleep(rqtp: 0x7ffdedd61ec0) ... 0.021 ( ): sched:sched_switch:usleep:17962 [120] S ==> swapper/1:0 [120]) 0.000 ( 0.066 ms): usleep/17962 ... [continued]: nanosleep()) = 0 # The old style --expr and using both -e and --event continues to work. Cc: Adrian Hunter <[email protected]> Cc: David Ahern <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Milian Wolff <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Wang Nan <[email protected]> Link: http://lkml.kernel.org/n/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 3556377 commit 017037f

File tree

2 files changed

+96
-32
lines changed

2 files changed

+96
-32
lines changed

tools/perf/Documentation/perf-trace.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ OPTIONS
3535

3636
-e::
3737
--expr::
38-
List of syscalls to show, currently only syscall names.
38+
--event::
39+
List of syscalls and other perf events (tracepoints, HW cache events,
40+
etc) to show.
41+
See 'perf list' for a complete list of events.
3942
Prefixing with ! shows all syscalls but the ones specified. You may
4043
need to escape it.
4144

@@ -135,9 +138,6 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
135138
--kernel-syscall-graph::
136139
Show the kernel callchains on the syscall exit path.
137140

138-
--event::
139-
Trace other events, see 'perf list' for a complete list.
140-
141141
--max-stack::
142142
Set the stack depth limit when parsing the callchain, anything
143143
beyond the specified depth will be ignored. Note that at this point

tools/perf/builtin-trace.c

Lines changed: 92 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
4242
#include <stdlib.h>
43+
#include <string.h>
4344
#include <linux/err.h>
4445
#include <linux/filter.h>
4546
#include <linux/audit.h>
@@ -2699,6 +2700,91 @@ static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
26992700
evsel->handler = handler;
27002701
}
27012702

2703+
/*
2704+
* XXX: Hackish, just splitting the combined -e+--event (syscalls
2705+
* (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2706+
* existing facilities unchanged (trace->ev_qualifier + parse_options()).
2707+
*
2708+
* It'd be better to introduce a parse_options() variant that would return a
2709+
* list with the terms it didn't match to an event...
2710+
*/
2711+
static int trace__parse_events_option(const struct option *opt, const char *str,
2712+
int unset __maybe_unused)
2713+
{
2714+
struct trace *trace = (struct trace *)opt->value;
2715+
const char *s = str;
2716+
char *sep = NULL, *lists[2] = { NULL, NULL, };
2717+
int len = strlen(str), err = -1, list;
2718+
char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2719+
char group_name[PATH_MAX];
2720+
2721+
if (strace_groups_dir == NULL)
2722+
return -1;
2723+
2724+
if (*s == '!') {
2725+
++s;
2726+
trace->not_ev_qualifier = true;
2727+
}
2728+
2729+
while (1) {
2730+
if ((sep = strchr(s, ',')) != NULL)
2731+
*sep = '\0';
2732+
2733+
list = 0;
2734+
if (syscalltbl__id(trace->sctbl, s) >= 0) {
2735+
list = 1;
2736+
} else {
2737+
path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2738+
if (access(group_name, R_OK) == 0)
2739+
list = 1;
2740+
}
2741+
2742+
if (lists[list]) {
2743+
sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2744+
} else {
2745+
lists[list] = malloc(len);
2746+
if (lists[list] == NULL)
2747+
goto out;
2748+
strcpy(lists[list], s);
2749+
}
2750+
2751+
if (!sep)
2752+
break;
2753+
2754+
*sep = ',';
2755+
s = sep + 1;
2756+
}
2757+
2758+
if (lists[1] != NULL) {
2759+
struct strlist_config slist_config = {
2760+
.dirname = strace_groups_dir,
2761+
};
2762+
2763+
trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2764+
if (trace->ev_qualifier == NULL) {
2765+
fputs("Not enough memory to parse event qualifier", trace->output);
2766+
goto out;
2767+
}
2768+
2769+
if (trace__validate_ev_qualifier(trace))
2770+
goto out;
2771+
}
2772+
2773+
err = 0;
2774+
2775+
if (lists[0]) {
2776+
struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2777+
"event selector. use 'perf list' to list available events",
2778+
parse_events_option);
2779+
err = parse_events_option(&o, lists[0], 0);
2780+
}
2781+
out:
2782+
if (sep)
2783+
*sep = ',';
2784+
2785+
return err;
2786+
}
2787+
27022788
int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
27032789
{
27042790
const char *trace_usage[] = {
@@ -2730,15 +2816,15 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
27302816
.max_stack = UINT_MAX,
27312817
};
27322818
const char *output_name = NULL;
2733-
const char *ev_qualifier_str = NULL;
27342819
const struct option trace_options[] = {
2735-
OPT_CALLBACK(0, "event", &trace.evlist, "event",
2736-
"event selector. use 'perf list' to list available events",
2737-
parse_events_option),
2820+
OPT_CALLBACK('e', "event", &trace, "event",
2821+
"event/syscall selector. use 'perf list' to list available events",
2822+
trace__parse_events_option),
27382823
OPT_BOOLEAN(0, "comm", &trace.show_comm,
27392824
"show the thread COMM next to its id"),
27402825
OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
2741-
OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
2826+
OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2827+
trace__parse_events_option),
27422828
OPT_STRING('o', "output", &output_name, "file", "output file name"),
27432829
OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
27442830
OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
@@ -2863,7 +2949,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
28632949
return -1;
28642950
}
28652951

2866-
if (!trace.trace_syscalls && ev_qualifier_str) {
2952+
if (!trace.trace_syscalls && trace.ev_qualifier) {
28672953
pr_err("The -e option can't be used with --no-syscalls.\n");
28682954
goto out;
28692955
}
@@ -2878,28 +2964,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
28782964

28792965
trace.open_id = syscalltbl__id(trace.sctbl, "open");
28802966

2881-
if (ev_qualifier_str != NULL) {
2882-
const char *s = ev_qualifier_str;
2883-
struct strlist_config slist_config = {
2884-
.dirname = system_path(STRACE_GROUPS_DIR),
2885-
};
2886-
2887-
trace.not_ev_qualifier = *s == '!';
2888-
if (trace.not_ev_qualifier)
2889-
++s;
2890-
trace.ev_qualifier = strlist__new(s, &slist_config);
2891-
if (trace.ev_qualifier == NULL) {
2892-
fputs("Not enough memory to parse event qualifier",
2893-
trace.output);
2894-
err = -ENOMEM;
2895-
goto out_close;
2896-
}
2897-
2898-
err = trace__validate_ev_qualifier(&trace);
2899-
if (err)
2900-
goto out_close;
2901-
}
2902-
29032967
err = target__validate(&trace.opts.target);
29042968
if (err) {
29052969
target__strerror(&trace.opts.target, err, bf, sizeof(bf));

0 commit comments

Comments
 (0)