perf trace: Beautify fcntl 'cmd' arg
[platform/adaptation/renesas_rcar/renesas_kernel.git] / tools / perf / builtin-trace.c
1 #include <traceevent/event-parse.h>
2 #include "builtin.h"
3 #include "util/color.h"
4 #include "util/debug.h"
5 #include "util/evlist.h"
6 #include "util/machine.h"
7 #include "util/session.h"
8 #include "util/thread.h"
9 #include "util/parse-options.h"
10 #include "util/strlist.h"
11 #include "util/intlist.h"
12 #include "util/thread_map.h"
13
14 #include <libaudit.h>
15 #include <stdlib.h>
16 #include <sys/mman.h>
17 #include <linux/futex.h>
18
19 /* For older distros: */
20 #ifndef MAP_STACK
21 # define MAP_STACK              0x20000
22 #endif
23
24 #ifndef MADV_HWPOISON
25 # define MADV_HWPOISON          100
26 #endif
27
28 #ifndef MADV_MERGEABLE
29 # define MADV_MERGEABLE         12
30 #endif
31
32 #ifndef MADV_UNMERGEABLE
33 # define MADV_UNMERGEABLE       13
34 #endif
35
36 struct syscall_arg {
37         unsigned long val;
38         void          *parm;
39         u8            idx;
40         u8            mask;
41 };
42
43 struct strarray {
44         int         nr_entries;
45         const char **entries;
46 };
47
48 #define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
49         .nr_entries = ARRAY_SIZE(array), \
50         .entries = array, \
51 }
52
53 static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
54                                               struct syscall_arg *arg)
55 {
56         int idx = arg->val;
57         struct strarray *sa = arg->parm;
58
59         if (idx < 0 || idx >= sa->nr_entries)
60                 return scnprintf(bf, size, "%d", idx);
61
62         return scnprintf(bf, size, "%s", sa->entries[idx]);
63 }
64
65 #define SCA_STRARRAY syscall_arg__scnprintf_strarray
66
67 static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
68                                          struct syscall_arg *arg)
69 {
70         return scnprintf(bf, size, "%#lx", arg->val);
71 }
72
73 #define SCA_HEX syscall_arg__scnprintf_hex
74
75 static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
76                                                struct syscall_arg *arg)
77 {
78         int printed = 0, prot = arg->val;
79
80         if (prot == PROT_NONE)
81                 return scnprintf(bf, size, "NONE");
82 #define P_MMAP_PROT(n) \
83         if (prot & PROT_##n) { \
84                 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
85                 prot &= ~PROT_##n; \
86         }
87
88         P_MMAP_PROT(EXEC);
89         P_MMAP_PROT(READ);
90         P_MMAP_PROT(WRITE);
91 #ifdef PROT_SEM
92         P_MMAP_PROT(SEM);
93 #endif
94         P_MMAP_PROT(GROWSDOWN);
95         P_MMAP_PROT(GROWSUP);
96 #undef P_MMAP_PROT
97
98         if (prot)
99                 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
100
101         return printed;
102 }
103
104 #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
105
106 static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
107                                                 struct syscall_arg *arg)
108 {
109         int printed = 0, flags = arg->val;
110
111 #define P_MMAP_FLAG(n) \
112         if (flags & MAP_##n) { \
113                 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
114                 flags &= ~MAP_##n; \
115         }
116
117         P_MMAP_FLAG(SHARED);
118         P_MMAP_FLAG(PRIVATE);
119 #ifdef MAP_32BIT
120         P_MMAP_FLAG(32BIT);
121 #endif
122         P_MMAP_FLAG(ANONYMOUS);
123         P_MMAP_FLAG(DENYWRITE);
124         P_MMAP_FLAG(EXECUTABLE);
125         P_MMAP_FLAG(FILE);
126         P_MMAP_FLAG(FIXED);
127         P_MMAP_FLAG(GROWSDOWN);
128 #ifdef MAP_HUGETLB
129         P_MMAP_FLAG(HUGETLB);
130 #endif
131         P_MMAP_FLAG(LOCKED);
132         P_MMAP_FLAG(NONBLOCK);
133         P_MMAP_FLAG(NORESERVE);
134         P_MMAP_FLAG(POPULATE);
135         P_MMAP_FLAG(STACK);
136 #ifdef MAP_UNINITIALIZED
137         P_MMAP_FLAG(UNINITIALIZED);
138 #endif
139 #undef P_MMAP_FLAG
140
141         if (flags)
142                 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
143
144         return printed;
145 }
146
147 #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
148
149 static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
150                                                       struct syscall_arg *arg)
151 {
152         int behavior = arg->val;
153
154         switch (behavior) {
155 #define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
156         P_MADV_BHV(NORMAL);
157         P_MADV_BHV(RANDOM);
158         P_MADV_BHV(SEQUENTIAL);
159         P_MADV_BHV(WILLNEED);
160         P_MADV_BHV(DONTNEED);
161         P_MADV_BHV(REMOVE);
162         P_MADV_BHV(DONTFORK);
163         P_MADV_BHV(DOFORK);
164         P_MADV_BHV(HWPOISON);
165 #ifdef MADV_SOFT_OFFLINE
166         P_MADV_BHV(SOFT_OFFLINE);
167 #endif
168         P_MADV_BHV(MERGEABLE);
169         P_MADV_BHV(UNMERGEABLE);
170 #ifdef MADV_HUGEPAGE
171         P_MADV_BHV(HUGEPAGE);
172 #endif
173 #ifdef MADV_NOHUGEPAGE
174         P_MADV_BHV(NOHUGEPAGE);
175 #endif
176 #ifdef MADV_DONTDUMP
177         P_MADV_BHV(DONTDUMP);
178 #endif
179 #ifdef MADV_DODUMP
180         P_MADV_BHV(DODUMP);
181 #endif
182 #undef P_MADV_PHV
183         default: break;
184         }
185
186         return scnprintf(bf, size, "%#x", behavior);
187 }
188
189 #define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
190
191 static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
192 {
193         enum syscall_futex_args {
194                 SCF_UADDR   = (1 << 0),
195                 SCF_OP      = (1 << 1),
196                 SCF_VAL     = (1 << 2),
197                 SCF_TIMEOUT = (1 << 3),
198                 SCF_UADDR2  = (1 << 4),
199                 SCF_VAL3    = (1 << 5),
200         };
201         int op = arg->val;
202         int cmd = op & FUTEX_CMD_MASK;
203         size_t printed = 0;
204
205         switch (cmd) {
206 #define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
207         P_FUTEX_OP(WAIT);           arg->mask |= SCF_VAL3|SCF_UADDR2;             break;
208         P_FUTEX_OP(WAKE);           arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
209         P_FUTEX_OP(FD);             arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
210         P_FUTEX_OP(REQUEUE);        arg->mask |= SCF_VAL3|SCF_TIMEOUT;            break;
211         P_FUTEX_OP(CMP_REQUEUE);    arg->mask |= SCF_TIMEOUT;                     break;
212         P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT;                     break;
213         P_FUTEX_OP(WAKE_OP);                                                      break;
214         P_FUTEX_OP(LOCK_PI);        arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
215         P_FUTEX_OP(UNLOCK_PI);      arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
216         P_FUTEX_OP(TRYLOCK_PI);     arg->mask |= SCF_VAL3|SCF_UADDR2;             break;
217         P_FUTEX_OP(WAIT_BITSET);    arg->mask |= SCF_UADDR2;                      break;
218         P_FUTEX_OP(WAKE_BITSET);    arg->mask |= SCF_UADDR2;                      break;
219         P_FUTEX_OP(WAIT_REQUEUE_PI);                                              break;
220         default: printed = scnprintf(bf, size, "%#x", cmd);                       break;
221         }
222
223         if (op & FUTEX_PRIVATE_FLAG)
224                 printed += scnprintf(bf + printed, size - printed, "|PRIV");
225
226         if (op & FUTEX_CLOCK_REALTIME)
227                 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
228
229         return printed;
230 }
231
232 #define SCA_FUTEX_OP  syscall_arg__scnprintf_futex_op
233
234 static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
235 static DEFINE_STRARRAY(itimers);
236
237 static const char *whences[] = { "SET", "CUR", "END",
238 #ifdef SEEK_DATA
239 "DATA",
240 #endif
241 #ifdef SEEK_HOLE
242 "HOLE",
243 #endif
244 };
245 static DEFINE_STRARRAY(whences);
246
247 static const char *fcntl_cmds[] = {
248         "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
249         "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
250         "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
251         "F_GETOWNER_UIDS",
252 };
253 static DEFINE_STRARRAY(fcntl_cmds);
254
255 static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
256                                                struct syscall_arg *arg)
257 {
258         int printed = 0, flags = arg->val;
259
260         if (!(flags & O_CREAT))
261                 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
262
263         if (flags == 0)
264                 return scnprintf(bf, size, "RDONLY");
265 #define P_FLAG(n) \
266         if (flags & O_##n) { \
267                 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
268                 flags &= ~O_##n; \
269         }
270
271         P_FLAG(APPEND);
272         P_FLAG(ASYNC);
273         P_FLAG(CLOEXEC);
274         P_FLAG(CREAT);
275         P_FLAG(DIRECT);
276         P_FLAG(DIRECTORY);
277         P_FLAG(EXCL);
278         P_FLAG(LARGEFILE);
279         P_FLAG(NOATIME);
280         P_FLAG(NOCTTY);
281 #ifdef O_NONBLOCK
282         P_FLAG(NONBLOCK);
283 #elif O_NDELAY
284         P_FLAG(NDELAY);
285 #endif
286 #ifdef O_PATH
287         P_FLAG(PATH);
288 #endif
289         P_FLAG(RDWR);
290 #ifdef O_DSYNC
291         if ((flags & O_SYNC) == O_SYNC)
292                 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
293         else {
294                 P_FLAG(DSYNC);
295         }
296 #else
297         P_FLAG(SYNC);
298 #endif
299         P_FLAG(TRUNC);
300         P_FLAG(WRONLY);
301 #undef P_FLAG
302
303         if (flags)
304                 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
305
306         return printed;
307 }
308
309 #define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
310
311 static struct syscall_fmt {
312         const char *name;
313         const char *alias;
314         size_t     (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
315         void       *arg_parm[6];
316         bool       errmsg;
317         bool       timeout;
318         bool       hexret;
319 } syscall_fmts[] = {
320         { .name     = "access",     .errmsg = true, },
321         { .name     = "arch_prctl", .errmsg = true, .alias = "prctl", },
322         { .name     = "brk",        .hexret = true,
323           .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
324         { .name     = "mmap",       .hexret = true, },
325         { .name     = "connect",    .errmsg = true, },
326         { .name     = "fcntl",      .errmsg = true,
327           .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
328           .arg_parm      = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
329         { .name     = "fstat",      .errmsg = true, .alias = "newfstat", },
330         { .name     = "fstatat",    .errmsg = true, .alias = "newfstatat", },
331         { .name     = "futex",      .errmsg = true,
332           .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
333         { .name     = "getitimer",  .errmsg = true,
334           .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
335           .arg_parm      = { [0] = &strarray__itimers, /* which */ }, },
336         { .name     = "ioctl",      .errmsg = true,
337           .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
338         { .name     = "lseek",      .errmsg = true,
339           .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
340           .arg_parm      = { [2] = &strarray__whences, /* whence */ }, },
341         { .name     = "lstat",      .errmsg = true, .alias = "newlstat", },
342         { .name     = "madvise",    .errmsg = true,
343           .arg_scnprintf = { [0] = SCA_HEX,      /* start */
344                              [2] = SCA_MADV_BHV, /* behavior */ }, },
345         { .name     = "mmap",       .hexret = true,
346           .arg_scnprintf = { [0] = SCA_HEX,       /* addr */
347                              [2] = SCA_MMAP_PROT, /* prot */
348                              [3] = SCA_MMAP_FLAGS, /* flags */ }, },
349         { .name     = "mprotect",   .errmsg = true,
350           .arg_scnprintf = { [0] = SCA_HEX, /* start */
351                              [2] = SCA_MMAP_PROT, /* prot */ }, },
352         { .name     = "mremap",     .hexret = true,
353           .arg_scnprintf = { [0] = SCA_HEX, /* addr */
354                              [4] = SCA_HEX, /* new_addr */ }, },
355         { .name     = "munmap",     .errmsg = true,
356           .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
357         { .name     = "open",       .errmsg = true,
358           .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
359         { .name     = "open_by_handle_at", .errmsg = true,
360           .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
361         { .name     = "openat",     .errmsg = true,
362           .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
363         { .name     = "poll",       .errmsg = true, .timeout = true, },
364         { .name     = "ppoll",      .errmsg = true, .timeout = true, },
365         { .name     = "pread",      .errmsg = true, .alias = "pread64", },
366         { .name     = "pwrite",     .errmsg = true, .alias = "pwrite64", },
367         { .name     = "read",       .errmsg = true, },
368         { .name     = "recvfrom",   .errmsg = true, },
369         { .name     = "select",     .errmsg = true, .timeout = true, },
370         { .name     = "setitimer",  .errmsg = true,
371           .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
372           .arg_parm      = { [0] = &strarray__itimers, /* which */ }, },
373         { .name     = "socket",     .errmsg = true, },
374         { .name     = "stat",       .errmsg = true, .alias = "newstat", },
375         { .name     = "uname",      .errmsg = true, .alias = "newuname", },
376 };
377
378 static int syscall_fmt__cmp(const void *name, const void *fmtp)
379 {
380         const struct syscall_fmt *fmt = fmtp;
381         return strcmp(name, fmt->name);
382 }
383
384 static struct syscall_fmt *syscall_fmt__find(const char *name)
385 {
386         const int nmemb = ARRAY_SIZE(syscall_fmts);
387         return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
388 }
389
390 struct syscall {
391         struct event_format *tp_format;
392         const char          *name;
393         bool                filtered;
394         struct syscall_fmt  *fmt;
395         size_t              (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
396         void                **arg_parm;
397 };
398
399 static size_t fprintf_duration(unsigned long t, FILE *fp)
400 {
401         double duration = (double)t / NSEC_PER_MSEC;
402         size_t printed = fprintf(fp, "(");
403
404         if (duration >= 1.0)
405                 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
406         else if (duration >= 0.01)
407                 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
408         else
409                 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
410         return printed + fprintf(fp, "): ");
411 }
412
413 struct thread_trace {
414         u64               entry_time;
415         u64               exit_time;
416         bool              entry_pending;
417         unsigned long     nr_events;
418         char              *entry_str;
419         double            runtime_ms;
420 };
421
422 static struct thread_trace *thread_trace__new(void)
423 {
424         return zalloc(sizeof(struct thread_trace));
425 }
426
427 static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
428 {
429         struct thread_trace *ttrace;
430
431         if (thread == NULL)
432                 goto fail;
433
434         if (thread->priv == NULL)
435                 thread->priv = thread_trace__new();
436                 
437         if (thread->priv == NULL)
438                 goto fail;
439
440         ttrace = thread->priv;
441         ++ttrace->nr_events;
442
443         return ttrace;
444 fail:
445         color_fprintf(fp, PERF_COLOR_RED,
446                       "WARNING: not enough memory, dropping samples!\n");
447         return NULL;
448 }
449
450 struct trace {
451         struct perf_tool        tool;
452         int                     audit_machine;
453         struct {
454                 int             max;
455                 struct syscall  *table;
456         } syscalls;
457         struct perf_record_opts opts;
458         struct machine          host;
459         u64                     base_time;
460         FILE                    *output;
461         unsigned long           nr_events;
462         struct strlist          *ev_qualifier;
463         bool                    not_ev_qualifier;
464         struct intlist          *tid_list;
465         struct intlist          *pid_list;
466         bool                    sched;
467         bool                    multiple_threads;
468         double                  duration_filter;
469         double                  runtime_ms;
470 };
471
472 static bool trace__filter_duration(struct trace *trace, double t)
473 {
474         return t < (trace->duration_filter * NSEC_PER_MSEC);
475 }
476
477 static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
478 {
479         double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
480
481         return fprintf(fp, "%10.3f ", ts);
482 }
483
484 static bool done = false;
485
486 static void sig_handler(int sig __maybe_unused)
487 {
488         done = true;
489 }
490
491 static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
492                                         u64 duration, u64 tstamp, FILE *fp)
493 {
494         size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
495         printed += fprintf_duration(duration, fp);
496
497         if (trace->multiple_threads)
498                 printed += fprintf(fp, "%d ", thread->tid);
499
500         return printed;
501 }
502
503 static int trace__process_event(struct trace *trace, struct machine *machine,
504                                 union perf_event *event)
505 {
506         int ret = 0;
507
508         switch (event->header.type) {
509         case PERF_RECORD_LOST:
510                 color_fprintf(trace->output, PERF_COLOR_RED,
511                               "LOST %" PRIu64 " events!\n", event->lost.lost);
512                 ret = machine__process_lost_event(machine, event);
513         default:
514                 ret = machine__process_event(machine, event);
515                 break;
516         }
517
518         return ret;
519 }
520
521 static int trace__tool_process(struct perf_tool *tool,
522                                union perf_event *event,
523                                struct perf_sample *sample __maybe_unused,
524                                struct machine *machine)
525 {
526         struct trace *trace = container_of(tool, struct trace, tool);
527         return trace__process_event(trace, machine, event);
528 }
529
530 static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
531 {
532         int err = symbol__init();
533
534         if (err)
535                 return err;
536
537         machine__init(&trace->host, "", HOST_KERNEL_ID);
538         machine__create_kernel_maps(&trace->host);
539
540         if (perf_target__has_task(&trace->opts.target)) {
541                 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
542                                                         trace__tool_process,
543                                                         &trace->host);
544         } else {
545                 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
546                                                      &trace->host);
547         }
548
549         if (err)
550                 symbol__exit();
551
552         return err;
553 }
554
555 static int syscall__set_arg_fmts(struct syscall *sc)
556 {
557         struct format_field *field;
558         int idx = 0;
559
560         sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
561         if (sc->arg_scnprintf == NULL)
562                 return -1;
563
564         if (sc->fmt)
565                 sc->arg_parm = sc->fmt->arg_parm;
566
567         for (field = sc->tp_format->format.fields->next; field; field = field->next) {
568                 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
569                         sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
570                 else if (field->flags & FIELD_IS_POINTER)
571                         sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
572                 ++idx;
573         }
574
575         return 0;
576 }
577
578 static int trace__read_syscall_info(struct trace *trace, int id)
579 {
580         char tp_name[128];
581         struct syscall *sc;
582         const char *name = audit_syscall_to_name(id, trace->audit_machine);
583
584         if (name == NULL)
585                 return -1;
586
587         if (id > trace->syscalls.max) {
588                 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
589
590                 if (nsyscalls == NULL)
591                         return -1;
592
593                 if (trace->syscalls.max != -1) {
594                         memset(nsyscalls + trace->syscalls.max + 1, 0,
595                                (id - trace->syscalls.max) * sizeof(*sc));
596                 } else {
597                         memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
598                 }
599
600                 trace->syscalls.table = nsyscalls;
601                 trace->syscalls.max   = id;
602         }
603
604         sc = trace->syscalls.table + id;
605         sc->name = name;
606
607         if (trace->ev_qualifier) {
608                 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
609
610                 if (!(in ^ trace->not_ev_qualifier)) {
611                         sc->filtered = true;
612                         /*
613                          * No need to do read tracepoint information since this will be
614                          * filtered out.
615                          */
616                         return 0;
617                 }
618         }
619
620         sc->fmt  = syscall_fmt__find(sc->name);
621
622         snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
623         sc->tp_format = event_format__new("syscalls", tp_name);
624
625         if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
626                 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
627                 sc->tp_format = event_format__new("syscalls", tp_name);
628         }
629
630         if (sc->tp_format == NULL)
631                 return -1;
632
633         return syscall__set_arg_fmts(sc);
634 }
635
636 static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
637                                       unsigned long *args)
638 {
639         size_t printed = 0;
640
641         if (sc->tp_format != NULL) {
642                 struct format_field *field;
643                 u8 bit = 1;
644                 struct syscall_arg arg = {
645                         .idx  = 0,
646                         .mask = 0,
647                 };
648
649                 for (field = sc->tp_format->format.fields->next; field;
650                      field = field->next, ++arg.idx, bit <<= 1) {
651                         if (arg.mask & bit)
652                                 continue;
653
654                         printed += scnprintf(bf + printed, size - printed,
655                                              "%s%s: ", printed ? ", " : "", field->name);
656                         if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
657                                 arg.val = args[arg.idx];
658                                 if (sc->arg_parm)
659                                         arg.parm = sc->arg_parm[arg.idx];
660                                 printed += sc->arg_scnprintf[arg.idx](bf + printed,
661                                                                       size - printed, &arg);
662                         } else {
663                                 printed += scnprintf(bf + printed, size - printed,
664                                                      "%ld", args[arg.idx]);
665                         }
666                 }
667         } else {
668                 int i = 0;
669
670                 while (i < 6) {
671                         printed += scnprintf(bf + printed, size - printed,
672                                              "%sarg%d: %ld",
673                                              printed ? ", " : "", i, args[i]);
674                         ++i;
675                 }
676         }
677
678         return printed;
679 }
680
681 typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
682                                   struct perf_sample *sample);
683
684 static struct syscall *trace__syscall_info(struct trace *trace,
685                                            struct perf_evsel *evsel,
686                                            struct perf_sample *sample)
687 {
688         int id = perf_evsel__intval(evsel, sample, "id");
689
690         if (id < 0) {
691
692                 /*
693                  * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
694                  * before that, leaving at a higher verbosity level till that is
695                  * explained. Reproduced with plain ftrace with:
696                  *
697                  * echo 1 > /t/events/raw_syscalls/sys_exit/enable
698                  * grep "NR -1 " /t/trace_pipe
699                  *
700                  * After generating some load on the machine.
701                  */
702                 if (verbose > 1) {
703                         static u64 n;
704                         fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
705                                 id, perf_evsel__name(evsel), ++n);
706                 }
707                 return NULL;
708         }
709
710         if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
711             trace__read_syscall_info(trace, id))
712                 goto out_cant_read;
713
714         if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
715                 goto out_cant_read;
716
717         return &trace->syscalls.table[id];
718
719 out_cant_read:
720         if (verbose) {
721                 fprintf(trace->output, "Problems reading syscall %d", id);
722                 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
723                         fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
724                 fputs(" information\n", trace->output);
725         }
726         return NULL;
727 }
728
729 static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
730                             struct perf_sample *sample)
731 {
732         char *msg;
733         void *args;
734         size_t printed = 0;
735         struct thread *thread;
736         struct syscall *sc = trace__syscall_info(trace, evsel, sample);
737         struct thread_trace *ttrace;
738
739         if (sc == NULL)
740                 return -1;
741
742         if (sc->filtered)
743                 return 0;
744
745         thread = machine__findnew_thread(&trace->host, sample->pid,
746                                          sample->tid);
747         ttrace = thread__trace(thread, trace->output);
748         if (ttrace == NULL)
749                 return -1;
750
751         args = perf_evsel__rawptr(evsel, sample, "args");
752         if (args == NULL) {
753                 fprintf(trace->output, "Problems reading syscall arguments\n");
754                 return -1;
755         }
756
757         ttrace = thread->priv;
758
759         if (ttrace->entry_str == NULL) {
760                 ttrace->entry_str = malloc(1024);
761                 if (!ttrace->entry_str)
762                         return -1;
763         }
764
765         ttrace->entry_time = sample->time;
766         msg = ttrace->entry_str;
767         printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
768
769         printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,  args);
770
771         if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
772                 if (!trace->duration_filter) {
773                         trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
774                         fprintf(trace->output, "%-70s\n", ttrace->entry_str);
775                 }
776         } else
777                 ttrace->entry_pending = true;
778
779         return 0;
780 }
781
782 static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
783                            struct perf_sample *sample)
784 {
785         int ret;
786         u64 duration = 0;
787         struct thread *thread;
788         struct syscall *sc = trace__syscall_info(trace, evsel, sample);
789         struct thread_trace *ttrace;
790
791         if (sc == NULL)
792                 return -1;
793
794         if (sc->filtered)
795                 return 0;
796
797         thread = machine__findnew_thread(&trace->host, sample->pid,
798                                          sample->tid);
799         ttrace = thread__trace(thread, trace->output);
800         if (ttrace == NULL)
801                 return -1;
802
803         ret = perf_evsel__intval(evsel, sample, "ret");
804
805         ttrace = thread->priv;
806
807         ttrace->exit_time = sample->time;
808
809         if (ttrace->entry_time) {
810                 duration = sample->time - ttrace->entry_time;
811                 if (trace__filter_duration(trace, duration))
812                         goto out;
813         } else if (trace->duration_filter)
814                 goto out;
815
816         trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
817
818         if (ttrace->entry_pending) {
819                 fprintf(trace->output, "%-70s", ttrace->entry_str);
820         } else {
821                 fprintf(trace->output, " ... [");
822                 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
823                 fprintf(trace->output, "]: %s()", sc->name);
824         }
825
826         if (sc->fmt == NULL) {
827 signed_print:
828                 fprintf(trace->output, ") = %d", ret);
829         } else if (ret < 0 && sc->fmt->errmsg) {
830                 char bf[256];
831                 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
832                            *e = audit_errno_to_name(-ret);
833
834                 fprintf(trace->output, ") = -1 %s %s", e, emsg);
835         } else if (ret == 0 && sc->fmt->timeout)
836                 fprintf(trace->output, ") = 0 Timeout");
837         else if (sc->fmt->hexret)
838                 fprintf(trace->output, ") = %#x", ret);
839         else
840                 goto signed_print;
841
842         fputc('\n', trace->output);
843 out:
844         ttrace->entry_pending = false;
845
846         return 0;
847 }
848
849 static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
850                                      struct perf_sample *sample)
851 {
852         u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
853         double runtime_ms = (double)runtime / NSEC_PER_MSEC;
854         struct thread *thread = machine__findnew_thread(&trace->host,
855                                                         sample->pid,
856                                                         sample->tid);
857         struct thread_trace *ttrace = thread__trace(thread, trace->output);
858
859         if (ttrace == NULL)
860                 goto out_dump;
861
862         ttrace->runtime_ms += runtime_ms;
863         trace->runtime_ms += runtime_ms;
864         return 0;
865
866 out_dump:
867         fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
868                evsel->name,
869                perf_evsel__strval(evsel, sample, "comm"),
870                (pid_t)perf_evsel__intval(evsel, sample, "pid"),
871                runtime,
872                perf_evsel__intval(evsel, sample, "vruntime"));
873         return 0;
874 }
875
876 static bool skip_sample(struct trace *trace, struct perf_sample *sample)
877 {
878         if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
879             (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
880                 return false;
881
882         if (trace->pid_list || trace->tid_list)
883                 return true;
884
885         return false;
886 }
887
888 static int trace__process_sample(struct perf_tool *tool,
889                                  union perf_event *event __maybe_unused,
890                                  struct perf_sample *sample,
891                                  struct perf_evsel *evsel,
892                                  struct machine *machine __maybe_unused)
893 {
894         struct trace *trace = container_of(tool, struct trace, tool);
895         int err = 0;
896
897         tracepoint_handler handler = evsel->handler.func;
898
899         if (skip_sample(trace, sample))
900                 return 0;
901
902         if (trace->base_time == 0)
903                 trace->base_time = sample->time;
904
905         if (handler)
906                 handler(trace, evsel, sample);
907
908         return err;
909 }
910
911 static bool
912 perf_session__has_tp(struct perf_session *session, const char *name)
913 {
914         struct perf_evsel *evsel;
915
916         evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
917
918         return evsel != NULL;
919 }
920
921 static int parse_target_str(struct trace *trace)
922 {
923         if (trace->opts.target.pid) {
924                 trace->pid_list = intlist__new(trace->opts.target.pid);
925                 if (trace->pid_list == NULL) {
926                         pr_err("Error parsing process id string\n");
927                         return -EINVAL;
928                 }
929         }
930
931         if (trace->opts.target.tid) {
932                 trace->tid_list = intlist__new(trace->opts.target.tid);
933                 if (trace->tid_list == NULL) {
934                         pr_err("Error parsing thread id string\n");
935                         return -EINVAL;
936                 }
937         }
938
939         return 0;
940 }
941
942 static int trace__run(struct trace *trace, int argc, const char **argv)
943 {
944         struct perf_evlist *evlist = perf_evlist__new();
945         struct perf_evsel *evsel;
946         int err = -1, i;
947         unsigned long before;
948         const bool forks = argc > 0;
949
950         if (evlist == NULL) {
951                 fprintf(trace->output, "Not enough memory to run!\n");
952                 goto out;
953         }
954
955         if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
956             perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
957                 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
958                 goto out_delete_evlist;
959         }
960
961         if (trace->sched &&
962             perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
963                                    trace__sched_stat_runtime)) {
964                 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
965                 goto out_delete_evlist;
966         }
967
968         err = perf_evlist__create_maps(evlist, &trace->opts.target);
969         if (err < 0) {
970                 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
971                 goto out_delete_evlist;
972         }
973
974         err = trace__symbols_init(trace, evlist);
975         if (err < 0) {
976                 fprintf(trace->output, "Problems initializing symbol libraries!\n");
977                 goto out_delete_maps;
978         }
979
980         perf_evlist__config(evlist, &trace->opts);
981
982         signal(SIGCHLD, sig_handler);
983         signal(SIGINT, sig_handler);
984
985         if (forks) {
986                 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
987                                                     argv, false, false);
988                 if (err < 0) {
989                         fprintf(trace->output, "Couldn't run the workload!\n");
990                         goto out_delete_maps;
991                 }
992         }
993
994         err = perf_evlist__open(evlist);
995         if (err < 0) {
996                 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
997                 goto out_delete_maps;
998         }
999
1000         err = perf_evlist__mmap(evlist, UINT_MAX, false);
1001         if (err < 0) {
1002                 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
1003                 goto out_close_evlist;
1004         }
1005
1006         perf_evlist__enable(evlist);
1007
1008         if (forks)
1009                 perf_evlist__start_workload(evlist);
1010
1011         trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
1012 again:
1013         before = trace->nr_events;
1014
1015         for (i = 0; i < evlist->nr_mmaps; i++) {
1016                 union perf_event *event;
1017
1018                 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1019                         const u32 type = event->header.type;
1020                         tracepoint_handler handler;
1021                         struct perf_sample sample;
1022
1023                         ++trace->nr_events;
1024
1025                         err = perf_evlist__parse_sample(evlist, event, &sample);
1026                         if (err) {
1027                                 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
1028                                 continue;
1029                         }
1030
1031                         if (trace->base_time == 0)
1032                                 trace->base_time = sample.time;
1033
1034                         if (type != PERF_RECORD_SAMPLE) {
1035                                 trace__process_event(trace, &trace->host, event);
1036                                 continue;
1037                         }
1038
1039                         evsel = perf_evlist__id2evsel(evlist, sample.id);
1040                         if (evsel == NULL) {
1041                                 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
1042                                 continue;
1043                         }
1044
1045                         if (sample.raw_data == NULL) {
1046                                 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
1047                                        perf_evsel__name(evsel), sample.tid,
1048                                        sample.cpu, sample.raw_size);
1049                                 continue;
1050                         }
1051
1052                         handler = evsel->handler.func;
1053                         handler(trace, evsel, &sample);
1054
1055                         if (done)
1056                                 goto out_unmap_evlist;
1057                 }
1058         }
1059
1060         if (trace->nr_events == before) {
1061                 if (done)
1062                         goto out_unmap_evlist;
1063
1064                 poll(evlist->pollfd, evlist->nr_fds, -1);
1065         }
1066
1067         if (done)
1068                 perf_evlist__disable(evlist);
1069
1070         goto again;
1071
1072 out_unmap_evlist:
1073         perf_evlist__munmap(evlist);
1074 out_close_evlist:
1075         perf_evlist__close(evlist);
1076 out_delete_maps:
1077         perf_evlist__delete_maps(evlist);
1078 out_delete_evlist:
1079         perf_evlist__delete(evlist);
1080 out:
1081         return err;
1082 }
1083
1084 static int trace__replay(struct trace *trace)
1085 {
1086         const struct perf_evsel_str_handler handlers[] = {
1087                 { "raw_syscalls:sys_enter",  trace__sys_enter, },
1088                 { "raw_syscalls:sys_exit",   trace__sys_exit, },
1089         };
1090
1091         struct perf_session *session;
1092         int err = -1;
1093
1094         trace->tool.sample        = trace__process_sample;
1095         trace->tool.mmap          = perf_event__process_mmap;
1096         trace->tool.mmap2         = perf_event__process_mmap2;
1097         trace->tool.comm          = perf_event__process_comm;
1098         trace->tool.exit          = perf_event__process_exit;
1099         trace->tool.fork          = perf_event__process_fork;
1100         trace->tool.attr          = perf_event__process_attr;
1101         trace->tool.tracing_data = perf_event__process_tracing_data;
1102         trace->tool.build_id      = perf_event__process_build_id;
1103
1104         trace->tool.ordered_samples = true;
1105         trace->tool.ordering_requires_timestamps = true;
1106
1107         /* add tid to output */
1108         trace->multiple_threads = true;
1109
1110         if (symbol__init() < 0)
1111                 return -1;
1112
1113         session = perf_session__new(input_name, O_RDONLY, 0, false,
1114                                     &trace->tool);
1115         if (session == NULL)
1116                 return -ENOMEM;
1117
1118         err = perf_session__set_tracepoints_handlers(session, handlers);
1119         if (err)
1120                 goto out;
1121
1122         if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1123                 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1124                 goto out;
1125         }
1126
1127         if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1128                 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1129                 goto out;
1130         }
1131
1132         err = parse_target_str(trace);
1133         if (err != 0)
1134                 goto out;
1135
1136         setup_pager();
1137
1138         err = perf_session__process_events(session, &trace->tool);
1139         if (err)
1140                 pr_err("Failed to process events, error %d", err);
1141
1142 out:
1143         perf_session__delete(session);
1144
1145         return err;
1146 }
1147
1148 static size_t trace__fprintf_threads_header(FILE *fp)
1149 {
1150         size_t printed;
1151
1152         printed  = fprintf(fp, "\n _____________________________________________________________________\n");
1153         printed += fprintf(fp," __)    Summary of events    (__\n\n");
1154         printed += fprintf(fp,"              [ task - pid ]     [ events ] [ ratio ]  [ runtime ]\n");
1155         printed += fprintf(fp," _____________________________________________________________________\n\n");
1156
1157         return printed;
1158 }
1159
1160 static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1161 {
1162         size_t printed = trace__fprintf_threads_header(fp);
1163         struct rb_node *nd;
1164
1165         for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
1166                 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1167                 struct thread_trace *ttrace = thread->priv;
1168                 const char *color;
1169                 double ratio;
1170
1171                 if (ttrace == NULL)
1172                         continue;
1173
1174                 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1175
1176                 color = PERF_COLOR_NORMAL;
1177                 if (ratio > 50.0)
1178                         color = PERF_COLOR_RED;
1179                 else if (ratio > 25.0)
1180                         color = PERF_COLOR_GREEN;
1181                 else if (ratio > 5.0)
1182                         color = PERF_COLOR_YELLOW;
1183
1184                 printed += color_fprintf(fp, color, "%20s", thread->comm);
1185                 printed += fprintf(fp, " - %-5d :%11lu   [", thread->tid, ttrace->nr_events);
1186                 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1187                 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1188         }
1189
1190         return printed;
1191 }
1192
1193 static int trace__set_duration(const struct option *opt, const char *str,
1194                                int unset __maybe_unused)
1195 {
1196         struct trace *trace = opt->value;
1197
1198         trace->duration_filter = atof(str);
1199         return 0;
1200 }
1201
1202 static int trace__open_output(struct trace *trace, const char *filename)
1203 {
1204         struct stat st;
1205
1206         if (!stat(filename, &st) && st.st_size) {
1207                 char oldname[PATH_MAX];
1208
1209                 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1210                 unlink(oldname);
1211                 rename(filename, oldname);
1212         }
1213
1214         trace->output = fopen(filename, "w");
1215
1216         return trace->output == NULL ? -errno : 0;
1217 }
1218
1219 int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1220 {
1221         const char * const trace_usage[] = {
1222                 "perf trace [<options>] [<command>]",
1223                 "perf trace [<options>] -- <command> [<options>]",
1224                 NULL
1225         };
1226         struct trace trace = {
1227                 .audit_machine = audit_detect_machine(),
1228                 .syscalls = {
1229                         . max = -1,
1230                 },
1231                 .opts = {
1232                         .target = {
1233                                 .uid       = UINT_MAX,
1234                                 .uses_mmap = true,
1235                         },
1236                         .user_freq     = UINT_MAX,
1237                         .user_interval = ULLONG_MAX,
1238                         .no_delay      = true,
1239                         .mmap_pages    = 1024,
1240                 },
1241                 .output = stdout,
1242         };
1243         const char *output_name = NULL;
1244         const char *ev_qualifier_str = NULL;
1245         const struct option trace_options[] = {
1246         OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1247                     "list of events to trace"),
1248         OPT_STRING('o', "output", &output_name, "file", "output file name"),
1249         OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
1250         OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1251                     "trace events on existing process id"),
1252         OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
1253                     "trace events on existing thread id"),
1254         OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
1255                     "system-wide collection from all CPUs"),
1256         OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
1257                     "list of cpus to monitor"),
1258         OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
1259                     "child tasks do not inherit counters"),
1260         OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages,
1261                      "number of mmap data pages"),
1262         OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
1263                    "user to profile"),
1264         OPT_CALLBACK(0, "duration", &trace, "float",
1265                      "show only events with duration > N.M ms",
1266                      trace__set_duration),
1267         OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
1268         OPT_INCR('v', "verbose", &verbose, "be more verbose"),
1269         OPT_END()
1270         };
1271         int err;
1272         char bf[BUFSIZ];
1273
1274         argc = parse_options(argc, argv, trace_options, trace_usage, 0);
1275
1276         if (output_name != NULL) {
1277                 err = trace__open_output(&trace, output_name);
1278                 if (err < 0) {
1279                         perror("failed to create output file");
1280                         goto out;
1281                 }
1282         }
1283
1284         if (ev_qualifier_str != NULL) {
1285                 const char *s = ev_qualifier_str;
1286
1287                 trace.not_ev_qualifier = *s == '!';
1288                 if (trace.not_ev_qualifier)
1289                         ++s;
1290                 trace.ev_qualifier = strlist__new(true, s);
1291                 if (trace.ev_qualifier == NULL) {
1292                         fputs("Not enough memory to parse event qualifier",
1293                               trace.output);
1294                         err = -ENOMEM;
1295                         goto out_close;
1296                 }
1297         }
1298
1299         err = perf_target__validate(&trace.opts.target);
1300         if (err) {
1301                 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
1302                 fprintf(trace.output, "%s", bf);
1303                 goto out_close;
1304         }
1305
1306         err = perf_target__parse_uid(&trace.opts.target);
1307         if (err) {
1308                 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
1309                 fprintf(trace.output, "%s", bf);
1310                 goto out_close;
1311         }
1312
1313         if (!argc && perf_target__none(&trace.opts.target))
1314                 trace.opts.target.system_wide = true;
1315
1316         if (input_name)
1317                 err = trace__replay(&trace);
1318         else
1319                 err = trace__run(&trace, argc, argv);
1320
1321         if (trace.sched && !err)
1322                 trace__fprintf_thread_summary(&trace, trace.output);
1323
1324 out_close:
1325         if (output_name != NULL)
1326                 fclose(trace.output);
1327 out:
1328         return err;
1329 }