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