perf trace: Beautify flock 'cmd' arg
[linux/fpc-iii.git] / tools / perf / builtin-trace.c
blob2007c8c2c52b534ad0e848bd73d92ae46e88e21e
1 #include <traceevent/event-parse.h>
2 #include "builtin.h"
3 #include "util/color.h"
4 #include "util/debug.h"
5 #include "util/evlist.h"
6 #include "util/machine.h"
7 #include "util/session.h"
8 #include "util/thread.h"
9 #include "util/parse-options.h"
10 #include "util/strlist.h"
11 #include "util/intlist.h"
12 #include "util/thread_map.h"
14 #include <libaudit.h>
15 #include <stdlib.h>
16 #include <sys/eventfd.h>
17 #include <sys/mman.h>
18 #include <linux/futex.h>
20 /* For older distros: */
21 #ifndef MAP_STACK
22 # define MAP_STACK 0x20000
23 #endif
25 #ifndef MADV_HWPOISON
26 # define MADV_HWPOISON 100
27 #endif
29 #ifndef MADV_MERGEABLE
30 # define MADV_MERGEABLE 12
31 #endif
33 #ifndef MADV_UNMERGEABLE
34 # define MADV_UNMERGEABLE 13
35 #endif
37 struct syscall_arg {
38 unsigned long val;
39 void *parm;
40 u8 idx;
41 u8 mask;
44 struct strarray {
45 int nr_entries;
46 const char **entries;
49 #define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
50 .nr_entries = ARRAY_SIZE(array), \
51 .entries = array, \
54 static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
55 struct syscall_arg *arg)
57 int idx = arg->val;
58 struct strarray *sa = arg->parm;
60 if (idx < 0 || idx >= sa->nr_entries)
61 return scnprintf(bf, size, "%d", idx);
63 return scnprintf(bf, size, "%s", sa->entries[idx]);
66 #define SCA_STRARRAY syscall_arg__scnprintf_strarray
68 static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
69 struct syscall_arg *arg)
71 return scnprintf(bf, size, "%#lx", arg->val);
74 #define SCA_HEX syscall_arg__scnprintf_hex
76 static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
77 struct syscall_arg *arg)
79 int printed = 0, prot = arg->val;
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; \
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
99 if (prot)
100 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
102 return printed;
105 #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
107 static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
108 struct syscall_arg *arg)
110 int printed = 0, flags = arg->val;
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; \
118 P_MMAP_FLAG(SHARED);
119 P_MMAP_FLAG(PRIVATE);
120 #ifdef MAP_32BIT
121 P_MMAP_FLAG(32BIT);
122 #endif
123 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);
129 #ifdef MAP_HUGETLB
130 P_MMAP_FLAG(HUGETLB);
131 #endif
132 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
142 if (flags)
143 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
145 return printed;
148 #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
150 static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
151 struct syscall_arg *arg)
153 int behavior = arg->val;
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);
171 #ifdef MADV_HUGEPAGE
172 P_MADV_BHV(HUGEPAGE);
173 #endif
174 #ifdef MADV_NOHUGEPAGE
175 P_MADV_BHV(NOHUGEPAGE);
176 #endif
177 #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;
187 return scnprintf(bf, size, "%#x", behavior);
190 #define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
192 static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
193 struct syscall_arg *arg)
195 int printed = 0, op = arg->val;
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; \
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
215 if (op)
216 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
218 return printed;
221 #define SCA_FLOCK syscall_arg__scnprintf_flock
223 static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
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),
233 int op = arg->val;
234 int cmd = op & FUTEX_CMD_MASK;
235 size_t printed = 0;
237 switch (cmd) {
238 #define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
239 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;
245 P_FUTEX_OP(WAKE_OP); break;
246 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;
251 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
252 default: printed = scnprintf(bf, size, "%#x", cmd); break;
255 if (op & FUTEX_PRIVATE_FLAG)
256 printed += scnprintf(bf + printed, size - printed, "|PRIV");
258 if (op & FUTEX_CLOCK_REALTIME)
259 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
261 return printed;
264 #define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
266 static const char *epoll_ctl_ops[] = { [1] = "ADD", "DEL", "MOD", };
267 static DEFINE_STRARRAY(epoll_ctl_ops);
269 static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
270 static DEFINE_STRARRAY(itimers);
272 static const char *whences[] = { "SET", "CUR", "END",
273 #ifdef SEEK_DATA
274 "DATA",
275 #endif
276 #ifdef SEEK_HOLE
277 "HOLE",
278 #endif
280 static DEFINE_STRARRAY(whences);
282 static 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",
288 static DEFINE_STRARRAY(fcntl_cmds);
290 static const char *rlimit_resources[] = {
291 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
292 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
293 "RTTIME",
295 static DEFINE_STRARRAY(rlimit_resources);
297 static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
298 static DEFINE_STRARRAY(sighow);
300 static const char *socket_families[] = {
301 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
302 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
303 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
304 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
305 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
306 "ALG", "NFC", "VSOCK",
308 static DEFINE_STRARRAY(socket_families);
310 #ifndef SOCK_TYPE_MASK
311 #define SOCK_TYPE_MASK 0xf
312 #endif
314 static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
315 struct syscall_arg *arg)
317 size_t printed;
318 int type = arg->val,
319 flags = type & ~SOCK_TYPE_MASK;
321 type &= SOCK_TYPE_MASK;
323 * Can't use a strarray, MIPS may override for ABI reasons.
325 switch (type) {
326 #define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
327 P_SK_TYPE(STREAM);
328 P_SK_TYPE(DGRAM);
329 P_SK_TYPE(RAW);
330 P_SK_TYPE(RDM);
331 P_SK_TYPE(SEQPACKET);
332 P_SK_TYPE(DCCP);
333 P_SK_TYPE(PACKET);
334 #undef P_SK_TYPE
335 default:
336 printed = scnprintf(bf, size, "%#x", type);
339 #define P_SK_FLAG(n) \
340 if (flags & SOCK_##n) { \
341 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
342 flags &= ~SOCK_##n; \
345 P_SK_FLAG(CLOEXEC);
346 P_SK_FLAG(NONBLOCK);
347 #undef P_SK_FLAG
349 if (flags)
350 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
352 return printed;
355 #define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
357 #ifndef MSG_PROBE
358 #define MSG_PROBE 0x10
359 #endif
360 #ifndef MSG_SENDPAGE_NOTLAST
361 #define MSG_SENDPAGE_NOTLAST 0x20000
362 #endif
363 #ifndef MSG_FASTOPEN
364 #define MSG_FASTOPEN 0x20000000
365 #endif
367 static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
368 struct syscall_arg *arg)
370 int printed = 0, flags = arg->val;
372 if (flags == 0)
373 return scnprintf(bf, size, "NONE");
374 #define P_MSG_FLAG(n) \
375 if (flags & MSG_##n) { \
376 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
377 flags &= ~MSG_##n; \
380 P_MSG_FLAG(OOB);
381 P_MSG_FLAG(PEEK);
382 P_MSG_FLAG(DONTROUTE);
383 P_MSG_FLAG(TRYHARD);
384 P_MSG_FLAG(CTRUNC);
385 P_MSG_FLAG(PROBE);
386 P_MSG_FLAG(TRUNC);
387 P_MSG_FLAG(DONTWAIT);
388 P_MSG_FLAG(EOR);
389 P_MSG_FLAG(WAITALL);
390 P_MSG_FLAG(FIN);
391 P_MSG_FLAG(SYN);
392 P_MSG_FLAG(CONFIRM);
393 P_MSG_FLAG(RST);
394 P_MSG_FLAG(ERRQUEUE);
395 P_MSG_FLAG(NOSIGNAL);
396 P_MSG_FLAG(MORE);
397 P_MSG_FLAG(WAITFORONE);
398 P_MSG_FLAG(SENDPAGE_NOTLAST);
399 P_MSG_FLAG(FASTOPEN);
400 P_MSG_FLAG(CMSG_CLOEXEC);
401 #undef P_MSG_FLAG
403 if (flags)
404 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
406 return printed;
409 #define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
411 static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
412 struct syscall_arg *arg)
414 size_t printed = 0;
415 int mode = arg->val;
417 if (mode == F_OK) /* 0 */
418 return scnprintf(bf, size, "F");
419 #define P_MODE(n) \
420 if (mode & n##_OK) { \
421 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
422 mode &= ~n##_OK; \
425 P_MODE(R);
426 P_MODE(W);
427 P_MODE(X);
428 #undef P_MODE
430 if (mode)
431 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
433 return printed;
436 #define SCA_ACCMODE syscall_arg__scnprintf_access_mode
438 static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
439 struct syscall_arg *arg)
441 int printed = 0, flags = arg->val;
443 if (!(flags & O_CREAT))
444 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
446 if (flags == 0)
447 return scnprintf(bf, size, "RDONLY");
448 #define P_FLAG(n) \
449 if (flags & O_##n) { \
450 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
451 flags &= ~O_##n; \
454 P_FLAG(APPEND);
455 P_FLAG(ASYNC);
456 P_FLAG(CLOEXEC);
457 P_FLAG(CREAT);
458 P_FLAG(DIRECT);
459 P_FLAG(DIRECTORY);
460 P_FLAG(EXCL);
461 P_FLAG(LARGEFILE);
462 P_FLAG(NOATIME);
463 P_FLAG(NOCTTY);
464 #ifdef O_NONBLOCK
465 P_FLAG(NONBLOCK);
466 #elif O_NDELAY
467 P_FLAG(NDELAY);
468 #endif
469 #ifdef O_PATH
470 P_FLAG(PATH);
471 #endif
472 P_FLAG(RDWR);
473 #ifdef O_DSYNC
474 if ((flags & O_SYNC) == O_SYNC)
475 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
476 else {
477 P_FLAG(DSYNC);
479 #else
480 P_FLAG(SYNC);
481 #endif
482 P_FLAG(TRUNC);
483 P_FLAG(WRONLY);
484 #undef P_FLAG
486 if (flags)
487 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
489 return printed;
492 #define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
494 static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
495 struct syscall_arg *arg)
497 int printed = 0, flags = arg->val;
499 if (flags == 0)
500 return scnprintf(bf, size, "NONE");
501 #define P_FLAG(n) \
502 if (flags & EFD_##n) { \
503 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
504 flags &= ~EFD_##n; \
507 P_FLAG(SEMAPHORE);
508 P_FLAG(CLOEXEC);
509 P_FLAG(NONBLOCK);
510 #undef P_FLAG
512 if (flags)
513 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
515 return printed;
518 #define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
520 static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
522 int sig = arg->val;
524 switch (sig) {
525 #define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
526 P_SIGNUM(HUP);
527 P_SIGNUM(INT);
528 P_SIGNUM(QUIT);
529 P_SIGNUM(ILL);
530 P_SIGNUM(TRAP);
531 P_SIGNUM(ABRT);
532 P_SIGNUM(BUS);
533 P_SIGNUM(FPE);
534 P_SIGNUM(KILL);
535 P_SIGNUM(USR1);
536 P_SIGNUM(SEGV);
537 P_SIGNUM(USR2);
538 P_SIGNUM(PIPE);
539 P_SIGNUM(ALRM);
540 P_SIGNUM(TERM);
541 P_SIGNUM(STKFLT);
542 P_SIGNUM(CHLD);
543 P_SIGNUM(CONT);
544 P_SIGNUM(STOP);
545 P_SIGNUM(TSTP);
546 P_SIGNUM(TTIN);
547 P_SIGNUM(TTOU);
548 P_SIGNUM(URG);
549 P_SIGNUM(XCPU);
550 P_SIGNUM(XFSZ);
551 P_SIGNUM(VTALRM);
552 P_SIGNUM(PROF);
553 P_SIGNUM(WINCH);
554 P_SIGNUM(IO);
555 P_SIGNUM(PWR);
556 P_SIGNUM(SYS);
557 default: break;
560 return scnprintf(bf, size, "%#x", sig);
563 #define SCA_SIGNUM syscall_arg__scnprintf_signum
565 static struct syscall_fmt {
566 const char *name;
567 const char *alias;
568 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
569 void *arg_parm[6];
570 bool errmsg;
571 bool timeout;
572 bool hexret;
573 } syscall_fmts[] = {
574 { .name = "access", .errmsg = true,
575 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
576 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
577 { .name = "brk", .hexret = true,
578 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
579 { .name = "connect", .errmsg = true, },
580 { .name = "epoll_ctl", .errmsg = true,
581 .arg_scnprintf = { [1] = SCA_STRARRAY, /* op */ },
582 .arg_parm = { [1] = &strarray__epoll_ctl_ops, /* op */ }, },
583 { .name = "eventfd2", .errmsg = true,
584 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
585 { .name = "fcntl", .errmsg = true,
586 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
587 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
588 { .name = "flock", .errmsg = true,
589 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
590 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
591 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
592 { .name = "futex", .errmsg = true,
593 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
594 { .name = "getitimer", .errmsg = true,
595 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
596 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
597 { .name = "getrlimit", .errmsg = true,
598 .arg_scnprintf = { [0] = SCA_STRARRAY, /* resource */ },
599 .arg_parm = { [0] = &strarray__rlimit_resources, /* resource */ }, },
600 { .name = "ioctl", .errmsg = true,
601 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
602 { .name = "kill", .errmsg = true,
603 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
604 { .name = "lseek", .errmsg = true,
605 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
606 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
607 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
608 { .name = "madvise", .errmsg = true,
609 .arg_scnprintf = { [0] = SCA_HEX, /* start */
610 [2] = SCA_MADV_BHV, /* behavior */ }, },
611 { .name = "mmap", .hexret = true,
612 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
613 [2] = SCA_MMAP_PROT, /* prot */
614 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
615 { .name = "mprotect", .errmsg = true,
616 .arg_scnprintf = { [0] = SCA_HEX, /* start */
617 [2] = SCA_MMAP_PROT, /* prot */ }, },
618 { .name = "mremap", .hexret = true,
619 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
620 [4] = SCA_HEX, /* new_addr */ }, },
621 { .name = "munmap", .errmsg = true,
622 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
623 { .name = "open", .errmsg = true,
624 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
625 { .name = "open_by_handle_at", .errmsg = true,
626 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
627 { .name = "openat", .errmsg = true,
628 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
629 { .name = "poll", .errmsg = true, .timeout = true, },
630 { .name = "ppoll", .errmsg = true, .timeout = true, },
631 { .name = "pread", .errmsg = true, .alias = "pread64", },
632 { .name = "prlimit64", .errmsg = true,
633 .arg_scnprintf = { [1] = SCA_STRARRAY, /* resource */ },
634 .arg_parm = { [1] = &strarray__rlimit_resources, /* resource */ }, },
635 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
636 { .name = "read", .errmsg = true, },
637 { .name = "recvfrom", .errmsg = true,
638 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
639 { .name = "recvmmsg", .errmsg = true,
640 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
641 { .name = "recvmsg", .errmsg = true,
642 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
643 { .name = "rt_sigaction", .errmsg = true,
644 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
645 { .name = "rt_sigprocmask", .errmsg = true,
646 .arg_scnprintf = { [0] = SCA_STRARRAY, /* how */ },
647 .arg_parm = { [0] = &strarray__sighow, /* how */ }, },
648 { .name = "rt_sigqueueinfo", .errmsg = true,
649 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
650 { .name = "rt_tgsigqueueinfo", .errmsg = true,
651 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
652 { .name = "select", .errmsg = true, .timeout = true, },
653 { .name = "sendmmsg", .errmsg = true,
654 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
655 { .name = "sendmsg", .errmsg = true,
656 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
657 { .name = "sendto", .errmsg = true,
658 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
659 { .name = "setitimer", .errmsg = true,
660 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
661 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
662 { .name = "setrlimit", .errmsg = true,
663 .arg_scnprintf = { [0] = SCA_STRARRAY, /* resource */ },
664 .arg_parm = { [0] = &strarray__rlimit_resources, /* resource */ }, },
665 { .name = "socket", .errmsg = true,
666 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
667 [1] = SCA_SK_TYPE, /* type */ },
668 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
669 { .name = "stat", .errmsg = true, .alias = "newstat", },
670 { .name = "tgkill", .errmsg = true,
671 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
672 { .name = "tkill", .errmsg = true,
673 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
674 { .name = "uname", .errmsg = true, .alias = "newuname", },
677 static int syscall_fmt__cmp(const void *name, const void *fmtp)
679 const struct syscall_fmt *fmt = fmtp;
680 return strcmp(name, fmt->name);
683 static struct syscall_fmt *syscall_fmt__find(const char *name)
685 const int nmemb = ARRAY_SIZE(syscall_fmts);
686 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
689 struct syscall {
690 struct event_format *tp_format;
691 const char *name;
692 bool filtered;
693 struct syscall_fmt *fmt;
694 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
695 void **arg_parm;
698 static size_t fprintf_duration(unsigned long t, FILE *fp)
700 double duration = (double)t / NSEC_PER_MSEC;
701 size_t printed = fprintf(fp, "(");
703 if (duration >= 1.0)
704 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
705 else if (duration >= 0.01)
706 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
707 else
708 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
709 return printed + fprintf(fp, "): ");
712 struct thread_trace {
713 u64 entry_time;
714 u64 exit_time;
715 bool entry_pending;
716 unsigned long nr_events;
717 char *entry_str;
718 double runtime_ms;
721 static struct thread_trace *thread_trace__new(void)
723 return zalloc(sizeof(struct thread_trace));
726 static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
728 struct thread_trace *ttrace;
730 if (thread == NULL)
731 goto fail;
733 if (thread->priv == NULL)
734 thread->priv = thread_trace__new();
736 if (thread->priv == NULL)
737 goto fail;
739 ttrace = thread->priv;
740 ++ttrace->nr_events;
742 return ttrace;
743 fail:
744 color_fprintf(fp, PERF_COLOR_RED,
745 "WARNING: not enough memory, dropping samples!\n");
746 return NULL;
749 struct trace {
750 struct perf_tool tool;
751 int audit_machine;
752 struct {
753 int max;
754 struct syscall *table;
755 } syscalls;
756 struct perf_record_opts opts;
757 struct machine host;
758 u64 base_time;
759 bool full_time;
760 FILE *output;
761 unsigned long nr_events;
762 struct strlist *ev_qualifier;
763 bool not_ev_qualifier;
764 struct intlist *tid_list;
765 struct intlist *pid_list;
766 bool sched;
767 bool multiple_threads;
768 bool show_comm;
769 double duration_filter;
770 double runtime_ms;
773 static bool trace__filter_duration(struct trace *trace, double t)
775 return t < (trace->duration_filter * NSEC_PER_MSEC);
778 static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
780 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
782 return fprintf(fp, "%10.3f ", ts);
785 static bool done = false;
787 static void sig_handler(int sig __maybe_unused)
789 done = true;
792 static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
793 u64 duration, u64 tstamp, FILE *fp)
795 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
796 printed += fprintf_duration(duration, fp);
798 if (trace->multiple_threads) {
799 if (trace->show_comm)
800 printed += fprintf(fp, "%.14s/", thread->comm);
801 printed += fprintf(fp, "%d ", thread->tid);
804 return printed;
807 static int trace__process_event(struct trace *trace, struct machine *machine,
808 union perf_event *event)
810 int ret = 0;
812 switch (event->header.type) {
813 case PERF_RECORD_LOST:
814 color_fprintf(trace->output, PERF_COLOR_RED,
815 "LOST %" PRIu64 " events!\n", event->lost.lost);
816 ret = machine__process_lost_event(machine, event);
817 default:
818 ret = machine__process_event(machine, event);
819 break;
822 return ret;
825 static int trace__tool_process(struct perf_tool *tool,
826 union perf_event *event,
827 struct perf_sample *sample __maybe_unused,
828 struct machine *machine)
830 struct trace *trace = container_of(tool, struct trace, tool);
831 return trace__process_event(trace, machine, event);
834 static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
836 int err = symbol__init();
838 if (err)
839 return err;
841 machine__init(&trace->host, "", HOST_KERNEL_ID);
842 machine__create_kernel_maps(&trace->host);
844 if (perf_target__has_task(&trace->opts.target)) {
845 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
846 trace__tool_process,
847 &trace->host);
848 } else {
849 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
850 &trace->host);
853 if (err)
854 symbol__exit();
856 return err;
859 static int syscall__set_arg_fmts(struct syscall *sc)
861 struct format_field *field;
862 int idx = 0;
864 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
865 if (sc->arg_scnprintf == NULL)
866 return -1;
868 if (sc->fmt)
869 sc->arg_parm = sc->fmt->arg_parm;
871 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
872 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
873 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
874 else if (field->flags & FIELD_IS_POINTER)
875 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
876 ++idx;
879 return 0;
882 static int trace__read_syscall_info(struct trace *trace, int id)
884 char tp_name[128];
885 struct syscall *sc;
886 const char *name = audit_syscall_to_name(id, trace->audit_machine);
888 if (name == NULL)
889 return -1;
891 if (id > trace->syscalls.max) {
892 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
894 if (nsyscalls == NULL)
895 return -1;
897 if (trace->syscalls.max != -1) {
898 memset(nsyscalls + trace->syscalls.max + 1, 0,
899 (id - trace->syscalls.max) * sizeof(*sc));
900 } else {
901 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
904 trace->syscalls.table = nsyscalls;
905 trace->syscalls.max = id;
908 sc = trace->syscalls.table + id;
909 sc->name = name;
911 if (trace->ev_qualifier) {
912 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
914 if (!(in ^ trace->not_ev_qualifier)) {
915 sc->filtered = true;
917 * No need to do read tracepoint information since this will be
918 * filtered out.
920 return 0;
924 sc->fmt = syscall_fmt__find(sc->name);
926 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
927 sc->tp_format = event_format__new("syscalls", tp_name);
929 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
930 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
931 sc->tp_format = event_format__new("syscalls", tp_name);
934 if (sc->tp_format == NULL)
935 return -1;
937 return syscall__set_arg_fmts(sc);
940 static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
941 unsigned long *args)
943 size_t printed = 0;
945 if (sc->tp_format != NULL) {
946 struct format_field *field;
947 u8 bit = 1;
948 struct syscall_arg arg = {
949 .idx = 0,
950 .mask = 0,
953 for (field = sc->tp_format->format.fields->next; field;
954 field = field->next, ++arg.idx, bit <<= 1) {
955 if (arg.mask & bit)
956 continue;
958 if (args[arg.idx] == 0)
959 continue;
961 printed += scnprintf(bf + printed, size - printed,
962 "%s%s: ", printed ? ", " : "", field->name);
963 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
964 arg.val = args[arg.idx];
965 if (sc->arg_parm)
966 arg.parm = sc->arg_parm[arg.idx];
967 printed += sc->arg_scnprintf[arg.idx](bf + printed,
968 size - printed, &arg);
969 } else {
970 printed += scnprintf(bf + printed, size - printed,
971 "%ld", args[arg.idx]);
974 } else {
975 int i = 0;
977 while (i < 6) {
978 printed += scnprintf(bf + printed, size - printed,
979 "%sarg%d: %ld",
980 printed ? ", " : "", i, args[i]);
981 ++i;
985 return printed;
988 typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
989 struct perf_sample *sample);
991 static struct syscall *trace__syscall_info(struct trace *trace,
992 struct perf_evsel *evsel,
993 struct perf_sample *sample)
995 int id = perf_evsel__intval(evsel, sample, "id");
997 if (id < 0) {
1000 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1001 * before that, leaving at a higher verbosity level till that is
1002 * explained. Reproduced with plain ftrace with:
1004 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1005 * grep "NR -1 " /t/trace_pipe
1007 * After generating some load on the machine.
1009 if (verbose > 1) {
1010 static u64 n;
1011 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1012 id, perf_evsel__name(evsel), ++n);
1014 return NULL;
1017 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1018 trace__read_syscall_info(trace, id))
1019 goto out_cant_read;
1021 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1022 goto out_cant_read;
1024 return &trace->syscalls.table[id];
1026 out_cant_read:
1027 if (verbose) {
1028 fprintf(trace->output, "Problems reading syscall %d", id);
1029 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1030 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1031 fputs(" information\n", trace->output);
1033 return NULL;
1036 static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1037 struct perf_sample *sample)
1039 char *msg;
1040 void *args;
1041 size_t printed = 0;
1042 struct thread *thread;
1043 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
1044 struct thread_trace *ttrace;
1046 if (sc == NULL)
1047 return -1;
1049 if (sc->filtered)
1050 return 0;
1052 thread = machine__findnew_thread(&trace->host, sample->pid,
1053 sample->tid);
1054 ttrace = thread__trace(thread, trace->output);
1055 if (ttrace == NULL)
1056 return -1;
1058 args = perf_evsel__rawptr(evsel, sample, "args");
1059 if (args == NULL) {
1060 fprintf(trace->output, "Problems reading syscall arguments\n");
1061 return -1;
1064 ttrace = thread->priv;
1066 if (ttrace->entry_str == NULL) {
1067 ttrace->entry_str = malloc(1024);
1068 if (!ttrace->entry_str)
1069 return -1;
1072 ttrace->entry_time = sample->time;
1073 msg = ttrace->entry_str;
1074 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1076 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
1078 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
1079 if (!trace->duration_filter) {
1080 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1081 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
1083 } else
1084 ttrace->entry_pending = true;
1086 return 0;
1089 static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1090 struct perf_sample *sample)
1092 int ret;
1093 u64 duration = 0;
1094 struct thread *thread;
1095 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
1096 struct thread_trace *ttrace;
1098 if (sc == NULL)
1099 return -1;
1101 if (sc->filtered)
1102 return 0;
1104 thread = machine__findnew_thread(&trace->host, sample->pid,
1105 sample->tid);
1106 ttrace = thread__trace(thread, trace->output);
1107 if (ttrace == NULL)
1108 return -1;
1110 ret = perf_evsel__intval(evsel, sample, "ret");
1112 ttrace = thread->priv;
1114 ttrace->exit_time = sample->time;
1116 if (ttrace->entry_time) {
1117 duration = sample->time - ttrace->entry_time;
1118 if (trace__filter_duration(trace, duration))
1119 goto out;
1120 } else if (trace->duration_filter)
1121 goto out;
1123 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
1125 if (ttrace->entry_pending) {
1126 fprintf(trace->output, "%-70s", ttrace->entry_str);
1127 } else {
1128 fprintf(trace->output, " ... [");
1129 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1130 fprintf(trace->output, "]: %s()", sc->name);
1133 if (sc->fmt == NULL) {
1134 signed_print:
1135 fprintf(trace->output, ") = %d", ret);
1136 } else if (ret < 0 && sc->fmt->errmsg) {
1137 char bf[256];
1138 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1139 *e = audit_errno_to_name(-ret);
1141 fprintf(trace->output, ") = -1 %s %s", e, emsg);
1142 } else if (ret == 0 && sc->fmt->timeout)
1143 fprintf(trace->output, ") = 0 Timeout");
1144 else if (sc->fmt->hexret)
1145 fprintf(trace->output, ") = %#x", ret);
1146 else
1147 goto signed_print;
1149 fputc('\n', trace->output);
1150 out:
1151 ttrace->entry_pending = false;
1153 return 0;
1156 static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1157 struct perf_sample *sample)
1159 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1160 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
1161 struct thread *thread = machine__findnew_thread(&trace->host,
1162 sample->pid,
1163 sample->tid);
1164 struct thread_trace *ttrace = thread__trace(thread, trace->output);
1166 if (ttrace == NULL)
1167 goto out_dump;
1169 ttrace->runtime_ms += runtime_ms;
1170 trace->runtime_ms += runtime_ms;
1171 return 0;
1173 out_dump:
1174 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
1175 evsel->name,
1176 perf_evsel__strval(evsel, sample, "comm"),
1177 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1178 runtime,
1179 perf_evsel__intval(evsel, sample, "vruntime"));
1180 return 0;
1183 static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1185 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1186 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1187 return false;
1189 if (trace->pid_list || trace->tid_list)
1190 return true;
1192 return false;
1195 static int trace__process_sample(struct perf_tool *tool,
1196 union perf_event *event __maybe_unused,
1197 struct perf_sample *sample,
1198 struct perf_evsel *evsel,
1199 struct machine *machine __maybe_unused)
1201 struct trace *trace = container_of(tool, struct trace, tool);
1202 int err = 0;
1204 tracepoint_handler handler = evsel->handler.func;
1206 if (skip_sample(trace, sample))
1207 return 0;
1209 if (!trace->full_time && trace->base_time == 0)
1210 trace->base_time = sample->time;
1212 if (handler)
1213 handler(trace, evsel, sample);
1215 return err;
1218 static bool
1219 perf_session__has_tp(struct perf_session *session, const char *name)
1221 struct perf_evsel *evsel;
1223 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1225 return evsel != NULL;
1228 static int parse_target_str(struct trace *trace)
1230 if (trace->opts.target.pid) {
1231 trace->pid_list = intlist__new(trace->opts.target.pid);
1232 if (trace->pid_list == NULL) {
1233 pr_err("Error parsing process id string\n");
1234 return -EINVAL;
1238 if (trace->opts.target.tid) {
1239 trace->tid_list = intlist__new(trace->opts.target.tid);
1240 if (trace->tid_list == NULL) {
1241 pr_err("Error parsing thread id string\n");
1242 return -EINVAL;
1246 return 0;
1249 static int trace__run(struct trace *trace, int argc, const char **argv)
1251 struct perf_evlist *evlist = perf_evlist__new();
1252 struct perf_evsel *evsel;
1253 int err = -1, i;
1254 unsigned long before;
1255 const bool forks = argc > 0;
1257 if (evlist == NULL) {
1258 fprintf(trace->output, "Not enough memory to run!\n");
1259 goto out;
1262 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1263 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
1264 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
1265 goto out_delete_evlist;
1268 if (trace->sched &&
1269 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1270 trace__sched_stat_runtime)) {
1271 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
1272 goto out_delete_evlist;
1275 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1276 if (err < 0) {
1277 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
1278 goto out_delete_evlist;
1281 err = trace__symbols_init(trace, evlist);
1282 if (err < 0) {
1283 fprintf(trace->output, "Problems initializing symbol libraries!\n");
1284 goto out_delete_maps;
1287 perf_evlist__config(evlist, &trace->opts);
1289 signal(SIGCHLD, sig_handler);
1290 signal(SIGINT, sig_handler);
1292 if (forks) {
1293 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
1294 argv, false, false);
1295 if (err < 0) {
1296 fprintf(trace->output, "Couldn't run the workload!\n");
1297 goto out_delete_maps;
1301 err = perf_evlist__open(evlist);
1302 if (err < 0) {
1303 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
1304 goto out_delete_maps;
1307 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1308 if (err < 0) {
1309 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
1310 goto out_close_evlist;
1313 perf_evlist__enable(evlist);
1315 if (forks)
1316 perf_evlist__start_workload(evlist);
1318 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
1319 again:
1320 before = trace->nr_events;
1322 for (i = 0; i < evlist->nr_mmaps; i++) {
1323 union perf_event *event;
1325 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1326 const u32 type = event->header.type;
1327 tracepoint_handler handler;
1328 struct perf_sample sample;
1330 ++trace->nr_events;
1332 err = perf_evlist__parse_sample(evlist, event, &sample);
1333 if (err) {
1334 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
1335 continue;
1338 if (!trace->full_time && trace->base_time == 0)
1339 trace->base_time = sample.time;
1341 if (type != PERF_RECORD_SAMPLE) {
1342 trace__process_event(trace, &trace->host, event);
1343 continue;
1346 evsel = perf_evlist__id2evsel(evlist, sample.id);
1347 if (evsel == NULL) {
1348 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
1349 continue;
1352 if (sample.raw_data == NULL) {
1353 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
1354 perf_evsel__name(evsel), sample.tid,
1355 sample.cpu, sample.raw_size);
1356 continue;
1359 handler = evsel->handler.func;
1360 handler(trace, evsel, &sample);
1362 if (done)
1363 goto out_unmap_evlist;
1367 if (trace->nr_events == before) {
1368 if (done)
1369 goto out_unmap_evlist;
1371 poll(evlist->pollfd, evlist->nr_fds, -1);
1374 if (done)
1375 perf_evlist__disable(evlist);
1377 goto again;
1379 out_unmap_evlist:
1380 perf_evlist__munmap(evlist);
1381 out_close_evlist:
1382 perf_evlist__close(evlist);
1383 out_delete_maps:
1384 perf_evlist__delete_maps(evlist);
1385 out_delete_evlist:
1386 perf_evlist__delete(evlist);
1387 out:
1388 return err;
1391 static int trace__replay(struct trace *trace)
1393 const struct perf_evsel_str_handler handlers[] = {
1394 { "raw_syscalls:sys_enter", trace__sys_enter, },
1395 { "raw_syscalls:sys_exit", trace__sys_exit, },
1398 struct perf_session *session;
1399 int err = -1;
1401 trace->tool.sample = trace__process_sample;
1402 trace->tool.mmap = perf_event__process_mmap;
1403 trace->tool.mmap2 = perf_event__process_mmap2;
1404 trace->tool.comm = perf_event__process_comm;
1405 trace->tool.exit = perf_event__process_exit;
1406 trace->tool.fork = perf_event__process_fork;
1407 trace->tool.attr = perf_event__process_attr;
1408 trace->tool.tracing_data = perf_event__process_tracing_data;
1409 trace->tool.build_id = perf_event__process_build_id;
1411 trace->tool.ordered_samples = true;
1412 trace->tool.ordering_requires_timestamps = true;
1414 /* add tid to output */
1415 trace->multiple_threads = true;
1417 if (symbol__init() < 0)
1418 return -1;
1420 session = perf_session__new(input_name, O_RDONLY, 0, false,
1421 &trace->tool);
1422 if (session == NULL)
1423 return -ENOMEM;
1425 err = perf_session__set_tracepoints_handlers(session, handlers);
1426 if (err)
1427 goto out;
1429 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1430 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1431 goto out;
1434 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1435 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1436 goto out;
1439 err = parse_target_str(trace);
1440 if (err != 0)
1441 goto out;
1443 setup_pager();
1445 err = perf_session__process_events(session, &trace->tool);
1446 if (err)
1447 pr_err("Failed to process events, error %d", err);
1449 out:
1450 perf_session__delete(session);
1452 return err;
1455 static size_t trace__fprintf_threads_header(FILE *fp)
1457 size_t printed;
1459 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1460 printed += fprintf(fp," __) Summary of events (__\n\n");
1461 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1462 printed += fprintf(fp," _____________________________________________________________________\n\n");
1464 return printed;
1467 static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1469 size_t printed = trace__fprintf_threads_header(fp);
1470 struct rb_node *nd;
1472 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
1473 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1474 struct thread_trace *ttrace = thread->priv;
1475 const char *color;
1476 double ratio;
1478 if (ttrace == NULL)
1479 continue;
1481 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1483 color = PERF_COLOR_NORMAL;
1484 if (ratio > 50.0)
1485 color = PERF_COLOR_RED;
1486 else if (ratio > 25.0)
1487 color = PERF_COLOR_GREEN;
1488 else if (ratio > 5.0)
1489 color = PERF_COLOR_YELLOW;
1491 printed += color_fprintf(fp, color, "%20s", thread->comm);
1492 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
1493 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1494 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1497 return printed;
1500 static int trace__set_duration(const struct option *opt, const char *str,
1501 int unset __maybe_unused)
1503 struct trace *trace = opt->value;
1505 trace->duration_filter = atof(str);
1506 return 0;
1509 static int trace__open_output(struct trace *trace, const char *filename)
1511 struct stat st;
1513 if (!stat(filename, &st) && st.st_size) {
1514 char oldname[PATH_MAX];
1516 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1517 unlink(oldname);
1518 rename(filename, oldname);
1521 trace->output = fopen(filename, "w");
1523 return trace->output == NULL ? -errno : 0;
1526 int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1528 const char * const trace_usage[] = {
1529 "perf trace [<options>] [<command>]",
1530 "perf trace [<options>] -- <command> [<options>]",
1531 NULL
1533 struct trace trace = {
1534 .audit_machine = audit_detect_machine(),
1535 .syscalls = {
1536 . max = -1,
1538 .opts = {
1539 .target = {
1540 .uid = UINT_MAX,
1541 .uses_mmap = true,
1543 .user_freq = UINT_MAX,
1544 .user_interval = ULLONG_MAX,
1545 .no_delay = true,
1546 .mmap_pages = 1024,
1548 .output = stdout,
1549 .show_comm = true,
1551 const char *output_name = NULL;
1552 const char *ev_qualifier_str = NULL;
1553 const struct option trace_options[] = {
1554 OPT_BOOLEAN(0, "comm", &trace.show_comm,
1555 "show the thread COMM next to its id"),
1556 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1557 "list of events to trace"),
1558 OPT_STRING('o', "output", &output_name, "file", "output file name"),
1559 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
1560 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1561 "trace events on existing process id"),
1562 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
1563 "trace events on existing thread id"),
1564 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
1565 "system-wide collection from all CPUs"),
1566 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
1567 "list of cpus to monitor"),
1568 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
1569 "child tasks do not inherit counters"),
1570 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
1571 "number of mmap data pages",
1572 perf_evlist__parse_mmap_pages),
1573 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
1574 "user to profile"),
1575 OPT_CALLBACK(0, "duration", &trace, "float",
1576 "show only events with duration > N.M ms",
1577 trace__set_duration),
1578 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
1579 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
1580 OPT_BOOLEAN('T', "time", &trace.full_time,
1581 "Show full timestamp, not time relative to first start"),
1582 OPT_END()
1584 int err;
1585 char bf[BUFSIZ];
1587 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
1589 if (output_name != NULL) {
1590 err = trace__open_output(&trace, output_name);
1591 if (err < 0) {
1592 perror("failed to create output file");
1593 goto out;
1597 if (ev_qualifier_str != NULL) {
1598 const char *s = ev_qualifier_str;
1600 trace.not_ev_qualifier = *s == '!';
1601 if (trace.not_ev_qualifier)
1602 ++s;
1603 trace.ev_qualifier = strlist__new(true, s);
1604 if (trace.ev_qualifier == NULL) {
1605 fputs("Not enough memory to parse event qualifier",
1606 trace.output);
1607 err = -ENOMEM;
1608 goto out_close;
1612 err = perf_target__validate(&trace.opts.target);
1613 if (err) {
1614 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
1615 fprintf(trace.output, "%s", bf);
1616 goto out_close;
1619 err = perf_target__parse_uid(&trace.opts.target);
1620 if (err) {
1621 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
1622 fprintf(trace.output, "%s", bf);
1623 goto out_close;
1626 if (!argc && perf_target__none(&trace.opts.target))
1627 trace.opts.target.system_wide = true;
1629 if (input_name)
1630 err = trace__replay(&trace);
1631 else
1632 err = trace__run(&trace, argc, argv);
1634 if (trace.sched && !err)
1635 trace__fprintf_thread_summary(&trace, trace.output);
1637 out_close:
1638 if (output_name != NULL)
1639 fclose(trace.output);
1640 out:
1641 return err;