blob: 3ca6a856ba62d5031b64a3cf8b4430b19429fb06 [file] [log] [blame]
Robert Richter4e319022013-06-11 17:29:18 +02001#include <traceevent/event-parse.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03003#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03004#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03005#include "util/evlist.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03006#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -06007#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03008#include "util/thread.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03009#include "util/parse-options.h"
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030010#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060011#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030012#include "util/thread_map.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030013
14#include <libaudit.h>
15#include <stdlib.h>
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -030016#include <sys/eventfd.h>
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030017#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030018#include <linux/futex.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030019
Ingo Molnar456857b2013-09-12 15:29:00 +020020/* For older distros: */
21#ifndef MAP_STACK
22# define MAP_STACK 0x20000
23#endif
24
25#ifndef MADV_HWPOISON
26# define MADV_HWPOISON 100
27#endif
28
29#ifndef MADV_MERGEABLE
30# define MADV_MERGEABLE 12
31#endif
32
33#ifndef MADV_UNMERGEABLE
34# define MADV_UNMERGEABLE 13
35#endif
36
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030037struct syscall_arg {
38 unsigned long val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030039 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030040 u8 idx;
41 u8 mask;
42};
43
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030044struct strarray {
45 int nr_entries;
46 const char **entries;
47};
48
49#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
50 .nr_entries = ARRAY_SIZE(array), \
51 .entries = array, \
52}
53
54static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
55 struct syscall_arg *arg)
56{
57 int idx = arg->val;
58 struct strarray *sa = arg->parm;
59
60 if (idx < 0 || idx >= sa->nr_entries)
61 return scnprintf(bf, size, "%d", idx);
62
63 return scnprintf(bf, size, "%s", sa->entries[idx]);
64}
65
66#define SCA_STRARRAY syscall_arg__scnprintf_strarray
67
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -030068static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030069 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -030070{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030071 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -030072}
73
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -030074#define SCA_HEX syscall_arg__scnprintf_hex
75
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -030076static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030077 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030078{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030079 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030080
81 if (prot == PROT_NONE)
82 return scnprintf(bf, size, "NONE");
83#define P_MMAP_PROT(n) \
84 if (prot & PROT_##n) { \
85 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
86 prot &= ~PROT_##n; \
87 }
88
89 P_MMAP_PROT(EXEC);
90 P_MMAP_PROT(READ);
91 P_MMAP_PROT(WRITE);
92#ifdef PROT_SEM
93 P_MMAP_PROT(SEM);
94#endif
95 P_MMAP_PROT(GROWSDOWN);
96 P_MMAP_PROT(GROWSUP);
97#undef P_MMAP_PROT
98
99 if (prot)
100 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
101
102 return printed;
103}
104
105#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
106
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300107static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300108 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300109{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300110 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300111
112#define P_MMAP_FLAG(n) \
113 if (flags & MAP_##n) { \
114 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
115 flags &= ~MAP_##n; \
116 }
117
118 P_MMAP_FLAG(SHARED);
119 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400120#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300121 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400122#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300123 P_MMAP_FLAG(ANONYMOUS);
124 P_MMAP_FLAG(DENYWRITE);
125 P_MMAP_FLAG(EXECUTABLE);
126 P_MMAP_FLAG(FILE);
127 P_MMAP_FLAG(FIXED);
128 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600129#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300130 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600131#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300132 P_MMAP_FLAG(LOCKED);
133 P_MMAP_FLAG(NONBLOCK);
134 P_MMAP_FLAG(NORESERVE);
135 P_MMAP_FLAG(POPULATE);
136 P_MMAP_FLAG(STACK);
137#ifdef MAP_UNINITIALIZED
138 P_MMAP_FLAG(UNINITIALIZED);
139#endif
140#undef P_MMAP_FLAG
141
142 if (flags)
143 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
144
145 return printed;
146}
147
148#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
149
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300150static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300151 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300152{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300153 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300154
155 switch (behavior) {
156#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
157 P_MADV_BHV(NORMAL);
158 P_MADV_BHV(RANDOM);
159 P_MADV_BHV(SEQUENTIAL);
160 P_MADV_BHV(WILLNEED);
161 P_MADV_BHV(DONTNEED);
162 P_MADV_BHV(REMOVE);
163 P_MADV_BHV(DONTFORK);
164 P_MADV_BHV(DOFORK);
165 P_MADV_BHV(HWPOISON);
166#ifdef MADV_SOFT_OFFLINE
167 P_MADV_BHV(SOFT_OFFLINE);
168#endif
169 P_MADV_BHV(MERGEABLE);
170 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600171#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300172 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600173#endif
174#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300175 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600176#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300177#ifdef MADV_DONTDUMP
178 P_MADV_BHV(DONTDUMP);
179#endif
180#ifdef MADV_DODUMP
181 P_MADV_BHV(DODUMP);
182#endif
183#undef P_MADV_PHV
184 default: break;
185 }
186
187 return scnprintf(bf, size, "%#x", behavior);
188}
189
190#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
191
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300192static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
193 struct syscall_arg *arg)
194{
195 int printed = 0, op = arg->val;
196
197 if (op == 0)
198 return scnprintf(bf, size, "NONE");
199#define P_CMD(cmd) \
200 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
201 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
202 op &= ~LOCK_##cmd; \
203 }
204
205 P_CMD(SH);
206 P_CMD(EX);
207 P_CMD(NB);
208 P_CMD(UN);
209 P_CMD(MAND);
210 P_CMD(RW);
211 P_CMD(READ);
212 P_CMD(WRITE);
213#undef P_OP
214
215 if (op)
216 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
217
218 return printed;
219}
220
221#define SCA_FLOCK syscall_arg__scnprintf_flock
222
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300223static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300224{
225 enum syscall_futex_args {
226 SCF_UADDR = (1 << 0),
227 SCF_OP = (1 << 1),
228 SCF_VAL = (1 << 2),
229 SCF_TIMEOUT = (1 << 3),
230 SCF_UADDR2 = (1 << 4),
231 SCF_VAL3 = (1 << 5),
232 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300233 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300234 int cmd = op & FUTEX_CMD_MASK;
235 size_t printed = 0;
236
237 switch (cmd) {
238#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300239 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
240 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
241 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
242 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
243 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
244 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300245 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300246 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
247 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
248 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
249 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
250 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300251 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
252 default: printed = scnprintf(bf, size, "%#x", cmd); break;
253 }
254
255 if (op & FUTEX_PRIVATE_FLAG)
256 printed += scnprintf(bf + printed, size - printed, "|PRIV");
257
258 if (op & FUTEX_CLOCK_REALTIME)
259 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
260
261 return printed;
262}
263
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300264#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
265
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300266static const char *epoll_ctl_ops[] = { [1] = "ADD", "DEL", "MOD", };
267static DEFINE_STRARRAY(epoll_ctl_ops);
268
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300269static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
270static DEFINE_STRARRAY(itimers);
271
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300272static const char *whences[] = { "SET", "CUR", "END",
273#ifdef SEEK_DATA
274"DATA",
275#endif
276#ifdef SEEK_HOLE
277"HOLE",
278#endif
279};
280static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300281
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300282static const char *fcntl_cmds[] = {
283 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
284 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
285 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
286 "F_GETOWNER_UIDS",
287};
288static DEFINE_STRARRAY(fcntl_cmds);
289
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300290static const char *rlimit_resources[] = {
291 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
292 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
293 "RTTIME",
294};
295static DEFINE_STRARRAY(rlimit_resources);
296
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300297static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
298static DEFINE_STRARRAY(sighow);
299
David Ahern4f8c1b72013-09-22 19:45:00 -0600300static const char *clockid[] = {
301 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
302 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
303};
304static DEFINE_STRARRAY(clockid);
305
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300306static const char *socket_families[] = {
307 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
308 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
309 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
310 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
311 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
312 "ALG", "NFC", "VSOCK",
313};
314static DEFINE_STRARRAY(socket_families);
315
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300316#ifndef SOCK_TYPE_MASK
317#define SOCK_TYPE_MASK 0xf
318#endif
319
320static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
321 struct syscall_arg *arg)
322{
323 size_t printed;
324 int type = arg->val,
325 flags = type & ~SOCK_TYPE_MASK;
326
327 type &= SOCK_TYPE_MASK;
328 /*
329 * Can't use a strarray, MIPS may override for ABI reasons.
330 */
331 switch (type) {
332#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
333 P_SK_TYPE(STREAM);
334 P_SK_TYPE(DGRAM);
335 P_SK_TYPE(RAW);
336 P_SK_TYPE(RDM);
337 P_SK_TYPE(SEQPACKET);
338 P_SK_TYPE(DCCP);
339 P_SK_TYPE(PACKET);
340#undef P_SK_TYPE
341 default:
342 printed = scnprintf(bf, size, "%#x", type);
343 }
344
345#define P_SK_FLAG(n) \
346 if (flags & SOCK_##n) { \
347 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
348 flags &= ~SOCK_##n; \
349 }
350
351 P_SK_FLAG(CLOEXEC);
352 P_SK_FLAG(NONBLOCK);
353#undef P_SK_FLAG
354
355 if (flags)
356 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
357
358 return printed;
359}
360
361#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
362
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300363#ifndef MSG_PROBE
364#define MSG_PROBE 0x10
365#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600366#ifndef MSG_WAITFORONE
367#define MSG_WAITFORONE 0x10000
368#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300369#ifndef MSG_SENDPAGE_NOTLAST
370#define MSG_SENDPAGE_NOTLAST 0x20000
371#endif
372#ifndef MSG_FASTOPEN
373#define MSG_FASTOPEN 0x20000000
374#endif
375
376static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
377 struct syscall_arg *arg)
378{
379 int printed = 0, flags = arg->val;
380
381 if (flags == 0)
382 return scnprintf(bf, size, "NONE");
383#define P_MSG_FLAG(n) \
384 if (flags & MSG_##n) { \
385 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
386 flags &= ~MSG_##n; \
387 }
388
389 P_MSG_FLAG(OOB);
390 P_MSG_FLAG(PEEK);
391 P_MSG_FLAG(DONTROUTE);
392 P_MSG_FLAG(TRYHARD);
393 P_MSG_FLAG(CTRUNC);
394 P_MSG_FLAG(PROBE);
395 P_MSG_FLAG(TRUNC);
396 P_MSG_FLAG(DONTWAIT);
397 P_MSG_FLAG(EOR);
398 P_MSG_FLAG(WAITALL);
399 P_MSG_FLAG(FIN);
400 P_MSG_FLAG(SYN);
401 P_MSG_FLAG(CONFIRM);
402 P_MSG_FLAG(RST);
403 P_MSG_FLAG(ERRQUEUE);
404 P_MSG_FLAG(NOSIGNAL);
405 P_MSG_FLAG(MORE);
406 P_MSG_FLAG(WAITFORONE);
407 P_MSG_FLAG(SENDPAGE_NOTLAST);
408 P_MSG_FLAG(FASTOPEN);
409 P_MSG_FLAG(CMSG_CLOEXEC);
410#undef P_MSG_FLAG
411
412 if (flags)
413 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
414
415 return printed;
416}
417
418#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
419
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300420static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
421 struct syscall_arg *arg)
422{
423 size_t printed = 0;
424 int mode = arg->val;
425
426 if (mode == F_OK) /* 0 */
427 return scnprintf(bf, size, "F");
428#define P_MODE(n) \
429 if (mode & n##_OK) { \
430 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
431 mode &= ~n##_OK; \
432 }
433
434 P_MODE(R);
435 P_MODE(W);
436 P_MODE(X);
437#undef P_MODE
438
439 if (mode)
440 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
441
442 return printed;
443}
444
445#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
446
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300447static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300448 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300449{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300450 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300451
452 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300453 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300454
455 if (flags == 0)
456 return scnprintf(bf, size, "RDONLY");
457#define P_FLAG(n) \
458 if (flags & O_##n) { \
459 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
460 flags &= ~O_##n; \
461 }
462
463 P_FLAG(APPEND);
464 P_FLAG(ASYNC);
465 P_FLAG(CLOEXEC);
466 P_FLAG(CREAT);
467 P_FLAG(DIRECT);
468 P_FLAG(DIRECTORY);
469 P_FLAG(EXCL);
470 P_FLAG(LARGEFILE);
471 P_FLAG(NOATIME);
472 P_FLAG(NOCTTY);
473#ifdef O_NONBLOCK
474 P_FLAG(NONBLOCK);
475#elif O_NDELAY
476 P_FLAG(NDELAY);
477#endif
478#ifdef O_PATH
479 P_FLAG(PATH);
480#endif
481 P_FLAG(RDWR);
482#ifdef O_DSYNC
483 if ((flags & O_SYNC) == O_SYNC)
484 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
485 else {
486 P_FLAG(DSYNC);
487 }
488#else
489 P_FLAG(SYNC);
490#endif
491 P_FLAG(TRUNC);
492 P_FLAG(WRONLY);
493#undef P_FLAG
494
495 if (flags)
496 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
497
498 return printed;
499}
500
501#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
502
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300503static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
504 struct syscall_arg *arg)
505{
506 int printed = 0, flags = arg->val;
507
508 if (flags == 0)
509 return scnprintf(bf, size, "NONE");
510#define P_FLAG(n) \
511 if (flags & EFD_##n) { \
512 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
513 flags &= ~EFD_##n; \
514 }
515
516 P_FLAG(SEMAPHORE);
517 P_FLAG(CLOEXEC);
518 P_FLAG(NONBLOCK);
519#undef P_FLAG
520
521 if (flags)
522 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
523
524 return printed;
525}
526
527#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
528
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300529static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
530 struct syscall_arg *arg)
531{
532 int printed = 0, flags = arg->val;
533
534#define P_FLAG(n) \
535 if (flags & O_##n) { \
536 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
537 flags &= ~O_##n; \
538 }
539
540 P_FLAG(CLOEXEC);
541 P_FLAG(NONBLOCK);
542#undef P_FLAG
543
544 if (flags)
545 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
546
547 return printed;
548}
549
550#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
551
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300552static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
553{
554 int sig = arg->val;
555
556 switch (sig) {
557#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
558 P_SIGNUM(HUP);
559 P_SIGNUM(INT);
560 P_SIGNUM(QUIT);
561 P_SIGNUM(ILL);
562 P_SIGNUM(TRAP);
563 P_SIGNUM(ABRT);
564 P_SIGNUM(BUS);
565 P_SIGNUM(FPE);
566 P_SIGNUM(KILL);
567 P_SIGNUM(USR1);
568 P_SIGNUM(SEGV);
569 P_SIGNUM(USR2);
570 P_SIGNUM(PIPE);
571 P_SIGNUM(ALRM);
572 P_SIGNUM(TERM);
573 P_SIGNUM(STKFLT);
574 P_SIGNUM(CHLD);
575 P_SIGNUM(CONT);
576 P_SIGNUM(STOP);
577 P_SIGNUM(TSTP);
578 P_SIGNUM(TTIN);
579 P_SIGNUM(TTOU);
580 P_SIGNUM(URG);
581 P_SIGNUM(XCPU);
582 P_SIGNUM(XFSZ);
583 P_SIGNUM(VTALRM);
584 P_SIGNUM(PROF);
585 P_SIGNUM(WINCH);
586 P_SIGNUM(IO);
587 P_SIGNUM(PWR);
588 P_SIGNUM(SYS);
589 default: break;
590 }
591
592 return scnprintf(bf, size, "%#x", sig);
593}
594
595#define SCA_SIGNUM syscall_arg__scnprintf_signum
596
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300597#define STRARRAY(arg, name, array) \
598 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
599 .arg_parm = { [arg] = &strarray__##array, }
600
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300601static struct syscall_fmt {
602 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300603 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300604 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300605 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300606 bool errmsg;
607 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300608 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300609} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300610 { .name = "access", .errmsg = true,
611 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300612 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300613 { .name = "brk", .hexret = true,
614 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600615 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300616 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300617 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300618 { .name = "eventfd2", .errmsg = true,
619 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300620 { .name = "fcntl", .errmsg = true, STRARRAY(1, cmd, fcntl_cmds), },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300621 { .name = "flock", .errmsg = true,
622 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300623 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
624 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300625 { .name = "futex", .errmsg = true,
626 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300627 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
628 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300629 { .name = "ioctl", .errmsg = true,
630 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300631 { .name = "kill", .errmsg = true,
632 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300633 { .name = "lseek", .errmsg = true, STRARRAY(2, whence, whences), },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300634 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300635 { .name = "madvise", .errmsg = true,
636 .arg_scnprintf = { [0] = SCA_HEX, /* start */
637 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300638 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300639 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300640 [2] = SCA_MMAP_PROT, /* prot */
641 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300642 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300643 .arg_scnprintf = { [0] = SCA_HEX, /* start */
644 [2] = SCA_MMAP_PROT, /* prot */ }, },
645 { .name = "mremap", .hexret = true,
646 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
647 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300648 { .name = "munmap", .errmsg = true,
649 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300650 { .name = "open", .errmsg = true,
651 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300652 { .name = "open_by_handle_at", .errmsg = true,
653 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
654 { .name = "openat", .errmsg = true,
655 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300656 { .name = "pipe2", .errmsg = true,
657 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300658 { .name = "poll", .errmsg = true, .timeout = true, },
659 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300660 { .name = "pread", .errmsg = true, .alias = "pread64", },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300661 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300662 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300663 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300664 { .name = "recvfrom", .errmsg = true,
665 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
666 { .name = "recvmmsg", .errmsg = true,
667 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
668 { .name = "recvmsg", .errmsg = true,
669 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300670 { .name = "rt_sigaction", .errmsg = true,
671 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300672 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300673 { .name = "rt_sigqueueinfo", .errmsg = true,
674 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
675 { .name = "rt_tgsigqueueinfo", .errmsg = true,
676 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300677 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300678 { .name = "sendmmsg", .errmsg = true,
679 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
680 { .name = "sendmsg", .errmsg = true,
681 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
682 { .name = "sendto", .errmsg = true,
683 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300684 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
685 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300686 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300687 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
688 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300689 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300690 { .name = "socketpair", .errmsg = true,
691 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
692 [1] = SCA_SK_TYPE, /* type */ },
693 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300694 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300695 { .name = "tgkill", .errmsg = true,
696 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
697 { .name = "tkill", .errmsg = true,
698 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300699 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300700};
701
702static int syscall_fmt__cmp(const void *name, const void *fmtp)
703{
704 const struct syscall_fmt *fmt = fmtp;
705 return strcmp(name, fmt->name);
706}
707
708static struct syscall_fmt *syscall_fmt__find(const char *name)
709{
710 const int nmemb = ARRAY_SIZE(syscall_fmts);
711 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
712}
713
714struct syscall {
715 struct event_format *tp_format;
716 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300717 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300718 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300719 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300720 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300721};
722
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200723static size_t fprintf_duration(unsigned long t, FILE *fp)
724{
725 double duration = (double)t / NSEC_PER_MSEC;
726 size_t printed = fprintf(fp, "(");
727
728 if (duration >= 1.0)
729 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
730 else if (duration >= 0.01)
731 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
732 else
733 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300734 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200735}
736
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300737struct thread_trace {
738 u64 entry_time;
739 u64 exit_time;
740 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300741 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300742 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300743 double runtime_ms;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300744};
745
746static struct thread_trace *thread_trace__new(void)
747{
748 return zalloc(sizeof(struct thread_trace));
749}
750
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300751static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300752{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300753 struct thread_trace *ttrace;
754
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300755 if (thread == NULL)
756 goto fail;
757
758 if (thread->priv == NULL)
759 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300760
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300761 if (thread->priv == NULL)
762 goto fail;
763
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300764 ttrace = thread->priv;
765 ++ttrace->nr_events;
766
767 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300768fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300769 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300770 "WARNING: not enough memory, dropping samples!\n");
771 return NULL;
772}
773
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300774struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300775 struct perf_tool tool;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300776 int audit_machine;
777 struct {
778 int max;
779 struct syscall *table;
780 } syscalls;
781 struct perf_record_opts opts;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300782 struct machine host;
783 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -0600784 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300785 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300786 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300787 struct strlist *ev_qualifier;
788 bool not_ev_qualifier;
David Ahernbdc89662013-08-28 22:29:53 -0600789 struct intlist *tid_list;
790 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300791 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300792 bool multiple_threads;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300793 bool show_comm;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300794 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300795 double runtime_ms;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300796};
797
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300798static bool trace__filter_duration(struct trace *trace, double t)
799{
800 return t < (trace->duration_filter * NSEC_PER_MSEC);
801}
802
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300803static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
804{
805 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
806
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200807 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300808}
809
Namhyung Kimf15eb532012-10-05 14:02:16 +0900810static bool done = false;
811
812static void sig_handler(int sig __maybe_unused)
813{
814 done = true;
815}
816
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300817static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200818 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300819{
820 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200821 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300822
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300823 if (trace->multiple_threads) {
824 if (trace->show_comm)
825 printed += fprintf(fp, "%.14s/", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +0300826 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300827 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300828
829 return printed;
830}
831
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300832static int trace__process_event(struct trace *trace, struct machine *machine,
833 union perf_event *event)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300834{
835 int ret = 0;
836
837 switch (event->header.type) {
838 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300839 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300840 "LOST %" PRIu64 " events!\n", event->lost.lost);
841 ret = machine__process_lost_event(machine, event);
842 default:
843 ret = machine__process_event(machine, event);
844 break;
845 }
846
847 return ret;
848}
849
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300850static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300851 union perf_event *event,
852 struct perf_sample *sample __maybe_unused,
853 struct machine *machine)
854{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300855 struct trace *trace = container_of(tool, struct trace, tool);
856 return trace__process_event(trace, machine, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300857}
858
859static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
860{
861 int err = symbol__init();
862
863 if (err)
864 return err;
865
866 machine__init(&trace->host, "", HOST_KERNEL_ID);
867 machine__create_kernel_maps(&trace->host);
868
869 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300870 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300871 trace__tool_process,
872 &trace->host);
873 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300874 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300875 &trace->host);
876 }
877
878 if (err)
879 symbol__exit();
880
881 return err;
882}
883
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300884static int syscall__set_arg_fmts(struct syscall *sc)
885{
886 struct format_field *field;
887 int idx = 0;
888
889 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
890 if (sc->arg_scnprintf == NULL)
891 return -1;
892
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300893 if (sc->fmt)
894 sc->arg_parm = sc->fmt->arg_parm;
895
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300896 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300897 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
898 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
899 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300900 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
901 ++idx;
902 }
903
904 return 0;
905}
906
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300907static int trace__read_syscall_info(struct trace *trace, int id)
908{
909 char tp_name[128];
910 struct syscall *sc;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300911 const char *name = audit_syscall_to_name(id, trace->audit_machine);
912
913 if (name == NULL)
914 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300915
916 if (id > trace->syscalls.max) {
917 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
918
919 if (nsyscalls == NULL)
920 return -1;
921
922 if (trace->syscalls.max != -1) {
923 memset(nsyscalls + trace->syscalls.max + 1, 0,
924 (id - trace->syscalls.max) * sizeof(*sc));
925 } else {
926 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
927 }
928
929 trace->syscalls.table = nsyscalls;
930 trace->syscalls.max = id;
931 }
932
933 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300934 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300935
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300936 if (trace->ev_qualifier) {
937 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
938
939 if (!(in ^ trace->not_ev_qualifier)) {
940 sc->filtered = true;
941 /*
942 * No need to do read tracepoint information since this will be
943 * filtered out.
944 */
945 return 0;
946 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300947 }
948
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300949 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300950
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300951 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
952 sc->tp_format = event_format__new("syscalls", tp_name);
953
954 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
955 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
956 sc->tp_format = event_format__new("syscalls", tp_name);
957 }
958
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300959 if (sc->tp_format == NULL)
960 return -1;
961
962 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300963}
964
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300965static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
966 unsigned long *args)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300967{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300968 size_t printed = 0;
969
970 if (sc->tp_format != NULL) {
971 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300972 u8 bit = 1;
973 struct syscall_arg arg = {
974 .idx = 0,
975 .mask = 0,
976 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300977
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300978 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300979 field = field->next, ++arg.idx, bit <<= 1) {
980 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300981 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -0300982 /*
983 * Suppress this argument if its value is zero and
984 * and we don't have a string associated in an
985 * strarray for it.
986 */
987 if (args[arg.idx] == 0 &&
988 !(sc->arg_scnprintf &&
989 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
990 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -0300991 continue;
992
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300993 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300994 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300995 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
996 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300997 if (sc->arg_parm)
998 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300999 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1000 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001001 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001002 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001003 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001004 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001005 }
1006 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001007 int i = 0;
1008
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001009 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001010 printed += scnprintf(bf + printed, size - printed,
1011 "%sarg%d: %ld",
1012 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001013 ++i;
1014 }
1015 }
1016
1017 return printed;
1018}
1019
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001020typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1021 struct perf_sample *sample);
1022
1023static struct syscall *trace__syscall_info(struct trace *trace,
1024 struct perf_evsel *evsel,
1025 struct perf_sample *sample)
1026{
1027 int id = perf_evsel__intval(evsel, sample, "id");
1028
1029 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001030
1031 /*
1032 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1033 * before that, leaving at a higher verbosity level till that is
1034 * explained. Reproduced with plain ftrace with:
1035 *
1036 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1037 * grep "NR -1 " /t/trace_pipe
1038 *
1039 * After generating some load on the machine.
1040 */
1041 if (verbose > 1) {
1042 static u64 n;
1043 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1044 id, perf_evsel__name(evsel), ++n);
1045 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001046 return NULL;
1047 }
1048
1049 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1050 trace__read_syscall_info(trace, id))
1051 goto out_cant_read;
1052
1053 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1054 goto out_cant_read;
1055
1056 return &trace->syscalls.table[id];
1057
1058out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001059 if (verbose) {
1060 fprintf(trace->output, "Problems reading syscall %d", id);
1061 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1062 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1063 fputs(" information\n", trace->output);
1064 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001065 return NULL;
1066}
1067
1068static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1069 struct perf_sample *sample)
1070{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001071 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001072 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001073 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001074 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001075 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001076 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001077
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001078 if (sc == NULL)
1079 return -1;
1080
1081 if (sc->filtered)
1082 return 0;
1083
Adrian Hunter314add62013-08-27 11:23:03 +03001084 thread = machine__findnew_thread(&trace->host, sample->pid,
1085 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001086 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001087 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001088 return -1;
1089
1090 args = perf_evsel__rawptr(evsel, sample, "args");
1091 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001092 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001093 return -1;
1094 }
1095
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001096 ttrace = thread->priv;
1097
1098 if (ttrace->entry_str == NULL) {
1099 ttrace->entry_str = malloc(1024);
1100 if (!ttrace->entry_str)
1101 return -1;
1102 }
1103
1104 ttrace->entry_time = sample->time;
1105 msg = ttrace->entry_str;
1106 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1107
1108 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
1109
1110 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001111 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001112 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1113 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001114 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001115 } else
1116 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001117
1118 return 0;
1119}
1120
1121static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1122 struct perf_sample *sample)
1123{
1124 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001125 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001126 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001127 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001128 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001129
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001130 if (sc == NULL)
1131 return -1;
1132
1133 if (sc->filtered)
1134 return 0;
1135
Adrian Hunter314add62013-08-27 11:23:03 +03001136 thread = machine__findnew_thread(&trace->host, sample->pid,
1137 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001138 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001139 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001140 return -1;
1141
1142 ret = perf_evsel__intval(evsel, sample, "ret");
1143
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001144 ttrace = thread->priv;
1145
1146 ttrace->exit_time = sample->time;
1147
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001148 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001149 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001150 if (trace__filter_duration(trace, duration))
1151 goto out;
1152 } else if (trace->duration_filter)
1153 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001154
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001155 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001156
1157 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001158 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001159 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001160 fprintf(trace->output, " ... [");
1161 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1162 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001163 }
1164
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001165 if (sc->fmt == NULL) {
1166signed_print:
1167 fprintf(trace->output, ") = %d", ret);
1168 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001169 char bf[256];
1170 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1171 *e = audit_errno_to_name(-ret);
1172
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001173 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001174 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001175 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001176 else if (sc->fmt->hexret)
1177 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001178 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001179 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001180
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001181 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001182out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001183 ttrace->entry_pending = false;
1184
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001185 return 0;
1186}
1187
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001188static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1189 struct perf_sample *sample)
1190{
1191 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1192 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
Adrian Hunter314add62013-08-27 11:23:03 +03001193 struct thread *thread = machine__findnew_thread(&trace->host,
1194 sample->pid,
1195 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001196 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001197
1198 if (ttrace == NULL)
1199 goto out_dump;
1200
1201 ttrace->runtime_ms += runtime_ms;
1202 trace->runtime_ms += runtime_ms;
1203 return 0;
1204
1205out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001206 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001207 evsel->name,
1208 perf_evsel__strval(evsel, sample, "comm"),
1209 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1210 runtime,
1211 perf_evsel__intval(evsel, sample, "vruntime"));
1212 return 0;
1213}
1214
David Ahernbdc89662013-08-28 22:29:53 -06001215static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1216{
1217 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1218 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1219 return false;
1220
1221 if (trace->pid_list || trace->tid_list)
1222 return true;
1223
1224 return false;
1225}
1226
David Ahern6810fc92013-08-28 22:29:52 -06001227static int trace__process_sample(struct perf_tool *tool,
1228 union perf_event *event __maybe_unused,
1229 struct perf_sample *sample,
1230 struct perf_evsel *evsel,
1231 struct machine *machine __maybe_unused)
1232{
1233 struct trace *trace = container_of(tool, struct trace, tool);
1234 int err = 0;
1235
1236 tracepoint_handler handler = evsel->handler.func;
1237
David Ahernbdc89662013-08-28 22:29:53 -06001238 if (skip_sample(trace, sample))
1239 return 0;
1240
David Ahern4bb09192013-09-04 12:37:43 -06001241 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001242 trace->base_time = sample->time;
1243
1244 if (handler)
1245 handler(trace, evsel, sample);
1246
1247 return err;
1248}
1249
1250static bool
1251perf_session__has_tp(struct perf_session *session, const char *name)
1252{
1253 struct perf_evsel *evsel;
1254
1255 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1256
1257 return evsel != NULL;
1258}
1259
David Ahernbdc89662013-08-28 22:29:53 -06001260static int parse_target_str(struct trace *trace)
1261{
1262 if (trace->opts.target.pid) {
1263 trace->pid_list = intlist__new(trace->opts.target.pid);
1264 if (trace->pid_list == NULL) {
1265 pr_err("Error parsing process id string\n");
1266 return -EINVAL;
1267 }
1268 }
1269
1270 if (trace->opts.target.tid) {
1271 trace->tid_list = intlist__new(trace->opts.target.tid);
1272 if (trace->tid_list == NULL) {
1273 pr_err("Error parsing thread id string\n");
1274 return -EINVAL;
1275 }
1276 }
1277
1278 return 0;
1279}
1280
Namhyung Kimf15eb532012-10-05 14:02:16 +09001281static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001282{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001283 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001284 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001285 int err = -1, i;
1286 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001287 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001288
1289 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001290 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001291 goto out;
1292 }
1293
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001294 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1295 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001296 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001297 goto out_delete_evlist;
1298 }
1299
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001300 if (trace->sched &&
1301 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1302 trace__sched_stat_runtime)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001303 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001304 goto out_delete_evlist;
1305 }
1306
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001307 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1308 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001309 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001310 goto out_delete_evlist;
1311 }
1312
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001313 err = trace__symbols_init(trace, evlist);
1314 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001315 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001316 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001317 }
1318
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001319 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001320
Namhyung Kimf15eb532012-10-05 14:02:16 +09001321 signal(SIGCHLD, sig_handler);
1322 signal(SIGINT, sig_handler);
1323
1324 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001325 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001326 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001327 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001328 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001329 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001330 }
1331 }
1332
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001333 err = perf_evlist__open(evlist);
1334 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001335 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001336 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001337 }
1338
1339 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1340 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001341 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001342 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001343 }
1344
1345 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001346
1347 if (forks)
1348 perf_evlist__start_workload(evlist);
1349
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001350 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001351again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001352 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001353
1354 for (i = 0; i < evlist->nr_mmaps; i++) {
1355 union perf_event *event;
1356
1357 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1358 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001359 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001360 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001361
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001362 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001363
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001364 err = perf_evlist__parse_sample(evlist, event, &sample);
1365 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001366 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001367 continue;
1368 }
1369
David Ahern4bb09192013-09-04 12:37:43 -06001370 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001371 trace->base_time = sample.time;
1372
1373 if (type != PERF_RECORD_SAMPLE) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001374 trace__process_event(trace, &trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001375 continue;
1376 }
1377
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001378 evsel = perf_evlist__id2evsel(evlist, sample.id);
1379 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001380 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001381 continue;
1382 }
1383
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001384 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001385 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001386 perf_evsel__name(evsel), sample.tid,
1387 sample.cpu, sample.raw_size);
1388 continue;
1389 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001390
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001391 handler = evsel->handler.func;
1392 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001393
1394 if (done)
1395 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001396 }
1397 }
1398
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001399 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001400 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001401 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001402
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001403 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001404 }
1405
1406 if (done)
1407 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001408
1409 goto again;
1410
Namhyung Kim3beb0862013-03-15 14:48:50 +09001411out_unmap_evlist:
1412 perf_evlist__munmap(evlist);
1413out_close_evlist:
1414 perf_evlist__close(evlist);
1415out_delete_maps:
1416 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001417out_delete_evlist:
1418 perf_evlist__delete(evlist);
1419out:
1420 return err;
1421}
1422
David Ahern6810fc92013-08-28 22:29:52 -06001423static int trace__replay(struct trace *trace)
1424{
1425 const struct perf_evsel_str_handler handlers[] = {
1426 { "raw_syscalls:sys_enter", trace__sys_enter, },
1427 { "raw_syscalls:sys_exit", trace__sys_exit, },
1428 };
1429
1430 struct perf_session *session;
1431 int err = -1;
1432
1433 trace->tool.sample = trace__process_sample;
1434 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001435 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001436 trace->tool.comm = perf_event__process_comm;
1437 trace->tool.exit = perf_event__process_exit;
1438 trace->tool.fork = perf_event__process_fork;
1439 trace->tool.attr = perf_event__process_attr;
1440 trace->tool.tracing_data = perf_event__process_tracing_data;
1441 trace->tool.build_id = perf_event__process_build_id;
1442
1443 trace->tool.ordered_samples = true;
1444 trace->tool.ordering_requires_timestamps = true;
1445
1446 /* add tid to output */
1447 trace->multiple_threads = true;
1448
1449 if (symbol__init() < 0)
1450 return -1;
1451
1452 session = perf_session__new(input_name, O_RDONLY, 0, false,
1453 &trace->tool);
1454 if (session == NULL)
1455 return -ENOMEM;
1456
1457 err = perf_session__set_tracepoints_handlers(session, handlers);
1458 if (err)
1459 goto out;
1460
1461 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1462 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1463 goto out;
1464 }
1465
1466 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1467 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1468 goto out;
1469 }
1470
David Ahernbdc89662013-08-28 22:29:53 -06001471 err = parse_target_str(trace);
1472 if (err != 0)
1473 goto out;
1474
David Ahern6810fc92013-08-28 22:29:52 -06001475 setup_pager();
1476
1477 err = perf_session__process_events(session, &trace->tool);
1478 if (err)
1479 pr_err("Failed to process events, error %d", err);
1480
1481out:
1482 perf_session__delete(session);
1483
1484 return err;
1485}
1486
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001487static size_t trace__fprintf_threads_header(FILE *fp)
1488{
1489 size_t printed;
1490
1491 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1492 printed += fprintf(fp," __) Summary of events (__\n\n");
1493 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1494 printed += fprintf(fp," _____________________________________________________________________\n\n");
1495
1496 return printed;
1497}
1498
1499static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1500{
1501 size_t printed = trace__fprintf_threads_header(fp);
1502 struct rb_node *nd;
1503
1504 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
1505 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1506 struct thread_trace *ttrace = thread->priv;
1507 const char *color;
1508 double ratio;
1509
1510 if (ttrace == NULL)
1511 continue;
1512
1513 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1514
1515 color = PERF_COLOR_NORMAL;
1516 if (ratio > 50.0)
1517 color = PERF_COLOR_RED;
1518 else if (ratio > 25.0)
1519 color = PERF_COLOR_GREEN;
1520 else if (ratio > 5.0)
1521 color = PERF_COLOR_YELLOW;
1522
1523 printed += color_fprintf(fp, color, "%20s", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001524 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001525 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1526 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1527 }
1528
1529 return printed;
1530}
1531
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001532static int trace__set_duration(const struct option *opt, const char *str,
1533 int unset __maybe_unused)
1534{
1535 struct trace *trace = opt->value;
1536
1537 trace->duration_filter = atof(str);
1538 return 0;
1539}
1540
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001541static int trace__open_output(struct trace *trace, const char *filename)
1542{
1543 struct stat st;
1544
1545 if (!stat(filename, &st) && st.st_size) {
1546 char oldname[PATH_MAX];
1547
1548 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1549 unlink(oldname);
1550 rename(filename, oldname);
1551 }
1552
1553 trace->output = fopen(filename, "w");
1554
1555 return trace->output == NULL ? -errno : 0;
1556}
1557
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001558int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1559{
1560 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001561 "perf trace [<options>] [<command>]",
1562 "perf trace [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001563 NULL
1564 };
1565 struct trace trace = {
1566 .audit_machine = audit_detect_machine(),
1567 .syscalls = {
1568 . max = -1,
1569 },
1570 .opts = {
1571 .target = {
1572 .uid = UINT_MAX,
1573 .uses_mmap = true,
1574 },
1575 .user_freq = UINT_MAX,
1576 .user_interval = ULLONG_MAX,
1577 .no_delay = true,
1578 .mmap_pages = 1024,
1579 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001580 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001581 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001582 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001583 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001584 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001585 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001586 OPT_BOOLEAN(0, "comm", &trace.show_comm,
1587 "show the thread COMM next to its id"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001588 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1589 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001590 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06001591 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001592 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1593 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001594 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001595 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001596 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001597 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06001598 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001599 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06001600 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001601 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02001602 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
1603 "number of mmap data pages",
1604 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06001605 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001606 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001607 OPT_CALLBACK(0, "duration", &trace, "float",
1608 "show only events with duration > N.M ms",
1609 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001610 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001611 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06001612 OPT_BOOLEAN('T', "time", &trace.full_time,
1613 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001614 OPT_END()
1615 };
1616 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001617 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001618
1619 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001620
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001621 if (output_name != NULL) {
1622 err = trace__open_output(&trace, output_name);
1623 if (err < 0) {
1624 perror("failed to create output file");
1625 goto out;
1626 }
1627 }
1628
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001629 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001630 const char *s = ev_qualifier_str;
1631
1632 trace.not_ev_qualifier = *s == '!';
1633 if (trace.not_ev_qualifier)
1634 ++s;
1635 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001636 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001637 fputs("Not enough memory to parse event qualifier",
1638 trace.output);
1639 err = -ENOMEM;
1640 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001641 }
1642 }
1643
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001644 err = perf_target__validate(&trace.opts.target);
1645 if (err) {
1646 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001647 fprintf(trace.output, "%s", bf);
1648 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001649 }
1650
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001651 err = perf_target__parse_uid(&trace.opts.target);
1652 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001653 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001654 fprintf(trace.output, "%s", bf);
1655 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001656 }
1657
Namhyung Kimf15eb532012-10-05 14:02:16 +09001658 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09001659 trace.opts.target.system_wide = true;
1660
David Ahern6810fc92013-08-28 22:29:52 -06001661 if (input_name)
1662 err = trace__replay(&trace);
1663 else
1664 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001665
1666 if (trace.sched && !err)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001667 trace__fprintf_thread_summary(&trace, trace.output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001668
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001669out_close:
1670 if (output_name != NULL)
1671 fclose(trace.output);
1672out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001673 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001674}