Commit 6810fc915f7a89d8134edb3996dbbf8eac386c26

Authored by David Ahern
Committed by Arnaldo Carvalho de Melo
1 parent a2f2804a71

perf trace: Add option to analyze events in a file versus live

Allows capture of raw_syscall:* events and analyzed at a later time.

v2: change -i option from inherit to input name for consistency with
    other perf commands

Signed-off-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1377750593-48046-3-git-send-email-dsahern@gmail.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

Showing 2 changed files with 100 additions and 2 deletions Inline Diff

tools/perf/Documentation/perf-trace.txt
1 perf-trace(1) 1 perf-trace(1)
2 ============= 2 =============
3 3
4 NAME 4 NAME
5 ---- 5 ----
6 perf-trace - strace inspired tool 6 perf-trace - strace inspired tool
7 7
8 SYNOPSIS 8 SYNOPSIS
9 -------- 9 --------
10 [verse] 10 [verse]
11 'perf trace' 11 'perf trace'
12 12
13 DESCRIPTION 13 DESCRIPTION
14 ----------- 14 -----------
15 This command will show the events associated with the target, initially 15 This command will show the events associated with the target, initially
16 syscalls, but other system events like pagefaults, task lifetime events, 16 syscalls, but other system events like pagefaults, task lifetime events,
17 scheduling events, etc. 17 scheduling events, etc.
18 18
19 Initially this is a live mode only tool, but eventually will work with 19 Initially this is a live mode only tool, but eventually will work with
20 perf.data files like the other tools, allowing a detached 'record' from 20 perf.data files like the other tools, allowing a detached 'record' from
21 analysis phases. 21 analysis phases.
22 22
23 OPTIONS 23 OPTIONS
24 ------- 24 -------
25 25
26 -a:: 26 -a::
27 --all-cpus:: 27 --all-cpus::
28 System-wide collection from all CPUs. 28 System-wide collection from all CPUs.
29 29
30 -e:: 30 -e::
31 --expr:: 31 --expr::
32 List of events to show, currently only syscall names. 32 List of events to show, currently only syscall names.
33 Prefixing with ! shows all syscalls but the ones specified. You may 33 Prefixing with ! shows all syscalls but the ones specified. You may
34 need to escape it. 34 need to escape it.
35 35
36 -o:: 36 -o::
37 --output=:: 37 --output=::
38 Output file name. 38 Output file name.
39 39
40 -p:: 40 -p::
41 --pid=:: 41 --pid=::
42 Record events on existing process ID (comma separated list). 42 Record events on existing process ID (comma separated list).
43 43
44 -t:: 44 -t::
45 --tid=:: 45 --tid=::
46 Record events on existing thread ID (comma separated list). 46 Record events on existing thread ID (comma separated list).
47 47
48 -u:: 48 -u::
49 --uid=:: 49 --uid=::
50 Record events in threads owned by uid. Name or number. 50 Record events in threads owned by uid. Name or number.
51 51
52 -v:: 52 -v::
53 --verbose=:: 53 --verbose=::
54 Verbosity level. 54 Verbosity level.
55 55
56 -i:: 56 -i::
57 --no-inherit:: 57 --no-inherit::
58 Child tasks do not inherit counters. 58 Child tasks do not inherit counters.
59 59
60 -m:: 60 -m::
61 --mmap-pages=:: 61 --mmap-pages=::
62 Number of mmap data pages. Must be a power of two. 62 Number of mmap data pages. Must be a power of two.
63 63
64 -C:: 64 -C::
65 --cpu:: 65 --cpu::
66 Collect samples only on the list of CPUs provided. Multiple CPUs can be provided as a 66 Collect samples only on the list of CPUs provided. Multiple CPUs can be provided as a
67 comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. 67 comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
68 In per-thread mode with inheritance mode on (default), Events are captured only when 68 In per-thread mode with inheritance mode on (default), Events are captured only when
69 the thread executes on the designated CPUs. Default is to monitor all CPUs. 69 the thread executes on the designated CPUs. Default is to monitor all CPUs.
70 70
71 --duration: 71 --duration:
72 Show only events that had a duration greater than N.M ms. 72 Show only events that had a duration greater than N.M ms.
73 73
74 --sched: 74 --sched:
75 Accrue thread runtime and provide a summary at the end of the session. 75 Accrue thread runtime and provide a summary at the end of the session.
76 76
77 -i
78 --input
79 Process events from a given perf data file.
80
77 SEE ALSO 81 SEE ALSO
78 -------- 82 --------
79 linkperf:perf-record[1], linkperf:perf-script[1] 83 linkperf:perf-record[1], linkperf:perf-script[1]
80 84
tools/perf/builtin-trace.c
1 #include <traceevent/event-parse.h> 1 #include <traceevent/event-parse.h>
2 #include "builtin.h" 2 #include "builtin.h"
3 #include "util/color.h" 3 #include "util/color.h"
4 #include "util/debug.h" 4 #include "util/debug.h"
5 #include "util/evlist.h" 5 #include "util/evlist.h"
6 #include "util/machine.h" 6 #include "util/machine.h"
7 #include "util/session.h"
7 #include "util/thread.h" 8 #include "util/thread.h"
8 #include "util/parse-options.h" 9 #include "util/parse-options.h"
9 #include "util/strlist.h" 10 #include "util/strlist.h"
10 #include "util/thread_map.h" 11 #include "util/thread_map.h"
11 12
12 #include <libaudit.h> 13 #include <libaudit.h>
13 #include <stdlib.h> 14 #include <stdlib.h>
14 #include <sys/mman.h> 15 #include <sys/mman.h>
15 16
16 static size_t syscall_arg__scnprintf_hex(char *bf, size_t size, unsigned long arg) 17 static size_t syscall_arg__scnprintf_hex(char *bf, size_t size, unsigned long arg)
17 { 18 {
18 return scnprintf(bf, size, "%#lx", arg); 19 return scnprintf(bf, size, "%#lx", arg);
19 } 20 }
20 21
21 #define SCA_HEX syscall_arg__scnprintf_hex 22 #define SCA_HEX syscall_arg__scnprintf_hex
22 23
23 static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, unsigned long arg) 24 static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, unsigned long arg)
24 { 25 {
25 int printed = 0, prot = arg; 26 int printed = 0, prot = arg;
26 27
27 if (prot == PROT_NONE) 28 if (prot == PROT_NONE)
28 return scnprintf(bf, size, "NONE"); 29 return scnprintf(bf, size, "NONE");
29 #define P_MMAP_PROT(n) \ 30 #define P_MMAP_PROT(n) \
30 if (prot & PROT_##n) { \ 31 if (prot & PROT_##n) { \
31 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ 32 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
32 prot &= ~PROT_##n; \ 33 prot &= ~PROT_##n; \
33 } 34 }
34 35
35 P_MMAP_PROT(EXEC); 36 P_MMAP_PROT(EXEC);
36 P_MMAP_PROT(READ); 37 P_MMAP_PROT(READ);
37 P_MMAP_PROT(WRITE); 38 P_MMAP_PROT(WRITE);
38 #ifdef PROT_SEM 39 #ifdef PROT_SEM
39 P_MMAP_PROT(SEM); 40 P_MMAP_PROT(SEM);
40 #endif 41 #endif
41 P_MMAP_PROT(GROWSDOWN); 42 P_MMAP_PROT(GROWSDOWN);
42 P_MMAP_PROT(GROWSUP); 43 P_MMAP_PROT(GROWSUP);
43 #undef P_MMAP_PROT 44 #undef P_MMAP_PROT
44 45
45 if (prot) 46 if (prot)
46 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot); 47 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
47 48
48 return printed; 49 return printed;
49 } 50 }
50 51
51 #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot 52 #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
52 53
53 static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, unsigned long arg) 54 static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, unsigned long arg)
54 { 55 {
55 int printed = 0, flags = arg; 56 int printed = 0, flags = arg;
56 57
57 #define P_MMAP_FLAG(n) \ 58 #define P_MMAP_FLAG(n) \
58 if (flags & MAP_##n) { \ 59 if (flags & MAP_##n) { \
59 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ 60 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
60 flags &= ~MAP_##n; \ 61 flags &= ~MAP_##n; \
61 } 62 }
62 63
63 P_MMAP_FLAG(SHARED); 64 P_MMAP_FLAG(SHARED);
64 P_MMAP_FLAG(PRIVATE); 65 P_MMAP_FLAG(PRIVATE);
65 P_MMAP_FLAG(32BIT); 66 P_MMAP_FLAG(32BIT);
66 P_MMAP_FLAG(ANONYMOUS); 67 P_MMAP_FLAG(ANONYMOUS);
67 P_MMAP_FLAG(DENYWRITE); 68 P_MMAP_FLAG(DENYWRITE);
68 P_MMAP_FLAG(EXECUTABLE); 69 P_MMAP_FLAG(EXECUTABLE);
69 P_MMAP_FLAG(FILE); 70 P_MMAP_FLAG(FILE);
70 P_MMAP_FLAG(FIXED); 71 P_MMAP_FLAG(FIXED);
71 P_MMAP_FLAG(GROWSDOWN); 72 P_MMAP_FLAG(GROWSDOWN);
72 P_MMAP_FLAG(HUGETLB); 73 P_MMAP_FLAG(HUGETLB);
73 P_MMAP_FLAG(LOCKED); 74 P_MMAP_FLAG(LOCKED);
74 P_MMAP_FLAG(NONBLOCK); 75 P_MMAP_FLAG(NONBLOCK);
75 P_MMAP_FLAG(NORESERVE); 76 P_MMAP_FLAG(NORESERVE);
76 P_MMAP_FLAG(POPULATE); 77 P_MMAP_FLAG(POPULATE);
77 P_MMAP_FLAG(STACK); 78 P_MMAP_FLAG(STACK);
78 #ifdef MAP_UNINITIALIZED 79 #ifdef MAP_UNINITIALIZED
79 P_MMAP_FLAG(UNINITIALIZED); 80 P_MMAP_FLAG(UNINITIALIZED);
80 #endif 81 #endif
81 #undef P_MMAP_FLAG 82 #undef P_MMAP_FLAG
82 83
83 if (flags) 84 if (flags)
84 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); 85 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
85 86
86 return printed; 87 return printed;
87 } 88 }
88 89
89 #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags 90 #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
90 91
91 static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, unsigned long arg) 92 static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, unsigned long arg)
92 { 93 {
93 int behavior = arg; 94 int behavior = arg;
94 95
95 switch (behavior) { 96 switch (behavior) {
96 #define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n) 97 #define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
97 P_MADV_BHV(NORMAL); 98 P_MADV_BHV(NORMAL);
98 P_MADV_BHV(RANDOM); 99 P_MADV_BHV(RANDOM);
99 P_MADV_BHV(SEQUENTIAL); 100 P_MADV_BHV(SEQUENTIAL);
100 P_MADV_BHV(WILLNEED); 101 P_MADV_BHV(WILLNEED);
101 P_MADV_BHV(DONTNEED); 102 P_MADV_BHV(DONTNEED);
102 P_MADV_BHV(REMOVE); 103 P_MADV_BHV(REMOVE);
103 P_MADV_BHV(DONTFORK); 104 P_MADV_BHV(DONTFORK);
104 P_MADV_BHV(DOFORK); 105 P_MADV_BHV(DOFORK);
105 P_MADV_BHV(HWPOISON); 106 P_MADV_BHV(HWPOISON);
106 #ifdef MADV_SOFT_OFFLINE 107 #ifdef MADV_SOFT_OFFLINE
107 P_MADV_BHV(SOFT_OFFLINE); 108 P_MADV_BHV(SOFT_OFFLINE);
108 #endif 109 #endif
109 P_MADV_BHV(MERGEABLE); 110 P_MADV_BHV(MERGEABLE);
110 P_MADV_BHV(UNMERGEABLE); 111 P_MADV_BHV(UNMERGEABLE);
111 P_MADV_BHV(HUGEPAGE); 112 P_MADV_BHV(HUGEPAGE);
112 P_MADV_BHV(NOHUGEPAGE); 113 P_MADV_BHV(NOHUGEPAGE);
113 #ifdef MADV_DONTDUMP 114 #ifdef MADV_DONTDUMP
114 P_MADV_BHV(DONTDUMP); 115 P_MADV_BHV(DONTDUMP);
115 #endif 116 #endif
116 #ifdef MADV_DODUMP 117 #ifdef MADV_DODUMP
117 P_MADV_BHV(DODUMP); 118 P_MADV_BHV(DODUMP);
118 #endif 119 #endif
119 #undef P_MADV_PHV 120 #undef P_MADV_PHV
120 default: break; 121 default: break;
121 } 122 }
122 123
123 return scnprintf(bf, size, "%#x", behavior); 124 return scnprintf(bf, size, "%#x", behavior);
124 } 125 }
125 126
126 #define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior 127 #define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
127 128
128 static struct syscall_fmt { 129 static struct syscall_fmt {
129 const char *name; 130 const char *name;
130 const char *alias; 131 const char *alias;
131 size_t (*arg_scnprintf[6])(char *bf, size_t size, unsigned long arg); 132 size_t (*arg_scnprintf[6])(char *bf, size_t size, unsigned long arg);
132 bool errmsg; 133 bool errmsg;
133 bool timeout; 134 bool timeout;
134 bool hexret; 135 bool hexret;
135 } syscall_fmts[] = { 136 } syscall_fmts[] = {
136 { .name = "access", .errmsg = true, }, 137 { .name = "access", .errmsg = true, },
137 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", }, 138 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
138 { .name = "brk", .hexret = true, 139 { .name = "brk", .hexret = true,
139 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, }, 140 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
140 { .name = "mmap", .hexret = true, }, 141 { .name = "mmap", .hexret = true, },
141 { .name = "connect", .errmsg = true, }, 142 { .name = "connect", .errmsg = true, },
142 { .name = "fstat", .errmsg = true, .alias = "newfstat", }, 143 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
143 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", }, 144 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
144 { .name = "futex", .errmsg = true, }, 145 { .name = "futex", .errmsg = true, },
145 { .name = "ioctl", .errmsg = true, 146 { .name = "ioctl", .errmsg = true,
146 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, }, 147 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
147 { .name = "lstat", .errmsg = true, .alias = "newlstat", }, 148 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
148 { .name = "madvise", .errmsg = true, 149 { .name = "madvise", .errmsg = true,
149 .arg_scnprintf = { [0] = SCA_HEX, /* start */ 150 .arg_scnprintf = { [0] = SCA_HEX, /* start */
150 [2] = SCA_MADV_BHV, /* behavior */ }, }, 151 [2] = SCA_MADV_BHV, /* behavior */ }, },
151 { .name = "mmap", .hexret = true, 152 { .name = "mmap", .hexret = true,
152 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ 153 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
153 [2] = SCA_MMAP_PROT, /* prot */ 154 [2] = SCA_MMAP_PROT, /* prot */
154 [3] = SCA_MMAP_FLAGS, /* flags */ }, }, 155 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
155 { .name = "mprotect", .errmsg = true, 156 { .name = "mprotect", .errmsg = true,
156 .arg_scnprintf = { [0] = SCA_HEX, /* start */ 157 .arg_scnprintf = { [0] = SCA_HEX, /* start */
157 [2] = SCA_MMAP_PROT, /* prot */ }, }, 158 [2] = SCA_MMAP_PROT, /* prot */ }, },
158 { .name = "mremap", .hexret = true, 159 { .name = "mremap", .hexret = true,
159 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ 160 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
160 [4] = SCA_HEX, /* new_addr */ }, }, 161 [4] = SCA_HEX, /* new_addr */ }, },
161 { .name = "munmap", .errmsg = true, 162 { .name = "munmap", .errmsg = true,
162 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, 163 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
163 { .name = "open", .errmsg = true, }, 164 { .name = "open", .errmsg = true, },
164 { .name = "poll", .errmsg = true, .timeout = true, }, 165 { .name = "poll", .errmsg = true, .timeout = true, },
165 { .name = "ppoll", .errmsg = true, .timeout = true, }, 166 { .name = "ppoll", .errmsg = true, .timeout = true, },
166 { .name = "pread", .errmsg = true, .alias = "pread64", }, 167 { .name = "pread", .errmsg = true, .alias = "pread64", },
167 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", }, 168 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
168 { .name = "read", .errmsg = true, }, 169 { .name = "read", .errmsg = true, },
169 { .name = "recvfrom", .errmsg = true, }, 170 { .name = "recvfrom", .errmsg = true, },
170 { .name = "select", .errmsg = true, .timeout = true, }, 171 { .name = "select", .errmsg = true, .timeout = true, },
171 { .name = "socket", .errmsg = true, }, 172 { .name = "socket", .errmsg = true, },
172 { .name = "stat", .errmsg = true, .alias = "newstat", }, 173 { .name = "stat", .errmsg = true, .alias = "newstat", },
173 { .name = "uname", .errmsg = true, .alias = "newuname", }, 174 { .name = "uname", .errmsg = true, .alias = "newuname", },
174 }; 175 };
175 176
176 static int syscall_fmt__cmp(const void *name, const void *fmtp) 177 static int syscall_fmt__cmp(const void *name, const void *fmtp)
177 { 178 {
178 const struct syscall_fmt *fmt = fmtp; 179 const struct syscall_fmt *fmt = fmtp;
179 return strcmp(name, fmt->name); 180 return strcmp(name, fmt->name);
180 } 181 }
181 182
182 static struct syscall_fmt *syscall_fmt__find(const char *name) 183 static struct syscall_fmt *syscall_fmt__find(const char *name)
183 { 184 {
184 const int nmemb = ARRAY_SIZE(syscall_fmts); 185 const int nmemb = ARRAY_SIZE(syscall_fmts);
185 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp); 186 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
186 } 187 }
187 188
188 struct syscall { 189 struct syscall {
189 struct event_format *tp_format; 190 struct event_format *tp_format;
190 const char *name; 191 const char *name;
191 bool filtered; 192 bool filtered;
192 struct syscall_fmt *fmt; 193 struct syscall_fmt *fmt;
193 size_t (**arg_scnprintf)(char *bf, size_t size, unsigned long arg); 194 size_t (**arg_scnprintf)(char *bf, size_t size, unsigned long arg);
194 }; 195 };
195 196
196 static size_t fprintf_duration(unsigned long t, FILE *fp) 197 static size_t fprintf_duration(unsigned long t, FILE *fp)
197 { 198 {
198 double duration = (double)t / NSEC_PER_MSEC; 199 double duration = (double)t / NSEC_PER_MSEC;
199 size_t printed = fprintf(fp, "("); 200 size_t printed = fprintf(fp, "(");
200 201
201 if (duration >= 1.0) 202 if (duration >= 1.0)
202 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration); 203 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
203 else if (duration >= 0.01) 204 else if (duration >= 0.01)
204 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration); 205 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
205 else 206 else
206 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration); 207 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
207 return printed + fprintf(fp, "): "); 208 return printed + fprintf(fp, "): ");
208 } 209 }
209 210
210 struct thread_trace { 211 struct thread_trace {
211 u64 entry_time; 212 u64 entry_time;
212 u64 exit_time; 213 u64 exit_time;
213 bool entry_pending; 214 bool entry_pending;
214 unsigned long nr_events; 215 unsigned long nr_events;
215 char *entry_str; 216 char *entry_str;
216 double runtime_ms; 217 double runtime_ms;
217 }; 218 };
218 219
219 static struct thread_trace *thread_trace__new(void) 220 static struct thread_trace *thread_trace__new(void)
220 { 221 {
221 return zalloc(sizeof(struct thread_trace)); 222 return zalloc(sizeof(struct thread_trace));
222 } 223 }
223 224
224 static struct thread_trace *thread__trace(struct thread *thread, FILE *fp) 225 static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
225 { 226 {
226 struct thread_trace *ttrace; 227 struct thread_trace *ttrace;
227 228
228 if (thread == NULL) 229 if (thread == NULL)
229 goto fail; 230 goto fail;
230 231
231 if (thread->priv == NULL) 232 if (thread->priv == NULL)
232 thread->priv = thread_trace__new(); 233 thread->priv = thread_trace__new();
233 234
234 if (thread->priv == NULL) 235 if (thread->priv == NULL)
235 goto fail; 236 goto fail;
236 237
237 ttrace = thread->priv; 238 ttrace = thread->priv;
238 ++ttrace->nr_events; 239 ++ttrace->nr_events;
239 240
240 return ttrace; 241 return ttrace;
241 fail: 242 fail:
242 color_fprintf(fp, PERF_COLOR_RED, 243 color_fprintf(fp, PERF_COLOR_RED,
243 "WARNING: not enough memory, dropping samples!\n"); 244 "WARNING: not enough memory, dropping samples!\n");
244 return NULL; 245 return NULL;
245 } 246 }
246 247
247 struct trace { 248 struct trace {
248 struct perf_tool tool; 249 struct perf_tool tool;
249 int audit_machine; 250 int audit_machine;
250 struct { 251 struct {
251 int max; 252 int max;
252 struct syscall *table; 253 struct syscall *table;
253 } syscalls; 254 } syscalls;
254 struct perf_record_opts opts; 255 struct perf_record_opts opts;
255 struct machine host; 256 struct machine host;
256 u64 base_time; 257 u64 base_time;
257 FILE *output; 258 FILE *output;
258 unsigned long nr_events; 259 unsigned long nr_events;
259 struct strlist *ev_qualifier; 260 struct strlist *ev_qualifier;
260 bool not_ev_qualifier; 261 bool not_ev_qualifier;
261 bool sched; 262 bool sched;
262 bool multiple_threads; 263 bool multiple_threads;
263 double duration_filter; 264 double duration_filter;
264 double runtime_ms; 265 double runtime_ms;
265 }; 266 };
266 267
267 static bool trace__filter_duration(struct trace *trace, double t) 268 static bool trace__filter_duration(struct trace *trace, double t)
268 { 269 {
269 return t < (trace->duration_filter * NSEC_PER_MSEC); 270 return t < (trace->duration_filter * NSEC_PER_MSEC);
270 } 271 }
271 272
272 static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp) 273 static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
273 { 274 {
274 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC; 275 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
275 276
276 return fprintf(fp, "%10.3f ", ts); 277 return fprintf(fp, "%10.3f ", ts);
277 } 278 }
278 279
279 static bool done = false; 280 static bool done = false;
280 281
281 static void sig_handler(int sig __maybe_unused) 282 static void sig_handler(int sig __maybe_unused)
282 { 283 {
283 done = true; 284 done = true;
284 } 285 }
285 286
286 static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread, 287 static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
287 u64 duration, u64 tstamp, FILE *fp) 288 u64 duration, u64 tstamp, FILE *fp)
288 { 289 {
289 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp); 290 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
290 printed += fprintf_duration(duration, fp); 291 printed += fprintf_duration(duration, fp);
291 292
292 if (trace->multiple_threads) 293 if (trace->multiple_threads)
293 printed += fprintf(fp, "%d ", thread->tid); 294 printed += fprintf(fp, "%d ", thread->tid);
294 295
295 return printed; 296 return printed;
296 } 297 }
297 298
298 static int trace__process_event(struct trace *trace, struct machine *machine, 299 static int trace__process_event(struct trace *trace, struct machine *machine,
299 union perf_event *event) 300 union perf_event *event)
300 { 301 {
301 int ret = 0; 302 int ret = 0;
302 303
303 switch (event->header.type) { 304 switch (event->header.type) {
304 case PERF_RECORD_LOST: 305 case PERF_RECORD_LOST:
305 color_fprintf(trace->output, PERF_COLOR_RED, 306 color_fprintf(trace->output, PERF_COLOR_RED,
306 "LOST %" PRIu64 " events!\n", event->lost.lost); 307 "LOST %" PRIu64 " events!\n", event->lost.lost);
307 ret = machine__process_lost_event(machine, event); 308 ret = machine__process_lost_event(machine, event);
308 default: 309 default:
309 ret = machine__process_event(machine, event); 310 ret = machine__process_event(machine, event);
310 break; 311 break;
311 } 312 }
312 313
313 return ret; 314 return ret;
314 } 315 }
315 316
316 static int trace__tool_process(struct perf_tool *tool, 317 static int trace__tool_process(struct perf_tool *tool,
317 union perf_event *event, 318 union perf_event *event,
318 struct perf_sample *sample __maybe_unused, 319 struct perf_sample *sample __maybe_unused,
319 struct machine *machine) 320 struct machine *machine)
320 { 321 {
321 struct trace *trace = container_of(tool, struct trace, tool); 322 struct trace *trace = container_of(tool, struct trace, tool);
322 return trace__process_event(trace, machine, event); 323 return trace__process_event(trace, machine, event);
323 } 324 }
324 325
325 static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) 326 static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
326 { 327 {
327 int err = symbol__init(); 328 int err = symbol__init();
328 329
329 if (err) 330 if (err)
330 return err; 331 return err;
331 332
332 machine__init(&trace->host, "", HOST_KERNEL_ID); 333 machine__init(&trace->host, "", HOST_KERNEL_ID);
333 machine__create_kernel_maps(&trace->host); 334 machine__create_kernel_maps(&trace->host);
334 335
335 if (perf_target__has_task(&trace->opts.target)) { 336 if (perf_target__has_task(&trace->opts.target)) {
336 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads, 337 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
337 trace__tool_process, 338 trace__tool_process,
338 &trace->host); 339 &trace->host);
339 } else { 340 } else {
340 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process, 341 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
341 &trace->host); 342 &trace->host);
342 } 343 }
343 344
344 if (err) 345 if (err)
345 symbol__exit(); 346 symbol__exit();
346 347
347 return err; 348 return err;
348 } 349 }
349 350
350 static int syscall__set_arg_fmts(struct syscall *sc) 351 static int syscall__set_arg_fmts(struct syscall *sc)
351 { 352 {
352 struct format_field *field; 353 struct format_field *field;
353 int idx = 0; 354 int idx = 0;
354 355
355 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *)); 356 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
356 if (sc->arg_scnprintf == NULL) 357 if (sc->arg_scnprintf == NULL)
357 return -1; 358 return -1;
358 359
359 for (field = sc->tp_format->format.fields->next; field; field = field->next) { 360 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
360 if (sc->fmt && sc->fmt->arg_scnprintf[idx]) 361 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
361 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx]; 362 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
362 else if (field->flags & FIELD_IS_POINTER) 363 else if (field->flags & FIELD_IS_POINTER)
363 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex; 364 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
364 ++idx; 365 ++idx;
365 } 366 }
366 367
367 return 0; 368 return 0;
368 } 369 }
369 370
370 static int trace__read_syscall_info(struct trace *trace, int id) 371 static int trace__read_syscall_info(struct trace *trace, int id)
371 { 372 {
372 char tp_name[128]; 373 char tp_name[128];
373 struct syscall *sc; 374 struct syscall *sc;
374 const char *name = audit_syscall_to_name(id, trace->audit_machine); 375 const char *name = audit_syscall_to_name(id, trace->audit_machine);
375 376
376 if (name == NULL) 377 if (name == NULL)
377 return -1; 378 return -1;
378 379
379 if (id > trace->syscalls.max) { 380 if (id > trace->syscalls.max) {
380 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc)); 381 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
381 382
382 if (nsyscalls == NULL) 383 if (nsyscalls == NULL)
383 return -1; 384 return -1;
384 385
385 if (trace->syscalls.max != -1) { 386 if (trace->syscalls.max != -1) {
386 memset(nsyscalls + trace->syscalls.max + 1, 0, 387 memset(nsyscalls + trace->syscalls.max + 1, 0,
387 (id - trace->syscalls.max) * sizeof(*sc)); 388 (id - trace->syscalls.max) * sizeof(*sc));
388 } else { 389 } else {
389 memset(nsyscalls, 0, (id + 1) * sizeof(*sc)); 390 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
390 } 391 }
391 392
392 trace->syscalls.table = nsyscalls; 393 trace->syscalls.table = nsyscalls;
393 trace->syscalls.max = id; 394 trace->syscalls.max = id;
394 } 395 }
395 396
396 sc = trace->syscalls.table + id; 397 sc = trace->syscalls.table + id;
397 sc->name = name; 398 sc->name = name;
398 399
399 if (trace->ev_qualifier) { 400 if (trace->ev_qualifier) {
400 bool in = strlist__find(trace->ev_qualifier, name) != NULL; 401 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
401 402
402 if (!(in ^ trace->not_ev_qualifier)) { 403 if (!(in ^ trace->not_ev_qualifier)) {
403 sc->filtered = true; 404 sc->filtered = true;
404 /* 405 /*
405 * No need to do read tracepoint information since this will be 406 * No need to do read tracepoint information since this will be
406 * filtered out. 407 * filtered out.
407 */ 408 */
408 return 0; 409 return 0;
409 } 410 }
410 } 411 }
411 412
412 sc->fmt = syscall_fmt__find(sc->name); 413 sc->fmt = syscall_fmt__find(sc->name);
413 414
414 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); 415 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
415 sc->tp_format = event_format__new("syscalls", tp_name); 416 sc->tp_format = event_format__new("syscalls", tp_name);
416 417
417 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) { 418 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
418 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias); 419 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
419 sc->tp_format = event_format__new("syscalls", tp_name); 420 sc->tp_format = event_format__new("syscalls", tp_name);
420 } 421 }
421 422
422 if (sc->tp_format == NULL) 423 if (sc->tp_format == NULL)
423 return -1; 424 return -1;
424 425
425 return syscall__set_arg_fmts(sc); 426 return syscall__set_arg_fmts(sc);
426 } 427 }
427 428
428 static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, 429 static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
429 unsigned long *args) 430 unsigned long *args)
430 { 431 {
431 int i = 0; 432 int i = 0;
432 size_t printed = 0; 433 size_t printed = 0;
433 434
434 if (sc->tp_format != NULL) { 435 if (sc->tp_format != NULL) {
435 struct format_field *field; 436 struct format_field *field;
436 437
437 for (field = sc->tp_format->format.fields->next; field; field = field->next) { 438 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
438 printed += scnprintf(bf + printed, size - printed, 439 printed += scnprintf(bf + printed, size - printed,
439 "%s%s: ", printed ? ", " : "", field->name); 440 "%s%s: ", printed ? ", " : "", field->name);
440 441
441 if (sc->arg_scnprintf && sc->arg_scnprintf[i]) 442 if (sc->arg_scnprintf && sc->arg_scnprintf[i])
442 printed += sc->arg_scnprintf[i](bf + printed, size - printed, args[i]); 443 printed += sc->arg_scnprintf[i](bf + printed, size - printed, args[i]);
443 else 444 else
444 printed += scnprintf(bf + printed, size - printed, 445 printed += scnprintf(bf + printed, size - printed,
445 "%ld", args[i]); 446 "%ld", args[i]);
446 ++i; 447 ++i;
447 } 448 }
448 } else { 449 } else {
449 while (i < 6) { 450 while (i < 6) {
450 printed += scnprintf(bf + printed, size - printed, 451 printed += scnprintf(bf + printed, size - printed,
451 "%sarg%d: %ld", 452 "%sarg%d: %ld",
452 printed ? ", " : "", i, args[i]); 453 printed ? ", " : "", i, args[i]);
453 ++i; 454 ++i;
454 } 455 }
455 } 456 }
456 457
457 return printed; 458 return printed;
458 } 459 }
459 460
460 typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel, 461 typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
461 struct perf_sample *sample); 462 struct perf_sample *sample);
462 463
463 static struct syscall *trace__syscall_info(struct trace *trace, 464 static struct syscall *trace__syscall_info(struct trace *trace,
464 struct perf_evsel *evsel, 465 struct perf_evsel *evsel,
465 struct perf_sample *sample) 466 struct perf_sample *sample)
466 { 467 {
467 int id = perf_evsel__intval(evsel, sample, "id"); 468 int id = perf_evsel__intval(evsel, sample, "id");
468 469
469 if (id < 0) { 470 if (id < 0) {
470 471
471 /* 472 /*
472 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried 473 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
473 * before that, leaving at a higher verbosity level till that is 474 * before that, leaving at a higher verbosity level till that is
474 * explained. Reproduced with plain ftrace with: 475 * explained. Reproduced with plain ftrace with:
475 * 476 *
476 * echo 1 > /t/events/raw_syscalls/sys_exit/enable 477 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
477 * grep "NR -1 " /t/trace_pipe 478 * grep "NR -1 " /t/trace_pipe
478 * 479 *
479 * After generating some load on the machine. 480 * After generating some load on the machine.
480 */ 481 */
481 if (verbose > 1) { 482 if (verbose > 1) {
482 static u64 n; 483 static u64 n;
483 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n", 484 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
484 id, perf_evsel__name(evsel), ++n); 485 id, perf_evsel__name(evsel), ++n);
485 } 486 }
486 return NULL; 487 return NULL;
487 } 488 }
488 489
489 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) && 490 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
490 trace__read_syscall_info(trace, id)) 491 trace__read_syscall_info(trace, id))
491 goto out_cant_read; 492 goto out_cant_read;
492 493
493 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL)) 494 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
494 goto out_cant_read; 495 goto out_cant_read;
495 496
496 return &trace->syscalls.table[id]; 497 return &trace->syscalls.table[id];
497 498
498 out_cant_read: 499 out_cant_read:
499 if (verbose) { 500 if (verbose) {
500 fprintf(trace->output, "Problems reading syscall %d", id); 501 fprintf(trace->output, "Problems reading syscall %d", id);
501 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL) 502 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
502 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name); 503 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
503 fputs(" information\n", trace->output); 504 fputs(" information\n", trace->output);
504 } 505 }
505 return NULL; 506 return NULL;
506 } 507 }
507 508
508 static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, 509 static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
509 struct perf_sample *sample) 510 struct perf_sample *sample)
510 { 511 {
511 char *msg; 512 char *msg;
512 void *args; 513 void *args;
513 size_t printed = 0; 514 size_t printed = 0;
514 struct thread *thread; 515 struct thread *thread;
515 struct syscall *sc = trace__syscall_info(trace, evsel, sample); 516 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
516 struct thread_trace *ttrace; 517 struct thread_trace *ttrace;
517 518
518 if (sc == NULL) 519 if (sc == NULL)
519 return -1; 520 return -1;
520 521
521 if (sc->filtered) 522 if (sc->filtered)
522 return 0; 523 return 0;
523 524
524 thread = machine__findnew_thread(&trace->host, sample->pid, 525 thread = machine__findnew_thread(&trace->host, sample->pid,
525 sample->tid); 526 sample->tid);
526 ttrace = thread__trace(thread, trace->output); 527 ttrace = thread__trace(thread, trace->output);
527 if (ttrace == NULL) 528 if (ttrace == NULL)
528 return -1; 529 return -1;
529 530
530 args = perf_evsel__rawptr(evsel, sample, "args"); 531 args = perf_evsel__rawptr(evsel, sample, "args");
531 if (args == NULL) { 532 if (args == NULL) {
532 fprintf(trace->output, "Problems reading syscall arguments\n"); 533 fprintf(trace->output, "Problems reading syscall arguments\n");
533 return -1; 534 return -1;
534 } 535 }
535 536
536 ttrace = thread->priv; 537 ttrace = thread->priv;
537 538
538 if (ttrace->entry_str == NULL) { 539 if (ttrace->entry_str == NULL) {
539 ttrace->entry_str = malloc(1024); 540 ttrace->entry_str = malloc(1024);
540 if (!ttrace->entry_str) 541 if (!ttrace->entry_str)
541 return -1; 542 return -1;
542 } 543 }
543 544
544 ttrace->entry_time = sample->time; 545 ttrace->entry_time = sample->time;
545 msg = ttrace->entry_str; 546 msg = ttrace->entry_str;
546 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name); 547 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
547 548
548 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args); 549 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
549 550
550 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) { 551 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
551 if (!trace->duration_filter) { 552 if (!trace->duration_filter) {
552 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output); 553 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
553 fprintf(trace->output, "%-70s\n", ttrace->entry_str); 554 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
554 } 555 }
555 } else 556 } else
556 ttrace->entry_pending = true; 557 ttrace->entry_pending = true;
557 558
558 return 0; 559 return 0;
559 } 560 }
560 561
561 static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, 562 static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
562 struct perf_sample *sample) 563 struct perf_sample *sample)
563 { 564 {
564 int ret; 565 int ret;
565 u64 duration = 0; 566 u64 duration = 0;
566 struct thread *thread; 567 struct thread *thread;
567 struct syscall *sc = trace__syscall_info(trace, evsel, sample); 568 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
568 struct thread_trace *ttrace; 569 struct thread_trace *ttrace;
569 570
570 if (sc == NULL) 571 if (sc == NULL)
571 return -1; 572 return -1;
572 573
573 if (sc->filtered) 574 if (sc->filtered)
574 return 0; 575 return 0;
575 576
576 thread = machine__findnew_thread(&trace->host, sample->pid, 577 thread = machine__findnew_thread(&trace->host, sample->pid,
577 sample->tid); 578 sample->tid);
578 ttrace = thread__trace(thread, trace->output); 579 ttrace = thread__trace(thread, trace->output);
579 if (ttrace == NULL) 580 if (ttrace == NULL)
580 return -1; 581 return -1;
581 582
582 ret = perf_evsel__intval(evsel, sample, "ret"); 583 ret = perf_evsel__intval(evsel, sample, "ret");
583 584
584 ttrace = thread->priv; 585 ttrace = thread->priv;
585 586
586 ttrace->exit_time = sample->time; 587 ttrace->exit_time = sample->time;
587 588
588 if (ttrace->entry_time) { 589 if (ttrace->entry_time) {
589 duration = sample->time - ttrace->entry_time; 590 duration = sample->time - ttrace->entry_time;
590 if (trace__filter_duration(trace, duration)) 591 if (trace__filter_duration(trace, duration))
591 goto out; 592 goto out;
592 } else if (trace->duration_filter) 593 } else if (trace->duration_filter)
593 goto out; 594 goto out;
594 595
595 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output); 596 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
596 597
597 if (ttrace->entry_pending) { 598 if (ttrace->entry_pending) {
598 fprintf(trace->output, "%-70s", ttrace->entry_str); 599 fprintf(trace->output, "%-70s", ttrace->entry_str);
599 } else { 600 } else {
600 fprintf(trace->output, " ... ["); 601 fprintf(trace->output, " ... [");
601 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued"); 602 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
602 fprintf(trace->output, "]: %s()", sc->name); 603 fprintf(trace->output, "]: %s()", sc->name);
603 } 604 }
604 605
605 if (sc->fmt == NULL) { 606 if (sc->fmt == NULL) {
606 signed_print: 607 signed_print:
607 fprintf(trace->output, ") = %d", ret); 608 fprintf(trace->output, ") = %d", ret);
608 } else if (ret < 0 && sc->fmt->errmsg) { 609 } else if (ret < 0 && sc->fmt->errmsg) {
609 char bf[256]; 610 char bf[256];
610 const char *emsg = strerror_r(-ret, bf, sizeof(bf)), 611 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
611 *e = audit_errno_to_name(-ret); 612 *e = audit_errno_to_name(-ret);
612 613
613 fprintf(trace->output, ") = -1 %s %s", e, emsg); 614 fprintf(trace->output, ") = -1 %s %s", e, emsg);
614 } else if (ret == 0 && sc->fmt->timeout) 615 } else if (ret == 0 && sc->fmt->timeout)
615 fprintf(trace->output, ") = 0 Timeout"); 616 fprintf(trace->output, ") = 0 Timeout");
616 else if (sc->fmt->hexret) 617 else if (sc->fmt->hexret)
617 fprintf(trace->output, ") = %#x", ret); 618 fprintf(trace->output, ") = %#x", ret);
618 else 619 else
619 goto signed_print; 620 goto signed_print;
620 621
621 fputc('\n', trace->output); 622 fputc('\n', trace->output);
622 out: 623 out:
623 ttrace->entry_pending = false; 624 ttrace->entry_pending = false;
624 625
625 return 0; 626 return 0;
626 } 627 }
627 628
628 static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel, 629 static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
629 struct perf_sample *sample) 630 struct perf_sample *sample)
630 { 631 {
631 u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); 632 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
632 double runtime_ms = (double)runtime / NSEC_PER_MSEC; 633 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
633 struct thread *thread = machine__findnew_thread(&trace->host, 634 struct thread *thread = machine__findnew_thread(&trace->host,
634 sample->pid, 635 sample->pid,
635 sample->tid); 636 sample->tid);
636 struct thread_trace *ttrace = thread__trace(thread, trace->output); 637 struct thread_trace *ttrace = thread__trace(thread, trace->output);
637 638
638 if (ttrace == NULL) 639 if (ttrace == NULL)
639 goto out_dump; 640 goto out_dump;
640 641
641 ttrace->runtime_ms += runtime_ms; 642 ttrace->runtime_ms += runtime_ms;
642 trace->runtime_ms += runtime_ms; 643 trace->runtime_ms += runtime_ms;
643 return 0; 644 return 0;
644 645
645 out_dump: 646 out_dump:
646 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n", 647 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
647 evsel->name, 648 evsel->name,
648 perf_evsel__strval(evsel, sample, "comm"), 649 perf_evsel__strval(evsel, sample, "comm"),
649 (pid_t)perf_evsel__intval(evsel, sample, "pid"), 650 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
650 runtime, 651 runtime,
651 perf_evsel__intval(evsel, sample, "vruntime")); 652 perf_evsel__intval(evsel, sample, "vruntime"));
652 return 0; 653 return 0;
653 } 654 }
654 655
656 static int trace__process_sample(struct perf_tool *tool,
657 union perf_event *event __maybe_unused,
658 struct perf_sample *sample,
659 struct perf_evsel *evsel,
660 struct machine *machine __maybe_unused)
661 {
662 struct trace *trace = container_of(tool, struct trace, tool);
663 int err = 0;
664
665 tracepoint_handler handler = evsel->handler.func;
666
667 if (trace->base_time == 0)
668 trace->base_time = sample->time;
669
670 if (handler)
671 handler(trace, evsel, sample);
672
673 return err;
674 }
675
676 static bool
677 perf_session__has_tp(struct perf_session *session, const char *name)
678 {
679 struct perf_evsel *evsel;
680
681 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
682
683 return evsel != NULL;
684 }
685
655 static int trace__run(struct trace *trace, int argc, const char **argv) 686 static int trace__run(struct trace *trace, int argc, const char **argv)
656 { 687 {
657 struct perf_evlist *evlist = perf_evlist__new(); 688 struct perf_evlist *evlist = perf_evlist__new();
658 struct perf_evsel *evsel; 689 struct perf_evsel *evsel;
659 int err = -1, i; 690 int err = -1, i;
660 unsigned long before; 691 unsigned long before;
661 const bool forks = argc > 0; 692 const bool forks = argc > 0;
662 693
663 if (evlist == NULL) { 694 if (evlist == NULL) {
664 fprintf(trace->output, "Not enough memory to run!\n"); 695 fprintf(trace->output, "Not enough memory to run!\n");
665 goto out; 696 goto out;
666 } 697 }
667 698
668 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) || 699 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
669 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) { 700 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
670 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n"); 701 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
671 goto out_delete_evlist; 702 goto out_delete_evlist;
672 } 703 }
673 704
674 if (trace->sched && 705 if (trace->sched &&
675 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", 706 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
676 trace__sched_stat_runtime)) { 707 trace__sched_stat_runtime)) {
677 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n"); 708 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
678 goto out_delete_evlist; 709 goto out_delete_evlist;
679 } 710 }
680 711
681 err = perf_evlist__create_maps(evlist, &trace->opts.target); 712 err = perf_evlist__create_maps(evlist, &trace->opts.target);
682 if (err < 0) { 713 if (err < 0) {
683 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n"); 714 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
684 goto out_delete_evlist; 715 goto out_delete_evlist;
685 } 716 }
686 717
687 err = trace__symbols_init(trace, evlist); 718 err = trace__symbols_init(trace, evlist);
688 if (err < 0) { 719 if (err < 0) {
689 fprintf(trace->output, "Problems initializing symbol libraries!\n"); 720 fprintf(trace->output, "Problems initializing symbol libraries!\n");
690 goto out_delete_maps; 721 goto out_delete_maps;
691 } 722 }
692 723
693 perf_evlist__config(evlist, &trace->opts); 724 perf_evlist__config(evlist, &trace->opts);
694 725
695 signal(SIGCHLD, sig_handler); 726 signal(SIGCHLD, sig_handler);
696 signal(SIGINT, sig_handler); 727 signal(SIGINT, sig_handler);
697 728
698 if (forks) { 729 if (forks) {
699 err = perf_evlist__prepare_workload(evlist, &trace->opts.target, 730 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
700 argv, false, false); 731 argv, false, false);
701 if (err < 0) { 732 if (err < 0) {
702 fprintf(trace->output, "Couldn't run the workload!\n"); 733 fprintf(trace->output, "Couldn't run the workload!\n");
703 goto out_delete_maps; 734 goto out_delete_maps;
704 } 735 }
705 } 736 }
706 737
707 err = perf_evlist__open(evlist); 738 err = perf_evlist__open(evlist);
708 if (err < 0) { 739 if (err < 0) {
709 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno)); 740 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
710 goto out_delete_maps; 741 goto out_delete_maps;
711 } 742 }
712 743
713 err = perf_evlist__mmap(evlist, UINT_MAX, false); 744 err = perf_evlist__mmap(evlist, UINT_MAX, false);
714 if (err < 0) { 745 if (err < 0) {
715 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno)); 746 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
716 goto out_close_evlist; 747 goto out_close_evlist;
717 } 748 }
718 749
719 perf_evlist__enable(evlist); 750 perf_evlist__enable(evlist);
720 751
721 if (forks) 752 if (forks)
722 perf_evlist__start_workload(evlist); 753 perf_evlist__start_workload(evlist);
723 754
724 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1; 755 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
725 again: 756 again:
726 before = trace->nr_events; 757 before = trace->nr_events;
727 758
728 for (i = 0; i < evlist->nr_mmaps; i++) { 759 for (i = 0; i < evlist->nr_mmaps; i++) {
729 union perf_event *event; 760 union perf_event *event;
730 761
731 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { 762 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
732 const u32 type = event->header.type; 763 const u32 type = event->header.type;
733 tracepoint_handler handler; 764 tracepoint_handler handler;
734 struct perf_sample sample; 765 struct perf_sample sample;
735 766
736 ++trace->nr_events; 767 ++trace->nr_events;
737 768
738 err = perf_evlist__parse_sample(evlist, event, &sample); 769 err = perf_evlist__parse_sample(evlist, event, &sample);
739 if (err) { 770 if (err) {
740 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err); 771 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
741 continue; 772 continue;
742 } 773 }
743 774
744 if (trace->base_time == 0) 775 if (trace->base_time == 0)
745 trace->base_time = sample.time; 776 trace->base_time = sample.time;
746 777
747 if (type != PERF_RECORD_SAMPLE) { 778 if (type != PERF_RECORD_SAMPLE) {
748 trace__process_event(trace, &trace->host, event); 779 trace__process_event(trace, &trace->host, event);
749 continue; 780 continue;
750 } 781 }
751 782
752 evsel = perf_evlist__id2evsel(evlist, sample.id); 783 evsel = perf_evlist__id2evsel(evlist, sample.id);
753 if (evsel == NULL) { 784 if (evsel == NULL) {
754 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id); 785 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
755 continue; 786 continue;
756 } 787 }
757 788
758 if (sample.raw_data == NULL) { 789 if (sample.raw_data == NULL) {
759 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", 790 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
760 perf_evsel__name(evsel), sample.tid, 791 perf_evsel__name(evsel), sample.tid,
761 sample.cpu, sample.raw_size); 792 sample.cpu, sample.raw_size);
762 continue; 793 continue;
763 } 794 }
764 795
765 handler = evsel->handler.func; 796 handler = evsel->handler.func;
766 handler(trace, evsel, &sample); 797 handler(trace, evsel, &sample);
767 } 798 }
768 } 799 }
769 800
770 if (trace->nr_events == before) { 801 if (trace->nr_events == before) {
771 if (done) 802 if (done)
772 goto out_unmap_evlist; 803 goto out_unmap_evlist;
773 804
774 poll(evlist->pollfd, evlist->nr_fds, -1); 805 poll(evlist->pollfd, evlist->nr_fds, -1);
775 } 806 }
776 807
777 if (done) 808 if (done)
778 perf_evlist__disable(evlist); 809 perf_evlist__disable(evlist);
779 810
780 goto again; 811 goto again;
781 812
782 out_unmap_evlist: 813 out_unmap_evlist:
783 perf_evlist__munmap(evlist); 814 perf_evlist__munmap(evlist);
784 out_close_evlist: 815 out_close_evlist:
785 perf_evlist__close(evlist); 816 perf_evlist__close(evlist);
786 out_delete_maps: 817 out_delete_maps:
787 perf_evlist__delete_maps(evlist); 818 perf_evlist__delete_maps(evlist);
788 out_delete_evlist: 819 out_delete_evlist:
789 perf_evlist__delete(evlist); 820 perf_evlist__delete(evlist);
790 out: 821 out:
791 return err; 822 return err;
792 } 823 }
793 824
825 static int trace__replay(struct trace *trace)
826 {
827 const struct perf_evsel_str_handler handlers[] = {
828 { "raw_syscalls:sys_enter", trace__sys_enter, },
829 { "raw_syscalls:sys_exit", trace__sys_exit, },
830 };
831
832 struct perf_session *session;
833 int err = -1;
834
835 trace->tool.sample = trace__process_sample;
836 trace->tool.mmap = perf_event__process_mmap;
837 trace->tool.comm = perf_event__process_comm;
838 trace->tool.exit = perf_event__process_exit;
839 trace->tool.fork = perf_event__process_fork;
840 trace->tool.attr = perf_event__process_attr;
841 trace->tool.tracing_data = perf_event__process_tracing_data;
842 trace->tool.build_id = perf_event__process_build_id;
843
844 trace->tool.ordered_samples = true;
845 trace->tool.ordering_requires_timestamps = true;
846
847 /* add tid to output */
848 trace->multiple_threads = true;
849
850 if (symbol__init() < 0)
851 return -1;
852
853 session = perf_session__new(input_name, O_RDONLY, 0, false,
854 &trace->tool);
855 if (session == NULL)
856 return -ENOMEM;
857
858 err = perf_session__set_tracepoints_handlers(session, handlers);
859 if (err)
860 goto out;
861
862 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
863 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
864 goto out;
865 }
866
867 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
868 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
869 goto out;
870 }
871
872 setup_pager();
873
874 err = perf_session__process_events(session, &trace->tool);
875 if (err)
876 pr_err("Failed to process events, error %d", err);
877
878 out:
879 perf_session__delete(session);
880
881 return err;
882 }
883
794 static size_t trace__fprintf_threads_header(FILE *fp) 884 static size_t trace__fprintf_threads_header(FILE *fp)
795 { 885 {
796 size_t printed; 886 size_t printed;
797 887
798 printed = fprintf(fp, "\n _____________________________________________________________________\n"); 888 printed = fprintf(fp, "\n _____________________________________________________________________\n");
799 printed += fprintf(fp," __) Summary of events (__\n\n"); 889 printed += fprintf(fp," __) Summary of events (__\n\n");
800 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n"); 890 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
801 printed += fprintf(fp," _____________________________________________________________________\n\n"); 891 printed += fprintf(fp," _____________________________________________________________________\n\n");
802 892
803 return printed; 893 return printed;
804 } 894 }
805 895
806 static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp) 896 static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
807 { 897 {
808 size_t printed = trace__fprintf_threads_header(fp); 898 size_t printed = trace__fprintf_threads_header(fp);
809 struct rb_node *nd; 899 struct rb_node *nd;
810 900
811 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) { 901 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
812 struct thread *thread = rb_entry(nd, struct thread, rb_node); 902 struct thread *thread = rb_entry(nd, struct thread, rb_node);
813 struct thread_trace *ttrace = thread->priv; 903 struct thread_trace *ttrace = thread->priv;
814 const char *color; 904 const char *color;
815 double ratio; 905 double ratio;
816 906
817 if (ttrace == NULL) 907 if (ttrace == NULL)
818 continue; 908 continue;
819 909
820 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0; 910 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
821 911
822 color = PERF_COLOR_NORMAL; 912 color = PERF_COLOR_NORMAL;
823 if (ratio > 50.0) 913 if (ratio > 50.0)
824 color = PERF_COLOR_RED; 914 color = PERF_COLOR_RED;
825 else if (ratio > 25.0) 915 else if (ratio > 25.0)
826 color = PERF_COLOR_GREEN; 916 color = PERF_COLOR_GREEN;
827 else if (ratio > 5.0) 917 else if (ratio > 5.0)
828 color = PERF_COLOR_YELLOW; 918 color = PERF_COLOR_YELLOW;
829 919
830 printed += color_fprintf(fp, color, "%20s", thread->comm); 920 printed += color_fprintf(fp, color, "%20s", thread->comm);
831 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events); 921 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
832 printed += color_fprintf(fp, color, "%5.1f%%", ratio); 922 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
833 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms); 923 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
834 } 924 }
835 925
836 return printed; 926 return printed;
837 } 927 }
838 928
839 static int trace__set_duration(const struct option *opt, const char *str, 929 static int trace__set_duration(const struct option *opt, const char *str,
840 int unset __maybe_unused) 930 int unset __maybe_unused)
841 { 931 {
842 struct trace *trace = opt->value; 932 struct trace *trace = opt->value;
843 933
844 trace->duration_filter = atof(str); 934 trace->duration_filter = atof(str);
845 return 0; 935 return 0;
846 } 936 }
847 937
848 static int trace__open_output(struct trace *trace, const char *filename) 938 static int trace__open_output(struct trace *trace, const char *filename)
849 { 939 {
850 struct stat st; 940 struct stat st;
851 941
852 if (!stat(filename, &st) && st.st_size) { 942 if (!stat(filename, &st) && st.st_size) {
853 char oldname[PATH_MAX]; 943 char oldname[PATH_MAX];
854 944
855 scnprintf(oldname, sizeof(oldname), "%s.old", filename); 945 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
856 unlink(oldname); 946 unlink(oldname);
857 rename(filename, oldname); 947 rename(filename, oldname);
858 } 948 }
859 949
860 trace->output = fopen(filename, "w"); 950 trace->output = fopen(filename, "w");
861 951
862 return trace->output == NULL ? -errno : 0; 952 return trace->output == NULL ? -errno : 0;
863 } 953 }
864 954
865 int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) 955 int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
866 { 956 {
867 const char * const trace_usage[] = { 957 const char * const trace_usage[] = {
868 "perf trace [<options>] [<command>]", 958 "perf trace [<options>] [<command>]",
869 "perf trace [<options>] -- <command> [<options>]", 959 "perf trace [<options>] -- <command> [<options>]",
870 NULL 960 NULL
871 }; 961 };
872 struct trace trace = { 962 struct trace trace = {
873 .audit_machine = audit_detect_machine(), 963 .audit_machine = audit_detect_machine(),
874 .syscalls = { 964 .syscalls = {
875 . max = -1, 965 . max = -1,
876 }, 966 },
877 .opts = { 967 .opts = {
878 .target = { 968 .target = {
879 .uid = UINT_MAX, 969 .uid = UINT_MAX,
880 .uses_mmap = true, 970 .uses_mmap = true,
881 }, 971 },
882 .user_freq = UINT_MAX, 972 .user_freq = UINT_MAX,
883 .user_interval = ULLONG_MAX, 973 .user_interval = ULLONG_MAX,
884 .no_delay = true, 974 .no_delay = true,
885 .mmap_pages = 1024, 975 .mmap_pages = 1024,
886 }, 976 },
887 .output = stdout, 977 .output = stdout,
888 }; 978 };
889 const char *output_name = NULL; 979 const char *output_name = NULL;
890 const char *ev_qualifier_str = NULL; 980 const char *ev_qualifier_str = NULL;
891 const struct option trace_options[] = { 981 const struct option trace_options[] = {
892 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", 982 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
893 "list of events to trace"), 983 "list of events to trace"),
894 OPT_STRING('o', "output", &output_name, "file", "output file name"), 984 OPT_STRING('o', "output", &output_name, "file", "output file name"),
985 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
895 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid", 986 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
896 "trace events on existing process id"), 987 "trace events on existing process id"),
897 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid", 988 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
898 "trace events on existing thread id"), 989 "trace events on existing thread id"),
899 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide, 990 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
900 "system-wide collection from all CPUs"), 991 "system-wide collection from all CPUs"),
901 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu", 992 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
902 "list of cpus to monitor"), 993 "list of cpus to monitor"),
903 OPT_BOOLEAN('i', "no-inherit", &trace.opts.no_inherit, 994 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
904 "child tasks do not inherit counters"), 995 "child tasks do not inherit counters"),
905 OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages, 996 OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages,
906 "number of mmap data pages"), 997 "number of mmap data pages"),
907 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user", 998 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
908 "user to profile"), 999 "user to profile"),
909 OPT_CALLBACK(0, "duration", &trace, "float", 1000 OPT_CALLBACK(0, "duration", &trace, "float",
910 "show only events with duration > N.M ms", 1001 "show only events with duration > N.M ms",
911 trace__set_duration), 1002 trace__set_duration),
912 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"), 1003 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
913 OPT_INCR('v', "verbose", &verbose, "be more verbose"), 1004 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
914 OPT_END() 1005 OPT_END()
915 }; 1006 };
916 int err; 1007 int err;
917 char bf[BUFSIZ]; 1008 char bf[BUFSIZ];
918 1009
919 argc = parse_options(argc, argv, trace_options, trace_usage, 0); 1010 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
920 1011
921 if (output_name != NULL) { 1012 if (output_name != NULL) {
922 err = trace__open_output(&trace, output_name); 1013 err = trace__open_output(&trace, output_name);
923 if (err < 0) { 1014 if (err < 0) {
924 perror("failed to create output file"); 1015 perror("failed to create output file");
925 goto out; 1016 goto out;
926 } 1017 }
927 } 1018 }
928 1019
929 if (ev_qualifier_str != NULL) { 1020 if (ev_qualifier_str != NULL) {
930 const char *s = ev_qualifier_str; 1021 const char *s = ev_qualifier_str;
931 1022
932 trace.not_ev_qualifier = *s == '!'; 1023 trace.not_ev_qualifier = *s == '!';
933 if (trace.not_ev_qualifier) 1024 if (trace.not_ev_qualifier)
934 ++s; 1025 ++s;
935 trace.ev_qualifier = strlist__new(true, s); 1026 trace.ev_qualifier = strlist__new(true, s);
936 if (trace.ev_qualifier == NULL) { 1027 if (trace.ev_qualifier == NULL) {
937 fputs("Not enough memory to parse event qualifier", 1028 fputs("Not enough memory to parse event qualifier",
938 trace.output); 1029 trace.output);
939 err = -ENOMEM; 1030 err = -ENOMEM;
940 goto out_close; 1031 goto out_close;
941 } 1032 }
942 } 1033 }
943 1034
944 err = perf_target__validate(&trace.opts.target); 1035 err = perf_target__validate(&trace.opts.target);
945 if (err) { 1036 if (err) {
946 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf)); 1037 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
947 fprintf(trace.output, "%s", bf); 1038 fprintf(trace.output, "%s", bf);
948 goto out_close; 1039 goto out_close;
949 } 1040 }
950 1041
951 err = perf_target__parse_uid(&trace.opts.target); 1042 err = perf_target__parse_uid(&trace.opts.target);
952 if (err) { 1043 if (err) {
953 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf)); 1044 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
954 fprintf(trace.output, "%s", bf); 1045 fprintf(trace.output, "%s", bf);
955 goto out_close; 1046 goto out_close;
956 } 1047 }
957 1048
958 if (!argc && perf_target__none(&trace.opts.target)) 1049 if (!argc && perf_target__none(&trace.opts.target))
959 trace.opts.target.system_wide = true; 1050 trace.opts.target.system_wide = true;
960 1051
961 err = trace__run(&trace, argc, argv); 1052 if (input_name)
1053 err = trace__replay(&trace);
1054 else
1055 err = trace__run(&trace, argc, argv);
962 1056
963 if (trace.sched && !err) 1057 if (trace.sched && !err)
964 trace__fprintf_thread_summary(&trace, trace.output); 1058 trace__fprintf_thread_summary(&trace, trace.output);
965 1059
966 out_close: 1060 out_close:
967 if (output_name != NULL) 1061 if (output_name != NULL)
968 fclose(trace.output); 1062 fclose(trace.output);
969 out: 1063 out:
970 return err; 1064 return err;
971 } 1065 }
972 1066