aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-trace.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-trace.c')
-rw-r--r--tools/perf/builtin-trace.c143
1 files changed, 80 insertions, 63 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 329b7832b5da..6b230af940e2 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -149,21 +149,32 @@ static void perf_evsel__delete_priv(struct perf_evsel *evsel)
149 perf_evsel__delete(evsel); 149 perf_evsel__delete(evsel);
150} 150}
151 151
152static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, 152static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
153 void *handler, int idx)
154{ 153{
155 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction, idx); 154 evsel->priv = malloc(sizeof(struct syscall_tp));
156 155 if (evsel->priv != NULL) {
157 if (evsel) {
158 evsel->priv = malloc(sizeof(struct syscall_tp));
159
160 if (evsel->priv == NULL)
161 goto out_delete;
162
163 if (perf_evsel__init_sc_tp_uint_field(evsel, id)) 156 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
164 goto out_delete; 157 goto out_delete;
165 158
166 evsel->handler = handler; 159 evsel->handler = handler;
160 return 0;
161 }
162
163 return -ENOMEM;
164
165out_delete:
166 free(evsel->priv);
167 evsel->priv = NULL;
168 return -ENOENT;
169}
170
171static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
172{
173 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
174
175 if (evsel) {
176 if (perf_evsel__init_syscall_tp(evsel, handler))
177 goto out_delete;
167 } 178 }
168 179
169 return evsel; 180 return evsel;
@@ -186,17 +197,16 @@ static int perf_evlist__add_syscall_newtp(struct perf_evlist *evlist,
186 void *sys_exit_handler) 197 void *sys_exit_handler)
187{ 198{
188 int ret = -1; 199 int ret = -1;
189 int idx = evlist->nr_entries;
190 struct perf_evsel *sys_enter, *sys_exit; 200 struct perf_evsel *sys_enter, *sys_exit;
191 201
192 sys_enter = perf_evsel__syscall_newtp("sys_enter", sys_enter_handler, idx++); 202 sys_enter = perf_evsel__syscall_newtp("sys_enter", sys_enter_handler);
193 if (sys_enter == NULL) 203 if (sys_enter == NULL)
194 goto out; 204 goto out;
195 205
196 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args)) 206 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
197 goto out_delete_sys_enter; 207 goto out_delete_sys_enter;
198 208
199 sys_exit = perf_evsel__syscall_newtp("sys_exit", sys_exit_handler, idx++); 209 sys_exit = perf_evsel__syscall_newtp("sys_exit", sys_exit_handler);
200 if (sys_exit == NULL) 210 if (sys_exit == NULL)
201 goto out_delete_sys_enter; 211 goto out_delete_sys_enter;
202 212
@@ -953,7 +963,8 @@ static struct syscall_fmt {
953 { .name = "mmap", .hexret = true, 963 { .name = "mmap", .hexret = true,
954 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ 964 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
955 [2] = SCA_MMAP_PROT, /* prot */ 965 [2] = SCA_MMAP_PROT, /* prot */
956 [3] = SCA_MMAP_FLAGS, /* flags */ }, }, 966 [3] = SCA_MMAP_FLAGS, /* flags */
967 [4] = SCA_FD, /* fd */ }, },
957 { .name = "mprotect", .errmsg = true, 968 { .name = "mprotect", .errmsg = true,
958 .arg_scnprintf = { [0] = SCA_HEX, /* start */ 969 .arg_scnprintf = { [0] = SCA_HEX, /* start */
959 [2] = SCA_MMAP_PROT, /* prot */ }, }, 970 [2] = SCA_MMAP_PROT, /* prot */ }, },
@@ -1157,6 +1168,7 @@ struct trace {
1157 bool sched; 1168 bool sched;
1158 bool multiple_threads; 1169 bool multiple_threads;
1159 bool summary; 1170 bool summary;
1171 bool summary_only;
1160 bool show_comm; 1172 bool show_comm;
1161 bool show_tool_stats; 1173 bool show_tool_stats;
1162 double duration_filter; 1174 double duration_filter;
@@ -1342,15 +1354,8 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1342 if (trace->host == NULL) 1354 if (trace->host == NULL)
1343 return -ENOMEM; 1355 return -ENOMEM;
1344 1356
1345 if (perf_target__has_task(&trace->opts.target)) { 1357 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
1346 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads, 1358 evlist->threads, trace__tool_process, false);
1347 trace__tool_process,
1348 trace->host);
1349 } else {
1350 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
1351 trace->host);
1352 }
1353
1354 if (err) 1359 if (err)
1355 symbol__exit(); 1360 symbol__exit();
1356 1361
@@ -1607,7 +1612,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1607 args, trace, thread); 1612 args, trace, thread);
1608 1613
1609 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) { 1614 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
1610 if (!trace->duration_filter) { 1615 if (!trace->duration_filter && !trace->summary_only) {
1611 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output); 1616 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1612 fprintf(trace->output, "%-70s\n", ttrace->entry_str); 1617 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
1613 } 1618 }
@@ -1660,6 +1665,9 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1660 } else if (trace->duration_filter) 1665 } else if (trace->duration_filter)
1661 goto out; 1666 goto out;
1662 1667
1668 if (trace->summary_only)
1669 goto out;
1670
1663 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output); 1671 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
1664 1672
1665 if (ttrace->entry_pending) { 1673 if (ttrace->entry_pending) {
@@ -1762,16 +1770,6 @@ static int trace__process_sample(struct perf_tool *tool,
1762 return err; 1770 return err;
1763} 1771}
1764 1772
1765static bool
1766perf_session__has_tp(struct perf_session *session, const char *name)
1767{
1768 struct perf_evsel *evsel;
1769
1770 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1771
1772 return evsel != NULL;
1773}
1774
1775static int parse_target_str(struct trace *trace) 1773static int parse_target_str(struct trace *trace)
1776{ 1774{
1777 if (trace->opts.target.pid) { 1775 if (trace->opts.target.pid) {
@@ -1824,8 +1822,7 @@ static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
1824 1822
1825static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist) 1823static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
1826{ 1824{
1827 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname", 1825 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
1828 evlist->nr_entries);
1829 if (evsel == NULL) 1826 if (evsel == NULL)
1830 return; 1827 return;
1831 1828
@@ -2009,8 +2006,6 @@ out_error:
2009static int trace__replay(struct trace *trace) 2006static int trace__replay(struct trace *trace)
2010{ 2007{
2011 const struct perf_evsel_str_handler handlers[] = { 2008 const struct perf_evsel_str_handler handlers[] = {
2012 { "raw_syscalls:sys_enter", trace__sys_enter, },
2013 { "raw_syscalls:sys_exit", trace__sys_exit, },
2014 { "probe:vfs_getname", trace__vfs_getname, }, 2009 { "probe:vfs_getname", trace__vfs_getname, },
2015 }; 2010 };
2016 struct perf_data_file file = { 2011 struct perf_data_file file = {
@@ -2018,6 +2013,7 @@ static int trace__replay(struct trace *trace)
2018 .mode = PERF_DATA_MODE_READ, 2013 .mode = PERF_DATA_MODE_READ,
2019 }; 2014 };
2020 struct perf_session *session; 2015 struct perf_session *session;
2016 struct perf_evsel *evsel;
2021 int err = -1; 2017 int err = -1;
2022 2018
2023 trace->tool.sample = trace__process_sample; 2019 trace->tool.sample = trace__process_sample;
@@ -2049,13 +2045,29 @@ static int trace__replay(struct trace *trace)
2049 if (err) 2045 if (err)
2050 goto out; 2046 goto out;
2051 2047
2052 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) { 2048 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2053 pr_err("Data file does not have raw_syscalls:sys_enter events\n"); 2049 "raw_syscalls:sys_enter");
2050 if (evsel == NULL) {
2051 pr_err("Data file does not have raw_syscalls:sys_enter event\n");
2054 goto out; 2052 goto out;
2055 } 2053 }
2056 2054
2057 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) { 2055 if (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2058 pr_err("Data file does not have raw_syscalls:sys_exit events\n"); 2056 perf_evsel__init_sc_tp_ptr_field(evsel, args)) {
2057 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2058 goto out;
2059 }
2060
2061 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2062 "raw_syscalls:sys_exit");
2063 if (evsel == NULL) {
2064 pr_err("Data file does not have raw_syscalls:sys_exit event\n");
2065 goto out;
2066 }
2067
2068 if (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2069 perf_evsel__init_sc_tp_uint_field(evsel, ret)) {
2070 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
2059 goto out; 2071 goto out;
2060 } 2072 }
2061 2073
@@ -2082,12 +2094,7 @@ static size_t trace__fprintf_threads_header(FILE *fp)
2082{ 2094{
2083 size_t printed; 2095 size_t printed;
2084 2096
2085 printed = fprintf(fp, "\n _____________________________________________________________________________\n"); 2097 printed = fprintf(fp, "\n Summary of events:\n\n");
2086 printed += fprintf(fp, " __) Summary of events (__\n\n");
2087 printed += fprintf(fp, " [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
2088 printed += fprintf(fp, " syscall count min max avg stddev\n");
2089 printed += fprintf(fp, " msec msec msec %%\n");
2090 printed += fprintf(fp, " _____________________________________________________________________________\n\n");
2091 2098
2092 return printed; 2099 return printed;
2093} 2100}
@@ -2105,6 +2112,10 @@ static size_t thread__dump_stats(struct thread_trace *ttrace,
2105 2112
2106 printed += fprintf(fp, "\n"); 2113 printed += fprintf(fp, "\n");
2107 2114
2115 printed += fprintf(fp, " msec/call\n");
2116 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2117 printed += fprintf(fp, " --------------- -------- -------- -------- -------- ------\n");
2118
2108 /* each int_node is a syscall */ 2119 /* each int_node is a syscall */
2109 while (inode) { 2120 while (inode) {
2110 stats = inode->priv; 2121 stats = inode->priv;
@@ -2119,10 +2130,10 @@ static size_t thread__dump_stats(struct thread_trace *ttrace,
2119 avg /= NSEC_PER_MSEC; 2130 avg /= NSEC_PER_MSEC;
2120 2131
2121 sc = &trace->syscalls.table[inode->i]; 2132 sc = &trace->syscalls.table[inode->i];
2122 printed += fprintf(fp, "%24s %14s : ", "", sc->name); 2133 printed += fprintf(fp, " %-15s", sc->name);
2123 printed += fprintf(fp, "%5" PRIu64 " %8.3f %8.3f", 2134 printed += fprintf(fp, " %8" PRIu64 " %8.3f %8.3f",
2124 n, min, max); 2135 n, min, avg);
2125 printed += fprintf(fp, " %8.3f %6.2f\n", avg, pct); 2136 printed += fprintf(fp, " %8.3f %6.2f\n", max, pct);
2126 } 2137 }
2127 2138
2128 inode = intlist__next(inode); 2139 inode = intlist__next(inode);
@@ -2163,10 +2174,10 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2163 else if (ratio > 5.0) 2174 else if (ratio > 5.0)
2164 color = PERF_COLOR_YELLOW; 2175 color = PERF_COLOR_YELLOW;
2165 2176
2166 printed += color_fprintf(fp, color, "%20s", thread__comm_str(thread)); 2177 printed += color_fprintf(fp, color, " %s (%d), ", thread__comm_str(thread), thread->tid);
2167 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events); 2178 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
2168 printed += color_fprintf(fp, color, "%5.1f%%", ratio); 2179 printed += color_fprintf(fp, color, "%.1f%%", ratio);
2169 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms); 2180 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2170 printed += thread__dump_stats(ttrace, trace, fp); 2181 printed += thread__dump_stats(ttrace, trace, fp);
2171 2182
2172 data->printed += printed; 2183 data->printed += printed;
@@ -2275,8 +2286,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2275 OPT_INCR('v', "verbose", &verbose, "be more verbose"), 2286 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
2276 OPT_BOOLEAN('T', "time", &trace.full_time, 2287 OPT_BOOLEAN('T', "time", &trace.full_time,
2277 "Show full timestamp, not time relative to first start"), 2288 "Show full timestamp, not time relative to first start"),
2278 OPT_BOOLEAN(0, "summary", &trace.summary, 2289 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2279 "Show syscall summary with statistics"), 2290 "Show only syscall summary with statistics"),
2291 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2292 "Show all syscalls and summary with statistics"),
2280 OPT_END() 2293 OPT_END()
2281 }; 2294 };
2282 int err; 2295 int err;
@@ -2287,6 +2300,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2287 2300
2288 argc = parse_options(argc, argv, trace_options, trace_usage, 0); 2301 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
2289 2302
2303 /* summary_only implies summary option, but don't overwrite summary if set */
2304 if (trace.summary_only)
2305 trace.summary = trace.summary_only;
2306
2290 if (output_name != NULL) { 2307 if (output_name != NULL) {
2291 err = trace__open_output(&trace, output_name); 2308 err = trace__open_output(&trace, output_name);
2292 if (err < 0) { 2309 if (err < 0) {
@@ -2310,21 +2327,21 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2310 } 2327 }
2311 } 2328 }
2312 2329
2313 err = perf_target__validate(&trace.opts.target); 2330 err = target__validate(&trace.opts.target);
2314 if (err) { 2331 if (err) {
2315 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf)); 2332 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
2316 fprintf(trace.output, "%s", bf); 2333 fprintf(trace.output, "%s", bf);
2317 goto out_close; 2334 goto out_close;
2318 } 2335 }
2319 2336
2320 err = perf_target__parse_uid(&trace.opts.target); 2337 err = target__parse_uid(&trace.opts.target);
2321 if (err) { 2338 if (err) {
2322 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf)); 2339 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
2323 fprintf(trace.output, "%s", bf); 2340 fprintf(trace.output, "%s", bf);
2324 goto out_close; 2341 goto out_close;
2325 } 2342 }
2326 2343
2327 if (!argc && perf_target__none(&trace.opts.target)) 2344 if (!argc && target__none(&trace.opts.target))
2328 trace.opts.target.system_wide = true; 2345 trace.opts.target.system_wide = true;
2329 2346
2330 if (input_name) 2347 if (input_name)