1 #include <traceevent/event-parse.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"
16 #include <sys/eventfd.h>
18 #include <linux/futex.h>
20 /* For older distros: */
22 # define MAP_STACK 0x20000
26 # define MADV_HWPOISON 100
29 #ifndef MADV_MERGEABLE
30 # define MADV_MERGEABLE 12
33 #ifndef MADV_UNMERGEABLE
34 # define MADV_UNMERGEABLE 13
39 struct thread
*thread
;
52 #define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
53 .nr_entries = ARRAY_SIZE(array), \
57 #define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
59 .nr_entries = ARRAY_SIZE(array), \
63 static size_t __syscall_arg__scnprintf_strarray(char *bf
, size_t size
,
65 struct syscall_arg
*arg
)
67 struct strarray
*sa
= arg
->parm
;
68 int idx
= arg
->val
- sa
->offset
;
70 if (idx
< 0 || idx
>= sa
->nr_entries
)
71 return scnprintf(bf
, size
, intfmt
, arg
->val
);
73 return scnprintf(bf
, size
, "%s", sa
->entries
[idx
]);
76 static size_t syscall_arg__scnprintf_strarray(char *bf
, size_t size
,
77 struct syscall_arg
*arg
)
79 return __syscall_arg__scnprintf_strarray(bf
, size
, "%d", arg
);
82 #define SCA_STRARRAY syscall_arg__scnprintf_strarray
84 static size_t syscall_arg__scnprintf_fd(char *bf
, size_t size
,
85 struct syscall_arg
*arg
);
87 #define SCA_FD syscall_arg__scnprintf_fd
89 static size_t syscall_arg__scnprintf_fd_at(char *bf
, size_t size
,
90 struct syscall_arg
*arg
)
95 return scnprintf(bf
, size
, "CWD");
97 return syscall_arg__scnprintf_fd(bf
, size
, arg
);
100 #define SCA_FDAT syscall_arg__scnprintf_fd_at
102 static size_t syscall_arg__scnprintf_close_fd(char *bf
, size_t size
,
103 struct syscall_arg
*arg
);
105 #define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
107 static size_t syscall_arg__scnprintf_hex(char *bf
, size_t size
,
108 struct syscall_arg
*arg
)
110 return scnprintf(bf
, size
, "%#lx", arg
->val
);
113 #define SCA_HEX syscall_arg__scnprintf_hex
115 static size_t syscall_arg__scnprintf_mmap_prot(char *bf
, size_t size
,
116 struct syscall_arg
*arg
)
118 int printed
= 0, prot
= arg
->val
;
120 if (prot
== PROT_NONE
)
121 return scnprintf(bf
, size
, "NONE");
122 #define P_MMAP_PROT(n) \
123 if (prot & PROT_##n) { \
124 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
134 P_MMAP_PROT(GROWSDOWN
);
135 P_MMAP_PROT(GROWSUP
);
139 printed
+= scnprintf(bf
+ printed
, size
- printed
, "%s%#x", printed
? "|" : "", prot
);
144 #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
146 static size_t syscall_arg__scnprintf_mmap_flags(char *bf
, size_t size
,
147 struct syscall_arg
*arg
)
149 int printed
= 0, flags
= arg
->val
;
151 #define P_MMAP_FLAG(n) \
152 if (flags & MAP_##n) { \
153 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
158 P_MMAP_FLAG(PRIVATE
);
162 P_MMAP_FLAG(ANONYMOUS
);
163 P_MMAP_FLAG(DENYWRITE
);
164 P_MMAP_FLAG(EXECUTABLE
);
167 P_MMAP_FLAG(GROWSDOWN
);
169 P_MMAP_FLAG(HUGETLB
);
172 P_MMAP_FLAG(NONBLOCK
);
173 P_MMAP_FLAG(NORESERVE
);
174 P_MMAP_FLAG(POPULATE
);
176 #ifdef MAP_UNINITIALIZED
177 P_MMAP_FLAG(UNINITIALIZED
);
182 printed
+= scnprintf(bf
+ printed
, size
- printed
, "%s%#x", printed
? "|" : "", flags
);
187 #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
189 static size_t syscall_arg__scnprintf_madvise_behavior(char *bf
, size_t size
,
190 struct syscall_arg
*arg
)
192 int behavior
= arg
->val
;
195 #define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
198 P_MADV_BHV(SEQUENTIAL
);
199 P_MADV_BHV(WILLNEED
);
200 P_MADV_BHV(DONTNEED
);
202 P_MADV_BHV(DONTFORK
);
204 P_MADV_BHV(HWPOISON
);
205 #ifdef MADV_SOFT_OFFLINE
206 P_MADV_BHV(SOFT_OFFLINE
);
208 P_MADV_BHV(MERGEABLE
);
209 P_MADV_BHV(UNMERGEABLE
);
211 P_MADV_BHV(HUGEPAGE
);
213 #ifdef MADV_NOHUGEPAGE
214 P_MADV_BHV(NOHUGEPAGE
);
217 P_MADV_BHV(DONTDUMP
);
226 return scnprintf(bf
, size
, "%#x", behavior
);
229 #define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
231 static size_t syscall_arg__scnprintf_flock(char *bf
, size_t size
,
232 struct syscall_arg
*arg
)
234 int printed
= 0, op
= arg
->val
;
237 return scnprintf(bf
, size
, "NONE");
239 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
240 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
255 printed
+= scnprintf(bf
+ printed
, size
- printed
, "%s%#x", printed
? "|" : "", op
);
260 #define SCA_FLOCK syscall_arg__scnprintf_flock
262 static size_t syscall_arg__scnprintf_futex_op(char *bf
, size_t size
, struct syscall_arg
*arg
)
264 enum syscall_futex_args
{
265 SCF_UADDR
= (1 << 0),
268 SCF_TIMEOUT
= (1 << 3),
269 SCF_UADDR2
= (1 << 4),
273 int cmd
= op
& FUTEX_CMD_MASK
;
277 #define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
278 P_FUTEX_OP(WAIT
); arg
->mask
|= SCF_VAL3
|SCF_UADDR2
; break;
279 P_FUTEX_OP(WAKE
); arg
->mask
|= SCF_VAL3
|SCF_UADDR2
|SCF_TIMEOUT
; break;
280 P_FUTEX_OP(FD
); arg
->mask
|= SCF_VAL3
|SCF_UADDR2
|SCF_TIMEOUT
; break;
281 P_FUTEX_OP(REQUEUE
); arg
->mask
|= SCF_VAL3
|SCF_TIMEOUT
; break;
282 P_FUTEX_OP(CMP_REQUEUE
); arg
->mask
|= SCF_TIMEOUT
; break;
283 P_FUTEX_OP(CMP_REQUEUE_PI
); arg
->mask
|= SCF_TIMEOUT
; break;
284 P_FUTEX_OP(WAKE_OP
); break;
285 P_FUTEX_OP(LOCK_PI
); arg
->mask
|= SCF_VAL3
|SCF_UADDR2
|SCF_TIMEOUT
; break;
286 P_FUTEX_OP(UNLOCK_PI
); arg
->mask
|= SCF_VAL3
|SCF_UADDR2
|SCF_TIMEOUT
; break;
287 P_FUTEX_OP(TRYLOCK_PI
); arg
->mask
|= SCF_VAL3
|SCF_UADDR2
; break;
288 P_FUTEX_OP(WAIT_BITSET
); arg
->mask
|= SCF_UADDR2
; break;
289 P_FUTEX_OP(WAKE_BITSET
); arg
->mask
|= SCF_UADDR2
; break;
290 P_FUTEX_OP(WAIT_REQUEUE_PI
); break;
291 default: printed
= scnprintf(bf
, size
, "%#x", cmd
); break;
294 if (op
& FUTEX_PRIVATE_FLAG
)
295 printed
+= scnprintf(bf
+ printed
, size
- printed
, "|PRIV");
297 if (op
& FUTEX_CLOCK_REALTIME
)
298 printed
+= scnprintf(bf
+ printed
, size
- printed
, "|CLKRT");
303 #define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
305 static const char *epoll_ctl_ops
[] = { "ADD", "DEL", "MOD", };
306 static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops
, 1);
308 static const char *itimers
[] = { "REAL", "VIRTUAL", "PROF", };
309 static DEFINE_STRARRAY(itimers
);
311 static const char *whences
[] = { "SET", "CUR", "END",
319 static DEFINE_STRARRAY(whences
);
321 static const char *fcntl_cmds
[] = {
322 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
323 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
324 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
327 static DEFINE_STRARRAY(fcntl_cmds
);
329 static const char *rlimit_resources
[] = {
330 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
331 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
334 static DEFINE_STRARRAY(rlimit_resources
);
336 static const char *sighow
[] = { "BLOCK", "UNBLOCK", "SETMASK", };
337 static DEFINE_STRARRAY(sighow
);
339 static const char *clockid
[] = {
340 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
341 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
343 static DEFINE_STRARRAY(clockid
);
345 static const char *socket_families
[] = {
346 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
347 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
348 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
349 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
350 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
351 "ALG", "NFC", "VSOCK",
353 static DEFINE_STRARRAY(socket_families
);
355 #ifndef SOCK_TYPE_MASK
356 #define SOCK_TYPE_MASK 0xf
359 static size_t syscall_arg__scnprintf_socket_type(char *bf
, size_t size
,
360 struct syscall_arg
*arg
)
364 flags
= type
& ~SOCK_TYPE_MASK
;
366 type
&= SOCK_TYPE_MASK
;
368 * Can't use a strarray, MIPS may override for ABI reasons.
371 #define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
376 P_SK_TYPE(SEQPACKET
);
381 printed
= scnprintf(bf
, size
, "%#x", type
);
384 #define P_SK_FLAG(n) \
385 if (flags & SOCK_##n) { \
386 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
387 flags &= ~SOCK_##n; \
395 printed
+= scnprintf(bf
+ printed
, size
- printed
, "|%#x", flags
);
400 #define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
403 #define MSG_PROBE 0x10
405 #ifndef MSG_WAITFORONE
406 #define MSG_WAITFORONE 0x10000
408 #ifndef MSG_SENDPAGE_NOTLAST
409 #define MSG_SENDPAGE_NOTLAST 0x20000
412 #define MSG_FASTOPEN 0x20000000
415 static size_t syscall_arg__scnprintf_msg_flags(char *bf
, size_t size
,
416 struct syscall_arg
*arg
)
418 int printed
= 0, flags
= arg
->val
;
421 return scnprintf(bf
, size
, "NONE");
422 #define P_MSG_FLAG(n) \
423 if (flags & MSG_##n) { \
424 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
430 P_MSG_FLAG(DONTROUTE
);
435 P_MSG_FLAG(DONTWAIT
);
442 P_MSG_FLAG(ERRQUEUE
);
443 P_MSG_FLAG(NOSIGNAL
);
445 P_MSG_FLAG(WAITFORONE
);
446 P_MSG_FLAG(SENDPAGE_NOTLAST
);
447 P_MSG_FLAG(FASTOPEN
);
448 P_MSG_FLAG(CMSG_CLOEXEC
);
452 printed
+= scnprintf(bf
+ printed
, size
- printed
, "%s%#x", printed
? "|" : "", flags
);
457 #define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
459 static size_t syscall_arg__scnprintf_access_mode(char *bf
, size_t size
,
460 struct syscall_arg
*arg
)
465 if (mode
== F_OK
) /* 0 */
466 return scnprintf(bf
, size
, "F");
468 if (mode & n##_OK) { \
469 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
479 printed
+= scnprintf(bf
+ printed
, size
- printed
, "|%#x", mode
);
484 #define SCA_ACCMODE syscall_arg__scnprintf_access_mode
486 static size_t syscall_arg__scnprintf_open_flags(char *bf
, size_t size
,
487 struct syscall_arg
*arg
)
489 int printed
= 0, flags
= arg
->val
;
491 if (!(flags
& O_CREAT
))
492 arg
->mask
|= 1 << (arg
->idx
+ 1); /* Mask the mode parm */
495 return scnprintf(bf
, size
, "RDONLY");
497 if (flags & O_##n) { \
498 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
522 if ((flags
& O_SYNC
) == O_SYNC
)
523 printed
+= scnprintf(bf
+ printed
, size
- printed
, "%s%s", printed
? "|" : "", "SYNC");
535 printed
+= scnprintf(bf
+ printed
, size
- printed
, "%s%#x", printed
? "|" : "", flags
);
540 #define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
542 static size_t syscall_arg__scnprintf_eventfd_flags(char *bf
, size_t size
,
543 struct syscall_arg
*arg
)
545 int printed
= 0, flags
= arg
->val
;
548 return scnprintf(bf
, size
, "NONE");
550 if (flags & EFD_##n) { \
551 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
561 printed
+= scnprintf(bf
+ printed
, size
- printed
, "%s%#x", printed
? "|" : "", flags
);
566 #define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
568 static size_t syscall_arg__scnprintf_pipe_flags(char *bf
, size_t size
,
569 struct syscall_arg
*arg
)
571 int printed
= 0, flags
= arg
->val
;
574 if (flags & O_##n) { \
575 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
584 printed
+= scnprintf(bf
+ printed
, size
- printed
, "%s%#x", printed
? "|" : "", flags
);
589 #define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
591 static size_t syscall_arg__scnprintf_signum(char *bf
, size_t size
, struct syscall_arg
*arg
)
596 #define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
631 return scnprintf(bf
, size
, "%#x", sig
);
634 #define SCA_SIGNUM syscall_arg__scnprintf_signum
636 #define STRARRAY(arg, name, array) \
637 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
638 .arg_parm = { [arg] = &strarray__##array, }
640 static struct syscall_fmt
{
643 size_t (*arg_scnprintf
[6])(char *bf
, size_t size
, struct syscall_arg
*arg
);
649 { .name
= "access", .errmsg
= true,
650 .arg_scnprintf
= { [1] = SCA_ACCMODE
, /* mode */ }, },
651 { .name
= "arch_prctl", .errmsg
= true, .alias
= "prctl", },
652 { .name
= "brk", .hexret
= true,
653 .arg_scnprintf
= { [0] = SCA_HEX
, /* brk */ }, },
654 { .name
= "clock_gettime", .errmsg
= true, STRARRAY(0, clk_id
, clockid
), },
655 { .name
= "close", .errmsg
= true,
656 .arg_scnprintf
= { [0] = SCA_CLOSE_FD
, /* fd */ }, },
657 { .name
= "connect", .errmsg
= true, },
658 { .name
= "dup", .errmsg
= true,
659 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
660 { .name
= "dup2", .errmsg
= true,
661 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
662 { .name
= "dup3", .errmsg
= true,
663 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
664 { .name
= "epoll_ctl", .errmsg
= true, STRARRAY(1, op
, epoll_ctl_ops
), },
665 { .name
= "eventfd2", .errmsg
= true,
666 .arg_scnprintf
= { [1] = SCA_EFD_FLAGS
, /* flags */ }, },
667 { .name
= "faccessat", .errmsg
= true,
668 .arg_scnprintf
= { [0] = SCA_FDAT
, /* dfd */ }, },
669 { .name
= "fadvise64", .errmsg
= true,
670 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
671 { .name
= "fallocate", .errmsg
= true,
672 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
673 { .name
= "fchdir", .errmsg
= true,
674 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
675 { .name
= "fchmod", .errmsg
= true,
676 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
677 { .name
= "fchmodat", .errmsg
= true,
678 .arg_scnprintf
= { [0] = SCA_FDAT
, /* fd */ }, },
679 { .name
= "fchown", .errmsg
= true,
680 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
681 { .name
= "fchownat", .errmsg
= true,
682 .arg_scnprintf
= { [0] = SCA_FDAT
, /* fd */ }, },
683 { .name
= "fcntl", .errmsg
= true,
684 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */
685 [1] = SCA_STRARRAY
, /* cmd */ },
686 .arg_parm
= { [1] = &strarray__fcntl_cmds
, /* cmd */ }, },
687 { .name
= "fdatasync", .errmsg
= true,
688 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
689 { .name
= "flock", .errmsg
= true,
690 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */
691 [1] = SCA_FLOCK
, /* cmd */ }, },
692 { .name
= "fsetxattr", .errmsg
= true,
693 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
694 { .name
= "fstat", .errmsg
= true, .alias
= "newfstat",
695 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
696 { .name
= "fstatat", .errmsg
= true, .alias
= "newfstatat",
697 .arg_scnprintf
= { [0] = SCA_FDAT
, /* dfd */ }, },
698 { .name
= "fstatfs", .errmsg
= true,
699 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
700 { .name
= "fsync", .errmsg
= true,
701 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
702 { .name
= "ftruncate", .errmsg
= true,
703 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
704 { .name
= "futex", .errmsg
= true,
705 .arg_scnprintf
= { [1] = SCA_FUTEX_OP
, /* op */ }, },
706 { .name
= "futimesat", .errmsg
= true,
707 .arg_scnprintf
= { [0] = SCA_FDAT
, /* fd */ }, },
708 { .name
= "getdents", .errmsg
= true,
709 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
710 { .name
= "getdents64", .errmsg
= true,
711 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
712 { .name
= "getitimer", .errmsg
= true, STRARRAY(0, which
, itimers
), },
713 { .name
= "getrlimit", .errmsg
= true, STRARRAY(0, resource
, rlimit_resources
), },
714 { .name
= "ioctl", .errmsg
= true,
715 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */
716 [2] = SCA_HEX
, /* arg */ }, },
717 { .name
= "kill", .errmsg
= true,
718 .arg_scnprintf
= { [1] = SCA_SIGNUM
, /* sig */ }, },
719 { .name
= "linkat", .errmsg
= true,
720 .arg_scnprintf
= { [0] = SCA_FDAT
, /* fd */ }, },
721 { .name
= "lseek", .errmsg
= true,
722 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */
723 [2] = SCA_STRARRAY
, /* whence */ },
724 .arg_parm
= { [2] = &strarray__whences
, /* whence */ }, },
725 { .name
= "lstat", .errmsg
= true, .alias
= "newlstat", },
726 { .name
= "madvise", .errmsg
= true,
727 .arg_scnprintf
= { [0] = SCA_HEX
, /* start */
728 [2] = SCA_MADV_BHV
, /* behavior */ }, },
729 { .name
= "mkdirat", .errmsg
= true,
730 .arg_scnprintf
= { [0] = SCA_FDAT
, /* fd */ }, },
731 { .name
= "mknodat", .errmsg
= true,
732 .arg_scnprintf
= { [0] = SCA_FDAT
, /* fd */ }, },
733 { .name
= "mlock", .errmsg
= true,
734 .arg_scnprintf
= { [0] = SCA_HEX
, /* addr */ }, },
735 { .name
= "mlockall", .errmsg
= true,
736 .arg_scnprintf
= { [0] = SCA_HEX
, /* addr */ }, },
737 { .name
= "mmap", .hexret
= true,
738 .arg_scnprintf
= { [0] = SCA_HEX
, /* addr */
739 [2] = SCA_MMAP_PROT
, /* prot */
740 [3] = SCA_MMAP_FLAGS
, /* flags */ }, },
741 { .name
= "mprotect", .errmsg
= true,
742 .arg_scnprintf
= { [0] = SCA_HEX
, /* start */
743 [2] = SCA_MMAP_PROT
, /* prot */ }, },
744 { .name
= "mremap", .hexret
= true,
745 .arg_scnprintf
= { [0] = SCA_HEX
, /* addr */
746 [4] = SCA_HEX
, /* new_addr */ }, },
747 { .name
= "munlock", .errmsg
= true,
748 .arg_scnprintf
= { [0] = SCA_HEX
, /* addr */ }, },
749 { .name
= "munmap", .errmsg
= true,
750 .arg_scnprintf
= { [0] = SCA_HEX
, /* addr */ }, },
751 { .name
= "name_to_handle_at", .errmsg
= true,
752 .arg_scnprintf
= { [0] = SCA_FDAT
, /* dfd */ }, },
753 { .name
= "newfstatat", .errmsg
= true,
754 .arg_scnprintf
= { [0] = SCA_FDAT
, /* dfd */ }, },
755 { .name
= "open", .errmsg
= true,
756 .arg_scnprintf
= { [1] = SCA_OPEN_FLAGS
, /* flags */ }, },
757 { .name
= "open_by_handle_at", .errmsg
= true,
758 .arg_scnprintf
= { [0] = SCA_FDAT
, /* dfd */
759 [2] = SCA_OPEN_FLAGS
, /* flags */ }, },
760 { .name
= "openat", .errmsg
= true,
761 .arg_scnprintf
= { [0] = SCA_FDAT
, /* dfd */
762 [2] = SCA_OPEN_FLAGS
, /* flags */ }, },
763 { .name
= "pipe2", .errmsg
= true,
764 .arg_scnprintf
= { [1] = SCA_PIPE_FLAGS
, /* flags */ }, },
765 { .name
= "poll", .errmsg
= true, .timeout
= true, },
766 { .name
= "ppoll", .errmsg
= true, .timeout
= true, },
767 { .name
= "pread", .errmsg
= true, .alias
= "pread64",
768 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
769 { .name
= "preadv", .errmsg
= true, .alias
= "pread",
770 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
771 { .name
= "prlimit64", .errmsg
= true, STRARRAY(1, resource
, rlimit_resources
), },
772 { .name
= "pwrite", .errmsg
= true, .alias
= "pwrite64",
773 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
774 { .name
= "pwritev", .errmsg
= true,
775 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
776 { .name
= "read", .errmsg
= true,
777 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
778 { .name
= "readlinkat", .errmsg
= true,
779 .arg_scnprintf
= { [0] = SCA_FDAT
, /* dfd */ }, },
780 { .name
= "readv", .errmsg
= true,
781 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
782 { .name
= "recvfrom", .errmsg
= true,
783 .arg_scnprintf
= { [3] = SCA_MSG_FLAGS
, /* flags */ }, },
784 { .name
= "recvmmsg", .errmsg
= true,
785 .arg_scnprintf
= { [3] = SCA_MSG_FLAGS
, /* flags */ }, },
786 { .name
= "recvmsg", .errmsg
= true,
787 .arg_scnprintf
= { [2] = SCA_MSG_FLAGS
, /* flags */ }, },
788 { .name
= "renameat", .errmsg
= true,
789 .arg_scnprintf
= { [0] = SCA_FDAT
, /* dfd */ }, },
790 { .name
= "rt_sigaction", .errmsg
= true,
791 .arg_scnprintf
= { [0] = SCA_SIGNUM
, /* sig */ }, },
792 { .name
= "rt_sigprocmask", .errmsg
= true, STRARRAY(0, how
, sighow
), },
793 { .name
= "rt_sigqueueinfo", .errmsg
= true,
794 .arg_scnprintf
= { [1] = SCA_SIGNUM
, /* sig */ }, },
795 { .name
= "rt_tgsigqueueinfo", .errmsg
= true,
796 .arg_scnprintf
= { [2] = SCA_SIGNUM
, /* sig */ }, },
797 { .name
= "select", .errmsg
= true, .timeout
= true, },
798 { .name
= "sendmmsg", .errmsg
= true,
799 .arg_scnprintf
= { [3] = SCA_MSG_FLAGS
, /* flags */ }, },
800 { .name
= "sendmsg", .errmsg
= true,
801 .arg_scnprintf
= { [2] = SCA_MSG_FLAGS
, /* flags */ }, },
802 { .name
= "sendto", .errmsg
= true,
803 .arg_scnprintf
= { [3] = SCA_MSG_FLAGS
, /* flags */ }, },
804 { .name
= "setitimer", .errmsg
= true, STRARRAY(0, which
, itimers
), },
805 { .name
= "setrlimit", .errmsg
= true, STRARRAY(0, resource
, rlimit_resources
), },
806 { .name
= "shutdown", .errmsg
= true,
807 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
808 { .name
= "socket", .errmsg
= true,
809 .arg_scnprintf
= { [0] = SCA_STRARRAY
, /* family */
810 [1] = SCA_SK_TYPE
, /* type */ },
811 .arg_parm
= { [0] = &strarray__socket_families
, /* family */ }, },
812 { .name
= "socketpair", .errmsg
= true,
813 .arg_scnprintf
= { [0] = SCA_STRARRAY
, /* family */
814 [1] = SCA_SK_TYPE
, /* type */ },
815 .arg_parm
= { [0] = &strarray__socket_families
, /* family */ }, },
816 { .name
= "stat", .errmsg
= true, .alias
= "newstat", },
817 { .name
= "symlinkat", .errmsg
= true,
818 .arg_scnprintf
= { [0] = SCA_FDAT
, /* dfd */ }, },
819 { .name
= "tgkill", .errmsg
= true,
820 .arg_scnprintf
= { [2] = SCA_SIGNUM
, /* sig */ }, },
821 { .name
= "tkill", .errmsg
= true,
822 .arg_scnprintf
= { [1] = SCA_SIGNUM
, /* sig */ }, },
823 { .name
= "uname", .errmsg
= true, .alias
= "newuname", },
824 { .name
= "unlinkat", .errmsg
= true,
825 .arg_scnprintf
= { [0] = SCA_FDAT
, /* dfd */ }, },
826 { .name
= "utimensat", .errmsg
= true,
827 .arg_scnprintf
= { [0] = SCA_FDAT
, /* dirfd */ }, },
828 { .name
= "write", .errmsg
= true,
829 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
830 { .name
= "writev", .errmsg
= true,
831 .arg_scnprintf
= { [0] = SCA_FD
, /* fd */ }, },
834 static int syscall_fmt__cmp(const void *name
, const void *fmtp
)
836 const struct syscall_fmt
*fmt
= fmtp
;
837 return strcmp(name
, fmt
->name
);
840 static struct syscall_fmt
*syscall_fmt__find(const char *name
)
842 const int nmemb
= ARRAY_SIZE(syscall_fmts
);
843 return bsearch(name
, syscall_fmts
, nmemb
, sizeof(struct syscall_fmt
), syscall_fmt__cmp
);
847 struct event_format
*tp_format
;
850 struct syscall_fmt
*fmt
;
851 size_t (**arg_scnprintf
)(char *bf
, size_t size
, struct syscall_arg
*arg
);
855 static size_t fprintf_duration(unsigned long t
, FILE *fp
)
857 double duration
= (double)t
/ NSEC_PER_MSEC
;
858 size_t printed
= fprintf(fp
, "(");
861 printed
+= color_fprintf(fp
, PERF_COLOR_RED
, "%6.3f ms", duration
);
862 else if (duration
>= 0.01)
863 printed
+= color_fprintf(fp
, PERF_COLOR_YELLOW
, "%6.3f ms", duration
);
865 printed
+= color_fprintf(fp
, PERF_COLOR_NORMAL
, "%6.3f ms", duration
);
866 return printed
+ fprintf(fp
, "): ");
869 struct thread_trace
{
873 unsigned long nr_events
;
882 static struct thread_trace
*thread_trace__new(void)
884 struct thread_trace
*ttrace
= zalloc(sizeof(struct thread_trace
));
887 ttrace
->paths
.max
= -1;
892 static struct thread_trace
*thread__trace(struct thread
*thread
, FILE *fp
)
894 struct thread_trace
*ttrace
;
899 if (thread
->priv
== NULL
)
900 thread
->priv
= thread_trace__new();
902 if (thread
->priv
== NULL
)
905 ttrace
= thread
->priv
;
910 color_fprintf(fp
, PERF_COLOR_RED
,
911 "WARNING: not enough memory, dropping samples!\n");
916 struct perf_tool tool
;
920 struct syscall
*table
;
922 struct perf_record_opts opts
;
923 struct machine
*host
;
927 unsigned long nr_events
;
928 struct strlist
*ev_qualifier
;
929 bool not_ev_qualifier
;
931 struct intlist
*tid_list
;
932 struct intlist
*pid_list
;
934 bool multiple_threads
;
936 double duration_filter
;
940 static int thread__read_fd_path(struct thread
*thread
, int fd
)
942 struct thread_trace
*ttrace
= thread
->priv
;
943 char linkname
[PATH_MAX
], pathname
[PATH_MAX
];
947 if (thread
->pid_
== thread
->tid
) {
948 scnprintf(linkname
, sizeof(linkname
),
949 "/proc/%d/fd/%d", thread
->pid_
, fd
);
951 scnprintf(linkname
, sizeof(linkname
),
952 "/proc/%d/task/%d/fd/%d", thread
->pid_
, thread
->tid
, fd
);
955 if (lstat(linkname
, &st
) < 0 || st
.st_size
+ 1 > (off_t
)sizeof(pathname
))
958 ret
= readlink(linkname
, pathname
, sizeof(pathname
));
960 if (ret
< 0 || ret
> st
.st_size
)
963 pathname
[ret
] = '\0';
965 if (fd
> ttrace
->paths
.max
) {
966 char **npath
= realloc(ttrace
->paths
.table
, (fd
+ 1) * sizeof(char *));
971 if (ttrace
->paths
.max
!= -1) {
972 memset(npath
+ ttrace
->paths
.max
+ 1, 0,
973 (fd
- ttrace
->paths
.max
) * sizeof(char *));
975 memset(npath
, 0, (fd
+ 1) * sizeof(char *));
978 ttrace
->paths
.table
= npath
;
979 ttrace
->paths
.max
= fd
;
982 ttrace
->paths
.table
[fd
] = strdup(pathname
);
984 return ttrace
->paths
.table
[fd
] != NULL
? 0 : -1;
987 static const char *thread__fd_path(struct thread
*thread
, int fd
, bool live
)
989 struct thread_trace
*ttrace
= thread
->priv
;
997 if ((fd
> ttrace
->paths
.max
|| ttrace
->paths
.table
[fd
] == NULL
) &&
998 (!live
|| thread__read_fd_path(thread
, fd
)))
1001 return ttrace
->paths
.table
[fd
];
1004 static size_t syscall_arg__scnprintf_fd(char *bf
, size_t size
,
1005 struct syscall_arg
*arg
)
1008 size_t printed
= scnprintf(bf
, size
, "%d", fd
);
1009 const char *path
= thread__fd_path(arg
->thread
, fd
, arg
->trace
->live
);
1012 printed
+= scnprintf(bf
+ printed
, size
- printed
, "<%s>", path
);
1017 static size_t syscall_arg__scnprintf_close_fd(char *bf
, size_t size
,
1018 struct syscall_arg
*arg
)
1021 size_t printed
= syscall_arg__scnprintf_fd(bf
, size
, arg
);
1022 struct thread_trace
*ttrace
= arg
->thread
->priv
;
1024 if (ttrace
&& fd
>= 0 && fd
<= ttrace
->paths
.max
) {
1025 free(ttrace
->paths
.table
[fd
]);
1026 ttrace
->paths
.table
[fd
] = NULL
;
1032 static bool trace__filter_duration(struct trace
*trace
, double t
)
1034 return t
< (trace
->duration_filter
* NSEC_PER_MSEC
);
1037 static size_t trace__fprintf_tstamp(struct trace
*trace
, u64 tstamp
, FILE *fp
)
1039 double ts
= (double)(tstamp
- trace
->base_time
) / NSEC_PER_MSEC
;
1041 return fprintf(fp
, "%10.3f ", ts
);
1044 static bool done
= false;
1046 static void sig_handler(int sig __maybe_unused
)
1051 static size_t trace__fprintf_entry_head(struct trace
*trace
, struct thread
*thread
,
1052 u64 duration
, u64 tstamp
, FILE *fp
)
1054 size_t printed
= trace__fprintf_tstamp(trace
, tstamp
, fp
);
1055 printed
+= fprintf_duration(duration
, fp
);
1057 if (trace
->multiple_threads
) {
1058 if (trace
->show_comm
)
1059 printed
+= fprintf(fp
, "%.14s/", thread
->comm
);
1060 printed
+= fprintf(fp
, "%d ", thread
->tid
);
1066 static int trace__process_event(struct trace
*trace
, struct machine
*machine
,
1067 union perf_event
*event
)
1071 switch (event
->header
.type
) {
1072 case PERF_RECORD_LOST
:
1073 color_fprintf(trace
->output
, PERF_COLOR_RED
,
1074 "LOST %" PRIu64
" events!\n", event
->lost
.lost
);
1075 ret
= machine__process_lost_event(machine
, event
);
1077 ret
= machine__process_event(machine
, event
);
1084 static int trace__tool_process(struct perf_tool
*tool
,
1085 union perf_event
*event
,
1086 struct perf_sample
*sample __maybe_unused
,
1087 struct machine
*machine
)
1089 struct trace
*trace
= container_of(tool
, struct trace
, tool
);
1090 return trace__process_event(trace
, machine
, event
);
1093 static int trace__symbols_init(struct trace
*trace
, struct perf_evlist
*evlist
)
1095 int err
= symbol__init();
1100 trace
->host
= machine__new_host();
1101 if (trace
->host
== NULL
)
1104 if (perf_target__has_task(&trace
->opts
.target
)) {
1105 err
= perf_event__synthesize_thread_map(&trace
->tool
, evlist
->threads
,
1106 trace__tool_process
,
1109 err
= perf_event__synthesize_threads(&trace
->tool
, trace__tool_process
,
1119 static int syscall__set_arg_fmts(struct syscall
*sc
)
1121 struct format_field
*field
;
1124 sc
->arg_scnprintf
= calloc(sc
->tp_format
->format
.nr_fields
- 1, sizeof(void *));
1125 if (sc
->arg_scnprintf
== NULL
)
1129 sc
->arg_parm
= sc
->fmt
->arg_parm
;
1131 for (field
= sc
->tp_format
->format
.fields
->next
; field
; field
= field
->next
) {
1132 if (sc
->fmt
&& sc
->fmt
->arg_scnprintf
[idx
])
1133 sc
->arg_scnprintf
[idx
] = sc
->fmt
->arg_scnprintf
[idx
];
1134 else if (field
->flags
& FIELD_IS_POINTER
)
1135 sc
->arg_scnprintf
[idx
] = syscall_arg__scnprintf_hex
;
1142 static int trace__read_syscall_info(struct trace
*trace
, int id
)
1146 const char *name
= audit_syscall_to_name(id
, trace
->audit_machine
);
1151 if (id
> trace
->syscalls
.max
) {
1152 struct syscall
*nsyscalls
= realloc(trace
->syscalls
.table
, (id
+ 1) * sizeof(*sc
));
1154 if (nsyscalls
== NULL
)
1157 if (trace
->syscalls
.max
!= -1) {
1158 memset(nsyscalls
+ trace
->syscalls
.max
+ 1, 0,
1159 (id
- trace
->syscalls
.max
) * sizeof(*sc
));
1161 memset(nsyscalls
, 0, (id
+ 1) * sizeof(*sc
));
1164 trace
->syscalls
.table
= nsyscalls
;
1165 trace
->syscalls
.max
= id
;
1168 sc
= trace
->syscalls
.table
+ id
;
1171 if (trace
->ev_qualifier
) {
1172 bool in
= strlist__find(trace
->ev_qualifier
, name
) != NULL
;
1174 if (!(in
^ trace
->not_ev_qualifier
)) {
1175 sc
->filtered
= true;
1177 * No need to do read tracepoint information since this will be
1184 sc
->fmt
= syscall_fmt__find(sc
->name
);
1186 snprintf(tp_name
, sizeof(tp_name
), "sys_enter_%s", sc
->name
);
1187 sc
->tp_format
= event_format__new("syscalls", tp_name
);
1189 if (sc
->tp_format
== NULL
&& sc
->fmt
&& sc
->fmt
->alias
) {
1190 snprintf(tp_name
, sizeof(tp_name
), "sys_enter_%s", sc
->fmt
->alias
);
1191 sc
->tp_format
= event_format__new("syscalls", tp_name
);
1194 if (sc
->tp_format
== NULL
)
1197 return syscall__set_arg_fmts(sc
);
1200 static size_t syscall__scnprintf_args(struct syscall
*sc
, char *bf
, size_t size
,
1201 unsigned long *args
, struct trace
*trace
,
1202 struct thread
*thread
)
1206 if (sc
->tp_format
!= NULL
) {
1207 struct format_field
*field
;
1209 struct syscall_arg arg
= {
1216 for (field
= sc
->tp_format
->format
.fields
->next
; field
;
1217 field
= field
->next
, ++arg
.idx
, bit
<<= 1) {
1221 * Suppress this argument if its value is zero and
1222 * and we don't have a string associated in an
1225 if (args
[arg
.idx
] == 0 &&
1226 !(sc
->arg_scnprintf
&&
1227 sc
->arg_scnprintf
[arg
.idx
] == SCA_STRARRAY
&&
1228 sc
->arg_parm
[arg
.idx
]))
1231 printed
+= scnprintf(bf
+ printed
, size
- printed
,
1232 "%s%s: ", printed
? ", " : "", field
->name
);
1233 if (sc
->arg_scnprintf
&& sc
->arg_scnprintf
[arg
.idx
]) {
1234 arg
.val
= args
[arg
.idx
];
1236 arg
.parm
= sc
->arg_parm
[arg
.idx
];
1237 printed
+= sc
->arg_scnprintf
[arg
.idx
](bf
+ printed
,
1238 size
- printed
, &arg
);
1240 printed
+= scnprintf(bf
+ printed
, size
- printed
,
1241 "%ld", args
[arg
.idx
]);
1248 printed
+= scnprintf(bf
+ printed
, size
- printed
,
1250 printed
? ", " : "", i
, args
[i
]);
1258 typedef int (*tracepoint_handler
)(struct trace
*trace
, struct perf_evsel
*evsel
,
1259 struct perf_sample
*sample
);
1261 static struct syscall
*trace__syscall_info(struct trace
*trace
,
1262 struct perf_evsel
*evsel
,
1263 struct perf_sample
*sample
)
1265 int id
= perf_evsel__intval(evsel
, sample
, "id");
1270 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1271 * before that, leaving at a higher verbosity level till that is
1272 * explained. Reproduced with plain ftrace with:
1274 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1275 * grep "NR -1 " /t/trace_pipe
1277 * After generating some load on the machine.
1281 fprintf(trace
->output
, "Invalid syscall %d id, skipping (%s, %" PRIu64
") ...\n",
1282 id
, perf_evsel__name(evsel
), ++n
);
1287 if ((id
> trace
->syscalls
.max
|| trace
->syscalls
.table
[id
].name
== NULL
) &&
1288 trace__read_syscall_info(trace
, id
))
1291 if ((id
> trace
->syscalls
.max
|| trace
->syscalls
.table
[id
].name
== NULL
))
1294 return &trace
->syscalls
.table
[id
];
1298 fprintf(trace
->output
, "Problems reading syscall %d", id
);
1299 if (id
<= trace
->syscalls
.max
&& trace
->syscalls
.table
[id
].name
!= NULL
)
1300 fprintf(trace
->output
, "(%s)", trace
->syscalls
.table
[id
].name
);
1301 fputs(" information\n", trace
->output
);
1306 static int trace__sys_enter(struct trace
*trace
, struct perf_evsel
*evsel
,
1307 struct perf_sample
*sample
)
1312 struct thread
*thread
;
1313 struct syscall
*sc
= trace__syscall_info(trace
, evsel
, sample
);
1314 struct thread_trace
*ttrace
;
1322 thread
= machine__findnew_thread(trace
->host
, sample
->pid
, sample
->tid
);
1323 ttrace
= thread__trace(thread
, trace
->output
);
1327 args
= perf_evsel__rawptr(evsel
, sample
, "args");
1329 fprintf(trace
->output
, "Problems reading syscall arguments\n");
1333 ttrace
= thread
->priv
;
1335 if (ttrace
->entry_str
== NULL
) {
1336 ttrace
->entry_str
= malloc(1024);
1337 if (!ttrace
->entry_str
)
1341 ttrace
->entry_time
= sample
->time
;
1342 msg
= ttrace
->entry_str
;
1343 printed
+= scnprintf(msg
+ printed
, 1024 - printed
, "%s(", sc
->name
);
1345 printed
+= syscall__scnprintf_args(sc
, msg
+ printed
, 1024 - printed
,
1346 args
, trace
, thread
);
1348 if (!strcmp(sc
->name
, "exit_group") || !strcmp(sc
->name
, "exit")) {
1349 if (!trace
->duration_filter
) {
1350 trace__fprintf_entry_head(trace
, thread
, 1, sample
->time
, trace
->output
);
1351 fprintf(trace
->output
, "%-70s\n", ttrace
->entry_str
);
1354 ttrace
->entry_pending
= true;
1359 static int trace__sys_exit(struct trace
*trace
, struct perf_evsel
*evsel
,
1360 struct perf_sample
*sample
)
1364 struct thread
*thread
;
1365 struct syscall
*sc
= trace__syscall_info(trace
, evsel
, sample
);
1366 struct thread_trace
*ttrace
;
1374 thread
= machine__findnew_thread(trace
->host
, sample
->pid
, sample
->tid
);
1375 ttrace
= thread__trace(thread
, trace
->output
);
1379 ret
= perf_evsel__intval(evsel
, sample
, "ret");
1381 ttrace
= thread
->priv
;
1383 ttrace
->exit_time
= sample
->time
;
1385 if (ttrace
->entry_time
) {
1386 duration
= sample
->time
- ttrace
->entry_time
;
1387 if (trace__filter_duration(trace
, duration
))
1389 } else if (trace
->duration_filter
)
1392 trace__fprintf_entry_head(trace
, thread
, duration
, sample
->time
, trace
->output
);
1394 if (ttrace
->entry_pending
) {
1395 fprintf(trace
->output
, "%-70s", ttrace
->entry_str
);
1397 fprintf(trace
->output
, " ... [");
1398 color_fprintf(trace
->output
, PERF_COLOR_YELLOW
, "continued");
1399 fprintf(trace
->output
, "]: %s()", sc
->name
);
1402 if (sc
->fmt
== NULL
) {
1404 fprintf(trace
->output
, ") = %d", ret
);
1405 } else if (ret
< 0 && sc
->fmt
->errmsg
) {
1407 const char *emsg
= strerror_r(-ret
, bf
, sizeof(bf
)),
1408 *e
= audit_errno_to_name(-ret
);
1410 fprintf(trace
->output
, ") = -1 %s %s", e
, emsg
);
1411 } else if (ret
== 0 && sc
->fmt
->timeout
)
1412 fprintf(trace
->output
, ") = 0 Timeout");
1413 else if (sc
->fmt
->hexret
)
1414 fprintf(trace
->output
, ") = %#x", ret
);
1418 fputc('\n', trace
->output
);
1420 ttrace
->entry_pending
= false;
1425 static int trace__sched_stat_runtime(struct trace
*trace
, struct perf_evsel
*evsel
,
1426 struct perf_sample
*sample
)
1428 u64 runtime
= perf_evsel__intval(evsel
, sample
, "runtime");
1429 double runtime_ms
= (double)runtime
/ NSEC_PER_MSEC
;
1430 struct thread
*thread
= machine__findnew_thread(trace
->host
,
1433 struct thread_trace
*ttrace
= thread__trace(thread
, trace
->output
);
1438 ttrace
->runtime_ms
+= runtime_ms
;
1439 trace
->runtime_ms
+= runtime_ms
;
1443 fprintf(trace
->output
, "%s: comm=%s,pid=%u,runtime=%" PRIu64
",vruntime=%" PRIu64
")\n",
1445 perf_evsel__strval(evsel
, sample
, "comm"),
1446 (pid_t
)perf_evsel__intval(evsel
, sample
, "pid"),
1448 perf_evsel__intval(evsel
, sample
, "vruntime"));
1452 static bool skip_sample(struct trace
*trace
, struct perf_sample
*sample
)
1454 if ((trace
->pid_list
&& intlist__find(trace
->pid_list
, sample
->pid
)) ||
1455 (trace
->tid_list
&& intlist__find(trace
->tid_list
, sample
->tid
)))
1458 if (trace
->pid_list
|| trace
->tid_list
)
1464 static int trace__process_sample(struct perf_tool
*tool
,
1465 union perf_event
*event __maybe_unused
,
1466 struct perf_sample
*sample
,
1467 struct perf_evsel
*evsel
,
1468 struct machine
*machine __maybe_unused
)
1470 struct trace
*trace
= container_of(tool
, struct trace
, tool
);
1473 tracepoint_handler handler
= evsel
->handler
.func
;
1475 if (skip_sample(trace
, sample
))
1478 if (!trace
->full_time
&& trace
->base_time
== 0)
1479 trace
->base_time
= sample
->time
;
1482 handler(trace
, evsel
, sample
);
1488 perf_session__has_tp(struct perf_session
*session
, const char *name
)
1490 struct perf_evsel
*evsel
;
1492 evsel
= perf_evlist__find_tracepoint_by_name(session
->evlist
, name
);
1494 return evsel
!= NULL
;
1497 static int parse_target_str(struct trace
*trace
)
1499 if (trace
->opts
.target
.pid
) {
1500 trace
->pid_list
= intlist__new(trace
->opts
.target
.pid
);
1501 if (trace
->pid_list
== NULL
) {
1502 pr_err("Error parsing process id string\n");
1507 if (trace
->opts
.target
.tid
) {
1508 trace
->tid_list
= intlist__new(trace
->opts
.target
.tid
);
1509 if (trace
->tid_list
== NULL
) {
1510 pr_err("Error parsing thread id string\n");
1518 static int trace__record(int argc
, const char **argv
)
1520 unsigned int rec_argc
, i
, j
;
1521 const char **rec_argv
;
1522 const char * const record_args
[] = {
1527 "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit",
1530 rec_argc
= ARRAY_SIZE(record_args
) + argc
;
1531 rec_argv
= calloc(rec_argc
+ 1, sizeof(char *));
1533 if (rec_argv
== NULL
)
1536 for (i
= 0; i
< ARRAY_SIZE(record_args
); i
++)
1537 rec_argv
[i
] = record_args
[i
];
1539 for (j
= 0; j
< (unsigned int)argc
; j
++, i
++)
1540 rec_argv
[i
] = argv
[j
];
1542 return cmd_record(i
, rec_argv
, NULL
);
1545 static int trace__run(struct trace
*trace
, int argc
, const char **argv
)
1547 struct perf_evlist
*evlist
= perf_evlist__new();
1548 struct perf_evsel
*evsel
;
1550 unsigned long before
;
1551 const bool forks
= argc
> 0;
1555 if (evlist
== NULL
) {
1556 fprintf(trace
->output
, "Not enough memory to run!\n");
1560 if (perf_evlist__add_newtp(evlist
, "raw_syscalls", "sys_enter", trace__sys_enter
) ||
1561 perf_evlist__add_newtp(evlist
, "raw_syscalls", "sys_exit", trace__sys_exit
)) {
1562 fprintf(trace
->output
, "Couldn't read the raw_syscalls tracepoints information!\n");
1563 goto out_delete_evlist
;
1567 perf_evlist__add_newtp(evlist
, "sched", "sched_stat_runtime",
1568 trace__sched_stat_runtime
)) {
1569 fprintf(trace
->output
, "Couldn't read the sched_stat_runtime tracepoint information!\n");
1570 goto out_delete_evlist
;
1573 err
= perf_evlist__create_maps(evlist
, &trace
->opts
.target
);
1575 fprintf(trace
->output
, "Problems parsing the target to trace, check your options!\n");
1576 goto out_delete_evlist
;
1579 err
= trace__symbols_init(trace
, evlist
);
1581 fprintf(trace
->output
, "Problems initializing symbol libraries!\n");
1582 goto out_delete_maps
;
1585 perf_evlist__config(evlist
, &trace
->opts
);
1587 signal(SIGCHLD
, sig_handler
);
1588 signal(SIGINT
, sig_handler
);
1591 err
= perf_evlist__prepare_workload(evlist
, &trace
->opts
.target
,
1592 argv
, false, false);
1594 fprintf(trace
->output
, "Couldn't run the workload!\n");
1595 goto out_delete_maps
;
1599 err
= perf_evlist__open(evlist
);
1601 fprintf(trace
->output
, "Couldn't create the events: %s\n", strerror(errno
));
1602 goto out_delete_maps
;
1605 err
= perf_evlist__mmap(evlist
, UINT_MAX
, false);
1607 fprintf(trace
->output
, "Couldn't mmap the events: %s\n", strerror(errno
));
1608 goto out_close_evlist
;
1611 perf_evlist__enable(evlist
);
1614 perf_evlist__start_workload(evlist
);
1616 trace
->multiple_threads
= evlist
->threads
->map
[0] == -1 || evlist
->threads
->nr
> 1;
1618 before
= trace
->nr_events
;
1620 for (i
= 0; i
< evlist
->nr_mmaps
; i
++) {
1621 union perf_event
*event
;
1623 while ((event
= perf_evlist__mmap_read(evlist
, i
)) != NULL
) {
1624 const u32 type
= event
->header
.type
;
1625 tracepoint_handler handler
;
1626 struct perf_sample sample
;
1630 err
= perf_evlist__parse_sample(evlist
, event
, &sample
);
1632 fprintf(trace
->output
, "Can't parse sample, err = %d, skipping...\n", err
);
1636 if (!trace
->full_time
&& trace
->base_time
== 0)
1637 trace
->base_time
= sample
.time
;
1639 if (type
!= PERF_RECORD_SAMPLE
) {
1640 trace__process_event(trace
, trace
->host
, event
);
1644 evsel
= perf_evlist__id2evsel(evlist
, sample
.id
);
1645 if (evsel
== NULL
) {
1646 fprintf(trace
->output
, "Unknown tp ID %" PRIu64
", skipping...\n", sample
.id
);
1650 if (sample
.raw_data
== NULL
) {
1651 fprintf(trace
->output
, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
1652 perf_evsel__name(evsel
), sample
.tid
,
1653 sample
.cpu
, sample
.raw_size
);
1657 handler
= evsel
->handler
.func
;
1658 handler(trace
, evsel
, &sample
);
1661 goto out_unmap_evlist
;
1665 if (trace
->nr_events
== before
) {
1667 goto out_unmap_evlist
;
1669 poll(evlist
->pollfd
, evlist
->nr_fds
, -1);
1673 perf_evlist__disable(evlist
);
1678 perf_evlist__munmap(evlist
);
1680 perf_evlist__close(evlist
);
1682 perf_evlist__delete_maps(evlist
);
1684 perf_evlist__delete(evlist
);
1686 trace
->live
= false;
1690 static int trace__replay(struct trace
*trace
)
1692 const struct perf_evsel_str_handler handlers
[] = {
1693 { "raw_syscalls:sys_enter", trace__sys_enter
, },
1694 { "raw_syscalls:sys_exit", trace__sys_exit
, },
1697 struct perf_session
*session
;
1700 trace
->tool
.sample
= trace__process_sample
;
1701 trace
->tool
.mmap
= perf_event__process_mmap
;
1702 trace
->tool
.mmap2
= perf_event__process_mmap2
;
1703 trace
->tool
.comm
= perf_event__process_comm
;
1704 trace
->tool
.exit
= perf_event__process_exit
;
1705 trace
->tool
.fork
= perf_event__process_fork
;
1706 trace
->tool
.attr
= perf_event__process_attr
;
1707 trace
->tool
.tracing_data
= perf_event__process_tracing_data
;
1708 trace
->tool
.build_id
= perf_event__process_build_id
;
1710 trace
->tool
.ordered_samples
= true;
1711 trace
->tool
.ordering_requires_timestamps
= true;
1713 /* add tid to output */
1714 trace
->multiple_threads
= true;
1716 if (symbol__init() < 0)
1719 session
= perf_session__new(input_name
, O_RDONLY
, 0, false,
1721 if (session
== NULL
)
1724 trace
->host
= &session
->machines
.host
;
1726 err
= perf_session__set_tracepoints_handlers(session
, handlers
);
1730 if (!perf_session__has_tp(session
, "raw_syscalls:sys_enter")) {
1731 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1735 if (!perf_session__has_tp(session
, "raw_syscalls:sys_exit")) {
1736 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1740 err
= parse_target_str(trace
);
1746 err
= perf_session__process_events(session
, &trace
->tool
);
1748 pr_err("Failed to process events, error %d", err
);
1751 perf_session__delete(session
);
1756 static size_t trace__fprintf_threads_header(FILE *fp
)
1760 printed
= fprintf(fp
, "\n _____________________________________________________________________\n");
1761 printed
+= fprintf(fp
," __) Summary of events (__\n\n");
1762 printed
+= fprintf(fp
," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1763 printed
+= fprintf(fp
," _____________________________________________________________________\n\n");
1768 /* struct used to pass data to per-thread function */
1769 struct summary_data
{
1771 struct trace
*trace
;
1775 static int trace__fprintf_one_thread(struct thread
*thread
, void *priv
)
1777 struct summary_data
*data
= priv
;
1778 FILE *fp
= data
->fp
;
1779 size_t printed
= data
->printed
;
1780 struct trace
*trace
= data
->trace
;
1781 struct thread_trace
*ttrace
= thread
->priv
;
1788 ratio
= (double)ttrace
->nr_events
/ trace
->nr_events
* 100.0;
1790 color
= PERF_COLOR_NORMAL
;
1792 color
= PERF_COLOR_RED
;
1793 else if (ratio
> 25.0)
1794 color
= PERF_COLOR_GREEN
;
1795 else if (ratio
> 5.0)
1796 color
= PERF_COLOR_YELLOW
;
1798 printed
+= color_fprintf(fp
, color
, "%20s", thread
->comm
);
1799 printed
+= fprintf(fp
, " - %-5d :%11lu [", thread
->tid
, ttrace
->nr_events
);
1800 printed
+= color_fprintf(fp
, color
, "%5.1f%%", ratio
);
1801 printed
+= fprintf(fp
, " ] %10.3f ms\n", ttrace
->runtime_ms
);
1803 data
->printed
+= printed
;
1808 static size_t trace__fprintf_thread_summary(struct trace
*trace
, FILE *fp
)
1810 struct summary_data data
= {
1814 data
.printed
= trace__fprintf_threads_header(fp
);
1816 machine__for_each_thread(trace
->host
, trace__fprintf_one_thread
, &data
);
1818 return data
.printed
;
1821 static int trace__set_duration(const struct option
*opt
, const char *str
,
1822 int unset __maybe_unused
)
1824 struct trace
*trace
= opt
->value
;
1826 trace
->duration_filter
= atof(str
);
1830 static int trace__open_output(struct trace
*trace
, const char *filename
)
1834 if (!stat(filename
, &st
) && st
.st_size
) {
1835 char oldname
[PATH_MAX
];
1837 scnprintf(oldname
, sizeof(oldname
), "%s.old", filename
);
1839 rename(filename
, oldname
);
1842 trace
->output
= fopen(filename
, "w");
1844 return trace
->output
== NULL
? -errno
: 0;
1847 int cmd_trace(int argc
, const char **argv
, const char *prefix __maybe_unused
)
1849 const char * const trace_usage
[] = {
1850 "perf trace [<options>] [<command>]",
1851 "perf trace [<options>] -- <command> [<options>]",
1852 "perf trace record [<options>] [<command>]",
1853 "perf trace record [<options>] -- <command> [<options>]",
1856 struct trace trace
= {
1857 .audit_machine
= audit_detect_machine(),
1866 .user_freq
= UINT_MAX
,
1867 .user_interval
= ULLONG_MAX
,
1874 const char *output_name
= NULL
;
1875 const char *ev_qualifier_str
= NULL
;
1876 const struct option trace_options
[] = {
1877 OPT_BOOLEAN(0, "comm", &trace
.show_comm
,
1878 "show the thread COMM next to its id"),
1879 OPT_STRING('e', "expr", &ev_qualifier_str
, "expr",
1880 "list of events to trace"),
1881 OPT_STRING('o', "output", &output_name
, "file", "output file name"),
1882 OPT_STRING('i', "input", &input_name
, "file", "Analyze events in file"),
1883 OPT_STRING('p', "pid", &trace
.opts
.target
.pid
, "pid",
1884 "trace events on existing process id"),
1885 OPT_STRING('t', "tid", &trace
.opts
.target
.tid
, "tid",
1886 "trace events on existing thread id"),
1887 OPT_BOOLEAN('a', "all-cpus", &trace
.opts
.target
.system_wide
,
1888 "system-wide collection from all CPUs"),
1889 OPT_STRING('C', "cpu", &trace
.opts
.target
.cpu_list
, "cpu",
1890 "list of cpus to monitor"),
1891 OPT_BOOLEAN(0, "no-inherit", &trace
.opts
.no_inherit
,
1892 "child tasks do not inherit counters"),
1893 OPT_CALLBACK('m', "mmap-pages", &trace
.opts
.mmap_pages
, "pages",
1894 "number of mmap data pages",
1895 perf_evlist__parse_mmap_pages
),
1896 OPT_STRING('u', "uid", &trace
.opts
.target
.uid_str
, "user",
1898 OPT_CALLBACK(0, "duration", &trace
, "float",
1899 "show only events with duration > N.M ms",
1900 trace__set_duration
),
1901 OPT_BOOLEAN(0, "sched", &trace
.sched
, "show blocking scheduler events"),
1902 OPT_INCR('v', "verbose", &verbose
, "be more verbose"),
1903 OPT_BOOLEAN('T', "time", &trace
.full_time
,
1904 "Show full timestamp, not time relative to first start"),
1910 if ((argc
> 1) && (strcmp(argv
[1], "record") == 0))
1911 return trace__record(argc
-2, &argv
[2]);
1913 argc
= parse_options(argc
, argv
, trace_options
, trace_usage
, 0);
1915 if (output_name
!= NULL
) {
1916 err
= trace__open_output(&trace
, output_name
);
1918 perror("failed to create output file");
1923 if (ev_qualifier_str
!= NULL
) {
1924 const char *s
= ev_qualifier_str
;
1926 trace
.not_ev_qualifier
= *s
== '!';
1927 if (trace
.not_ev_qualifier
)
1929 trace
.ev_qualifier
= strlist__new(true, s
);
1930 if (trace
.ev_qualifier
== NULL
) {
1931 fputs("Not enough memory to parse event qualifier",
1938 err
= perf_target__validate(&trace
.opts
.target
);
1940 perf_target__strerror(&trace
.opts
.target
, err
, bf
, sizeof(bf
));
1941 fprintf(trace
.output
, "%s", bf
);
1945 err
= perf_target__parse_uid(&trace
.opts
.target
);
1947 perf_target__strerror(&trace
.opts
.target
, err
, bf
, sizeof(bf
));
1948 fprintf(trace
.output
, "%s", bf
);
1952 if (!argc
&& perf_target__none(&trace
.opts
.target
))
1953 trace
.opts
.target
.system_wide
= true;
1956 err
= trace__replay(&trace
);
1958 err
= trace__run(&trace
, argc
, argv
);
1960 if (trace
.sched
&& !err
)
1961 trace__fprintf_thread_summary(&trace
, trace
.output
);
1964 if (output_name
!= NULL
)
1965 fclose(trace
.output
);