aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-trace.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2012-10-06 17:43:19 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2012-10-24 15:23:03 -0400
commit752fde44fd1c4a411d709c7d4ad0f121f427f234 (patch)
tree333fcb269d142c023845a844bc8df32c28c57775 /tools/perf/builtin-trace.c
parent9a8e85ad0b61ec0720df7d24392163c2a12626d0 (diff)
perf trace: Support interrupted syscalls
Using the same strategies as in the tmp.perf/trace2, i.e. the 'trace' tool implemented by tglx, just updated to the current codebase. Example: [root@sandy linux]# perf trace usleep 1 | tail 2.003: mmap(addr: 0, len: 4096, prot: 3, flags: 34, fd: 4294967295, off: 0 ) = -2128396288 2.017: mmap(addr: 0, len: 4096, prot: 3, flags: 34, fd: 4294967295, off: 0 ) = -2128400384 2.029: arch_prctl(option: 4098, arg2: 140146949441280, arg3: 140146949435392, arg4: 34, arg5: 4294967295) = 0 2.084: mprotect(start: 208741634048, len: 16384, prot: 1 ) = 0 2.098: mprotect(start: 208735956992, len: 4096, prot: 1 ) = 0 2.122: munmap(addr: 140146949447680, len: 91882 ) = 0 2.359: brk(brk: 0 ) = 28987392 2.371: brk(brk: 29122560 ) = 29122560 2.490: nanosleep(rqtp: 140735694241504, rmtp: 0 ) = 0 2.507: exit_group(error_code: 0 [root@sandy linux]# For now the timestamp and duration are always on, will be selectable. Also if multiple threads are being monitored, its tid will appear. The ret output continues to be interpreted a la strace. Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Namhyung Kim <namhyung@gmail.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/n/tip-ly9ulroru4my5isn0xe9gr0m@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-trace.c')
-rw-r--r--tools/perf/builtin-trace.c199
1 files changed, 177 insertions, 22 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 14b322961807..873f50b10cc9 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1,5 +1,8 @@
1#include "builtin.h" 1#include "builtin.h"
2#include "util/color.h"
2#include "util/evlist.h" 3#include "util/evlist.h"
4#include "util/machine.h"
5#include "util/thread.h"
3#include "util/parse-options.h" 6#include "util/parse-options.h"
4#include "util/thread_map.h" 7#include "util/thread_map.h"
5#include "event-parse.h" 8#include "event-parse.h"
@@ -43,6 +46,36 @@ struct syscall {
43 struct syscall_fmt *fmt; 46 struct syscall_fmt *fmt;
44}; 47};
45 48
49struct thread_trace {
50 u64 entry_time;
51 u64 exit_time;
52 bool entry_pending;
53 char *entry_str;
54};
55
56static struct thread_trace *thread_trace__new(void)
57{
58 return zalloc(sizeof(struct thread_trace));
59}
60
61static struct thread_trace *thread__trace(struct thread *thread)
62{
63 if (thread == NULL)
64 goto fail;
65
66 if (thread->priv == NULL)
67 thread->priv = thread_trace__new();
68
69 if (thread->priv == NULL)
70 goto fail;
71
72 return thread->priv;
73fail:
74 color_fprintf(stdout, PERF_COLOR_RED,
75 "WARNING: not enough memory, dropping samples!\n");
76 return NULL;
77}
78
46struct trace { 79struct trace {
47 int audit_machine; 80 int audit_machine;
48 struct { 81 struct {
@@ -50,8 +83,18 @@ struct trace {
50 struct syscall *table; 83 struct syscall *table;
51 } syscalls; 84 } syscalls;
52 struct perf_record_opts opts; 85 struct perf_record_opts opts;
86 struct machine host;
87 u64 base_time;
88 bool multiple_threads;
53}; 89};
54 90
91static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
92{
93 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
94
95 return fprintf(fp, "%10.3f: ", ts);
96}
97
55static bool done = false; 98static bool done = false;
56 99
57static void sig_handler(int sig __maybe_unused) 100static void sig_handler(int sig __maybe_unused)
@@ -59,6 +102,67 @@ static void sig_handler(int sig __maybe_unused)
59 done = true; 102 done = true;
60} 103}
61 104
105static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
106 u64 tstamp, FILE *fp)
107{
108 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
109
110 if (trace->multiple_threads)
111 printed += fprintf(fp, "%d ", thread->pid);
112
113 return printed;
114}
115
116static int trace__process_event(struct machine *machine, union perf_event *event)
117{
118 int ret = 0;
119
120 switch (event->header.type) {
121 case PERF_RECORD_LOST:
122 color_fprintf(stdout, PERF_COLOR_RED,
123 "LOST %" PRIu64 " events!\n", event->lost.lost);
124 ret = machine__process_lost_event(machine, event);
125 default:
126 ret = machine__process_event(machine, event);
127 break;
128 }
129
130 return ret;
131}
132
133static int trace__tool_process(struct perf_tool *tool __maybe_unused,
134 union perf_event *event,
135 struct perf_sample *sample __maybe_unused,
136 struct machine *machine)
137{
138 return trace__process_event(machine, event);
139}
140
141static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
142{
143 int err = symbol__init();
144
145 if (err)
146 return err;
147
148 machine__init(&trace->host, "", HOST_KERNEL_ID);
149 machine__create_kernel_maps(&trace->host);
150
151 if (perf_target__has_task(&trace->opts.target)) {
152 err = perf_event__synthesize_thread_map(NULL, evlist->threads,
153 trace__tool_process,
154 &trace->host);
155 } else {
156 err = perf_event__synthesize_threads(NULL, trace__tool_process,
157 &trace->host);
158 }
159
160 if (err)
161 symbol__exit();
162
163 return err;
164}
165
62static int trace__read_syscall_info(struct trace *trace, int id) 166static int trace__read_syscall_info(struct trace *trace, int id)
63{ 167{
64 char tp_name[128]; 168 char tp_name[128];
@@ -100,7 +204,8 @@ static int trace__read_syscall_info(struct trace *trace, int id)
100 return sc->tp_format != NULL ? 0 : -1; 204 return sc->tp_format != NULL ? 0 : -1;
101} 205}
102 206
103static size_t syscall__fprintf_args(struct syscall *sc, unsigned long *args, FILE *fp) 207static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
208 unsigned long *args)
104{ 209{
105 int i = 0; 210 int i = 0;
106 size_t printed = 0; 211 size_t printed = 0;
@@ -109,12 +214,15 @@ static size_t syscall__fprintf_args(struct syscall *sc, unsigned long *args, FIL
109 struct format_field *field; 214 struct format_field *field;
110 215
111 for (field = sc->tp_format->format.fields->next; field; field = field->next) { 216 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
112 printed += fprintf(fp, "%s%s: %ld", printed ? ", " : "", 217 printed += scnprintf(bf + printed, size - printed,
113 field->name, args[i++]); 218 "%s%s: %ld", printed ? ", " : "",
219 field->name, args[i++]);
114 } 220 }
115 } else { 221 } else {
116 while (i < 6) { 222 while (i < 6) {
117 printed += fprintf(fp, "%sarg%d: %ld", printed ? ", " : "", i, args[i]); 223 printed += scnprintf(bf + printed, size - printed,
224 "%sarg%d: %ld",
225 printed ? ", " : "", i, args[i]);
118 ++i; 226 ++i;
119 } 227 }
120 } 228 }
@@ -153,10 +261,14 @@ out_cant_read:
153static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, 261static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
154 struct perf_sample *sample) 262 struct perf_sample *sample)
155{ 263{
264 char *msg;
156 void *args; 265 void *args;
266 size_t printed = 0;
267 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid);
157 struct syscall *sc = trace__syscall_info(trace, evsel, sample); 268 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
269 struct thread_trace *ttrace = thread__trace(thread);
158 270
159 if (sc == NULL) 271 if (ttrace == NULL || sc == NULL)
160 return -1; 272 return -1;
161 273
162 args = perf_evsel__rawptr(evsel, sample, "args"); 274 args = perf_evsel__rawptr(evsel, sample, "args");
@@ -165,8 +277,25 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
165 return -1; 277 return -1;
166 } 278 }
167 279
168 printf("%s(", sc->name); 280 ttrace = thread->priv;
169 syscall__fprintf_args(sc, args, stdout); 281
282 if (ttrace->entry_str == NULL) {
283 ttrace->entry_str = malloc(1024);
284 if (!ttrace->entry_str)
285 return -1;
286 }
287
288 ttrace->entry_time = sample->time;
289 msg = ttrace->entry_str;
290 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
291
292 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
293
294 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
295 trace__fprintf_entry_head(trace, thread, sample->time, stdout);
296 printf("%-70s\n", ttrace->entry_str);
297 } else
298 ttrace->entry_pending = true;
170 299
171 return 0; 300 return 0;
172} 301}
@@ -175,13 +304,29 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
175 struct perf_sample *sample) 304 struct perf_sample *sample)
176{ 305{
177 int ret; 306 int ret;
307 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid);
308 struct thread_trace *ttrace = thread__trace(thread);
178 struct syscall *sc = trace__syscall_info(trace, evsel, sample); 309 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
179 310
180 if (sc == NULL) 311 if (ttrace == NULL || sc == NULL)
181 return -1; 312 return -1;
182 313
183 ret = perf_evsel__intval(evsel, sample, "ret"); 314 ret = perf_evsel__intval(evsel, sample, "ret");
184 315
316 ttrace = thread->priv;
317
318 ttrace->exit_time = sample->time;
319
320 trace__fprintf_entry_head(trace, thread, sample->time, stdout);
321
322 if (ttrace->entry_pending) {
323 printf("%-70s", ttrace->entry_str);
324 } else {
325 printf(" ... [");
326 color_fprintf(stdout, PERF_COLOR_YELLOW, "continued");
327 printf("]: %s()", sc->name);
328 }
329
185 if (ret < 0 && sc->fmt && sc->fmt->errmsg) { 330 if (ret < 0 && sc->fmt && sc->fmt->errmsg) {
186 char bf[256]; 331 char bf[256];
187 const char *emsg = strerror_r(-ret, bf, sizeof(bf)), 332 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
@@ -194,6 +339,9 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
194 printf(") = %d", ret); 339 printf(") = %d", ret);
195 340
196 putchar('\n'); 341 putchar('\n');
342
343 ttrace->entry_pending = false;
344
197 return 0; 345 return 0;
198} 346}
199 347
@@ -221,6 +369,12 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
221 goto out_delete_evlist; 369 goto out_delete_evlist;
222 } 370 }
223 371
372 err = trace__symbols_init(trace, evlist);
373 if (err < 0) {
374 printf("Problems initializing symbol libraries!\n");
375 goto out_delete_evlist;
376 }
377
224 perf_evlist__config_attrs(evlist, &trace->opts); 378 perf_evlist__config_attrs(evlist, &trace->opts);
225 379
226 signal(SIGCHLD, sig_handler); 380 signal(SIGCHLD, sig_handler);
@@ -251,6 +405,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
251 if (forks) 405 if (forks)
252 perf_evlist__start_workload(evlist); 406 perf_evlist__start_workload(evlist);
253 407
408 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
254again: 409again:
255 before = nr_events; 410 before = nr_events;
256 411
@@ -264,32 +419,32 @@ again:
264 419
265 ++nr_events; 420 ++nr_events;
266 421
267 switch (type) {
268 case PERF_RECORD_SAMPLE:
269 break;
270 case PERF_RECORD_LOST:
271 printf("LOST %" PRIu64 " events!\n", event->lost.lost);
272 continue;
273 default:
274 printf("Unexpected %s event, skipping...\n",
275 perf_event__name(type));
276 continue;
277 }
278
279 err = perf_evlist__parse_sample(evlist, event, &sample); 422 err = perf_evlist__parse_sample(evlist, event, &sample);
280 if (err) { 423 if (err) {
281 printf("Can't parse sample, err = %d, skipping...\n", err); 424 printf("Can't parse sample, err = %d, skipping...\n", err);
282 continue; 425 continue;
283 } 426 }
284 427
428 if (trace->base_time == 0)
429 trace->base_time = sample.time;
430
431 if (type != PERF_RECORD_SAMPLE) {
432 trace__process_event(&trace->host, event);
433 continue;
434 }
435
285 evsel = perf_evlist__id2evsel(evlist, sample.id); 436 evsel = perf_evlist__id2evsel(evlist, sample.id);
286 if (evsel == NULL) { 437 if (evsel == NULL) {
287 printf("Unknown tp ID %" PRIu64 ", skipping...\n", sample.id); 438 printf("Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
288 continue; 439 continue;
289 } 440 }
290 441
291 if (evlist->threads->map[0] == -1 || evlist->threads->nr > 1) 442 if (sample.raw_data == NULL) {
292 printf("%d ", sample.tid); 443 printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
444 perf_evsel__name(evsel), sample.tid,
445 sample.cpu, sample.raw_size);
446 continue;
447 }
293 448
294 if (sample.raw_data == NULL) { 449 if (sample.raw_data == NULL) {
295 printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", 450 printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",