diff options
102 files changed, 3616 insertions, 539 deletions
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h index f35eb72739c0..9de8780ac8d9 100644 --- a/include/uapi/linux/perf_event.h +++ b/include/uapi/linux/perf_event.h | |||
@@ -646,10 +646,12 @@ struct perf_event_mmap_page { | |||
646 | * | 646 | * |
647 | * PERF_RECORD_MISC_MMAP_DATA - PERF_RECORD_MMAP* events | 647 | * PERF_RECORD_MISC_MMAP_DATA - PERF_RECORD_MMAP* events |
648 | * PERF_RECORD_MISC_COMM_EXEC - PERF_RECORD_COMM event | 648 | * PERF_RECORD_MISC_COMM_EXEC - PERF_RECORD_COMM event |
649 | * PERF_RECORD_MISC_FORK_EXEC - PERF_RECORD_FORK event (perf internal) | ||
649 | * PERF_RECORD_MISC_SWITCH_OUT - PERF_RECORD_SWITCH* events | 650 | * PERF_RECORD_MISC_SWITCH_OUT - PERF_RECORD_SWITCH* events |
650 | */ | 651 | */ |
651 | #define PERF_RECORD_MISC_MMAP_DATA (1 << 13) | 652 | #define PERF_RECORD_MISC_MMAP_DATA (1 << 13) |
652 | #define PERF_RECORD_MISC_COMM_EXEC (1 << 13) | 653 | #define PERF_RECORD_MISC_COMM_EXEC (1 << 13) |
654 | #define PERF_RECORD_MISC_FORK_EXEC (1 << 13) | ||
653 | #define PERF_RECORD_MISC_SWITCH_OUT (1 << 13) | 655 | #define PERF_RECORD_MISC_SWITCH_OUT (1 << 13) |
654 | /* | 656 | /* |
655 | * These PERF_RECORD_MISC_* flags below are safely reused | 657 | * These PERF_RECORD_MISC_* flags below are safely reused |
diff --git a/kernel/events/core.c b/kernel/events/core.c index 8c490130c4fb..84530ab358c3 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -750,7 +750,7 @@ static inline void update_cgrp_time_from_event(struct perf_event *event) | |||
750 | /* | 750 | /* |
751 | * Do not update time when cgroup is not active | 751 | * Do not update time when cgroup is not active |
752 | */ | 752 | */ |
753 | if (cgroup_is_descendant(cgrp->css.cgroup, event->cgrp->css.cgroup)) | 753 | if (cgroup_is_descendant(cgrp->css.cgroup, event->cgrp->css.cgroup)) |
754 | __update_cgrp_time(event->cgrp); | 754 | __update_cgrp_time(event->cgrp); |
755 | } | 755 | } |
756 | 756 | ||
diff --git a/tools/arch/arm64/include/uapi/asm/unistd.h b/tools/arch/arm64/include/uapi/asm/unistd.h index 5072cbd15c82..dae1584cf017 100644 --- a/tools/arch/arm64/include/uapi/asm/unistd.h +++ b/tools/arch/arm64/include/uapi/asm/unistd.h | |||
@@ -16,5 +16,6 @@ | |||
16 | */ | 16 | */ |
17 | 17 | ||
18 | #define __ARCH_WANT_RENAMEAT | 18 | #define __ARCH_WANT_RENAMEAT |
19 | #define __ARCH_WANT_NEW_STAT | ||
19 | 20 | ||
20 | #include <asm-generic/unistd.h> | 21 | #include <asm-generic/unistd.h> |
diff --git a/tools/arch/powerpc/include/uapi/asm/kvm.h b/tools/arch/powerpc/include/uapi/asm/kvm.h index 1b32b56a03d3..8c876c166ef2 100644 --- a/tools/arch/powerpc/include/uapi/asm/kvm.h +++ b/tools/arch/powerpc/include/uapi/asm/kvm.h | |||
@@ -634,6 +634,7 @@ struct kvm_ppc_cpu_char { | |||
634 | 634 | ||
635 | #define KVM_REG_PPC_DEC_EXPIRY (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbe) | 635 | #define KVM_REG_PPC_DEC_EXPIRY (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbe) |
636 | #define KVM_REG_PPC_ONLINE (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xbf) | 636 | #define KVM_REG_PPC_ONLINE (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xbf) |
637 | #define KVM_REG_PPC_PTCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc0) | ||
637 | 638 | ||
638 | /* Transactional Memory checkpointed state: | 639 | /* Transactional Memory checkpointed state: |
639 | * This is all GPRs, all VSX regs and a subset of SPRs | 640 | * This is all GPRs, all VSX regs and a subset of SPRs |
diff --git a/tools/arch/s390/include/uapi/asm/kvm.h b/tools/arch/s390/include/uapi/asm/kvm.h index 9a50f02b9894..16511d97e8dc 100644 --- a/tools/arch/s390/include/uapi/asm/kvm.h +++ b/tools/arch/s390/include/uapi/asm/kvm.h | |||
@@ -160,6 +160,8 @@ struct kvm_s390_vm_cpu_subfunc { | |||
160 | #define KVM_S390_VM_CRYPTO_ENABLE_DEA_KW 1 | 160 | #define KVM_S390_VM_CRYPTO_ENABLE_DEA_KW 1 |
161 | #define KVM_S390_VM_CRYPTO_DISABLE_AES_KW 2 | 161 | #define KVM_S390_VM_CRYPTO_DISABLE_AES_KW 2 |
162 | #define KVM_S390_VM_CRYPTO_DISABLE_DEA_KW 3 | 162 | #define KVM_S390_VM_CRYPTO_DISABLE_DEA_KW 3 |
163 | #define KVM_S390_VM_CRYPTO_ENABLE_APIE 4 | ||
164 | #define KVM_S390_VM_CRYPTO_DISABLE_APIE 5 | ||
163 | 165 | ||
164 | /* kvm attributes for migration mode */ | 166 | /* kvm attributes for migration mode */ |
165 | #define KVM_S390_VM_MIGRATION_STOP 0 | 167 | #define KVM_S390_VM_MIGRATION_STOP 0 |
diff --git a/tools/arch/x86/include/uapi/asm/kvm.h b/tools/arch/x86/include/uapi/asm/kvm.h index 8a6eff9c27f3..dabfcf7c3941 100644 --- a/tools/arch/x86/include/uapi/asm/kvm.h +++ b/tools/arch/x86/include/uapi/asm/kvm.h | |||
@@ -300,10 +300,7 @@ struct kvm_vcpu_events { | |||
300 | __u8 injected; | 300 | __u8 injected; |
301 | __u8 nr; | 301 | __u8 nr; |
302 | __u8 has_error_code; | 302 | __u8 has_error_code; |
303 | union { | 303 | __u8 pending; |
304 | __u8 pad; | ||
305 | __u8 pending; | ||
306 | }; | ||
307 | __u32 error_code; | 304 | __u32 error_code; |
308 | } exception; | 305 | } exception; |
309 | struct { | 306 | struct { |
@@ -387,6 +384,7 @@ struct kvm_sync_regs { | |||
387 | 384 | ||
388 | #define KVM_STATE_NESTED_GUEST_MODE 0x00000001 | 385 | #define KVM_STATE_NESTED_GUEST_MODE 0x00000001 |
389 | #define KVM_STATE_NESTED_RUN_PENDING 0x00000002 | 386 | #define KVM_STATE_NESTED_RUN_PENDING 0x00000002 |
387 | #define KVM_STATE_NESTED_EVMCS 0x00000004 | ||
390 | 388 | ||
391 | #define KVM_STATE_NESTED_SMM_GUEST_MODE 0x00000001 | 389 | #define KVM_STATE_NESTED_SMM_GUEST_MODE 0x00000001 |
392 | #define KVM_STATE_NESTED_SMM_VMXON 0x00000002 | 390 | #define KVM_STATE_NESTED_SMM_VMXON 0x00000002 |
diff --git a/tools/include/uapi/asm-generic/unistd.h b/tools/include/uapi/asm-generic/unistd.h index df4bedb9b01c..538546edbfbd 100644 --- a/tools/include/uapi/asm-generic/unistd.h +++ b/tools/include/uapi/asm-generic/unistd.h | |||
@@ -242,10 +242,12 @@ __SYSCALL(__NR_tee, sys_tee) | |||
242 | /* fs/stat.c */ | 242 | /* fs/stat.c */ |
243 | #define __NR_readlinkat 78 | 243 | #define __NR_readlinkat 78 |
244 | __SYSCALL(__NR_readlinkat, sys_readlinkat) | 244 | __SYSCALL(__NR_readlinkat, sys_readlinkat) |
245 | #if defined(__ARCH_WANT_NEW_STAT) || defined(__ARCH_WANT_STAT64) | ||
245 | #define __NR3264_fstatat 79 | 246 | #define __NR3264_fstatat 79 |
246 | __SC_3264(__NR3264_fstatat, sys_fstatat64, sys_newfstatat) | 247 | __SC_3264(__NR3264_fstatat, sys_fstatat64, sys_newfstatat) |
247 | #define __NR3264_fstat 80 | 248 | #define __NR3264_fstat 80 |
248 | __SC_3264(__NR3264_fstat, sys_fstat64, sys_newfstat) | 249 | __SC_3264(__NR3264_fstat, sys_fstat64, sys_newfstat) |
250 | #endif | ||
249 | 251 | ||
250 | /* fs/sync.c */ | 252 | /* fs/sync.c */ |
251 | #define __NR_sync 81 | 253 | #define __NR_sync 81 |
diff --git a/tools/include/uapi/linux/fs.h b/tools/include/uapi/linux/fs.h new file mode 100644 index 000000000000..a441ea1bfe6d --- /dev/null +++ b/tools/include/uapi/linux/fs.h | |||
@@ -0,0 +1,393 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ | ||
2 | #ifndef _UAPI_LINUX_FS_H | ||
3 | #define _UAPI_LINUX_FS_H | ||
4 | |||
5 | /* | ||
6 | * This file has definitions for some important file table structures | ||
7 | * and constants and structures used by various generic file system | ||
8 | * ioctl's. Please do not make any changes in this file before | ||
9 | * sending patches for review to linux-fsdevel@vger.kernel.org and | ||
10 | * linux-api@vger.kernel.org. | ||
11 | */ | ||
12 | |||
13 | #include <linux/limits.h> | ||
14 | #include <linux/ioctl.h> | ||
15 | #include <linux/types.h> | ||
16 | |||
17 | /* | ||
18 | * It's silly to have NR_OPEN bigger than NR_FILE, but you can change | ||
19 | * the file limit at runtime and only root can increase the per-process | ||
20 | * nr_file rlimit, so it's safe to set up a ridiculously high absolute | ||
21 | * upper limit on files-per-process. | ||
22 | * | ||
23 | * Some programs (notably those using select()) may have to be | ||
24 | * recompiled to take full advantage of the new limits.. | ||
25 | */ | ||
26 | |||
27 | /* Fixed constants first: */ | ||
28 | #undef NR_OPEN | ||
29 | #define INR_OPEN_CUR 1024 /* Initial setting for nfile rlimits */ | ||
30 | #define INR_OPEN_MAX 4096 /* Hard limit for nfile rlimits */ | ||
31 | |||
32 | #define BLOCK_SIZE_BITS 10 | ||
33 | #define BLOCK_SIZE (1<<BLOCK_SIZE_BITS) | ||
34 | |||
35 | #define SEEK_SET 0 /* seek relative to beginning of file */ | ||
36 | #define SEEK_CUR 1 /* seek relative to current file position */ | ||
37 | #define SEEK_END 2 /* seek relative to end of file */ | ||
38 | #define SEEK_DATA 3 /* seek to the next data */ | ||
39 | #define SEEK_HOLE 4 /* seek to the next hole */ | ||
40 | #define SEEK_MAX SEEK_HOLE | ||
41 | |||
42 | #define RENAME_NOREPLACE (1 << 0) /* Don't overwrite target */ | ||
43 | #define RENAME_EXCHANGE (1 << 1) /* Exchange source and dest */ | ||
44 | #define RENAME_WHITEOUT (1 << 2) /* Whiteout source */ | ||
45 | |||
46 | struct file_clone_range { | ||
47 | __s64 src_fd; | ||
48 | __u64 src_offset; | ||
49 | __u64 src_length; | ||
50 | __u64 dest_offset; | ||
51 | }; | ||
52 | |||
53 | struct fstrim_range { | ||
54 | __u64 start; | ||
55 | __u64 len; | ||
56 | __u64 minlen; | ||
57 | }; | ||
58 | |||
59 | /* extent-same (dedupe) ioctls; these MUST match the btrfs ioctl definitions */ | ||
60 | #define FILE_DEDUPE_RANGE_SAME 0 | ||
61 | #define FILE_DEDUPE_RANGE_DIFFERS 1 | ||
62 | |||
63 | /* from struct btrfs_ioctl_file_extent_same_info */ | ||
64 | struct file_dedupe_range_info { | ||
65 | __s64 dest_fd; /* in - destination file */ | ||
66 | __u64 dest_offset; /* in - start of extent in destination */ | ||
67 | __u64 bytes_deduped; /* out - total # of bytes we were able | ||
68 | * to dedupe from this file. */ | ||
69 | /* status of this dedupe operation: | ||
70 | * < 0 for error | ||
71 | * == FILE_DEDUPE_RANGE_SAME if dedupe succeeds | ||
72 | * == FILE_DEDUPE_RANGE_DIFFERS if data differs | ||
73 | */ | ||
74 | __s32 status; /* out - see above description */ | ||
75 | __u32 reserved; /* must be zero */ | ||
76 | }; | ||
77 | |||
78 | /* from struct btrfs_ioctl_file_extent_same_args */ | ||
79 | struct file_dedupe_range { | ||
80 | __u64 src_offset; /* in - start of extent in source */ | ||
81 | __u64 src_length; /* in - length of extent */ | ||
82 | __u16 dest_count; /* in - total elements in info array */ | ||
83 | __u16 reserved1; /* must be zero */ | ||
84 | __u32 reserved2; /* must be zero */ | ||
85 | struct file_dedupe_range_info info[0]; | ||
86 | }; | ||
87 | |||
88 | /* And dynamically-tunable limits and defaults: */ | ||
89 | struct files_stat_struct { | ||
90 | unsigned long nr_files; /* read only */ | ||
91 | unsigned long nr_free_files; /* read only */ | ||
92 | unsigned long max_files; /* tunable */ | ||
93 | }; | ||
94 | |||
95 | struct inodes_stat_t { | ||
96 | long nr_inodes; | ||
97 | long nr_unused; | ||
98 | long dummy[5]; /* padding for sysctl ABI compatibility */ | ||
99 | }; | ||
100 | |||
101 | |||
102 | #define NR_FILE 8192 /* this can well be larger on a larger system */ | ||
103 | |||
104 | |||
105 | /* | ||
106 | * These are the fs-independent mount-flags: up to 32 flags are supported | ||
107 | */ | ||
108 | #define MS_RDONLY 1 /* Mount read-only */ | ||
109 | #define MS_NOSUID 2 /* Ignore suid and sgid bits */ | ||
110 | #define MS_NODEV 4 /* Disallow access to device special files */ | ||
111 | #define MS_NOEXEC 8 /* Disallow program execution */ | ||
112 | #define MS_SYNCHRONOUS 16 /* Writes are synced at once */ | ||
113 | #define MS_REMOUNT 32 /* Alter flags of a mounted FS */ | ||
114 | #define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */ | ||
115 | #define MS_DIRSYNC 128 /* Directory modifications are synchronous */ | ||
116 | #define MS_NOATIME 1024 /* Do not update access times. */ | ||
117 | #define MS_NODIRATIME 2048 /* Do not update directory access times */ | ||
118 | #define MS_BIND 4096 | ||
119 | #define MS_MOVE 8192 | ||
120 | #define MS_REC 16384 | ||
121 | #define MS_VERBOSE 32768 /* War is peace. Verbosity is silence. | ||
122 | MS_VERBOSE is deprecated. */ | ||
123 | #define MS_SILENT 32768 | ||
124 | #define MS_POSIXACL (1<<16) /* VFS does not apply the umask */ | ||
125 | #define MS_UNBINDABLE (1<<17) /* change to unbindable */ | ||
126 | #define MS_PRIVATE (1<<18) /* change to private */ | ||
127 | #define MS_SLAVE (1<<19) /* change to slave */ | ||
128 | #define MS_SHARED (1<<20) /* change to shared */ | ||
129 | #define MS_RELATIME (1<<21) /* Update atime relative to mtime/ctime. */ | ||
130 | #define MS_KERNMOUNT (1<<22) /* this is a kern_mount call */ | ||
131 | #define MS_I_VERSION (1<<23) /* Update inode I_version field */ | ||
132 | #define MS_STRICTATIME (1<<24) /* Always perform atime updates */ | ||
133 | #define MS_LAZYTIME (1<<25) /* Update the on-disk [acm]times lazily */ | ||
134 | |||
135 | /* These sb flags are internal to the kernel */ | ||
136 | #define MS_SUBMOUNT (1<<26) | ||
137 | #define MS_NOREMOTELOCK (1<<27) | ||
138 | #define MS_NOSEC (1<<28) | ||
139 | #define MS_BORN (1<<29) | ||
140 | #define MS_ACTIVE (1<<30) | ||
141 | #define MS_NOUSER (1<<31) | ||
142 | |||
143 | /* | ||
144 | * Superblock flags that can be altered by MS_REMOUNT | ||
145 | */ | ||
146 | #define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|\ | ||
147 | MS_LAZYTIME) | ||
148 | |||
149 | /* | ||
150 | * Old magic mount flag and mask | ||
151 | */ | ||
152 | #define MS_MGC_VAL 0xC0ED0000 | ||
153 | #define MS_MGC_MSK 0xffff0000 | ||
154 | |||
155 | /* | ||
156 | * Structure for FS_IOC_FSGETXATTR[A] and FS_IOC_FSSETXATTR. | ||
157 | */ | ||
158 | struct fsxattr { | ||
159 | __u32 fsx_xflags; /* xflags field value (get/set) */ | ||
160 | __u32 fsx_extsize; /* extsize field value (get/set)*/ | ||
161 | __u32 fsx_nextents; /* nextents field value (get) */ | ||
162 | __u32 fsx_projid; /* project identifier (get/set) */ | ||
163 | __u32 fsx_cowextsize; /* CoW extsize field value (get/set)*/ | ||
164 | unsigned char fsx_pad[8]; | ||
165 | }; | ||
166 | |||
167 | /* | ||
168 | * Flags for the fsx_xflags field | ||
169 | */ | ||
170 | #define FS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */ | ||
171 | #define FS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */ | ||
172 | #define FS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */ | ||
173 | #define FS_XFLAG_APPEND 0x00000010 /* all writes append */ | ||
174 | #define FS_XFLAG_SYNC 0x00000020 /* all writes synchronous */ | ||
175 | #define FS_XFLAG_NOATIME 0x00000040 /* do not update access time */ | ||
176 | #define FS_XFLAG_NODUMP 0x00000080 /* do not include in backups */ | ||
177 | #define FS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */ | ||
178 | #define FS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */ | ||
179 | #define FS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */ | ||
180 | #define FS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */ | ||
181 | #define FS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */ | ||
182 | #define FS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */ | ||
183 | #define FS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */ | ||
184 | #define FS_XFLAG_DAX 0x00008000 /* use DAX for IO */ | ||
185 | #define FS_XFLAG_COWEXTSIZE 0x00010000 /* CoW extent size allocator hint */ | ||
186 | #define FS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ | ||
187 | |||
188 | /* the read-only stuff doesn't really belong here, but any other place is | ||
189 | probably as bad and I don't want to create yet another include file. */ | ||
190 | |||
191 | #define BLKROSET _IO(0x12,93) /* set device read-only (0 = read-write) */ | ||
192 | #define BLKROGET _IO(0x12,94) /* get read-only status (0 = read_write) */ | ||
193 | #define BLKRRPART _IO(0x12,95) /* re-read partition table */ | ||
194 | #define BLKGETSIZE _IO(0x12,96) /* return device size /512 (long *arg) */ | ||
195 | #define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */ | ||
196 | #define BLKRASET _IO(0x12,98) /* set read ahead for block device */ | ||
197 | #define BLKRAGET _IO(0x12,99) /* get current read ahead setting */ | ||
198 | #define BLKFRASET _IO(0x12,100)/* set filesystem (mm/filemap.c) read-ahead */ | ||
199 | #define BLKFRAGET _IO(0x12,101)/* get filesystem (mm/filemap.c) read-ahead */ | ||
200 | #define BLKSECTSET _IO(0x12,102)/* set max sectors per request (ll_rw_blk.c) */ | ||
201 | #define BLKSECTGET _IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */ | ||
202 | #define BLKSSZGET _IO(0x12,104)/* get block device sector size */ | ||
203 | #if 0 | ||
204 | #define BLKPG _IO(0x12,105)/* See blkpg.h */ | ||
205 | |||
206 | /* Some people are morons. Do not use sizeof! */ | ||
207 | |||
208 | #define BLKELVGET _IOR(0x12,106,size_t)/* elevator get */ | ||
209 | #define BLKELVSET _IOW(0x12,107,size_t)/* elevator set */ | ||
210 | /* This was here just to show that the number is taken - | ||
211 | probably all these _IO(0x12,*) ioctls should be moved to blkpg.h. */ | ||
212 | #endif | ||
213 | /* A jump here: 108-111 have been used for various private purposes. */ | ||
214 | #define BLKBSZGET _IOR(0x12,112,size_t) | ||
215 | #define BLKBSZSET _IOW(0x12,113,size_t) | ||
216 | #define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */ | ||
217 | #define BLKTRACESETUP _IOWR(0x12,115,struct blk_user_trace_setup) | ||
218 | #define BLKTRACESTART _IO(0x12,116) | ||
219 | #define BLKTRACESTOP _IO(0x12,117) | ||
220 | #define BLKTRACETEARDOWN _IO(0x12,118) | ||
221 | #define BLKDISCARD _IO(0x12,119) | ||
222 | #define BLKIOMIN _IO(0x12,120) | ||
223 | #define BLKIOOPT _IO(0x12,121) | ||
224 | #define BLKALIGNOFF _IO(0x12,122) | ||
225 | #define BLKPBSZGET _IO(0x12,123) | ||
226 | #define BLKDISCARDZEROES _IO(0x12,124) | ||
227 | #define BLKSECDISCARD _IO(0x12,125) | ||
228 | #define BLKROTATIONAL _IO(0x12,126) | ||
229 | #define BLKZEROOUT _IO(0x12,127) | ||
230 | /* | ||
231 | * A jump here: 130-131 are reserved for zoned block devices | ||
232 | * (see uapi/linux/blkzoned.h) | ||
233 | */ | ||
234 | |||
235 | #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ | ||
236 | #define FIBMAP _IO(0x00,1) /* bmap access */ | ||
237 | #define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */ | ||
238 | #define FIFREEZE _IOWR('X', 119, int) /* Freeze */ | ||
239 | #define FITHAW _IOWR('X', 120, int) /* Thaw */ | ||
240 | #define FITRIM _IOWR('X', 121, struct fstrim_range) /* Trim */ | ||
241 | #define FICLONE _IOW(0x94, 9, int) | ||
242 | #define FICLONERANGE _IOW(0x94, 13, struct file_clone_range) | ||
243 | #define FIDEDUPERANGE _IOWR(0x94, 54, struct file_dedupe_range) | ||
244 | |||
245 | #define FSLABEL_MAX 256 /* Max chars for the interface; each fs may differ */ | ||
246 | |||
247 | #define FS_IOC_GETFLAGS _IOR('f', 1, long) | ||
248 | #define FS_IOC_SETFLAGS _IOW('f', 2, long) | ||
249 | #define FS_IOC_GETVERSION _IOR('v', 1, long) | ||
250 | #define FS_IOC_SETVERSION _IOW('v', 2, long) | ||
251 | #define FS_IOC_FIEMAP _IOWR('f', 11, struct fiemap) | ||
252 | #define FS_IOC32_GETFLAGS _IOR('f', 1, int) | ||
253 | #define FS_IOC32_SETFLAGS _IOW('f', 2, int) | ||
254 | #define FS_IOC32_GETVERSION _IOR('v', 1, int) | ||
255 | #define FS_IOC32_SETVERSION _IOW('v', 2, int) | ||
256 | #define FS_IOC_FSGETXATTR _IOR('X', 31, struct fsxattr) | ||
257 | #define FS_IOC_FSSETXATTR _IOW('X', 32, struct fsxattr) | ||
258 | #define FS_IOC_GETFSLABEL _IOR(0x94, 49, char[FSLABEL_MAX]) | ||
259 | #define FS_IOC_SETFSLABEL _IOW(0x94, 50, char[FSLABEL_MAX]) | ||
260 | |||
261 | /* | ||
262 | * File system encryption support | ||
263 | */ | ||
264 | /* Policy provided via an ioctl on the topmost directory */ | ||
265 | #define FS_KEY_DESCRIPTOR_SIZE 8 | ||
266 | |||
267 | #define FS_POLICY_FLAGS_PAD_4 0x00 | ||
268 | #define FS_POLICY_FLAGS_PAD_8 0x01 | ||
269 | #define FS_POLICY_FLAGS_PAD_16 0x02 | ||
270 | #define FS_POLICY_FLAGS_PAD_32 0x03 | ||
271 | #define FS_POLICY_FLAGS_PAD_MASK 0x03 | ||
272 | #define FS_POLICY_FLAGS_VALID 0x03 | ||
273 | |||
274 | /* Encryption algorithms */ | ||
275 | #define FS_ENCRYPTION_MODE_INVALID 0 | ||
276 | #define FS_ENCRYPTION_MODE_AES_256_XTS 1 | ||
277 | #define FS_ENCRYPTION_MODE_AES_256_GCM 2 | ||
278 | #define FS_ENCRYPTION_MODE_AES_256_CBC 3 | ||
279 | #define FS_ENCRYPTION_MODE_AES_256_CTS 4 | ||
280 | #define FS_ENCRYPTION_MODE_AES_128_CBC 5 | ||
281 | #define FS_ENCRYPTION_MODE_AES_128_CTS 6 | ||
282 | #define FS_ENCRYPTION_MODE_SPECK128_256_XTS 7 /* Removed, do not use. */ | ||
283 | #define FS_ENCRYPTION_MODE_SPECK128_256_CTS 8 /* Removed, do not use. */ | ||
284 | |||
285 | struct fscrypt_policy { | ||
286 | __u8 version; | ||
287 | __u8 contents_encryption_mode; | ||
288 | __u8 filenames_encryption_mode; | ||
289 | __u8 flags; | ||
290 | __u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE]; | ||
291 | }; | ||
292 | |||
293 | #define FS_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct fscrypt_policy) | ||
294 | #define FS_IOC_GET_ENCRYPTION_PWSALT _IOW('f', 20, __u8[16]) | ||
295 | #define FS_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct fscrypt_policy) | ||
296 | |||
297 | /* Parameters for passing an encryption key into the kernel keyring */ | ||
298 | #define FS_KEY_DESC_PREFIX "fscrypt:" | ||
299 | #define FS_KEY_DESC_PREFIX_SIZE 8 | ||
300 | |||
301 | /* Structure that userspace passes to the kernel keyring */ | ||
302 | #define FS_MAX_KEY_SIZE 64 | ||
303 | |||
304 | struct fscrypt_key { | ||
305 | __u32 mode; | ||
306 | __u8 raw[FS_MAX_KEY_SIZE]; | ||
307 | __u32 size; | ||
308 | }; | ||
309 | |||
310 | /* | ||
311 | * Inode flags (FS_IOC_GETFLAGS / FS_IOC_SETFLAGS) | ||
312 | * | ||
313 | * Note: for historical reasons, these flags were originally used and | ||
314 | * defined for use by ext2/ext3, and then other file systems started | ||
315 | * using these flags so they wouldn't need to write their own version | ||
316 | * of chattr/lsattr (which was shipped as part of e2fsprogs). You | ||
317 | * should think twice before trying to use these flags in new | ||
318 | * contexts, or trying to assign these flags, since they are used both | ||
319 | * as the UAPI and the on-disk encoding for ext2/3/4. Also, we are | ||
320 | * almost out of 32-bit flags. :-) | ||
321 | * | ||
322 | * We have recently hoisted FS_IOC_FSGETXATTR / FS_IOC_FSSETXATTR from | ||
323 | * XFS to the generic FS level interface. This uses a structure that | ||
324 | * has padding and hence has more room to grow, so it may be more | ||
325 | * appropriate for many new use cases. | ||
326 | * | ||
327 | * Please do not change these flags or interfaces before checking with | ||
328 | * linux-fsdevel@vger.kernel.org and linux-api@vger.kernel.org. | ||
329 | */ | ||
330 | #define FS_SECRM_FL 0x00000001 /* Secure deletion */ | ||
331 | #define FS_UNRM_FL 0x00000002 /* Undelete */ | ||
332 | #define FS_COMPR_FL 0x00000004 /* Compress file */ | ||
333 | #define FS_SYNC_FL 0x00000008 /* Synchronous updates */ | ||
334 | #define FS_IMMUTABLE_FL 0x00000010 /* Immutable file */ | ||
335 | #define FS_APPEND_FL 0x00000020 /* writes to file may only append */ | ||
336 | #define FS_NODUMP_FL 0x00000040 /* do not dump file */ | ||
337 | #define FS_NOATIME_FL 0x00000080 /* do not update atime */ | ||
338 | /* Reserved for compression usage... */ | ||
339 | #define FS_DIRTY_FL 0x00000100 | ||
340 | #define FS_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ | ||
341 | #define FS_NOCOMP_FL 0x00000400 /* Don't compress */ | ||
342 | /* End compression flags --- maybe not all used */ | ||
343 | #define FS_ENCRYPT_FL 0x00000800 /* Encrypted file */ | ||
344 | #define FS_BTREE_FL 0x00001000 /* btree format dir */ | ||
345 | #define FS_INDEX_FL 0x00001000 /* hash-indexed directory */ | ||
346 | #define FS_IMAGIC_FL 0x00002000 /* AFS directory */ | ||
347 | #define FS_JOURNAL_DATA_FL 0x00004000 /* Reserved for ext3 */ | ||
348 | #define FS_NOTAIL_FL 0x00008000 /* file tail should not be merged */ | ||
349 | #define FS_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ | ||
350 | #define FS_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ | ||
351 | #define FS_HUGE_FILE_FL 0x00040000 /* Reserved for ext4 */ | ||
352 | #define FS_EXTENT_FL 0x00080000 /* Extents */ | ||
353 | #define FS_EA_INODE_FL 0x00200000 /* Inode used for large EA */ | ||
354 | #define FS_EOFBLOCKS_FL 0x00400000 /* Reserved for ext4 */ | ||
355 | #define FS_NOCOW_FL 0x00800000 /* Do not cow file */ | ||
356 | #define FS_INLINE_DATA_FL 0x10000000 /* Reserved for ext4 */ | ||
357 | #define FS_PROJINHERIT_FL 0x20000000 /* Create with parents projid */ | ||
358 | #define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ | ||
359 | |||
360 | #define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ | ||
361 | #define FS_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ | ||
362 | |||
363 | |||
364 | #define SYNC_FILE_RANGE_WAIT_BEFORE 1 | ||
365 | #define SYNC_FILE_RANGE_WRITE 2 | ||
366 | #define SYNC_FILE_RANGE_WAIT_AFTER 4 | ||
367 | |||
368 | /* | ||
369 | * Flags for preadv2/pwritev2: | ||
370 | */ | ||
371 | |||
372 | typedef int __bitwise __kernel_rwf_t; | ||
373 | |||
374 | /* high priority request, poll if possible */ | ||
375 | #define RWF_HIPRI ((__force __kernel_rwf_t)0x00000001) | ||
376 | |||
377 | /* per-IO O_DSYNC */ | ||
378 | #define RWF_DSYNC ((__force __kernel_rwf_t)0x00000002) | ||
379 | |||
380 | /* per-IO O_SYNC */ | ||
381 | #define RWF_SYNC ((__force __kernel_rwf_t)0x00000004) | ||
382 | |||
383 | /* per-IO, return -EAGAIN if operation would block */ | ||
384 | #define RWF_NOWAIT ((__force __kernel_rwf_t)0x00000008) | ||
385 | |||
386 | /* per-IO O_APPEND */ | ||
387 | #define RWF_APPEND ((__force __kernel_rwf_t)0x00000010) | ||
388 | |||
389 | /* mask of flags supported by the kernel */ | ||
390 | #define RWF_SUPPORTED (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT |\ | ||
391 | RWF_APPEND) | ||
392 | |||
393 | #endif /* _UAPI_LINUX_FS_H */ | ||
diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index 58faab897201..1debfa42cba1 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h | |||
@@ -287,6 +287,7 @@ enum { | |||
287 | IFLA_BR_MCAST_STATS_ENABLED, | 287 | IFLA_BR_MCAST_STATS_ENABLED, |
288 | IFLA_BR_MCAST_IGMP_VERSION, | 288 | IFLA_BR_MCAST_IGMP_VERSION, |
289 | IFLA_BR_MCAST_MLD_VERSION, | 289 | IFLA_BR_MCAST_MLD_VERSION, |
290 | IFLA_BR_VLAN_STATS_PER_PORT, | ||
290 | __IFLA_BR_MAX, | 291 | __IFLA_BR_MAX, |
291 | }; | 292 | }; |
292 | 293 | ||
diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index 2875ce85b322..2b7a652c9fa4 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h | |||
@@ -420,13 +420,19 @@ struct kvm_run { | |||
420 | struct kvm_coalesced_mmio_zone { | 420 | struct kvm_coalesced_mmio_zone { |
421 | __u64 addr; | 421 | __u64 addr; |
422 | __u32 size; | 422 | __u32 size; |
423 | __u32 pad; | 423 | union { |
424 | __u32 pad; | ||
425 | __u32 pio; | ||
426 | }; | ||
424 | }; | 427 | }; |
425 | 428 | ||
426 | struct kvm_coalesced_mmio { | 429 | struct kvm_coalesced_mmio { |
427 | __u64 phys_addr; | 430 | __u64 phys_addr; |
428 | __u32 len; | 431 | __u32 len; |
429 | __u32 pad; | 432 | union { |
433 | __u32 pad; | ||
434 | __u32 pio; | ||
435 | }; | ||
430 | __u8 data[8]; | 436 | __u8 data[8]; |
431 | }; | 437 | }; |
432 | 438 | ||
@@ -752,6 +758,15 @@ struct kvm_ppc_resize_hpt { | |||
752 | #define KVM_S390_SIE_PAGE_OFFSET 1 | 758 | #define KVM_S390_SIE_PAGE_OFFSET 1 |
753 | 759 | ||
754 | /* | 760 | /* |
761 | * On arm64, machine type can be used to request the physical | ||
762 | * address size for the VM. Bits[7-0] are reserved for the guest | ||
763 | * PA size shift (i.e, log2(PA_Size)). For backward compatibility, | ||
764 | * value 0 implies the default IPA size, 40bits. | ||
765 | */ | ||
766 | #define KVM_VM_TYPE_ARM_IPA_SIZE_MASK 0xffULL | ||
767 | #define KVM_VM_TYPE_ARM_IPA_SIZE(x) \ | ||
768 | ((x) & KVM_VM_TYPE_ARM_IPA_SIZE_MASK) | ||
769 | /* | ||
755 | * ioctls for /dev/kvm fds: | 770 | * ioctls for /dev/kvm fds: |
756 | */ | 771 | */ |
757 | #define KVM_GET_API_VERSION _IO(KVMIO, 0x00) | 772 | #define KVM_GET_API_VERSION _IO(KVMIO, 0x00) |
@@ -958,6 +973,8 @@ struct kvm_ppc_resize_hpt { | |||
958 | #define KVM_CAP_HYPERV_SEND_IPI 161 | 973 | #define KVM_CAP_HYPERV_SEND_IPI 161 |
959 | #define KVM_CAP_COALESCED_PIO 162 | 974 | #define KVM_CAP_COALESCED_PIO 162 |
960 | #define KVM_CAP_HYPERV_ENLIGHTENED_VMCS 163 | 975 | #define KVM_CAP_HYPERV_ENLIGHTENED_VMCS 163 |
976 | #define KVM_CAP_EXCEPTION_PAYLOAD 164 | ||
977 | #define KVM_CAP_ARM_VM_IPA_SIZE 165 | ||
961 | 978 | ||
962 | #ifdef KVM_CAP_IRQ_ROUTING | 979 | #ifdef KVM_CAP_IRQ_ROUTING |
963 | 980 | ||
diff --git a/tools/include/uapi/linux/mman.h b/tools/include/uapi/linux/mman.h index bfd5938fede6..d0f515d53299 100644 --- a/tools/include/uapi/linux/mman.h +++ b/tools/include/uapi/linux/mman.h | |||
@@ -28,7 +28,9 @@ | |||
28 | #define MAP_HUGE_2MB HUGETLB_FLAG_ENCODE_2MB | 28 | #define MAP_HUGE_2MB HUGETLB_FLAG_ENCODE_2MB |
29 | #define MAP_HUGE_8MB HUGETLB_FLAG_ENCODE_8MB | 29 | #define MAP_HUGE_8MB HUGETLB_FLAG_ENCODE_8MB |
30 | #define MAP_HUGE_16MB HUGETLB_FLAG_ENCODE_16MB | 30 | #define MAP_HUGE_16MB HUGETLB_FLAG_ENCODE_16MB |
31 | #define MAP_HUGE_32MB HUGETLB_FLAG_ENCODE_32MB | ||
31 | #define MAP_HUGE_256MB HUGETLB_FLAG_ENCODE_256MB | 32 | #define MAP_HUGE_256MB HUGETLB_FLAG_ENCODE_256MB |
33 | #define MAP_HUGE_512MB HUGETLB_FLAG_ENCODE_512MB | ||
32 | #define MAP_HUGE_1GB HUGETLB_FLAG_ENCODE_1GB | 34 | #define MAP_HUGE_1GB HUGETLB_FLAG_ENCODE_1GB |
33 | #define MAP_HUGE_2GB HUGETLB_FLAG_ENCODE_2GB | 35 | #define MAP_HUGE_2GB HUGETLB_FLAG_ENCODE_2GB |
34 | #define MAP_HUGE_16GB HUGETLB_FLAG_ENCODE_16GB | 36 | #define MAP_HUGE_16GB HUGETLB_FLAG_ENCODE_16GB |
diff --git a/tools/include/uapi/linux/netlink.h b/tools/include/uapi/linux/netlink.h index 776bc92e9118..486ed1f0c0bc 100644 --- a/tools/include/uapi/linux/netlink.h +++ b/tools/include/uapi/linux/netlink.h | |||
@@ -155,6 +155,7 @@ enum nlmsgerr_attrs { | |||
155 | #define NETLINK_LIST_MEMBERSHIPS 9 | 155 | #define NETLINK_LIST_MEMBERSHIPS 9 |
156 | #define NETLINK_CAP_ACK 10 | 156 | #define NETLINK_CAP_ACK 10 |
157 | #define NETLINK_EXT_ACK 11 | 157 | #define NETLINK_EXT_ACK 11 |
158 | #define NETLINK_DUMP_STRICT_CHK 12 | ||
158 | 159 | ||
159 | struct nl_pktinfo { | 160 | struct nl_pktinfo { |
160 | __u32 group; | 161 | __u32 group; |
diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h index f35eb72739c0..9de8780ac8d9 100644 --- a/tools/include/uapi/linux/perf_event.h +++ b/tools/include/uapi/linux/perf_event.h | |||
@@ -646,10 +646,12 @@ struct perf_event_mmap_page { | |||
646 | * | 646 | * |
647 | * PERF_RECORD_MISC_MMAP_DATA - PERF_RECORD_MMAP* events | 647 | * PERF_RECORD_MISC_MMAP_DATA - PERF_RECORD_MMAP* events |
648 | * PERF_RECORD_MISC_COMM_EXEC - PERF_RECORD_COMM event | 648 | * PERF_RECORD_MISC_COMM_EXEC - PERF_RECORD_COMM event |
649 | * PERF_RECORD_MISC_FORK_EXEC - PERF_RECORD_FORK event (perf internal) | ||
649 | * PERF_RECORD_MISC_SWITCH_OUT - PERF_RECORD_SWITCH* events | 650 | * PERF_RECORD_MISC_SWITCH_OUT - PERF_RECORD_SWITCH* events |
650 | */ | 651 | */ |
651 | #define PERF_RECORD_MISC_MMAP_DATA (1 << 13) | 652 | #define PERF_RECORD_MISC_MMAP_DATA (1 << 13) |
652 | #define PERF_RECORD_MISC_COMM_EXEC (1 << 13) | 653 | #define PERF_RECORD_MISC_COMM_EXEC (1 << 13) |
654 | #define PERF_RECORD_MISC_FORK_EXEC (1 << 13) | ||
653 | #define PERF_RECORD_MISC_SWITCH_OUT (1 << 13) | 655 | #define PERF_RECORD_MISC_SWITCH_OUT (1 << 13) |
654 | /* | 656 | /* |
655 | * These PERF_RECORD_MISC_* flags below are safely reused | 657 | * These PERF_RECORD_MISC_* flags below are safely reused |
diff --git a/tools/include/uapi/sound/asound.h b/tools/include/uapi/sound/asound.h index ed0a120d4f08..404d4b9ffe76 100644 --- a/tools/include/uapi/sound/asound.h +++ b/tools/include/uapi/sound/asound.h | |||
@@ -752,7 +752,7 @@ struct snd_timer_info { | |||
752 | #define SNDRV_TIMER_PSFLG_EARLY_EVENT (1<<2) /* write early event to the poll queue */ | 752 | #define SNDRV_TIMER_PSFLG_EARLY_EVENT (1<<2) /* write early event to the poll queue */ |
753 | 753 | ||
754 | struct snd_timer_params { | 754 | struct snd_timer_params { |
755 | unsigned int flags; /* flags - SNDRV_MIXER_PSFLG_* */ | 755 | unsigned int flags; /* flags - SNDRV_TIMER_PSFLG_* */ |
756 | unsigned int ticks; /* requested resolution in ticks */ | 756 | unsigned int ticks; /* requested resolution in ticks */ |
757 | unsigned int queue_size; /* total size of queue (32-1024) */ | 757 | unsigned int queue_size; /* total size of queue (32-1024) */ |
758 | unsigned int reserved0; /* reserved, was: failure locations */ | 758 | unsigned int reserved0; /* reserved, was: failure locations */ |
diff --git a/tools/lib/subcmd/parse-options.c b/tools/lib/subcmd/parse-options.c index cb7154eccbdc..dbb9efbf718a 100644 --- a/tools/lib/subcmd/parse-options.c +++ b/tools/lib/subcmd/parse-options.c | |||
@@ -116,6 +116,7 @@ static int get_value(struct parse_opt_ctx_t *p, | |||
116 | case OPTION_INTEGER: | 116 | case OPTION_INTEGER: |
117 | case OPTION_UINTEGER: | 117 | case OPTION_UINTEGER: |
118 | case OPTION_LONG: | 118 | case OPTION_LONG: |
119 | case OPTION_ULONG: | ||
119 | case OPTION_U64: | 120 | case OPTION_U64: |
120 | default: | 121 | default: |
121 | break; | 122 | break; |
@@ -166,6 +167,7 @@ static int get_value(struct parse_opt_ctx_t *p, | |||
166 | case OPTION_INTEGER: | 167 | case OPTION_INTEGER: |
167 | case OPTION_UINTEGER: | 168 | case OPTION_UINTEGER: |
168 | case OPTION_LONG: | 169 | case OPTION_LONG: |
170 | case OPTION_ULONG: | ||
169 | case OPTION_U64: | 171 | case OPTION_U64: |
170 | default: | 172 | default: |
171 | break; | 173 | break; |
@@ -295,6 +297,22 @@ static int get_value(struct parse_opt_ctx_t *p, | |||
295 | return opterror(opt, "expects a numerical value", flags); | 297 | return opterror(opt, "expects a numerical value", flags); |
296 | return 0; | 298 | return 0; |
297 | 299 | ||
300 | case OPTION_ULONG: | ||
301 | if (unset) { | ||
302 | *(unsigned long *)opt->value = 0; | ||
303 | return 0; | ||
304 | } | ||
305 | if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { | ||
306 | *(unsigned long *)opt->value = opt->defval; | ||
307 | return 0; | ||
308 | } | ||
309 | if (get_arg(p, opt, flags, &arg)) | ||
310 | return -1; | ||
311 | *(unsigned long *)opt->value = strtoul(arg, (char **)&s, 10); | ||
312 | if (*s) | ||
313 | return opterror(opt, "expects a numerical value", flags); | ||
314 | return 0; | ||
315 | |||
298 | case OPTION_U64: | 316 | case OPTION_U64: |
299 | if (unset) { | 317 | if (unset) { |
300 | *(u64 *)opt->value = 0; | 318 | *(u64 *)opt->value = 0; |
@@ -703,6 +721,7 @@ static void print_option_help(const struct option *opts, int full) | |||
703 | case OPTION_ARGUMENT: | 721 | case OPTION_ARGUMENT: |
704 | break; | 722 | break; |
705 | case OPTION_LONG: | 723 | case OPTION_LONG: |
724 | case OPTION_ULONG: | ||
706 | case OPTION_U64: | 725 | case OPTION_U64: |
707 | case OPTION_INTEGER: | 726 | case OPTION_INTEGER: |
708 | case OPTION_UINTEGER: | 727 | case OPTION_UINTEGER: |
diff --git a/tools/lib/subcmd/parse-options.h b/tools/lib/subcmd/parse-options.h index 92fdbe1519f6..6ca2a8bfe716 100644 --- a/tools/lib/subcmd/parse-options.h +++ b/tools/lib/subcmd/parse-options.h | |||
@@ -25,6 +25,7 @@ enum parse_opt_type { | |||
25 | OPTION_STRING, | 25 | OPTION_STRING, |
26 | OPTION_INTEGER, | 26 | OPTION_INTEGER, |
27 | OPTION_LONG, | 27 | OPTION_LONG, |
28 | OPTION_ULONG, | ||
28 | OPTION_CALLBACK, | 29 | OPTION_CALLBACK, |
29 | OPTION_U64, | 30 | OPTION_U64, |
30 | OPTION_UINTEGER, | 31 | OPTION_UINTEGER, |
@@ -133,6 +134,7 @@ struct option { | |||
133 | #define OPT_INTEGER(s, l, v, h) { .type = OPTION_INTEGER, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) } | 134 | #define OPT_INTEGER(s, l, v, h) { .type = OPTION_INTEGER, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) } |
134 | #define OPT_UINTEGER(s, l, v, h) { .type = OPTION_UINTEGER, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h) } | 135 | #define OPT_UINTEGER(s, l, v, h) { .type = OPTION_UINTEGER, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h) } |
135 | #define OPT_LONG(s, l, v, h) { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = check_vtype(v, long *), .help = (h) } | 136 | #define OPT_LONG(s, l, v, h) { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = check_vtype(v, long *), .help = (h) } |
137 | #define OPT_ULONG(s, l, v, h) { .type = OPTION_ULONG, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned long *), .help = (h) } | ||
136 | #define OPT_U64(s, l, v, h) { .type = OPTION_U64, .short_name = (s), .long_name = (l), .value = check_vtype(v, u64 *), .help = (h) } | 138 | #define OPT_U64(s, l, v, h) { .type = OPTION_U64, .short_name = (s), .long_name = (l), .value = check_vtype(v, u64 *), .help = (h) } |
137 | #define OPT_STRING(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), .argh = (a), .help = (h) } | 139 | #define OPT_STRING(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), .argh = (a), .help = (h) } |
138 | #define OPT_STRING_OPTARG(s, l, v, a, h, d) \ | 140 | #define OPT_STRING_OPTARG(s, l, v, a, h, d) \ |
diff --git a/tools/perf/Documentation/build-xed.txt b/tools/perf/Documentation/build-xed.txt new file mode 100644 index 000000000000..6222c1e7231f --- /dev/null +++ b/tools/perf/Documentation/build-xed.txt | |||
@@ -0,0 +1,19 @@ | |||
1 | |||
2 | For --xed the xed tool is needed. Here is how to install it: | ||
3 | |||
4 | $ git clone https://github.com/intelxed/mbuild.git mbuild | ||
5 | $ git clone https://github.com/intelxed/xed | ||
6 | $ cd xed | ||
7 | $ ./mfile.py --share | ||
8 | $ ./mfile.py examples | ||
9 | $ sudo ./mfile.py --prefix=/usr/local install | ||
10 | $ sudo ldconfig | ||
11 | $ sudo cp obj/examples/xed /usr/local/bin | ||
12 | |||
13 | Basic xed testing: | ||
14 | |||
15 | $ xed | head -3 | ||
16 | ERROR: required argument(s) were missing | ||
17 | Copyright (C) 2017, Intel Corporation. All rights reserved. | ||
18 | XED version: [v10.0-328-g7d62c8c49b7b] | ||
19 | $ | ||
diff --git a/tools/perf/Documentation/intel-pt.txt b/tools/perf/Documentation/intel-pt.txt index 76971d2e4164..115eaacc455f 100644 --- a/tools/perf/Documentation/intel-pt.txt +++ b/tools/perf/Documentation/intel-pt.txt | |||
@@ -106,7 +106,7 @@ in transaction, respectively. | |||
106 | While it is possible to create scripts to analyze the data, an alternative | 106 | While it is possible to create scripts to analyze the data, an alternative |
107 | approach is available to export the data to a sqlite or postgresql database. | 107 | approach is available to export the data to a sqlite or postgresql database. |
108 | Refer to script export-to-sqlite.py or export-to-postgresql.py for more details, | 108 | Refer to script export-to-sqlite.py or export-to-postgresql.py for more details, |
109 | and to script call-graph-from-sql.py for an example of using the database. | 109 | and to script exported-sql-viewer.py for an example of using the database. |
110 | 110 | ||
111 | There is also script intel-pt-events.py which provides an example of how to | 111 | There is also script intel-pt-events.py which provides an example of how to |
112 | unpack the raw data for power events and PTWRITE. | 112 | unpack the raw data for power events and PTWRITE. |
diff --git a/tools/perf/Documentation/itrace.txt b/tools/perf/Documentation/itrace.txt index a3abe04c779d..c2182cbabde3 100644 --- a/tools/perf/Documentation/itrace.txt +++ b/tools/perf/Documentation/itrace.txt | |||
@@ -11,10 +11,11 @@ | |||
11 | l synthesize last branch entries (use with i or x) | 11 | l synthesize last branch entries (use with i or x) |
12 | s skip initial number of events | 12 | s skip initial number of events |
13 | 13 | ||
14 | The default is all events i.e. the same as --itrace=ibxwpe | 14 | The default is all events i.e. the same as --itrace=ibxwpe, |
15 | except for perf script where it is --itrace=ce | ||
15 | 16 | ||
16 | In addition, the period (default 100000) for instructions events | 17 | In addition, the period (default 100000, except for perf script where it is 1) |
17 | can be specified in units of: | 18 | for instructions events can be specified in units of: |
18 | 19 | ||
19 | i instructions | 20 | i instructions |
20 | t ticks | 21 | t ticks |
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index afdafe2110a1..a2b37ce48094 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt | |||
@@ -383,6 +383,24 @@ include::itrace.txt[] | |||
383 | will be printed. Each entry has function name and file/line. Enabled by | 383 | will be printed. Each entry has function name and file/line. Enabled by |
384 | default, disable with --no-inline. | 384 | default, disable with --no-inline. |
385 | 385 | ||
386 | --insn-trace:: | ||
387 | Show instruction stream for intel_pt traces. Combine with --xed to | ||
388 | show disassembly. | ||
389 | |||
390 | --xed:: | ||
391 | Run xed disassembler on output. Requires installing the xed disassembler. | ||
392 | |||
393 | --call-trace:: | ||
394 | Show call stream for intel_pt traces. The CPUs are interleaved, but | ||
395 | can be filtered with -C. | ||
396 | |||
397 | --call-ret-trace:: | ||
398 | Show call and return stream for intel_pt traces. | ||
399 | |||
400 | --graph-function:: | ||
401 | For itrace only show specified functions and their callees for | ||
402 | itrace. Multiple functions can be separated by comma. | ||
403 | |||
386 | SEE ALSO | 404 | SEE ALSO |
387 | -------- | 405 | -------- |
388 | linkperf:perf-record[1], linkperf:perf-script-perl[1], | 406 | linkperf:perf-record[1], linkperf:perf-script-perl[1], |
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 114fda12aa49..808b664343c9 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt | |||
@@ -242,6 +242,16 @@ Default is to monitor all CPUS. | |||
242 | --hierarchy:: | 242 | --hierarchy:: |
243 | Enable hierarchy output. | 243 | Enable hierarchy output. |
244 | 244 | ||
245 | --overwrite:: | ||
246 | Enable this to use just the most recent records, which helps in high core count | ||
247 | machines such as Knights Landing/Mill, but right now is disabled by default as | ||
248 | the pausing used in this technique is leading to loss of metadata events such | ||
249 | as PERF_RECORD_MMAP which makes 'perf top' unable to resolve samples, leading | ||
250 | to lots of unknown samples appearing on the UI. Enable this if you are in such | ||
251 | machines and profiling a workload that doesn't creates short lived threads and/or | ||
252 | doesn't uses many executable mmap operations. Work is being planed to solve | ||
253 | this situation, till then, this will remain disabled by default. | ||
254 | |||
245 | --force:: | 255 | --force:: |
246 | Don't do ownership validation. | 256 | Don't do ownership validation. |
247 | 257 | ||
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index 115db9e06ecd..e113450503d2 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt | |||
@@ -171,6 +171,11 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. | |||
171 | --kernel-syscall-graph:: | 171 | --kernel-syscall-graph:: |
172 | Show the kernel callchains on the syscall exit path. | 172 | Show the kernel callchains on the syscall exit path. |
173 | 173 | ||
174 | --max-events=N:: | ||
175 | Stop after processing N events. Note that strace-like events are considered | ||
176 | only at exit time or when a syscall is interrupted, i.e. in those cases this | ||
177 | option is equivalent to the number of lines printed. | ||
178 | |||
174 | --max-stack:: | 179 | --max-stack:: |
175 | Set the stack depth limit when parsing the callchain, anything | 180 | Set the stack depth limit when parsing the callchain, anything |
176 | beyond the specified depth will be ignored. Note that at this point | 181 | beyond the specified depth will be ignored. Note that at this point |
@@ -238,6 +243,68 @@ Trace syscalls, major and minor pagefaults: | |||
238 | As you can see, there was major pagefault in python process, from | 243 | As you can see, there was major pagefault in python process, from |
239 | CRYPTO_push_info_ routine which faulted somewhere in libcrypto.so. | 244 | CRYPTO_push_info_ routine which faulted somewhere in libcrypto.so. |
240 | 245 | ||
246 | Trace the first 4 open, openat or open_by_handle_at syscalls (in the future more syscalls may match here): | ||
247 | |||
248 | $ perf trace -e open* --max-events 4 | ||
249 | [root@jouet perf]# trace -e open* --max-events 4 | ||
250 | 2272.992 ( 0.037 ms): gnome-shell/1370 openat(dfd: CWD, filename: /proc/self/stat) = 31 | ||
251 | 2277.481 ( 0.139 ms): gnome-shell/3039 openat(dfd: CWD, filename: /proc/self/stat) = 65 | ||
252 | 3026.398 ( 0.076 ms): gnome-shell/3039 openat(dfd: CWD, filename: /proc/self/stat) = 65 | ||
253 | 4294.665 ( 0.015 ms): sed/15879 openat(dfd: CWD, filename: /etc/ld.so.cache, flags: CLOEXEC) = 3 | ||
254 | $ | ||
255 | |||
256 | Trace the first minor page fault when running a workload: | ||
257 | |||
258 | # perf trace -F min --max-stack=7 --max-events 1 sleep 1 | ||
259 | 0.000 ( 0.000 ms): sleep/18006 minfault [__clear_user+0x1a] => 0x5626efa56080 (?k) | ||
260 | __clear_user ([kernel.kallsyms]) | ||
261 | load_elf_binary ([kernel.kallsyms]) | ||
262 | search_binary_handler ([kernel.kallsyms]) | ||
263 | __do_execve_file.isra.33 ([kernel.kallsyms]) | ||
264 | __x64_sys_execve ([kernel.kallsyms]) | ||
265 | do_syscall_64 ([kernel.kallsyms]) | ||
266 | entry_SYSCALL_64 ([kernel.kallsyms]) | ||
267 | # | ||
268 | |||
269 | Trace the next min page page fault to take place on the first CPU: | ||
270 | |||
271 | # perf trace -F min --call-graph=dwarf --max-events 1 --cpu 0 | ||
272 | 0.000 ( 0.000 ms): Web Content/17136 minfault [js::gc::Chunk::fetchNextDecommittedArena+0x4b] => 0x7fbe6181b000 (?.) | ||
273 | js::gc::FreeSpan::initAsEmpty (inlined) | ||
274 | js::gc::Arena::setAsNotAllocated (inlined) | ||
275 | js::gc::Chunk::fetchNextDecommittedArena (/usr/lib64/firefox/libxul.so) | ||
276 | js::gc::Chunk::allocateArena (/usr/lib64/firefox/libxul.so) | ||
277 | js::gc::GCRuntime::allocateArena (/usr/lib64/firefox/libxul.so) | ||
278 | js::gc::ArenaLists::allocateFromArena (/usr/lib64/firefox/libxul.so) | ||
279 | js::gc::GCRuntime::tryNewTenuredThing<JSString, (js::AllowGC)1> (inlined) | ||
280 | js::AllocateString<JSString, (js::AllowGC)1> (/usr/lib64/firefox/libxul.so) | ||
281 | js::Allocate<JSThinInlineString, (js::AllowGC)1> (inlined) | ||
282 | JSThinInlineString::new_<(js::AllowGC)1> (inlined) | ||
283 | AllocateInlineString<(js::AllowGC)1, unsigned char> (inlined) | ||
284 | js::ConcatStrings<(js::AllowGC)1> (/usr/lib64/firefox/libxul.so) | ||
285 | [0x18b26e6bc2bd] (/tmp/perf-17136.map) | ||
286 | # | ||
287 | |||
288 | Trace the next two sched:sched_switch events, four block:*_plug events, the | ||
289 | next block:*_unplug and the next three net:*dev_queue events, this last one | ||
290 | with a backtrace of at most 16 entries, system wide: | ||
291 | |||
292 | # perf trace -e sched:*switch/nr=2/,block:*_plug/nr=4/,block:*_unplug/nr=1/,net:*dev_queue/nr=3,max-stack=16/ | ||
293 | 0.000 :0/0 sched:sched_switch:swapper/2:0 [120] S ==> rcu_sched:10 [120] | ||
294 | 0.015 rcu_sched/10 sched:sched_switch:rcu_sched:10 [120] R ==> swapper/2:0 [120] | ||
295 | 254.198 irq/50-iwlwifi/680 net:net_dev_queue:dev=wlp3s0 skbaddr=0xffff93498051f600 len=66 | ||
296 | __dev_queue_xmit ([kernel.kallsyms]) | ||
297 | 273.977 :0/0 net:net_dev_queue:dev=wlp3s0 skbaddr=0xffff93498051f600 len=78 | ||
298 | __dev_queue_xmit ([kernel.kallsyms]) | ||
299 | 274.007 :0/0 net:net_dev_queue:dev=wlp3s0 skbaddr=0xffff93498051ff00 len=78 | ||
300 | __dev_queue_xmit ([kernel.kallsyms]) | ||
301 | 2930.140 kworker/u16:58/2722 block:block_plug:[kworker/u16:58] | ||
302 | 2930.162 kworker/u16:58/2722 block:block_unplug:[kworker/u16:58] 1 | ||
303 | 4466.094 jbd2/dm-2-8/748 block:block_plug:[jbd2/dm-2-8] | ||
304 | 8050.123 kworker/u16:30/2694 block:block_plug:[kworker/u16:30] | ||
305 | 8050.271 kworker/u16:30/2694 block:block_plug:[kworker/u16:30] | ||
306 | # | ||
307 | |||
241 | SEE ALSO | 308 | SEE ALSO |
242 | -------- | 309 | -------- |
243 | linkperf:perf-record[1], linkperf:perf-script[1] | 310 | linkperf:perf-record[1], linkperf:perf-script[1] |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 2f3bf025e305..3ccb4f0bf088 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -1,4 +1,5 @@ | |||
1 | include ../scripts/Makefile.include | 1 | include ../scripts/Makefile.include |
2 | include ../scripts/Makefile.arch | ||
2 | 3 | ||
3 | # The default target of this Makefile is... | 4 | # The default target of this Makefile is... |
4 | all: | 5 | all: |
@@ -385,6 +386,8 @@ export INSTALL SHELL_PATH | |||
385 | SHELL = $(SHELL_PATH) | 386 | SHELL = $(SHELL_PATH) |
386 | 387 | ||
387 | linux_uapi_dir := $(srctree)/tools/include/uapi/linux | 388 | linux_uapi_dir := $(srctree)/tools/include/uapi/linux |
389 | asm_generic_uapi_dir := $(srctree)/tools/include/uapi/asm-generic | ||
390 | arch_asm_uapi_dir := $(srctree)/tools/arch/$(ARCH)/include/uapi/asm/ | ||
388 | 391 | ||
389 | beauty_outdir := $(OUTPUT)trace/beauty/generated | 392 | beauty_outdir := $(OUTPUT)trace/beauty/generated |
390 | beauty_ioctl_outdir := $(beauty_outdir)/ioctl | 393 | beauty_ioctl_outdir := $(beauty_outdir)/ioctl |
@@ -460,6 +463,18 @@ madvise_behavior_tbl := $(srctree)/tools/perf/trace/beauty/madvise_behavior.sh | |||
460 | $(madvise_behavior_array): $(madvise_hdr_dir)/mman-common.h $(madvise_behavior_tbl) | 463 | $(madvise_behavior_array): $(madvise_hdr_dir)/mman-common.h $(madvise_behavior_tbl) |
461 | $(Q)$(SHELL) '$(madvise_behavior_tbl)' $(madvise_hdr_dir) > $@ | 464 | $(Q)$(SHELL) '$(madvise_behavior_tbl)' $(madvise_hdr_dir) > $@ |
462 | 465 | ||
466 | mmap_flags_array := $(beauty_outdir)/mmap_flags_array.c | ||
467 | mmap_flags_tbl := $(srctree)/tools/perf/trace/beauty/mmap_flags.sh | ||
468 | |||
469 | $(mmap_flags_array): $(asm_generic_uapi_dir)/mman.h $(asm_generic_uapi_dir)/mman-common.h $(arch_asm_uapi_dir)/mman.h $(mmap_flags_tbl) | ||
470 | $(Q)$(SHELL) '$(mmap_flags_tbl)' $(asm_generic_uapi_dir) $(arch_asm_uapi_dir) > $@ | ||
471 | |||
472 | mount_flags_array := $(beauty_outdir)/mount_flags_array.c | ||
473 | mount_flags_tbl := $(srctree)/tools/perf/trace/beauty/mount_flags.sh | ||
474 | |||
475 | $(mount_flags_array): $(linux_uapi_dir)/fs.h $(mount_flags_tbl) | ||
476 | $(Q)$(SHELL) '$(mount_flags_tbl)' $(linux_uapi_dir) > $@ | ||
477 | |||
463 | prctl_option_array := $(beauty_outdir)/prctl_option_array.c | 478 | prctl_option_array := $(beauty_outdir)/prctl_option_array.c |
464 | prctl_hdr_dir := $(srctree)/tools/include/uapi/linux/ | 479 | prctl_hdr_dir := $(srctree)/tools/include/uapi/linux/ |
465 | prctl_option_tbl := $(srctree)/tools/perf/trace/beauty/prctl_option.sh | 480 | prctl_option_tbl := $(srctree)/tools/perf/trace/beauty/prctl_option.sh |
@@ -577,6 +592,8 @@ prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders $(drm_ioc | |||
577 | $(socket_ipproto_array) \ | 592 | $(socket_ipproto_array) \ |
578 | $(vhost_virtio_ioctl_array) \ | 593 | $(vhost_virtio_ioctl_array) \ |
579 | $(madvise_behavior_array) \ | 594 | $(madvise_behavior_array) \ |
595 | $(mmap_flags_array) \ | ||
596 | $(mount_flags_array) \ | ||
580 | $(perf_ioctl_array) \ | 597 | $(perf_ioctl_array) \ |
581 | $(prctl_option_array) \ | 598 | $(prctl_option_array) \ |
582 | $(arch_errno_name_array) | 599 | $(arch_errno_name_array) |
@@ -863,6 +880,8 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea | |||
863 | $(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c \ | 880 | $(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c \ |
864 | $(OUTPUT)pmu-events/pmu-events.c \ | 881 | $(OUTPUT)pmu-events/pmu-events.c \ |
865 | $(OUTPUT)$(madvise_behavior_array) \ | 882 | $(OUTPUT)$(madvise_behavior_array) \ |
883 | $(OUTPUT)$(mmap_flags_array) \ | ||
884 | $(OUTPUT)$(mount_flags_array) \ | ||
866 | $(OUTPUT)$(drm_ioctl_array) \ | 885 | $(OUTPUT)$(drm_ioctl_array) \ |
867 | $(OUTPUT)$(pkey_alloc_access_rights_array) \ | 886 | $(OUTPUT)$(pkey_alloc_access_rights_array) \ |
868 | $(OUTPUT)$(sndrv_ctl_ioctl_array) \ | 887 | $(OUTPUT)$(sndrv_ctl_ioctl_array) \ |
diff --git a/tools/perf/arch/arm64/entry/syscalls/mksyscalltbl b/tools/perf/arch/arm64/entry/syscalls/mksyscalltbl index 2dbb8cade048..c88fd32563eb 100755 --- a/tools/perf/arch/arm64/entry/syscalls/mksyscalltbl +++ b/tools/perf/arch/arm64/entry/syscalls/mksyscalltbl | |||
@@ -23,7 +23,7 @@ create_table_from_c() | |||
23 | { | 23 | { |
24 | local sc nr last_sc | 24 | local sc nr last_sc |
25 | 25 | ||
26 | create_table_exe=`mktemp /tmp/create-table-XXXXXX` | 26 | create_table_exe=`mktemp ${TMPDIR:-/tmp}/create-table-XXXXXX` |
27 | 27 | ||
28 | { | 28 | { |
29 | 29 | ||
diff --git a/tools/perf/arch/sparc/Makefile b/tools/perf/arch/sparc/Makefile index 7fbca175099e..275dea7ff59a 100644 --- a/tools/perf/arch/sparc/Makefile +++ b/tools/perf/arch/sparc/Makefile | |||
@@ -1,3 +1,5 @@ | |||
1 | ifndef NO_DWARF | 1 | ifndef NO_DWARF |
2 | PERF_HAVE_DWARF_REGS := 1 | 2 | PERF_HAVE_DWARF_REGS := 1 |
3 | endif | 3 | endif |
4 | |||
5 | PERF_HAVE_JITDUMP := 1 | ||
diff --git a/tools/perf/arch/sparc/annotate/instructions.c b/tools/perf/arch/sparc/annotate/instructions.c new file mode 100644 index 000000000000..2614c010c235 --- /dev/null +++ b/tools/perf/arch/sparc/annotate/instructions.c | |||
@@ -0,0 +1,169 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | |||
3 | static int is_branch_cond(const char *cond) | ||
4 | { | ||
5 | if (cond[0] == '\0') | ||
6 | return 1; | ||
7 | |||
8 | if (cond[0] == 'a' && cond[1] == '\0') | ||
9 | return 1; | ||
10 | |||
11 | if (cond[0] == 'c' && | ||
12 | (cond[1] == 'c' || cond[1] == 's') && | ||
13 | cond[2] == '\0') | ||
14 | return 1; | ||
15 | |||
16 | if (cond[0] == 'e' && | ||
17 | (cond[1] == '\0' || | ||
18 | (cond[1] == 'q' && cond[2] == '\0'))) | ||
19 | return 1; | ||
20 | |||
21 | if (cond[0] == 'g' && | ||
22 | (cond[1] == '\0' || | ||
23 | (cond[1] == 't' && cond[2] == '\0') || | ||
24 | (cond[1] == 'e' && cond[2] == '\0') || | ||
25 | (cond[1] == 'e' && cond[2] == 'u' && cond[3] == '\0'))) | ||
26 | return 1; | ||
27 | |||
28 | if (cond[0] == 'l' && | ||
29 | (cond[1] == '\0' || | ||
30 | (cond[1] == 't' && cond[2] == '\0') || | ||
31 | (cond[1] == 'u' && cond[2] == '\0') || | ||
32 | (cond[1] == 'e' && cond[2] == '\0') || | ||
33 | (cond[1] == 'e' && cond[2] == 'u' && cond[3] == '\0'))) | ||
34 | return 1; | ||
35 | |||
36 | if (cond[0] == 'n' && | ||
37 | (cond[1] == '\0' || | ||
38 | (cond[1] == 'e' && cond[2] == '\0') || | ||
39 | (cond[1] == 'z' && cond[2] == '\0') || | ||
40 | (cond[1] == 'e' && cond[2] == 'g' && cond[3] == '\0'))) | ||
41 | return 1; | ||
42 | |||
43 | if (cond[0] == 'b' && | ||
44 | cond[1] == 'p' && | ||
45 | cond[2] == 'o' && | ||
46 | cond[3] == 's' && | ||
47 | cond[4] == '\0') | ||
48 | return 1; | ||
49 | |||
50 | if (cond[0] == 'v' && | ||
51 | (cond[1] == 'c' || cond[1] == 's') && | ||
52 | cond[2] == '\0') | ||
53 | return 1; | ||
54 | |||
55 | if (cond[0] == 'b' && | ||
56 | cond[1] == 'z' && | ||
57 | cond[2] == '\0') | ||
58 | return 1; | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static int is_branch_reg_cond(const char *cond) | ||
64 | { | ||
65 | if ((cond[0] == 'n' || cond[0] == 'l') && | ||
66 | cond[1] == 'z' && | ||
67 | cond[2] == '\0') | ||
68 | return 1; | ||
69 | |||
70 | if (cond[0] == 'z' && | ||
71 | cond[1] == '\0') | ||
72 | return 1; | ||
73 | |||
74 | if ((cond[0] == 'g' || cond[0] == 'l') && | ||
75 | cond[1] == 'e' && | ||
76 | cond[2] == 'z' && | ||
77 | cond[3] == '\0') | ||
78 | return 1; | ||
79 | |||
80 | if (cond[0] == 'g' && | ||
81 | cond[1] == 'z' && | ||
82 | cond[2] == '\0') | ||
83 | return 1; | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int is_branch_float_cond(const char *cond) | ||
89 | { | ||
90 | if (cond[0] == '\0') | ||
91 | return 1; | ||
92 | |||
93 | if ((cond[0] == 'a' || cond[0] == 'e' || | ||
94 | cond[0] == 'z' || cond[0] == 'g' || | ||
95 | cond[0] == 'l' || cond[0] == 'n' || | ||
96 | cond[0] == 'o' || cond[0] == 'u') && | ||
97 | cond[1] == '\0') | ||
98 | return 1; | ||
99 | |||
100 | if (((cond[0] == 'g' && cond[1] == 'e') || | ||
101 | (cond[0] == 'l' && (cond[1] == 'e' || | ||
102 | cond[1] == 'g')) || | ||
103 | (cond[0] == 'n' && (cond[1] == 'e' || | ||
104 | cond[1] == 'z')) || | ||
105 | (cond[0] == 'u' && (cond[1] == 'e' || | ||
106 | cond[1] == 'g' || | ||
107 | cond[1] == 'l'))) && | ||
108 | cond[2] == '\0') | ||
109 | return 1; | ||
110 | |||
111 | if (cond[0] == 'u' && | ||
112 | (cond[1] == 'g' || cond[1] == 'l') && | ||
113 | cond[2] == 'e' && | ||
114 | cond[3] == '\0') | ||
115 | return 1; | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static struct ins_ops *sparc__associate_instruction_ops(struct arch *arch, const char *name) | ||
121 | { | ||
122 | struct ins_ops *ops = NULL; | ||
123 | |||
124 | if (!strcmp(name, "call") || | ||
125 | !strcmp(name, "jmp") || | ||
126 | !strcmp(name, "jmpl")) { | ||
127 | ops = &call_ops; | ||
128 | } else if (!strcmp(name, "ret") || | ||
129 | !strcmp(name, "retl") || | ||
130 | !strcmp(name, "return")) { | ||
131 | ops = &ret_ops; | ||
132 | } else if (!strcmp(name, "mov")) { | ||
133 | ops = &mov_ops; | ||
134 | } else { | ||
135 | if (name[0] == 'c' && | ||
136 | (name[1] == 'w' || name[1] == 'x')) | ||
137 | name += 2; | ||
138 | |||
139 | if (name[0] == 'b') { | ||
140 | const char *cond = name + 1; | ||
141 | |||
142 | if (cond[0] == 'r') { | ||
143 | if (is_branch_reg_cond(cond + 1)) | ||
144 | ops = &jump_ops; | ||
145 | } else if (is_branch_cond(cond)) { | ||
146 | ops = &jump_ops; | ||
147 | } | ||
148 | } else if (name[0] == 'f' && name[1] == 'b') { | ||
149 | if (is_branch_float_cond(name + 2)) | ||
150 | ops = &jump_ops; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | if (ops) | ||
155 | arch__associate_ins_ops(arch, name, ops); | ||
156 | |||
157 | return ops; | ||
158 | } | ||
159 | |||
160 | static int sparc__annotate_init(struct arch *arch, char *cpuid __maybe_unused) | ||
161 | { | ||
162 | if (!arch->initialized) { | ||
163 | arch->initialized = true; | ||
164 | arch->associate_instruction_ops = sparc__associate_instruction_ops; | ||
165 | arch->objdump.comment_char = '#'; | ||
166 | } | ||
167 | |||
168 | return 0; | ||
169 | } | ||
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 0980dfe3396b..10cf889c6d75 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -592,6 +592,9 @@ static void record__init_features(struct record *rec) | |||
592 | if (!rec->opts.full_auxtrace) | 592 | if (!rec->opts.full_auxtrace) |
593 | perf_header__clear_feat(&session->header, HEADER_AUXTRACE); | 593 | perf_header__clear_feat(&session->header, HEADER_AUXTRACE); |
594 | 594 | ||
595 | if (!(rec->opts.use_clockid && rec->opts.clockid_res_ns)) | ||
596 | perf_header__clear_feat(&session->header, HEADER_CLOCKID); | ||
597 | |||
595 | perf_header__clear_feat(&session->header, HEADER_STAT); | 598 | perf_header__clear_feat(&session->header, HEADER_STAT); |
596 | } | 599 | } |
597 | 600 | ||
@@ -897,6 +900,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
897 | 900 | ||
898 | record__init_features(rec); | 901 | record__init_features(rec); |
899 | 902 | ||
903 | if (rec->opts.use_clockid && rec->opts.clockid_res_ns) | ||
904 | session->header.env.clockid_res_ns = rec->opts.clockid_res_ns; | ||
905 | |||
900 | if (forks) { | 906 | if (forks) { |
901 | err = perf_evlist__prepare_workload(rec->evlist, &opts->target, | 907 | err = perf_evlist__prepare_workload(rec->evlist, &opts->target, |
902 | argv, data->is_pipe, | 908 | argv, data->is_pipe, |
@@ -1337,6 +1343,19 @@ static const struct clockid_map clockids[] = { | |||
1337 | CLOCKID_END, | 1343 | CLOCKID_END, |
1338 | }; | 1344 | }; |
1339 | 1345 | ||
1346 | static int get_clockid_res(clockid_t clk_id, u64 *res_ns) | ||
1347 | { | ||
1348 | struct timespec res; | ||
1349 | |||
1350 | *res_ns = 0; | ||
1351 | if (!clock_getres(clk_id, &res)) | ||
1352 | *res_ns = res.tv_nsec + res.tv_sec * NSEC_PER_SEC; | ||
1353 | else | ||
1354 | pr_warning("WARNING: Failed to determine specified clock resolution.\n"); | ||
1355 | |||
1356 | return 0; | ||
1357 | } | ||
1358 | |||
1340 | static int parse_clockid(const struct option *opt, const char *str, int unset) | 1359 | static int parse_clockid(const struct option *opt, const char *str, int unset) |
1341 | { | 1360 | { |
1342 | struct record_opts *opts = (struct record_opts *)opt->value; | 1361 | struct record_opts *opts = (struct record_opts *)opt->value; |
@@ -1360,7 +1379,7 @@ static int parse_clockid(const struct option *opt, const char *str, int unset) | |||
1360 | 1379 | ||
1361 | /* if its a number, we're done */ | 1380 | /* if its a number, we're done */ |
1362 | if (sscanf(str, "%d", &opts->clockid) == 1) | 1381 | if (sscanf(str, "%d", &opts->clockid) == 1) |
1363 | return 0; | 1382 | return get_clockid_res(opts->clockid, &opts->clockid_res_ns); |
1364 | 1383 | ||
1365 | /* allow a "CLOCK_" prefix to the name */ | 1384 | /* allow a "CLOCK_" prefix to the name */ |
1366 | if (!strncasecmp(str, "CLOCK_", 6)) | 1385 | if (!strncasecmp(str, "CLOCK_", 6)) |
@@ -1369,7 +1388,8 @@ static int parse_clockid(const struct option *opt, const char *str, int unset) | |||
1369 | for (cm = clockids; cm->name; cm++) { | 1388 | for (cm = clockids; cm->name; cm++) { |
1370 | if (!strcasecmp(str, cm->name)) { | 1389 | if (!strcasecmp(str, cm->name)) { |
1371 | opts->clockid = cm->clockid; | 1390 | opts->clockid = cm->clockid; |
1372 | return 0; | 1391 | return get_clockid_res(opts->clockid, |
1392 | &opts->clockid_res_ns); | ||
1373 | } | 1393 | } |
1374 | } | 1394 | } |
1375 | 1395 | ||
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 4da5e32b9e03..b5bc85bd0bbe 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <sys/stat.h> | 44 | #include <sys/stat.h> |
45 | #include <fcntl.h> | 45 | #include <fcntl.h> |
46 | #include <unistd.h> | 46 | #include <unistd.h> |
47 | #include <subcmd/pager.h> | ||
47 | 48 | ||
48 | #include "sane_ctype.h" | 49 | #include "sane_ctype.h" |
49 | 50 | ||
@@ -912,7 +913,7 @@ static int grab_bb(u8 *buffer, u64 start, u64 end, | |||
912 | 913 | ||
913 | static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en, | 914 | static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en, |
914 | struct perf_insn *x, u8 *inbuf, int len, | 915 | struct perf_insn *x, u8 *inbuf, int len, |
915 | int insn, FILE *fp) | 916 | int insn, FILE *fp, int *total_cycles) |
916 | { | 917 | { |
917 | int printed = fprintf(fp, "\t%016" PRIx64 "\t%-30s\t#%s%s%s%s", ip, | 918 | int printed = fprintf(fp, "\t%016" PRIx64 "\t%-30s\t#%s%s%s%s", ip, |
918 | dump_insn(x, ip, inbuf, len, NULL), | 919 | dump_insn(x, ip, inbuf, len, NULL), |
@@ -921,7 +922,8 @@ static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en, | |||
921 | en->flags.in_tx ? " INTX" : "", | 922 | en->flags.in_tx ? " INTX" : "", |
922 | en->flags.abort ? " ABORT" : ""); | 923 | en->flags.abort ? " ABORT" : ""); |
923 | if (en->flags.cycles) { | 924 | if (en->flags.cycles) { |
924 | printed += fprintf(fp, " %d cycles", en->flags.cycles); | 925 | *total_cycles += en->flags.cycles; |
926 | printed += fprintf(fp, " %d cycles [%d]", en->flags.cycles, *total_cycles); | ||
925 | if (insn) | 927 | if (insn) |
926 | printed += fprintf(fp, " %.2f IPC", (float)insn / en->flags.cycles); | 928 | printed += fprintf(fp, " %.2f IPC", (float)insn / en->flags.cycles); |
927 | } | 929 | } |
@@ -978,6 +980,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, | |||
978 | u8 buffer[MAXBB]; | 980 | u8 buffer[MAXBB]; |
979 | unsigned off; | 981 | unsigned off; |
980 | struct symbol *lastsym = NULL; | 982 | struct symbol *lastsym = NULL; |
983 | int total_cycles = 0; | ||
981 | 984 | ||
982 | if (!(br && br->nr)) | 985 | if (!(br && br->nr)) |
983 | return 0; | 986 | return 0; |
@@ -998,7 +1001,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, | |||
998 | printed += ip__fprintf_sym(br->entries[nr - 1].from, thread, | 1001 | printed += ip__fprintf_sym(br->entries[nr - 1].from, thread, |
999 | x.cpumode, x.cpu, &lastsym, attr, fp); | 1002 | x.cpumode, x.cpu, &lastsym, attr, fp); |
1000 | printed += ip__fprintf_jump(br->entries[nr - 1].from, &br->entries[nr - 1], | 1003 | printed += ip__fprintf_jump(br->entries[nr - 1].from, &br->entries[nr - 1], |
1001 | &x, buffer, len, 0, fp); | 1004 | &x, buffer, len, 0, fp, &total_cycles); |
1002 | } | 1005 | } |
1003 | 1006 | ||
1004 | /* Print all blocks */ | 1007 | /* Print all blocks */ |
@@ -1026,7 +1029,8 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, | |||
1026 | 1029 | ||
1027 | printed += ip__fprintf_sym(ip, thread, x.cpumode, x.cpu, &lastsym, attr, fp); | 1030 | printed += ip__fprintf_sym(ip, thread, x.cpumode, x.cpu, &lastsym, attr, fp); |
1028 | if (ip == end) { | 1031 | if (ip == end) { |
1029 | printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn, fp); | 1032 | printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn, fp, |
1033 | &total_cycles); | ||
1030 | break; | 1034 | break; |
1031 | } else { | 1035 | } else { |
1032 | printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", ip, | 1036 | printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", ip, |
@@ -1104,6 +1108,35 @@ out: | |||
1104 | return printed; | 1108 | return printed; |
1105 | } | 1109 | } |
1106 | 1110 | ||
1111 | static const char *resolve_branch_sym(struct perf_sample *sample, | ||
1112 | struct perf_evsel *evsel, | ||
1113 | struct thread *thread, | ||
1114 | struct addr_location *al, | ||
1115 | u64 *ip) | ||
1116 | { | ||
1117 | struct addr_location addr_al; | ||
1118 | struct perf_event_attr *attr = &evsel->attr; | ||
1119 | const char *name = NULL; | ||
1120 | |||
1121 | if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) { | ||
1122 | if (sample_addr_correlates_sym(attr)) { | ||
1123 | thread__resolve(thread, &addr_al, sample); | ||
1124 | if (addr_al.sym) | ||
1125 | name = addr_al.sym->name; | ||
1126 | else | ||
1127 | *ip = sample->addr; | ||
1128 | } else { | ||
1129 | *ip = sample->addr; | ||
1130 | } | ||
1131 | } else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) { | ||
1132 | if (al->sym) | ||
1133 | name = al->sym->name; | ||
1134 | else | ||
1135 | *ip = sample->ip; | ||
1136 | } | ||
1137 | return name; | ||
1138 | } | ||
1139 | |||
1107 | static int perf_sample__fprintf_callindent(struct perf_sample *sample, | 1140 | static int perf_sample__fprintf_callindent(struct perf_sample *sample, |
1108 | struct perf_evsel *evsel, | 1141 | struct perf_evsel *evsel, |
1109 | struct thread *thread, | 1142 | struct thread *thread, |
@@ -1111,7 +1144,6 @@ static int perf_sample__fprintf_callindent(struct perf_sample *sample, | |||
1111 | { | 1144 | { |
1112 | struct perf_event_attr *attr = &evsel->attr; | 1145 | struct perf_event_attr *attr = &evsel->attr; |
1113 | size_t depth = thread_stack__depth(thread); | 1146 | size_t depth = thread_stack__depth(thread); |
1114 | struct addr_location addr_al; | ||
1115 | const char *name = NULL; | 1147 | const char *name = NULL; |
1116 | static int spacing; | 1148 | static int spacing; |
1117 | int len = 0; | 1149 | int len = 0; |
@@ -1125,22 +1157,7 @@ static int perf_sample__fprintf_callindent(struct perf_sample *sample, | |||
1125 | if (thread->ts && sample->flags & PERF_IP_FLAG_RETURN) | 1157 | if (thread->ts && sample->flags & PERF_IP_FLAG_RETURN) |
1126 | depth += 1; | 1158 | depth += 1; |
1127 | 1159 | ||
1128 | if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) { | 1160 | name = resolve_branch_sym(sample, evsel, thread, al, &ip); |
1129 | if (sample_addr_correlates_sym(attr)) { | ||
1130 | thread__resolve(thread, &addr_al, sample); | ||
1131 | if (addr_al.sym) | ||
1132 | name = addr_al.sym->name; | ||
1133 | else | ||
1134 | ip = sample->addr; | ||
1135 | } else { | ||
1136 | ip = sample->addr; | ||
1137 | } | ||
1138 | } else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) { | ||
1139 | if (al->sym) | ||
1140 | name = al->sym->name; | ||
1141 | else | ||
1142 | ip = sample->ip; | ||
1143 | } | ||
1144 | 1161 | ||
1145 | if (PRINT_FIELD(DSO) && !(PRINT_FIELD(IP) || PRINT_FIELD(ADDR))) { | 1162 | if (PRINT_FIELD(DSO) && !(PRINT_FIELD(IP) || PRINT_FIELD(ADDR))) { |
1146 | dlen += fprintf(fp, "("); | 1163 | dlen += fprintf(fp, "("); |
@@ -1646,6 +1663,47 @@ static void perf_sample__fprint_metric(struct perf_script *script, | |||
1646 | } | 1663 | } |
1647 | } | 1664 | } |
1648 | 1665 | ||
1666 | static bool show_event(struct perf_sample *sample, | ||
1667 | struct perf_evsel *evsel, | ||
1668 | struct thread *thread, | ||
1669 | struct addr_location *al) | ||
1670 | { | ||
1671 | int depth = thread_stack__depth(thread); | ||
1672 | |||
1673 | if (!symbol_conf.graph_function) | ||
1674 | return true; | ||
1675 | |||
1676 | if (thread->filter) { | ||
1677 | if (depth <= thread->filter_entry_depth) { | ||
1678 | thread->filter = false; | ||
1679 | return false; | ||
1680 | } | ||
1681 | return true; | ||
1682 | } else { | ||
1683 | const char *s = symbol_conf.graph_function; | ||
1684 | u64 ip; | ||
1685 | const char *name = resolve_branch_sym(sample, evsel, thread, al, | ||
1686 | &ip); | ||
1687 | unsigned nlen; | ||
1688 | |||
1689 | if (!name) | ||
1690 | return false; | ||
1691 | nlen = strlen(name); | ||
1692 | while (*s) { | ||
1693 | unsigned len = strcspn(s, ","); | ||
1694 | if (nlen == len && !strncmp(name, s, len)) { | ||
1695 | thread->filter = true; | ||
1696 | thread->filter_entry_depth = depth; | ||
1697 | return true; | ||
1698 | } | ||
1699 | s += len; | ||
1700 | if (*s == ',') | ||
1701 | s++; | ||
1702 | } | ||
1703 | return false; | ||
1704 | } | ||
1705 | } | ||
1706 | |||
1649 | static void process_event(struct perf_script *script, | 1707 | static void process_event(struct perf_script *script, |
1650 | struct perf_sample *sample, struct perf_evsel *evsel, | 1708 | struct perf_sample *sample, struct perf_evsel *evsel, |
1651 | struct addr_location *al, | 1709 | struct addr_location *al, |
@@ -1660,6 +1718,9 @@ static void process_event(struct perf_script *script, | |||
1660 | if (output[type].fields == 0) | 1718 | if (output[type].fields == 0) |
1661 | return; | 1719 | return; |
1662 | 1720 | ||
1721 | if (!show_event(sample, evsel, thread, al)) | ||
1722 | return; | ||
1723 | |||
1663 | ++es->samples; | 1724 | ++es->samples; |
1664 | 1725 | ||
1665 | perf_sample__fprintf_start(sample, thread, evsel, | 1726 | perf_sample__fprintf_start(sample, thread, evsel, |
@@ -1737,6 +1798,9 @@ static void process_event(struct perf_script *script, | |||
1737 | 1798 | ||
1738 | if (PRINT_FIELD(METRIC)) | 1799 | if (PRINT_FIELD(METRIC)) |
1739 | perf_sample__fprint_metric(script, thread, evsel, sample, fp); | 1800 | perf_sample__fprint_metric(script, thread, evsel, sample, fp); |
1801 | |||
1802 | if (verbose) | ||
1803 | fflush(fp); | ||
1740 | } | 1804 | } |
1741 | 1805 | ||
1742 | static struct scripting_ops *scripting_ops; | 1806 | static struct scripting_ops *scripting_ops; |
@@ -3100,6 +3164,44 @@ static int perf_script__process_auxtrace_info(struct perf_session *session, | |||
3100 | #define perf_script__process_auxtrace_info 0 | 3164 | #define perf_script__process_auxtrace_info 0 |
3101 | #endif | 3165 | #endif |
3102 | 3166 | ||
3167 | static int parse_insn_trace(const struct option *opt __maybe_unused, | ||
3168 | const char *str __maybe_unused, | ||
3169 | int unset __maybe_unused) | ||
3170 | { | ||
3171 | parse_output_fields(NULL, "+insn,-event,-period", 0); | ||
3172 | itrace_parse_synth_opts(opt, "i0ns", 0); | ||
3173 | nanosecs = true; | ||
3174 | return 0; | ||
3175 | } | ||
3176 | |||
3177 | static int parse_xed(const struct option *opt __maybe_unused, | ||
3178 | const char *str __maybe_unused, | ||
3179 | int unset __maybe_unused) | ||
3180 | { | ||
3181 | force_pager("xed -F insn: -A -64 | less"); | ||
3182 | return 0; | ||
3183 | } | ||
3184 | |||
3185 | static int parse_call_trace(const struct option *opt __maybe_unused, | ||
3186 | const char *str __maybe_unused, | ||
3187 | int unset __maybe_unused) | ||
3188 | { | ||
3189 | parse_output_fields(NULL, "-ip,-addr,-event,-period,+callindent", 0); | ||
3190 | itrace_parse_synth_opts(opt, "cewp", 0); | ||
3191 | nanosecs = true; | ||
3192 | return 0; | ||
3193 | } | ||
3194 | |||
3195 | static int parse_callret_trace(const struct option *opt __maybe_unused, | ||
3196 | const char *str __maybe_unused, | ||
3197 | int unset __maybe_unused) | ||
3198 | { | ||
3199 | parse_output_fields(NULL, "-ip,-addr,-event,-period,+callindent,+flags", 0); | ||
3200 | itrace_parse_synth_opts(opt, "crewp", 0); | ||
3201 | nanosecs = true; | ||
3202 | return 0; | ||
3203 | } | ||
3204 | |||
3103 | int cmd_script(int argc, const char **argv) | 3205 | int cmd_script(int argc, const char **argv) |
3104 | { | 3206 | { |
3105 | bool show_full_info = false; | 3207 | bool show_full_info = false; |
@@ -3109,7 +3211,10 @@ int cmd_script(int argc, const char **argv) | |||
3109 | char *rec_script_path = NULL; | 3211 | char *rec_script_path = NULL; |
3110 | char *rep_script_path = NULL; | 3212 | char *rep_script_path = NULL; |
3111 | struct perf_session *session; | 3213 | struct perf_session *session; |
3112 | struct itrace_synth_opts itrace_synth_opts = { .set = false, }; | 3214 | struct itrace_synth_opts itrace_synth_opts = { |
3215 | .set = false, | ||
3216 | .default_no_sample = true, | ||
3217 | }; | ||
3113 | char *script_path = NULL; | 3218 | char *script_path = NULL; |
3114 | const char **__argv; | 3219 | const char **__argv; |
3115 | int i, j, err = 0; | 3220 | int i, j, err = 0; |
@@ -3184,6 +3289,16 @@ int cmd_script(int argc, const char **argv) | |||
3184 | "system-wide collection from all CPUs"), | 3289 | "system-wide collection from all CPUs"), |
3185 | OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", | 3290 | OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", |
3186 | "only consider these symbols"), | 3291 | "only consider these symbols"), |
3292 | OPT_CALLBACK_OPTARG(0, "insn-trace", &itrace_synth_opts, NULL, NULL, | ||
3293 | "Decode instructions from itrace", parse_insn_trace), | ||
3294 | OPT_CALLBACK_OPTARG(0, "xed", NULL, NULL, NULL, | ||
3295 | "Run xed disassembler on output", parse_xed), | ||
3296 | OPT_CALLBACK_OPTARG(0, "call-trace", &itrace_synth_opts, NULL, NULL, | ||
3297 | "Decode calls from from itrace", parse_call_trace), | ||
3298 | OPT_CALLBACK_OPTARG(0, "call-ret-trace", &itrace_synth_opts, NULL, NULL, | ||
3299 | "Decode calls and returns from itrace", parse_callret_trace), | ||
3300 | OPT_STRING(0, "graph-function", &symbol_conf.graph_function, "symbol[,symbol...]", | ||
3301 | "Only print symbols and callees with --call-trace/--call-ret-trace"), | ||
3187 | OPT_STRING(0, "stop-bt", &symbol_conf.bt_stop_list_str, "symbol[,symbol...]", | 3302 | OPT_STRING(0, "stop-bt", &symbol_conf.bt_stop_list_str, "symbol[,symbol...]", |
3188 | "Stop display of callgraph at these symbols"), | 3303 | "Stop display of callgraph at these symbols"), |
3189 | OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), | 3304 | OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), |
@@ -3417,8 +3532,10 @@ int cmd_script(int argc, const char **argv) | |||
3417 | exit(-1); | 3532 | exit(-1); |
3418 | } | 3533 | } |
3419 | 3534 | ||
3420 | if (!script_name) | 3535 | if (!script_name) { |
3421 | setup_pager(); | 3536 | setup_pager(); |
3537 | use_browser = 0; | ||
3538 | } | ||
3422 | 3539 | ||
3423 | session = perf_session__new(&data, false, &script.tool); | 3540 | session = perf_session__new(&data, false, &script.tool); |
3424 | if (session == NULL) | 3541 | if (session == NULL) |
@@ -3439,7 +3556,8 @@ int cmd_script(int argc, const char **argv) | |||
3439 | script.session = session; | 3556 | script.session = session; |
3440 | script__setup_sample_type(&script); | 3557 | script__setup_sample_type(&script); |
3441 | 3558 | ||
3442 | if (output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT) | 3559 | if ((output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT) || |
3560 | symbol_conf.graph_function) | ||
3443 | itrace_synth_opts.thread_stack = true; | 3561 | itrace_synth_opts.thread_stack = true; |
3444 | 3562 | ||
3445 | session->itrace_synth_opts = &itrace_synth_opts; | 3563 | session->itrace_synth_opts = &itrace_synth_opts; |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index b86aba1c8028..d1028d7755bb 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -409,6 +409,28 @@ static struct perf_evsel *perf_evsel__reset_weak_group(struct perf_evsel *evsel) | |||
409 | return leader; | 409 | return leader; |
410 | } | 410 | } |
411 | 411 | ||
412 | static bool is_target_alive(struct target *_target, | ||
413 | struct thread_map *threads) | ||
414 | { | ||
415 | struct stat st; | ||
416 | int i; | ||
417 | |||
418 | if (!target__has_task(_target)) | ||
419 | return true; | ||
420 | |||
421 | for (i = 0; i < threads->nr; i++) { | ||
422 | char path[PATH_MAX]; | ||
423 | |||
424 | scnprintf(path, PATH_MAX, "%s/%d", procfs__mountpoint(), | ||
425 | threads->map[i].pid); | ||
426 | |||
427 | if (!stat(path, &st)) | ||
428 | return true; | ||
429 | } | ||
430 | |||
431 | return false; | ||
432 | } | ||
433 | |||
412 | static int __run_perf_stat(int argc, const char **argv, int run_idx) | 434 | static int __run_perf_stat(int argc, const char **argv, int run_idx) |
413 | { | 435 | { |
414 | int interval = stat_config.interval; | 436 | int interval = stat_config.interval; |
@@ -579,6 +601,8 @@ try_again: | |||
579 | enable_counters(); | 601 | enable_counters(); |
580 | while (!done) { | 602 | while (!done) { |
581 | nanosleep(&ts, NULL); | 603 | nanosleep(&ts, NULL); |
604 | if (!is_target_alive(&target, evsel_list->threads)) | ||
605 | break; | ||
582 | if (timeout) | 606 | if (timeout) |
583 | break; | 607 | break; |
584 | if (interval) { | 608 | if (interval) { |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index d21d8751e749..b2838de13de0 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -1134,11 +1134,6 @@ static int __cmd_top(struct perf_top *top) | |||
1134 | if (!target__none(&opts->target)) | 1134 | if (!target__none(&opts->target)) |
1135 | perf_evlist__enable(top->evlist); | 1135 | perf_evlist__enable(top->evlist); |
1136 | 1136 | ||
1137 | /* Wait for a minimal set of events before starting the snapshot */ | ||
1138 | perf_evlist__poll(top->evlist, 100); | ||
1139 | |||
1140 | perf_top__mmap_read(top); | ||
1141 | |||
1142 | ret = -1; | 1137 | ret = -1; |
1143 | if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : | 1138 | if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : |
1144 | display_thread), top)) { | 1139 | display_thread), top)) { |
@@ -1156,6 +1151,11 @@ static int __cmd_top(struct perf_top *top) | |||
1156 | } | 1151 | } |
1157 | } | 1152 | } |
1158 | 1153 | ||
1154 | /* Wait for a minimal set of events before starting the snapshot */ | ||
1155 | perf_evlist__poll(top->evlist, 100); | ||
1156 | |||
1157 | perf_top__mmap_read(top); | ||
1158 | |||
1159 | while (!done) { | 1159 | while (!done) { |
1160 | u64 hits = top->samples; | 1160 | u64 hits = top->samples; |
1161 | 1161 | ||
@@ -1257,7 +1257,14 @@ int cmd_top(int argc, const char **argv) | |||
1257 | .uses_mmap = true, | 1257 | .uses_mmap = true, |
1258 | }, | 1258 | }, |
1259 | .proc_map_timeout = 500, | 1259 | .proc_map_timeout = 500, |
1260 | .overwrite = 1, | 1260 | /* |
1261 | * FIXME: This will lose PERF_RECORD_MMAP and other metadata | ||
1262 | * when we pause, fix that and reenable. Probably using a | ||
1263 | * separate evlist with a dummy event, i.e. a non-overwrite | ||
1264 | * ring buffer just for metadata events, while PERF_RECORD_SAMPLE | ||
1265 | * stays in overwrite mode. -acme | ||
1266 | * */ | ||
1267 | .overwrite = 0, | ||
1261 | }, | 1268 | }, |
1262 | .max_stack = sysctl__max_stack(), | 1269 | .max_stack = sysctl__max_stack(), |
1263 | .annotation_opts = annotation__default_options, | 1270 | .annotation_opts = annotation__default_options, |
@@ -1372,6 +1379,8 @@ int cmd_top(int argc, const char **argv) | |||
1372 | "Show raw trace event output (do not use print fmt or plugins)"), | 1379 | "Show raw trace event output (do not use print fmt or plugins)"), |
1373 | OPT_BOOLEAN(0, "hierarchy", &symbol_conf.report_hierarchy, | 1380 | OPT_BOOLEAN(0, "hierarchy", &symbol_conf.report_hierarchy, |
1374 | "Show entries in a hierarchy"), | 1381 | "Show entries in a hierarchy"), |
1382 | OPT_BOOLEAN(0, "overwrite", &top.record_opts.overwrite, | ||
1383 | "Use a backward ring buffer, default: no"), | ||
1375 | OPT_BOOLEAN(0, "force", &symbol_conf.force, "don't complain, do it"), | 1384 | OPT_BOOLEAN(0, "force", &symbol_conf.force, "don't complain, do it"), |
1376 | OPT_UINTEGER(0, "num-thread-synthesize", &top.nr_threads_synthesize, | 1385 | OPT_UINTEGER(0, "num-thread-synthesize", &top.nr_threads_synthesize, |
1377 | "number of thread to run event synthesize"), | 1386 | "number of thread to run event synthesize"), |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 90289f31dd87..dc8a6c4986ce 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -89,6 +89,8 @@ struct trace { | |||
89 | u64 base_time; | 89 | u64 base_time; |
90 | FILE *output; | 90 | FILE *output; |
91 | unsigned long nr_events; | 91 | unsigned long nr_events; |
92 | unsigned long nr_events_printed; | ||
93 | unsigned long max_events; | ||
92 | struct strlist *ev_qualifier; | 94 | struct strlist *ev_qualifier; |
93 | struct { | 95 | struct { |
94 | size_t nr; | 96 | size_t nr; |
@@ -612,6 +614,7 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size, | |||
612 | 614 | ||
613 | struct syscall_arg_fmt { | 615 | struct syscall_arg_fmt { |
614 | size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg); | 616 | size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg); |
617 | unsigned long (*mask_val)(struct syscall_arg *arg, unsigned long val); | ||
615 | void *parm; | 618 | void *parm; |
616 | const char *name; | 619 | const char *name; |
617 | bool show_zero; | 620 | bool show_zero; |
@@ -723,6 +726,10 @@ static struct syscall_fmt { | |||
723 | .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, | 726 | .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, |
724 | [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, | 727 | [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, |
725 | [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, }, | 728 | [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, }, |
729 | { .name = "mount", | ||
730 | .arg = { [0] = { .scnprintf = SCA_FILENAME, /* dev_name */ }, | ||
731 | [3] = { .scnprintf = SCA_MOUNT_FLAGS, /* flags */ | ||
732 | .mask_val = SCAMV_MOUNT_FLAGS, /* flags */ }, }, }, | ||
726 | { .name = "mprotect", | 733 | { .name = "mprotect", |
727 | .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ }, | 734 | .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ }, |
728 | [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, }, | 735 | [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, }, |
@@ -832,7 +839,8 @@ static struct syscall_fmt { | |||
832 | .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, | 839 | .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, |
833 | { .name = "tkill", | 840 | { .name = "tkill", |
834 | .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, | 841 | .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, |
835 | { .name = "umount2", .alias = "umount", }, | 842 | { .name = "umount2", .alias = "umount", |
843 | .arg = { [0] = { .scnprintf = SCA_FILENAME, /* name */ }, }, }, | ||
836 | { .name = "uname", .alias = "newuname", }, | 844 | { .name = "uname", .alias = "newuname", }, |
837 | { .name = "unlinkat", | 845 | { .name = "unlinkat", |
838 | .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, | 846 | .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, |
@@ -856,6 +864,18 @@ static struct syscall_fmt *syscall_fmt__find(const char *name) | |||
856 | return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp); | 864 | return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp); |
857 | } | 865 | } |
858 | 866 | ||
867 | static struct syscall_fmt *syscall_fmt__find_by_alias(const char *alias) | ||
868 | { | ||
869 | int i, nmemb = ARRAY_SIZE(syscall_fmts); | ||
870 | |||
871 | for (i = 0; i < nmemb; ++i) { | ||
872 | if (syscall_fmts[i].alias && strcmp(syscall_fmts[i].alias, alias) == 0) | ||
873 | return &syscall_fmts[i]; | ||
874 | } | ||
875 | |||
876 | return NULL; | ||
877 | } | ||
878 | |||
859 | /* | 879 | /* |
860 | * is_exit: is this "exit" or "exit_group"? | 880 | * is_exit: is this "exit" or "exit_group"? |
861 | * is_open: is this "open" or "openat"? To associate the fd returned in sys_exit with the pathname in sys_enter. | 881 | * is_open: is this "open" or "openat"? To associate the fd returned in sys_exit with the pathname in sys_enter. |
@@ -1485,6 +1505,19 @@ static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size, | |||
1485 | return scnprintf(bf, size, "arg%d: ", arg->idx); | 1505 | return scnprintf(bf, size, "arg%d: ", arg->idx); |
1486 | } | 1506 | } |
1487 | 1507 | ||
1508 | /* | ||
1509 | * Check if the value is in fact zero, i.e. mask whatever needs masking, such | ||
1510 | * as mount 'flags' argument that needs ignoring some magic flag, see comment | ||
1511 | * in tools/perf/trace/beauty/mount_flags.c | ||
1512 | */ | ||
1513 | static unsigned long syscall__mask_val(struct syscall *sc, struct syscall_arg *arg, unsigned long val) | ||
1514 | { | ||
1515 | if (sc->arg_fmt && sc->arg_fmt[arg->idx].mask_val) | ||
1516 | return sc->arg_fmt[arg->idx].mask_val(arg, val); | ||
1517 | |||
1518 | return val; | ||
1519 | } | ||
1520 | |||
1488 | static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size, | 1521 | static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size, |
1489 | struct syscall_arg *arg, unsigned long val) | 1522 | struct syscall_arg *arg, unsigned long val) |
1490 | { | 1523 | { |
@@ -1533,6 +1566,11 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, | |||
1533 | continue; | 1566 | continue; |
1534 | 1567 | ||
1535 | val = syscall_arg__val(&arg, arg.idx); | 1568 | val = syscall_arg__val(&arg, arg.idx); |
1569 | /* | ||
1570 | * Some syscall args need some mask, most don't and | ||
1571 | * return val untouched. | ||
1572 | */ | ||
1573 | val = syscall__mask_val(sc, &arg, val); | ||
1536 | 1574 | ||
1537 | /* | 1575 | /* |
1538 | * Suppress this argument if its value is zero and | 1576 | * Suppress this argument if its value is zero and |
@@ -1664,6 +1702,8 @@ static int trace__printf_interrupted_entry(struct trace *trace) | |||
1664 | printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str); | 1702 | printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str); |
1665 | ttrace->entry_pending = false; | 1703 | ttrace->entry_pending = false; |
1666 | 1704 | ||
1705 | ++trace->nr_events_printed; | ||
1706 | |||
1667 | return printed; | 1707 | return printed; |
1668 | } | 1708 | } |
1669 | 1709 | ||
@@ -1810,12 +1850,14 @@ static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evse | |||
1810 | int max_stack = evsel->attr.sample_max_stack ? | 1850 | int max_stack = evsel->attr.sample_max_stack ? |
1811 | evsel->attr.sample_max_stack : | 1851 | evsel->attr.sample_max_stack : |
1812 | trace->max_stack; | 1852 | trace->max_stack; |
1853 | int err; | ||
1813 | 1854 | ||
1814 | if (machine__resolve(trace->host, &al, sample) < 0 || | 1855 | if (machine__resolve(trace->host, &al, sample) < 0) |
1815 | thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack)) | ||
1816 | return -1; | 1856 | return -1; |
1817 | 1857 | ||
1818 | return 0; | 1858 | err = thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack); |
1859 | addr_location__put(&al); | ||
1860 | return err; | ||
1819 | } | 1861 | } |
1820 | 1862 | ||
1821 | static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample) | 1863 | static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample) |
@@ -1940,6 +1982,13 @@ errno_print: { | |||
1940 | 1982 | ||
1941 | fputc('\n', trace->output); | 1983 | fputc('\n', trace->output); |
1942 | 1984 | ||
1985 | /* | ||
1986 | * We only consider an 'event' for the sake of --max-events a non-filtered | ||
1987 | * sys_enter + sys_exit and other tracepoint events. | ||
1988 | */ | ||
1989 | if (++trace->nr_events_printed == trace->max_events && trace->max_events != ULONG_MAX) | ||
1990 | interrupted = true; | ||
1991 | |||
1943 | if (callchain_ret > 0) | 1992 | if (callchain_ret > 0) |
1944 | trace__fprintf_callchain(trace, sample); | 1993 | trace__fprintf_callchain(trace, sample); |
1945 | else if (callchain_ret < 0) | 1994 | else if (callchain_ret < 0) |
@@ -2072,14 +2121,25 @@ static void bpf_output__fprintf(struct trace *trace, | |||
2072 | { | 2121 | { |
2073 | binary__fprintf(sample->raw_data, sample->raw_size, 8, | 2122 | binary__fprintf(sample->raw_data, sample->raw_size, 8, |
2074 | bpf_output__printer, NULL, trace->output); | 2123 | bpf_output__printer, NULL, trace->output); |
2124 | ++trace->nr_events_printed; | ||
2075 | } | 2125 | } |
2076 | 2126 | ||
2077 | static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, | 2127 | static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, |
2078 | union perf_event *event __maybe_unused, | 2128 | union perf_event *event __maybe_unused, |
2079 | struct perf_sample *sample) | 2129 | struct perf_sample *sample) |
2080 | { | 2130 | { |
2081 | struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); | 2131 | struct thread *thread; |
2082 | int callchain_ret = 0; | 2132 | int callchain_ret = 0; |
2133 | /* | ||
2134 | * Check if we called perf_evsel__disable(evsel) due to, for instance, | ||
2135 | * this event's max_events having been hit and this is an entry coming | ||
2136 | * from the ring buffer that we should discard, since the max events | ||
2137 | * have already been considered/printed. | ||
2138 | */ | ||
2139 | if (evsel->disabled) | ||
2140 | return 0; | ||
2141 | |||
2142 | thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); | ||
2083 | 2143 | ||
2084 | if (sample->callchain) { | 2144 | if (sample->callchain) { |
2085 | callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor); | 2145 | callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor); |
@@ -2127,6 +2187,12 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, | |||
2127 | event_format__fprintf(evsel->tp_format, sample->cpu, | 2187 | event_format__fprintf(evsel->tp_format, sample->cpu, |
2128 | sample->raw_data, sample->raw_size, | 2188 | sample->raw_data, sample->raw_size, |
2129 | trace->output); | 2189 | trace->output); |
2190 | ++trace->nr_events_printed; | ||
2191 | |||
2192 | if (evsel->max_events != ULONG_MAX && ++evsel->nr_events_printed == evsel->max_events) { | ||
2193 | perf_evsel__disable(evsel); | ||
2194 | perf_evsel__close(evsel); | ||
2195 | } | ||
2130 | } | 2196 | } |
2131 | } | 2197 | } |
2132 | 2198 | ||
@@ -2137,8 +2203,8 @@ newline: | |||
2137 | trace__fprintf_callchain(trace, sample); | 2203 | trace__fprintf_callchain(trace, sample); |
2138 | else if (callchain_ret < 0) | 2204 | else if (callchain_ret < 0) |
2139 | pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel)); | 2205 | pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel)); |
2140 | thread__put(thread); | ||
2141 | out: | 2206 | out: |
2207 | thread__put(thread); | ||
2142 | return 0; | 2208 | return 0; |
2143 | } | 2209 | } |
2144 | 2210 | ||
@@ -2225,6 +2291,8 @@ static int trace__pgfault(struct trace *trace, | |||
2225 | trace__fprintf_callchain(trace, sample); | 2291 | trace__fprintf_callchain(trace, sample); |
2226 | else if (callchain_ret < 0) | 2292 | else if (callchain_ret < 0) |
2227 | pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel)); | 2293 | pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel)); |
2294 | |||
2295 | ++trace->nr_events_printed; | ||
2228 | out: | 2296 | out: |
2229 | err = 0; | 2297 | err = 0; |
2230 | out_put: | 2298 | out_put: |
@@ -2402,6 +2470,9 @@ static void trace__handle_event(struct trace *trace, union perf_event *event, st | |||
2402 | tracepoint_handler handler = evsel->handler; | 2470 | tracepoint_handler handler = evsel->handler; |
2403 | handler(trace, evsel, event, sample); | 2471 | handler(trace, evsel, event, sample); |
2404 | } | 2472 | } |
2473 | |||
2474 | if (trace->nr_events_printed >= trace->max_events && trace->max_events != ULONG_MAX) | ||
2475 | interrupted = true; | ||
2405 | } | 2476 | } |
2406 | 2477 | ||
2407 | static int trace__add_syscall_newtp(struct trace *trace) | 2478 | static int trace__add_syscall_newtp(struct trace *trace) |
@@ -2706,7 +2777,7 @@ next_event: | |||
2706 | int timeout = done ? 100 : -1; | 2777 | int timeout = done ? 100 : -1; |
2707 | 2778 | ||
2708 | if (!draining && perf_evlist__poll(evlist, timeout) > 0) { | 2779 | if (!draining && perf_evlist__poll(evlist, timeout) > 0) { |
2709 | if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0) | 2780 | if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP | POLLNVAL) == 0) |
2710 | draining = true; | 2781 | draining = true; |
2711 | 2782 | ||
2712 | goto again; | 2783 | goto again; |
@@ -3138,6 +3209,7 @@ static int trace__parse_events_option(const struct option *opt, const char *str, | |||
3138 | int len = strlen(str) + 1, err = -1, list, idx; | 3209 | int len = strlen(str) + 1, err = -1, list, idx; |
3139 | char *strace_groups_dir = system_path(STRACE_GROUPS_DIR); | 3210 | char *strace_groups_dir = system_path(STRACE_GROUPS_DIR); |
3140 | char group_name[PATH_MAX]; | 3211 | char group_name[PATH_MAX]; |
3212 | struct syscall_fmt *fmt; | ||
3141 | 3213 | ||
3142 | if (strace_groups_dir == NULL) | 3214 | if (strace_groups_dir == NULL) |
3143 | return -1; | 3215 | return -1; |
@@ -3155,12 +3227,19 @@ static int trace__parse_events_option(const struct option *opt, const char *str, | |||
3155 | if (syscalltbl__id(trace->sctbl, s) >= 0 || | 3227 | if (syscalltbl__id(trace->sctbl, s) >= 0 || |
3156 | syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) { | 3228 | syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) { |
3157 | list = 1; | 3229 | list = 1; |
3230 | goto do_concat; | ||
3231 | } | ||
3232 | |||
3233 | fmt = syscall_fmt__find_by_alias(s); | ||
3234 | if (fmt != NULL) { | ||
3235 | list = 1; | ||
3236 | s = fmt->name; | ||
3158 | } else { | 3237 | } else { |
3159 | path__join(group_name, sizeof(group_name), strace_groups_dir, s); | 3238 | path__join(group_name, sizeof(group_name), strace_groups_dir, s); |
3160 | if (access(group_name, R_OK) == 0) | 3239 | if (access(group_name, R_OK) == 0) |
3161 | list = 1; | 3240 | list = 1; |
3162 | } | 3241 | } |
3163 | 3242 | do_concat: | |
3164 | if (lists[list]) { | 3243 | if (lists[list]) { |
3165 | sprintf(lists[list] + strlen(lists[list]), ",%s", s); | 3244 | sprintf(lists[list] + strlen(lists[list]), ",%s", s); |
3166 | } else { | 3245 | } else { |
@@ -3249,6 +3328,7 @@ int cmd_trace(int argc, const char **argv) | |||
3249 | .trace_syscalls = false, | 3328 | .trace_syscalls = false, |
3250 | .kernel_syscallchains = false, | 3329 | .kernel_syscallchains = false, |
3251 | .max_stack = UINT_MAX, | 3330 | .max_stack = UINT_MAX, |
3331 | .max_events = ULONG_MAX, | ||
3252 | }; | 3332 | }; |
3253 | const char *output_name = NULL; | 3333 | const char *output_name = NULL; |
3254 | const struct option trace_options[] = { | 3334 | const struct option trace_options[] = { |
@@ -3301,6 +3381,8 @@ int cmd_trace(int argc, const char **argv) | |||
3301 | &record_parse_callchain_opt), | 3381 | &record_parse_callchain_opt), |
3302 | OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains, | 3382 | OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains, |
3303 | "Show the kernel callchains on the syscall exit path"), | 3383 | "Show the kernel callchains on the syscall exit path"), |
3384 | OPT_ULONG(0, "max-events", &trace.max_events, | ||
3385 | "Set the maximum number of events to print, exit after that is reached. "), | ||
3304 | OPT_UINTEGER(0, "min-stack", &trace.min_stack, | 3386 | OPT_UINTEGER(0, "min-stack", &trace.min_stack, |
3305 | "Set the minimum stack depth when parsing the callchain, " | 3387 | "Set the minimum stack depth when parsing the callchain, " |
3306 | "anything below the specified depth will be ignored."), | 3388 | "anything below the specified depth will be ignored."), |
diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index c72cc73a6b09..9531f7bd7d9b 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh | |||
@@ -5,6 +5,7 @@ HEADERS=' | |||
5 | include/uapi/drm/drm.h | 5 | include/uapi/drm/drm.h |
6 | include/uapi/drm/i915_drm.h | 6 | include/uapi/drm/i915_drm.h |
7 | include/uapi/linux/fcntl.h | 7 | include/uapi/linux/fcntl.h |
8 | include/uapi/linux/fs.h | ||
8 | include/uapi/linux/kcmp.h | 9 | include/uapi/linux/kcmp.h |
9 | include/uapi/linux/kvm.h | 10 | include/uapi/linux/kvm.h |
10 | include/uapi/linux/in.h | 11 | include/uapi/linux/in.h |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 21bf7f5a3cf5..0ed4a34c74c4 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -81,6 +81,7 @@ struct record_opts { | |||
81 | unsigned initial_delay; | 81 | unsigned initial_delay; |
82 | bool use_clockid; | 82 | bool use_clockid; |
83 | clockid_t clockid; | 83 | clockid_t clockid; |
84 | u64 clockid_res_ns; | ||
84 | unsigned int proc_map_timeout; | 85 | unsigned int proc_map_timeout; |
85 | }; | 86 | }; |
86 | 87 | ||
diff --git a/tools/perf/scripts/python/call-graph-from-sql.py b/tools/perf/scripts/python/call-graph-from-sql.py deleted file mode 100644 index b494a67a1c67..000000000000 --- a/tools/perf/scripts/python/call-graph-from-sql.py +++ /dev/null | |||
@@ -1,339 +0,0 @@ | |||
1 | #!/usr/bin/python2 | ||
2 | # call-graph-from-sql.py: create call-graph from sql database | ||
3 | # Copyright (c) 2014-2017, Intel Corporation. | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify it | ||
6 | # under the terms and conditions of the GNU General Public License, | ||
7 | # version 2, as published by the Free Software Foundation. | ||
8 | # | ||
9 | # This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | # more details. | ||
13 | |||
14 | # To use this script you will need to have exported data using either the | ||
15 | # export-to-sqlite.py or the export-to-postgresql.py script. Refer to those | ||
16 | # scripts for details. | ||
17 | # | ||
18 | # Following on from the example in the export scripts, a | ||
19 | # call-graph can be displayed for the pt_example database like this: | ||
20 | # | ||
21 | # python tools/perf/scripts/python/call-graph-from-sql.py pt_example | ||
22 | # | ||
23 | # Note that for PostgreSQL, this script supports connecting to remote databases | ||
24 | # by setting hostname, port, username, password, and dbname e.g. | ||
25 | # | ||
26 | # python tools/perf/scripts/python/call-graph-from-sql.py "hostname=myhost username=myuser password=mypassword dbname=pt_example" | ||
27 | # | ||
28 | # The result is a GUI window with a tree representing a context-sensitive | ||
29 | # call-graph. Expanding a couple of levels of the tree and adjusting column | ||
30 | # widths to suit will display something like: | ||
31 | # | ||
32 | # Call Graph: pt_example | ||
33 | # Call Path Object Count Time(ns) Time(%) Branch Count Branch Count(%) | ||
34 | # v- ls | ||
35 | # v- 2638:2638 | ||
36 | # v- _start ld-2.19.so 1 10074071 100.0 211135 100.0 | ||
37 | # |- unknown unknown 1 13198 0.1 1 0.0 | ||
38 | # >- _dl_start ld-2.19.so 1 1400980 13.9 19637 9.3 | ||
39 | # >- _d_linit_internal ld-2.19.so 1 448152 4.4 11094 5.3 | ||
40 | # v-__libc_start_main@plt ls 1 8211741 81.5 180397 85.4 | ||
41 | # >- _dl_fixup ld-2.19.so 1 7607 0.1 108 0.1 | ||
42 | # >- __cxa_atexit libc-2.19.so 1 11737 0.1 10 0.0 | ||
43 | # >- __libc_csu_init ls 1 10354 0.1 10 0.0 | ||
44 | # |- _setjmp libc-2.19.so 1 0 0.0 4 0.0 | ||
45 | # v- main ls 1 8182043 99.6 180254 99.9 | ||
46 | # | ||
47 | # Points to note: | ||
48 | # The top level is a command name (comm) | ||
49 | # The next level is a thread (pid:tid) | ||
50 | # Subsequent levels are functions | ||
51 | # 'Count' is the number of calls | ||
52 | # 'Time' is the elapsed time until the function returns | ||
53 | # Percentages are relative to the level above | ||
54 | # 'Branch Count' is the total number of branches for that function and all | ||
55 | # functions that it calls | ||
56 | |||
57 | import sys | ||
58 | from PySide.QtCore import * | ||
59 | from PySide.QtGui import * | ||
60 | from PySide.QtSql import * | ||
61 | from decimal import * | ||
62 | |||
63 | class TreeItem(): | ||
64 | |||
65 | def __init__(self, db, row, parent_item): | ||
66 | self.db = db | ||
67 | self.row = row | ||
68 | self.parent_item = parent_item | ||
69 | self.query_done = False; | ||
70 | self.child_count = 0 | ||
71 | self.child_items = [] | ||
72 | self.data = ["", "", "", "", "", "", ""] | ||
73 | self.comm_id = 0 | ||
74 | self.thread_id = 0 | ||
75 | self.call_path_id = 1 | ||
76 | self.branch_count = 0 | ||
77 | self.time = 0 | ||
78 | if not parent_item: | ||
79 | self.setUpRoot() | ||
80 | |||
81 | def setUpRoot(self): | ||
82 | self.query_done = True | ||
83 | query = QSqlQuery(self.db) | ||
84 | ret = query.exec_('SELECT id, comm FROM comms') | ||
85 | if not ret: | ||
86 | raise Exception("Query failed: " + query.lastError().text()) | ||
87 | while query.next(): | ||
88 | if not query.value(0): | ||
89 | continue | ||
90 | child_item = TreeItem(self.db, self.child_count, self) | ||
91 | self.child_items.append(child_item) | ||
92 | self.child_count += 1 | ||
93 | child_item.setUpLevel1(query.value(0), query.value(1)) | ||
94 | |||
95 | def setUpLevel1(self, comm_id, comm): | ||
96 | self.query_done = True; | ||
97 | self.comm_id = comm_id | ||
98 | self.data[0] = comm | ||
99 | self.child_items = [] | ||
100 | self.child_count = 0 | ||
101 | query = QSqlQuery(self.db) | ||
102 | ret = query.exec_('SELECT thread_id, ( SELECT pid FROM threads WHERE id = thread_id ), ( SELECT tid FROM threads WHERE id = thread_id ) FROM comm_threads WHERE comm_id = ' + str(comm_id)) | ||
103 | if not ret: | ||
104 | raise Exception("Query failed: " + query.lastError().text()) | ||
105 | while query.next(): | ||
106 | child_item = TreeItem(self.db, self.child_count, self) | ||
107 | self.child_items.append(child_item) | ||
108 | self.child_count += 1 | ||
109 | child_item.setUpLevel2(comm_id, query.value(0), query.value(1), query.value(2)) | ||
110 | |||
111 | def setUpLevel2(self, comm_id, thread_id, pid, tid): | ||
112 | self.comm_id = comm_id | ||
113 | self.thread_id = thread_id | ||
114 | self.data[0] = str(pid) + ":" + str(tid) | ||
115 | |||
116 | def getChildItem(self, row): | ||
117 | return self.child_items[row] | ||
118 | |||
119 | def getParentItem(self): | ||
120 | return self.parent_item | ||
121 | |||
122 | def getRow(self): | ||
123 | return self.row | ||
124 | |||
125 | def timePercent(self, b): | ||
126 | if not self.time: | ||
127 | return "0.0" | ||
128 | x = (b * Decimal(100)) / self.time | ||
129 | return str(x.quantize(Decimal('.1'), rounding=ROUND_HALF_UP)) | ||
130 | |||
131 | def branchPercent(self, b): | ||
132 | if not self.branch_count: | ||
133 | return "0.0" | ||
134 | x = (b * Decimal(100)) / self.branch_count | ||
135 | return str(x.quantize(Decimal('.1'), rounding=ROUND_HALF_UP)) | ||
136 | |||
137 | def addChild(self, call_path_id, name, dso, count, time, branch_count): | ||
138 | child_item = TreeItem(self.db, self.child_count, self) | ||
139 | child_item.comm_id = self.comm_id | ||
140 | child_item.thread_id = self.thread_id | ||
141 | child_item.call_path_id = call_path_id | ||
142 | child_item.branch_count = branch_count | ||
143 | child_item.time = time | ||
144 | child_item.data[0] = name | ||
145 | if dso == "[kernel.kallsyms]": | ||
146 | dso = "[kernel]" | ||
147 | child_item.data[1] = dso | ||
148 | child_item.data[2] = str(count) | ||
149 | child_item.data[3] = str(time) | ||
150 | child_item.data[4] = self.timePercent(time) | ||
151 | child_item.data[5] = str(branch_count) | ||
152 | child_item.data[6] = self.branchPercent(branch_count) | ||
153 | self.child_items.append(child_item) | ||
154 | self.child_count += 1 | ||
155 | |||
156 | def selectCalls(self): | ||
157 | self.query_done = True; | ||
158 | query = QSqlQuery(self.db) | ||
159 | ret = query.exec_('SELECT id, call_path_id, branch_count, call_time, return_time, ' | ||
160 | '( SELECT name FROM symbols WHERE id = ( SELECT symbol_id FROM call_paths WHERE id = call_path_id ) ), ' | ||
161 | '( SELECT short_name FROM dsos WHERE id = ( SELECT dso_id FROM symbols WHERE id = ( SELECT symbol_id FROM call_paths WHERE id = call_path_id ) ) ), ' | ||
162 | '( SELECT ip FROM call_paths where id = call_path_id ) ' | ||
163 | 'FROM calls WHERE parent_call_path_id = ' + str(self.call_path_id) + ' AND comm_id = ' + str(self.comm_id) + ' AND thread_id = ' + str(self.thread_id) + | ||
164 | ' ORDER BY call_path_id') | ||
165 | if not ret: | ||
166 | raise Exception("Query failed: " + query.lastError().text()) | ||
167 | last_call_path_id = 0 | ||
168 | name = "" | ||
169 | dso = "" | ||
170 | count = 0 | ||
171 | branch_count = 0 | ||
172 | total_branch_count = 0 | ||
173 | time = 0 | ||
174 | total_time = 0 | ||
175 | while query.next(): | ||
176 | if query.value(1) == last_call_path_id: | ||
177 | count += 1 | ||
178 | branch_count += query.value(2) | ||
179 | time += query.value(4) - query.value(3) | ||
180 | else: | ||
181 | if count: | ||
182 | self.addChild(last_call_path_id, name, dso, count, time, branch_count) | ||
183 | last_call_path_id = query.value(1) | ||
184 | name = query.value(5) | ||
185 | dso = query.value(6) | ||
186 | count = 1 | ||
187 | total_branch_count += branch_count | ||
188 | total_time += time | ||
189 | branch_count = query.value(2) | ||
190 | time = query.value(4) - query.value(3) | ||
191 | if count: | ||
192 | self.addChild(last_call_path_id, name, dso, count, time, branch_count) | ||
193 | total_branch_count += branch_count | ||
194 | total_time += time | ||
195 | # Top level does not have time or branch count, so fix that here | ||
196 | if total_branch_count > self.branch_count: | ||
197 | self.branch_count = total_branch_count | ||
198 | if self.branch_count: | ||
199 | for child_item in self.child_items: | ||
200 | child_item.data[6] = self.branchPercent(child_item.branch_count) | ||
201 | if total_time > self.time: | ||
202 | self.time = total_time | ||
203 | if self.time: | ||
204 | for child_item in self.child_items: | ||
205 | child_item.data[4] = self.timePercent(child_item.time) | ||
206 | |||
207 | def childCount(self): | ||
208 | if not self.query_done: | ||
209 | self.selectCalls() | ||
210 | return self.child_count | ||
211 | |||
212 | def columnCount(self): | ||
213 | return 7 | ||
214 | |||
215 | def columnHeader(self, column): | ||
216 | headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "] | ||
217 | return headers[column] | ||
218 | |||
219 | def getData(self, column): | ||
220 | return self.data[column] | ||
221 | |||
222 | class TreeModel(QAbstractItemModel): | ||
223 | |||
224 | def __init__(self, db, parent=None): | ||
225 | super(TreeModel, self).__init__(parent) | ||
226 | self.db = db | ||
227 | self.root = TreeItem(db, 0, None) | ||
228 | |||
229 | def columnCount(self, parent): | ||
230 | return self.root.columnCount() | ||
231 | |||
232 | def rowCount(self, parent): | ||
233 | if parent.isValid(): | ||
234 | parent_item = parent.internalPointer() | ||
235 | else: | ||
236 | parent_item = self.root | ||
237 | return parent_item.childCount() | ||
238 | |||
239 | def headerData(self, section, orientation, role): | ||
240 | if role == Qt.TextAlignmentRole: | ||
241 | if section > 1: | ||
242 | return Qt.AlignRight | ||
243 | if role != Qt.DisplayRole: | ||
244 | return None | ||
245 | if orientation != Qt.Horizontal: | ||
246 | return None | ||
247 | return self.root.columnHeader(section) | ||
248 | |||
249 | def parent(self, child): | ||
250 | child_item = child.internalPointer() | ||
251 | if child_item is self.root: | ||
252 | return QModelIndex() | ||
253 | parent_item = child_item.getParentItem() | ||
254 | return self.createIndex(parent_item.getRow(), 0, parent_item) | ||
255 | |||
256 | def index(self, row, column, parent): | ||
257 | if parent.isValid(): | ||
258 | parent_item = parent.internalPointer() | ||
259 | else: | ||
260 | parent_item = self.root | ||
261 | child_item = parent_item.getChildItem(row) | ||
262 | return self.createIndex(row, column, child_item) | ||
263 | |||
264 | def data(self, index, role): | ||
265 | if role == Qt.TextAlignmentRole: | ||
266 | if index.column() > 1: | ||
267 | return Qt.AlignRight | ||
268 | if role != Qt.DisplayRole: | ||
269 | return None | ||
270 | index_item = index.internalPointer() | ||
271 | return index_item.getData(index.column()) | ||
272 | |||
273 | class MainWindow(QMainWindow): | ||
274 | |||
275 | def __init__(self, db, dbname, parent=None): | ||
276 | super(MainWindow, self).__init__(parent) | ||
277 | |||
278 | self.setObjectName("MainWindow") | ||
279 | self.setWindowTitle("Call Graph: " + dbname) | ||
280 | self.move(100, 100) | ||
281 | self.resize(800, 600) | ||
282 | style = self.style() | ||
283 | icon = style.standardIcon(QStyle.SP_MessageBoxInformation) | ||
284 | self.setWindowIcon(icon); | ||
285 | |||
286 | self.model = TreeModel(db) | ||
287 | |||
288 | self.view = QTreeView() | ||
289 | self.view.setModel(self.model) | ||
290 | |||
291 | self.setCentralWidget(self.view) | ||
292 | |||
293 | if __name__ == '__main__': | ||
294 | if (len(sys.argv) < 2): | ||
295 | print >> sys.stderr, "Usage is: call-graph-from-sql.py <database name>" | ||
296 | raise Exception("Too few arguments") | ||
297 | |||
298 | dbname = sys.argv[1] | ||
299 | |||
300 | is_sqlite3 = False | ||
301 | try: | ||
302 | f = open(dbname) | ||
303 | if f.read(15) == "SQLite format 3": | ||
304 | is_sqlite3 = True | ||
305 | f.close() | ||
306 | except: | ||
307 | pass | ||
308 | |||
309 | if is_sqlite3: | ||
310 | db = QSqlDatabase.addDatabase('QSQLITE') | ||
311 | else: | ||
312 | db = QSqlDatabase.addDatabase('QPSQL') | ||
313 | opts = dbname.split() | ||
314 | for opt in opts: | ||
315 | if '=' in opt: | ||
316 | opt = opt.split('=') | ||
317 | if opt[0] == 'hostname': | ||
318 | db.setHostName(opt[1]) | ||
319 | elif opt[0] == 'port': | ||
320 | db.setPort(int(opt[1])) | ||
321 | elif opt[0] == 'username': | ||
322 | db.setUserName(opt[1]) | ||
323 | elif opt[0] == 'password': | ||
324 | db.setPassword(opt[1]) | ||
325 | elif opt[0] == 'dbname': | ||
326 | dbname = opt[1] | ||
327 | else: | ||
328 | dbname = opt | ||
329 | |||
330 | db.setDatabaseName(dbname) | ||
331 | if not db.open(): | ||
332 | raise Exception("Failed to open database " + dbname + " error: " + db.lastError().text()) | ||
333 | |||
334 | app = QApplication(sys.argv) | ||
335 | window = MainWindow(db, dbname) | ||
336 | window.show() | ||
337 | err = app.exec_() | ||
338 | db.close() | ||
339 | sys.exit(err) | ||
diff --git a/tools/perf/scripts/python/export-to-postgresql.py b/tools/perf/scripts/python/export-to-postgresql.py index e46f51b17513..0564dd7377f2 100644 --- a/tools/perf/scripts/python/export-to-postgresql.py +++ b/tools/perf/scripts/python/export-to-postgresql.py | |||
@@ -59,7 +59,7 @@ import datetime | |||
59 | # pt_example=# \q | 59 | # pt_example=# \q |
60 | # | 60 | # |
61 | # An example of using the database is provided by the script | 61 | # An example of using the database is provided by the script |
62 | # call-graph-from-sql.py. Refer to that script for details. | 62 | # exported-sql-viewer.py. Refer to that script for details. |
63 | # | 63 | # |
64 | # Tables: | 64 | # Tables: |
65 | # | 65 | # |
diff --git a/tools/perf/scripts/python/export-to-sqlite.py b/tools/perf/scripts/python/export-to-sqlite.py index e4bb82c8aba9..245caf2643ed 100644 --- a/tools/perf/scripts/python/export-to-sqlite.py +++ b/tools/perf/scripts/python/export-to-sqlite.py | |||
@@ -40,7 +40,7 @@ import datetime | |||
40 | # sqlite> .quit | 40 | # sqlite> .quit |
41 | # | 41 | # |
42 | # An example of using the database is provided by the script | 42 | # An example of using the database is provided by the script |
43 | # call-graph-from-sql.py. Refer to that script for details. | 43 | # exported-sql-viewer.py. Refer to that script for details. |
44 | # | 44 | # |
45 | # The database structure is practically the same as created by the script | 45 | # The database structure is practically the same as created by the script |
46 | # export-to-postgresql.py. Refer to that script for details. A notable | 46 | # export-to-postgresql.py. Refer to that script for details. A notable |
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py new file mode 100755 index 000000000000..24cb0bd56afa --- /dev/null +++ b/tools/perf/scripts/python/exported-sql-viewer.py | |||
@@ -0,0 +1,2128 @@ | |||
1 | #!/usr/bin/python2 | ||
2 | # SPDX-License-Identifier: GPL-2.0 | ||
3 | # exported-sql-viewer.py: view data from sql database | ||
4 | # Copyright (c) 2014-2018, Intel Corporation. | ||
5 | |||
6 | # To use this script you will need to have exported data using either the | ||
7 | # export-to-sqlite.py or the export-to-postgresql.py script. Refer to those | ||
8 | # scripts for details. | ||
9 | # | ||
10 | # Following on from the example in the export scripts, a | ||
11 | # call-graph can be displayed for the pt_example database like this: | ||
12 | # | ||
13 | # python tools/perf/scripts/python/exported-sql-viewer.py pt_example | ||
14 | # | ||
15 | # Note that for PostgreSQL, this script supports connecting to remote databases | ||
16 | # by setting hostname, port, username, password, and dbname e.g. | ||
17 | # | ||
18 | # python tools/perf/scripts/python/exported-sql-viewer.py "hostname=myhost username=myuser password=mypassword dbname=pt_example" | ||
19 | # | ||
20 | # The result is a GUI window with a tree representing a context-sensitive | ||
21 | # call-graph. Expanding a couple of levels of the tree and adjusting column | ||
22 | # widths to suit will display something like: | ||
23 | # | ||
24 | # Call Graph: pt_example | ||
25 | # Call Path Object Count Time(ns) Time(%) Branch Count Branch Count(%) | ||
26 | # v- ls | ||
27 | # v- 2638:2638 | ||
28 | # v- _start ld-2.19.so 1 10074071 100.0 211135 100.0 | ||
29 | # |- unknown unknown 1 13198 0.1 1 0.0 | ||
30 | # >- _dl_start ld-2.19.so 1 1400980 13.9 19637 9.3 | ||
31 | # >- _d_linit_internal ld-2.19.so 1 448152 4.4 11094 5.3 | ||
32 | # v-__libc_start_main@plt ls 1 8211741 81.5 180397 85.4 | ||
33 | # >- _dl_fixup ld-2.19.so 1 7607 0.1 108 0.1 | ||
34 | # >- __cxa_atexit libc-2.19.so 1 11737 0.1 10 0.0 | ||
35 | # >- __libc_csu_init ls 1 10354 0.1 10 0.0 | ||
36 | # |- _setjmp libc-2.19.so 1 0 0.0 4 0.0 | ||
37 | # v- main ls 1 8182043 99.6 180254 99.9 | ||
38 | # | ||
39 | # Points to note: | ||
40 | # The top level is a command name (comm) | ||
41 | # The next level is a thread (pid:tid) | ||
42 | # Subsequent levels are functions | ||
43 | # 'Count' is the number of calls | ||
44 | # 'Time' is the elapsed time until the function returns | ||
45 | # Percentages are relative to the level above | ||
46 | # 'Branch Count' is the total number of branches for that function and all | ||
47 | # functions that it calls | ||
48 | |||
49 | # There is also a "All branches" report, which displays branches and | ||
50 | # possibly disassembly. However, presently, the only supported disassembler is | ||
51 | # Intel XED, and additionally the object code must be present in perf build ID | ||
52 | # cache. To use Intel XED, libxed.so must be present. To build and install | ||
53 | # libxed.so: | ||
54 | # git clone https://github.com/intelxed/mbuild.git mbuild | ||
55 | # git clone https://github.com/intelxed/xed | ||
56 | # cd xed | ||
57 | # ./mfile.py --share | ||
58 | # sudo ./mfile.py --prefix=/usr/local install | ||
59 | # sudo ldconfig | ||
60 | # | ||
61 | # Example report: | ||
62 | # | ||
63 | # Time CPU Command PID TID Branch Type In Tx Branch | ||
64 | # 8107675239590 2 ls 22011 22011 return from interrupt No ffffffff86a00a67 native_irq_return_iret ([kernel]) -> 7fab593ea260 _start (ld-2.19.so) | ||
65 | # 7fab593ea260 48 89 e7 mov %rsp, %rdi | ||
66 | # 8107675239899 2 ls 22011 22011 hardware interrupt No 7fab593ea260 _start (ld-2.19.so) -> ffffffff86a012e0 page_fault ([kernel]) | ||
67 | # 8107675241900 2 ls 22011 22011 return from interrupt No ffffffff86a00a67 native_irq_return_iret ([kernel]) -> 7fab593ea260 _start (ld-2.19.so) | ||
68 | # 7fab593ea260 48 89 e7 mov %rsp, %rdi | ||
69 | # 7fab593ea263 e8 c8 06 00 00 callq 0x7fab593ea930 | ||
70 | # 8107675241900 2 ls 22011 22011 call No 7fab593ea263 _start+0x3 (ld-2.19.so) -> 7fab593ea930 _dl_start (ld-2.19.so) | ||
71 | # 7fab593ea930 55 pushq %rbp | ||
72 | # 7fab593ea931 48 89 e5 mov %rsp, %rbp | ||
73 | # 7fab593ea934 41 57 pushq %r15 | ||
74 | # 7fab593ea936 41 56 pushq %r14 | ||
75 | # 7fab593ea938 41 55 pushq %r13 | ||
76 | # 7fab593ea93a 41 54 pushq %r12 | ||
77 | # 7fab593ea93c 53 pushq %rbx | ||
78 | # 7fab593ea93d 48 89 fb mov %rdi, %rbx | ||
79 | # 7fab593ea940 48 83 ec 68 sub $0x68, %rsp | ||
80 | # 7fab593ea944 0f 31 rdtsc | ||
81 | # 7fab593ea946 48 c1 e2 20 shl $0x20, %rdx | ||
82 | # 7fab593ea94a 89 c0 mov %eax, %eax | ||
83 | # 7fab593ea94c 48 09 c2 or %rax, %rdx | ||
84 | # 7fab593ea94f 48 8b 05 1a 15 22 00 movq 0x22151a(%rip), %rax | ||
85 | # 8107675242232 2 ls 22011 22011 hardware interrupt No 7fab593ea94f _dl_start+0x1f (ld-2.19.so) -> ffffffff86a012e0 page_fault ([kernel]) | ||
86 | # 8107675242900 2 ls 22011 22011 return from interrupt No ffffffff86a00a67 native_irq_return_iret ([kernel]) -> 7fab593ea94f _dl_start+0x1f (ld-2.19.so) | ||
87 | # 7fab593ea94f 48 8b 05 1a 15 22 00 movq 0x22151a(%rip), %rax | ||
88 | # 7fab593ea956 48 89 15 3b 13 22 00 movq %rdx, 0x22133b(%rip) | ||
89 | # 8107675243232 2 ls 22011 22011 hardware interrupt No 7fab593ea956 _dl_start+0x26 (ld-2.19.so) -> ffffffff86a012e0 page_fault ([kernel]) | ||
90 | |||
91 | import sys | ||
92 | import weakref | ||
93 | import threading | ||
94 | import string | ||
95 | import cPickle | ||
96 | import re | ||
97 | import os | ||
98 | from PySide.QtCore import * | ||
99 | from PySide.QtGui import * | ||
100 | from PySide.QtSql import * | ||
101 | from decimal import * | ||
102 | from ctypes import * | ||
103 | from multiprocessing import Process, Array, Value, Event | ||
104 | |||
105 | # Data formatting helpers | ||
106 | |||
107 | def tohex(ip): | ||
108 | if ip < 0: | ||
109 | ip += 1 << 64 | ||
110 | return "%x" % ip | ||
111 | |||
112 | def offstr(offset): | ||
113 | if offset: | ||
114 | return "+0x%x" % offset | ||
115 | return "" | ||
116 | |||
117 | def dsoname(name): | ||
118 | if name == "[kernel.kallsyms]": | ||
119 | return "[kernel]" | ||
120 | return name | ||
121 | |||
122 | # Percent to one decimal place | ||
123 | |||
124 | def PercentToOneDP(n, d): | ||
125 | if not d: | ||
126 | return "0.0" | ||
127 | x = (n * Decimal(100)) / d | ||
128 | return str(x.quantize(Decimal(".1"), rounding=ROUND_HALF_UP)) | ||
129 | |||
130 | # Helper for queries that must not fail | ||
131 | |||
132 | def QueryExec(query, stmt): | ||
133 | ret = query.exec_(stmt) | ||
134 | if not ret: | ||
135 | raise Exception("Query failed: " + query.lastError().text()) | ||
136 | |||
137 | # Background thread | ||
138 | |||
139 | class Thread(QThread): | ||
140 | |||
141 | done = Signal(object) | ||
142 | |||
143 | def __init__(self, task, param=None, parent=None): | ||
144 | super(Thread, self).__init__(parent) | ||
145 | self.task = task | ||
146 | self.param = param | ||
147 | |||
148 | def run(self): | ||
149 | while True: | ||
150 | if self.param is None: | ||
151 | done, result = self.task() | ||
152 | else: | ||
153 | done, result = self.task(self.param) | ||
154 | self.done.emit(result) | ||
155 | if done: | ||
156 | break | ||
157 | |||
158 | # Tree data model | ||
159 | |||
160 | class TreeModel(QAbstractItemModel): | ||
161 | |||
162 | def __init__(self, root, parent=None): | ||
163 | super(TreeModel, self).__init__(parent) | ||
164 | self.root = root | ||
165 | self.last_row_read = 0 | ||
166 | |||
167 | def Item(self, parent): | ||
168 | if parent.isValid(): | ||
169 | return parent.internalPointer() | ||
170 | else: | ||
171 | return self.root | ||
172 | |||
173 | def rowCount(self, parent): | ||
174 | result = self.Item(parent).childCount() | ||
175 | if result < 0: | ||
176 | result = 0 | ||
177 | self.dataChanged.emit(parent, parent) | ||
178 | return result | ||
179 | |||
180 | def hasChildren(self, parent): | ||
181 | return self.Item(parent).hasChildren() | ||
182 | |||
183 | def headerData(self, section, orientation, role): | ||
184 | if role == Qt.TextAlignmentRole: | ||
185 | return self.columnAlignment(section) | ||
186 | if role != Qt.DisplayRole: | ||
187 | return None | ||
188 | if orientation != Qt.Horizontal: | ||
189 | return None | ||
190 | return self.columnHeader(section) | ||
191 | |||
192 | def parent(self, child): | ||
193 | child_item = child.internalPointer() | ||
194 | if child_item is self.root: | ||
195 | return QModelIndex() | ||
196 | parent_item = child_item.getParentItem() | ||
197 | return self.createIndex(parent_item.getRow(), 0, parent_item) | ||
198 | |||
199 | def index(self, row, column, parent): | ||
200 | child_item = self.Item(parent).getChildItem(row) | ||
201 | return self.createIndex(row, column, child_item) | ||
202 | |||
203 | def DisplayData(self, item, index): | ||
204 | return item.getData(index.column()) | ||
205 | |||
206 | def FetchIfNeeded(self, row): | ||
207 | if row > self.last_row_read: | ||
208 | self.last_row_read = row | ||
209 | if row + 10 >= self.root.child_count: | ||
210 | self.fetcher.Fetch(glb_chunk_sz) | ||
211 | |||
212 | def columnAlignment(self, column): | ||
213 | return Qt.AlignLeft | ||
214 | |||
215 | def columnFont(self, column): | ||
216 | return None | ||
217 | |||
218 | def data(self, index, role): | ||
219 | if role == Qt.TextAlignmentRole: | ||
220 | return self.columnAlignment(index.column()) | ||
221 | if role == Qt.FontRole: | ||
222 | return self.columnFont(index.column()) | ||
223 | if role != Qt.DisplayRole: | ||
224 | return None | ||
225 | item = index.internalPointer() | ||
226 | return self.DisplayData(item, index) | ||
227 | |||
228 | # Table data model | ||
229 | |||
230 | class TableModel(QAbstractTableModel): | ||
231 | |||
232 | def __init__(self, parent=None): | ||
233 | super(TableModel, self).__init__(parent) | ||
234 | self.child_count = 0 | ||
235 | self.child_items = [] | ||
236 | self.last_row_read = 0 | ||
237 | |||
238 | def Item(self, parent): | ||
239 | if parent.isValid(): | ||
240 | return parent.internalPointer() | ||
241 | else: | ||
242 | return self | ||
243 | |||
244 | def rowCount(self, parent): | ||
245 | return self.child_count | ||
246 | |||
247 | def headerData(self, section, orientation, role): | ||
248 | if role == Qt.TextAlignmentRole: | ||
249 | return self.columnAlignment(section) | ||
250 | if role != Qt.DisplayRole: | ||
251 | return None | ||
252 | if orientation != Qt.Horizontal: | ||
253 | return None | ||
254 | return self.columnHeader(section) | ||
255 | |||
256 | def index(self, row, column, parent): | ||
257 | return self.createIndex(row, column, self.child_items[row]) | ||
258 | |||
259 | def DisplayData(self, item, index): | ||
260 | return item.getData(index.column()) | ||
261 | |||
262 | def FetchIfNeeded(self, row): | ||
263 | if row > self.last_row_read: | ||
264 | self.last_row_read = row | ||
265 | if row + 10 >= self.child_count: | ||
266 | self.fetcher.Fetch(glb_chunk_sz) | ||
267 | |||
268 | def columnAlignment(self, column): | ||
269 | return Qt.AlignLeft | ||
270 | |||
271 | def columnFont(self, column): | ||
272 | return None | ||
273 | |||
274 | def data(self, index, role): | ||
275 | if role == Qt.TextAlignmentRole: | ||
276 | return self.columnAlignment(index.column()) | ||
277 | if role == Qt.FontRole: | ||
278 | return self.columnFont(index.column()) | ||
279 | if role != Qt.DisplayRole: | ||
280 | return None | ||
281 | item = index.internalPointer() | ||
282 | return self.DisplayData(item, index) | ||
283 | |||
284 | # Model cache | ||
285 | |||
286 | model_cache = weakref.WeakValueDictionary() | ||
287 | model_cache_lock = threading.Lock() | ||
288 | |||
289 | def LookupCreateModel(model_name, create_fn): | ||
290 | model_cache_lock.acquire() | ||
291 | try: | ||
292 | model = model_cache[model_name] | ||
293 | except: | ||
294 | model = None | ||
295 | if model is None: | ||
296 | model = create_fn() | ||
297 | model_cache[model_name] = model | ||
298 | model_cache_lock.release() | ||
299 | return model | ||
300 | |||
301 | # Find bar | ||
302 | |||
303 | class FindBar(): | ||
304 | |||
305 | def __init__(self, parent, finder, is_reg_expr=False): | ||
306 | self.finder = finder | ||
307 | self.context = [] | ||
308 | self.last_value = None | ||
309 | self.last_pattern = None | ||
310 | |||
311 | label = QLabel("Find:") | ||
312 | label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) | ||
313 | |||
314 | self.textbox = QComboBox() | ||
315 | self.textbox.setEditable(True) | ||
316 | self.textbox.currentIndexChanged.connect(self.ValueChanged) | ||
317 | |||
318 | self.progress = QProgressBar() | ||
319 | self.progress.setRange(0, 0) | ||
320 | self.progress.hide() | ||
321 | |||
322 | if is_reg_expr: | ||
323 | self.pattern = QCheckBox("Regular Expression") | ||
324 | else: | ||
325 | self.pattern = QCheckBox("Pattern") | ||
326 | self.pattern.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) | ||
327 | |||
328 | self.next_button = QToolButton() | ||
329 | self.next_button.setIcon(parent.style().standardIcon(QStyle.SP_ArrowDown)) | ||
330 | self.next_button.released.connect(lambda: self.NextPrev(1)) | ||
331 | |||
332 | self.prev_button = QToolButton() | ||
333 | self.prev_button.setIcon(parent.style().standardIcon(QStyle.SP_ArrowUp)) | ||
334 | self.prev_button.released.connect(lambda: self.NextPrev(-1)) | ||
335 | |||
336 | self.close_button = QToolButton() | ||
337 | self.close_button.setIcon(parent.style().standardIcon(QStyle.SP_DockWidgetCloseButton)) | ||
338 | self.close_button.released.connect(self.Deactivate) | ||
339 | |||
340 | self.hbox = QHBoxLayout() | ||
341 | self.hbox.setContentsMargins(0, 0, 0, 0) | ||
342 | |||
343 | self.hbox.addWidget(label) | ||
344 | self.hbox.addWidget(self.textbox) | ||
345 | self.hbox.addWidget(self.progress) | ||
346 | self.hbox.addWidget(self.pattern) | ||
347 | self.hbox.addWidget(self.next_button) | ||
348 | self.hbox.addWidget(self.prev_button) | ||
349 | self.hbox.addWidget(self.close_button) | ||
350 | |||
351 | self.bar = QWidget() | ||
352 | self.bar.setLayout(self.hbox); | ||
353 | self.bar.hide() | ||
354 | |||
355 | def Widget(self): | ||
356 | return self.bar | ||
357 | |||
358 | def Activate(self): | ||
359 | self.bar.show() | ||
360 | self.textbox.setFocus() | ||
361 | |||
362 | def Deactivate(self): | ||
363 | self.bar.hide() | ||
364 | |||
365 | def Busy(self): | ||
366 | self.textbox.setEnabled(False) | ||
367 | self.pattern.hide() | ||
368 | self.next_button.hide() | ||
369 | self.prev_button.hide() | ||
370 | self.progress.show() | ||
371 | |||
372 | def Idle(self): | ||
373 | self.textbox.setEnabled(True) | ||
374 | self.progress.hide() | ||
375 | self.pattern.show() | ||
376 | self.next_button.show() | ||
377 | self.prev_button.show() | ||
378 | |||
379 | def Find(self, direction): | ||
380 | value = self.textbox.currentText() | ||
381 | pattern = self.pattern.isChecked() | ||
382 | self.last_value = value | ||
383 | self.last_pattern = pattern | ||
384 | self.finder.Find(value, direction, pattern, self.context) | ||
385 | |||
386 | def ValueChanged(self): | ||
387 | value = self.textbox.currentText() | ||
388 | pattern = self.pattern.isChecked() | ||
389 | index = self.textbox.currentIndex() | ||
390 | data = self.textbox.itemData(index) | ||
391 | # Store the pattern in the combo box to keep it with the text value | ||
392 | if data == None: | ||
393 | self.textbox.setItemData(index, pattern) | ||
394 | else: | ||
395 | self.pattern.setChecked(data) | ||
396 | self.Find(0) | ||
397 | |||
398 | def NextPrev(self, direction): | ||
399 | value = self.textbox.currentText() | ||
400 | pattern = self.pattern.isChecked() | ||
401 | if value != self.last_value: | ||
402 | index = self.textbox.findText(value) | ||
403 | # Allow for a button press before the value has been added to the combo box | ||
404 | if index < 0: | ||
405 | index = self.textbox.count() | ||
406 | self.textbox.addItem(value, pattern) | ||
407 | self.textbox.setCurrentIndex(index) | ||
408 | return | ||
409 | else: | ||
410 | self.textbox.setItemData(index, pattern) | ||
411 | elif pattern != self.last_pattern: | ||
412 | # Keep the pattern recorded in the combo box up to date | ||
413 | index = self.textbox.currentIndex() | ||
414 | self.textbox.setItemData(index, pattern) | ||
415 | self.Find(direction) | ||
416 | |||
417 | def NotFound(self): | ||
418 | QMessageBox.information(self.bar, "Find", "'" + self.textbox.currentText() + "' not found") | ||
419 | |||
420 | # Context-sensitive call graph data model item base | ||
421 | |||
422 | class CallGraphLevelItemBase(object): | ||
423 | |||
424 | def __init__(self, glb, row, parent_item): | ||
425 | self.glb = glb | ||
426 | self.row = row | ||
427 | self.parent_item = parent_item | ||
428 | self.query_done = False; | ||
429 | self.child_count = 0 | ||
430 | self.child_items = [] | ||
431 | |||
432 | def getChildItem(self, row): | ||
433 | return self.child_items[row] | ||
434 | |||
435 | def getParentItem(self): | ||
436 | return self.parent_item | ||
437 | |||
438 | def getRow(self): | ||
439 | return self.row | ||
440 | |||
441 | def childCount(self): | ||
442 | if not self.query_done: | ||
443 | self.Select() | ||
444 | if not self.child_count: | ||
445 | return -1 | ||
446 | return self.child_count | ||
447 | |||
448 | def hasChildren(self): | ||
449 | if not self.query_done: | ||
450 | return True | ||
451 | return self.child_count > 0 | ||
452 | |||
453 | def getData(self, column): | ||
454 | return self.data[column] | ||
455 | |||
456 | # Context-sensitive call graph data model level 2+ item base | ||
457 | |||
458 | class CallGraphLevelTwoPlusItemBase(CallGraphLevelItemBase): | ||
459 | |||
460 | def __init__(self, glb, row, comm_id, thread_id, call_path_id, time, branch_count, parent_item): | ||
461 | super(CallGraphLevelTwoPlusItemBase, self).__init__(glb, row, parent_item) | ||
462 | self.comm_id = comm_id | ||
463 | self.thread_id = thread_id | ||
464 | self.call_path_id = call_path_id | ||
465 | self.branch_count = branch_count | ||
466 | self.time = time | ||
467 | |||
468 | def Select(self): | ||
469 | self.query_done = True; | ||
470 | query = QSqlQuery(self.glb.db) | ||
471 | QueryExec(query, "SELECT call_path_id, name, short_name, COUNT(calls.id), SUM(return_time - call_time), SUM(branch_count)" | ||
472 | " FROM calls" | ||
473 | " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" | ||
474 | " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" | ||
475 | " INNER JOIN dsos ON symbols.dso_id = dsos.id" | ||
476 | " WHERE parent_call_path_id = " + str(self.call_path_id) + | ||
477 | " AND comm_id = " + str(self.comm_id) + | ||
478 | " AND thread_id = " + str(self.thread_id) + | ||
479 | " GROUP BY call_path_id, name, short_name" | ||
480 | " ORDER BY call_path_id") | ||
481 | while query.next(): | ||
482 | child_item = CallGraphLevelThreeItem(self.glb, self.child_count, self.comm_id, self.thread_id, query.value(0), query.value(1), query.value(2), query.value(3), int(query.value(4)), int(query.value(5)), self) | ||
483 | self.child_items.append(child_item) | ||
484 | self.child_count += 1 | ||
485 | |||
486 | # Context-sensitive call graph data model level three item | ||
487 | |||
488 | class CallGraphLevelThreeItem(CallGraphLevelTwoPlusItemBase): | ||
489 | |||
490 | def __init__(self, glb, row, comm_id, thread_id, call_path_id, name, dso, count, time, branch_count, parent_item): | ||
491 | super(CallGraphLevelThreeItem, self).__init__(glb, row, comm_id, thread_id, call_path_id, time, branch_count, parent_item) | ||
492 | dso = dsoname(dso) | ||
493 | self.data = [ name, dso, str(count), str(time), PercentToOneDP(time, parent_item.time), str(branch_count), PercentToOneDP(branch_count, parent_item.branch_count) ] | ||
494 | self.dbid = call_path_id | ||
495 | |||
496 | # Context-sensitive call graph data model level two item | ||
497 | |||
498 | class CallGraphLevelTwoItem(CallGraphLevelTwoPlusItemBase): | ||
499 | |||
500 | def __init__(self, glb, row, comm_id, thread_id, pid, tid, parent_item): | ||
501 | super(CallGraphLevelTwoItem, self).__init__(glb, row, comm_id, thread_id, 1, 0, 0, parent_item) | ||
502 | self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", ""] | ||
503 | self.dbid = thread_id | ||
504 | |||
505 | def Select(self): | ||
506 | super(CallGraphLevelTwoItem, self).Select() | ||
507 | for child_item in self.child_items: | ||
508 | self.time += child_item.time | ||
509 | self.branch_count += child_item.branch_count | ||
510 | for child_item in self.child_items: | ||
511 | child_item.data[4] = PercentToOneDP(child_item.time, self.time) | ||
512 | child_item.data[6] = PercentToOneDP(child_item.branch_count, self.branch_count) | ||
513 | |||
514 | # Context-sensitive call graph data model level one item | ||
515 | |||
516 | class CallGraphLevelOneItem(CallGraphLevelItemBase): | ||
517 | |||
518 | def __init__(self, glb, row, comm_id, comm, parent_item): | ||
519 | super(CallGraphLevelOneItem, self).__init__(glb, row, parent_item) | ||
520 | self.data = [comm, "", "", "", "", "", ""] | ||
521 | self.dbid = comm_id | ||
522 | |||
523 | def Select(self): | ||
524 | self.query_done = True; | ||
525 | query = QSqlQuery(self.glb.db) | ||
526 | QueryExec(query, "SELECT thread_id, pid, tid" | ||
527 | " FROM comm_threads" | ||
528 | " INNER JOIN threads ON thread_id = threads.id" | ||
529 | " WHERE comm_id = " + str(self.dbid)) | ||
530 | while query.next(): | ||
531 | child_item = CallGraphLevelTwoItem(self.glb, self.child_count, self.dbid, query.value(0), query.value(1), query.value(2), self) | ||
532 | self.child_items.append(child_item) | ||
533 | self.child_count += 1 | ||
534 | |||
535 | # Context-sensitive call graph data model root item | ||
536 | |||
537 | class CallGraphRootItem(CallGraphLevelItemBase): | ||
538 | |||
539 | def __init__(self, glb): | ||
540 | super(CallGraphRootItem, self).__init__(glb, 0, None) | ||
541 | self.dbid = 0 | ||
542 | self.query_done = True; | ||
543 | query = QSqlQuery(glb.db) | ||
544 | QueryExec(query, "SELECT id, comm FROM comms") | ||
545 | while query.next(): | ||
546 | if not query.value(0): | ||
547 | continue | ||
548 | child_item = CallGraphLevelOneItem(glb, self.child_count, query.value(0), query.value(1), self) | ||
549 | self.child_items.append(child_item) | ||
550 | self.child_count += 1 | ||
551 | |||
552 | # Context-sensitive call graph data model | ||
553 | |||
554 | class CallGraphModel(TreeModel): | ||
555 | |||
556 | def __init__(self, glb, parent=None): | ||
557 | super(CallGraphModel, self).__init__(CallGraphRootItem(glb), parent) | ||
558 | self.glb = glb | ||
559 | |||
560 | def columnCount(self, parent=None): | ||
561 | return 7 | ||
562 | |||
563 | def columnHeader(self, column): | ||
564 | headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "] | ||
565 | return headers[column] | ||
566 | |||
567 | def columnAlignment(self, column): | ||
568 | alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ] | ||
569 | return alignment[column] | ||
570 | |||
571 | def FindSelect(self, value, pattern, query): | ||
572 | if pattern: | ||
573 | # postgresql and sqlite pattern patching differences: | ||
574 | # postgresql LIKE is case sensitive but sqlite LIKE is not | ||
575 | # postgresql LIKE allows % and _ to be escaped with \ but sqlite LIKE does not | ||
576 | # postgresql supports ILIKE which is case insensitive | ||
577 | # sqlite supports GLOB (text only) which uses * and ? and is case sensitive | ||
578 | if not self.glb.dbref.is_sqlite3: | ||
579 | # Escape % and _ | ||
580 | s = value.replace("%", "\%") | ||
581 | s = s.replace("_", "\_") | ||
582 | # Translate * and ? into SQL LIKE pattern characters % and _ | ||
583 | trans = string.maketrans("*?", "%_") | ||
584 | match = " LIKE '" + str(s).translate(trans) + "'" | ||
585 | else: | ||
586 | match = " GLOB '" + str(value) + "'" | ||
587 | else: | ||
588 | match = " = '" + str(value) + "'" | ||
589 | QueryExec(query, "SELECT call_path_id, comm_id, thread_id" | ||
590 | " FROM calls" | ||
591 | " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" | ||
592 | " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" | ||
593 | " WHERE symbols.name" + match + | ||
594 | " GROUP BY comm_id, thread_id, call_path_id" | ||
595 | " ORDER BY comm_id, thread_id, call_path_id") | ||
596 | |||
597 | def FindPath(self, query): | ||
598 | # Turn the query result into a list of ids that the tree view can walk | ||
599 | # to open the tree at the right place. | ||
600 | ids = [] | ||
601 | parent_id = query.value(0) | ||
602 | while parent_id: | ||
603 | ids.insert(0, parent_id) | ||
604 | q2 = QSqlQuery(self.glb.db) | ||
605 | QueryExec(q2, "SELECT parent_id" | ||
606 | " FROM call_paths" | ||
607 | " WHERE id = " + str(parent_id)) | ||
608 | if not q2.next(): | ||
609 | break | ||
610 | parent_id = q2.value(0) | ||
611 | # The call path root is not used | ||
612 | if ids[0] == 1: | ||
613 | del ids[0] | ||
614 | ids.insert(0, query.value(2)) | ||
615 | ids.insert(0, query.value(1)) | ||
616 | return ids | ||
617 | |||
618 | def Found(self, query, found): | ||
619 | if found: | ||
620 | return self.FindPath(query) | ||
621 | return [] | ||
622 | |||
623 | def FindValue(self, value, pattern, query, last_value, last_pattern): | ||
624 | if last_value == value and pattern == last_pattern: | ||
625 | found = query.first() | ||
626 | else: | ||
627 | self.FindSelect(value, pattern, query) | ||
628 | found = query.next() | ||
629 | return self.Found(query, found) | ||
630 | |||
631 | def FindNext(self, query): | ||
632 | found = query.next() | ||
633 | if not found: | ||
634 | found = query.first() | ||
635 | return self.Found(query, found) | ||
636 | |||
637 | def FindPrev(self, query): | ||
638 | found = query.previous() | ||
639 | if not found: | ||
640 | found = query.last() | ||
641 | return self.Found(query, found) | ||
642 | |||
643 | def FindThread(self, c): | ||
644 | if c.direction == 0 or c.value != c.last_value or c.pattern != c.last_pattern: | ||
645 | ids = self.FindValue(c.value, c.pattern, c.query, c.last_value, c.last_pattern) | ||
646 | elif c.direction > 0: | ||
647 | ids = self.FindNext(c.query) | ||
648 | else: | ||
649 | ids = self.FindPrev(c.query) | ||
650 | return (True, ids) | ||
651 | |||
652 | def Find(self, value, direction, pattern, context, callback): | ||
653 | class Context(): | ||
654 | def __init__(self, *x): | ||
655 | self.value, self.direction, self.pattern, self.query, self.last_value, self.last_pattern = x | ||
656 | def Update(self, *x): | ||
657 | self.value, self.direction, self.pattern, self.last_value, self.last_pattern = x + (self.value, self.pattern) | ||
658 | if len(context): | ||
659 | context[0].Update(value, direction, pattern) | ||
660 | else: | ||
661 | context.append(Context(value, direction, pattern, QSqlQuery(self.glb.db), None, None)) | ||
662 | # Use a thread so the UI is not blocked during the SELECT | ||
663 | thread = Thread(self.FindThread, context[0]) | ||
664 | thread.done.connect(lambda ids, t=thread, c=callback: self.FindDone(t, c, ids), Qt.QueuedConnection) | ||
665 | thread.start() | ||
666 | |||
667 | def FindDone(self, thread, callback, ids): | ||
668 | callback(ids) | ||
669 | |||
670 | # Vertical widget layout | ||
671 | |||
672 | class VBox(): | ||
673 | |||
674 | def __init__(self, w1, w2, w3=None): | ||
675 | self.vbox = QWidget() | ||
676 | self.vbox.setLayout(QVBoxLayout()); | ||
677 | |||
678 | self.vbox.layout().setContentsMargins(0, 0, 0, 0) | ||
679 | |||
680 | self.vbox.layout().addWidget(w1) | ||
681 | self.vbox.layout().addWidget(w2) | ||
682 | if w3: | ||
683 | self.vbox.layout().addWidget(w3) | ||
684 | |||
685 | def Widget(self): | ||
686 | return self.vbox | ||
687 | |||
688 | # Context-sensitive call graph window | ||
689 | |||
690 | class CallGraphWindow(QMdiSubWindow): | ||
691 | |||
692 | def __init__(self, glb, parent=None): | ||
693 | super(CallGraphWindow, self).__init__(parent) | ||
694 | |||
695 | self.model = LookupCreateModel("Context-Sensitive Call Graph", lambda x=glb: CallGraphModel(x)) | ||
696 | |||
697 | self.view = QTreeView() | ||
698 | self.view.setModel(self.model) | ||
699 | |||
700 | for c, w in ((0, 250), (1, 100), (2, 60), (3, 70), (4, 70), (5, 100)): | ||
701 | self.view.setColumnWidth(c, w) | ||
702 | |||
703 | self.find_bar = FindBar(self, self) | ||
704 | |||
705 | self.vbox = VBox(self.view, self.find_bar.Widget()) | ||
706 | |||
707 | self.setWidget(self.vbox.Widget()) | ||
708 | |||
709 | AddSubWindow(glb.mainwindow.mdi_area, self, "Context-Sensitive Call Graph") | ||
710 | |||
711 | def DisplayFound(self, ids): | ||
712 | if not len(ids): | ||
713 | return False | ||
714 | parent = QModelIndex() | ||
715 | for dbid in ids: | ||
716 | found = False | ||
717 | n = self.model.rowCount(parent) | ||
718 | for row in xrange(n): | ||
719 | child = self.model.index(row, 0, parent) | ||
720 | if child.internalPointer().dbid == dbid: | ||
721 | found = True | ||
722 | self.view.setCurrentIndex(child) | ||
723 | parent = child | ||
724 | break | ||
725 | if not found: | ||
726 | break | ||
727 | return found | ||
728 | |||
729 | def Find(self, value, direction, pattern, context): | ||
730 | self.view.setFocus() | ||
731 | self.find_bar.Busy() | ||
732 | self.model.Find(value, direction, pattern, context, self.FindDone) | ||
733 | |||
734 | def FindDone(self, ids): | ||
735 | found = True | ||
736 | if not self.DisplayFound(ids): | ||
737 | found = False | ||
738 | self.find_bar.Idle() | ||
739 | if not found: | ||
740 | self.find_bar.NotFound() | ||
741 | |||
742 | # Child data item finder | ||
743 | |||
744 | class ChildDataItemFinder(): | ||
745 | |||
746 | def __init__(self, root): | ||
747 | self.root = root | ||
748 | self.value, self.direction, self.pattern, self.last_value, self.last_pattern = (None,) * 5 | ||
749 | self.rows = [] | ||
750 | self.pos = 0 | ||
751 | |||
752 | def FindSelect(self): | ||
753 | self.rows = [] | ||
754 | if self.pattern: | ||
755 | pattern = re.compile(self.value) | ||
756 | for child in self.root.child_items: | ||
757 | for column_data in child.data: | ||
758 | if re.search(pattern, str(column_data)) is not None: | ||
759 | self.rows.append(child.row) | ||
760 | break | ||
761 | else: | ||
762 | for child in self.root.child_items: | ||
763 | for column_data in child.data: | ||
764 | if self.value in str(column_data): | ||
765 | self.rows.append(child.row) | ||
766 | break | ||
767 | |||
768 | def FindValue(self): | ||
769 | self.pos = 0 | ||
770 | if self.last_value != self.value or self.pattern != self.last_pattern: | ||
771 | self.FindSelect() | ||
772 | if not len(self.rows): | ||
773 | return -1 | ||
774 | return self.rows[self.pos] | ||
775 | |||
776 | def FindThread(self): | ||
777 | if self.direction == 0 or self.value != self.last_value or self.pattern != self.last_pattern: | ||
778 | row = self.FindValue() | ||
779 | elif len(self.rows): | ||
780 | if self.direction > 0: | ||
781 | self.pos += 1 | ||
782 | if self.pos >= len(self.rows): | ||
783 | self.pos = 0 | ||
784 | else: | ||
785 | self.pos -= 1 | ||
786 | if self.pos < 0: | ||
787 | self.pos = len(self.rows) - 1 | ||
788 | row = self.rows[self.pos] | ||
789 | else: | ||
790 | row = -1 | ||
791 | return (True, row) | ||
792 | |||
793 | def Find(self, value, direction, pattern, context, callback): | ||
794 | self.value, self.direction, self.pattern, self.last_value, self.last_pattern = (value, direction,pattern, self.value, self.pattern) | ||
795 | # Use a thread so the UI is not blocked | ||
796 | thread = Thread(self.FindThread) | ||
797 | thread.done.connect(lambda row, t=thread, c=callback: self.FindDone(t, c, row), Qt.QueuedConnection) | ||
798 | thread.start() | ||
799 | |||
800 | def FindDone(self, thread, callback, row): | ||
801 | callback(row) | ||
802 | |||
803 | # Number of database records to fetch in one go | ||
804 | |||
805 | glb_chunk_sz = 10000 | ||
806 | |||
807 | # size of pickled integer big enough for record size | ||
808 | |||
809 | glb_nsz = 8 | ||
810 | |||
811 | # Background process for SQL data fetcher | ||
812 | |||
813 | class SQLFetcherProcess(): | ||
814 | |||
815 | def __init__(self, dbref, sql, buffer, head, tail, fetch_count, fetching_done, process_target, wait_event, fetched_event, prep): | ||
816 | # Need a unique connection name | ||
817 | conn_name = "SQLFetcher" + str(os.getpid()) | ||
818 | self.db, dbname = dbref.Open(conn_name) | ||
819 | self.sql = sql | ||
820 | self.buffer = buffer | ||
821 | self.head = head | ||
822 | self.tail = tail | ||
823 | self.fetch_count = fetch_count | ||
824 | self.fetching_done = fetching_done | ||
825 | self.process_target = process_target | ||
826 | self.wait_event = wait_event | ||
827 | self.fetched_event = fetched_event | ||
828 | self.prep = prep | ||
829 | self.query = QSqlQuery(self.db) | ||
830 | self.query_limit = 0 if "$$last_id$$" in sql else 2 | ||
831 | self.last_id = -1 | ||
832 | self.fetched = 0 | ||
833 | self.more = True | ||
834 | self.local_head = self.head.value | ||
835 | self.local_tail = self.tail.value | ||
836 | |||
837 | def Select(self): | ||
838 | if self.query_limit: | ||
839 | if self.query_limit == 1: | ||
840 | return | ||
841 | self.query_limit -= 1 | ||
842 | stmt = self.sql.replace("$$last_id$$", str(self.last_id)) | ||
843 | QueryExec(self.query, stmt) | ||
844 | |||
845 | def Next(self): | ||
846 | if not self.query.next(): | ||
847 | self.Select() | ||
848 | if not self.query.next(): | ||
849 | return None | ||
850 | self.last_id = self.query.value(0) | ||
851 | return self.prep(self.query) | ||
852 | |||
853 | def WaitForTarget(self): | ||
854 | while True: | ||
855 | self.wait_event.clear() | ||
856 | target = self.process_target.value | ||
857 | if target > self.fetched or target < 0: | ||
858 | break | ||
859 | self.wait_event.wait() | ||
860 | return target | ||
861 | |||
862 | def HasSpace(self, sz): | ||
863 | if self.local_tail <= self.local_head: | ||
864 | space = len(self.buffer) - self.local_head | ||
865 | if space > sz: | ||
866 | return True | ||
867 | if space >= glb_nsz: | ||
868 | # Use 0 (or space < glb_nsz) to mean there is no more at the top of the buffer | ||
869 | nd = cPickle.dumps(0, cPickle.HIGHEST_PROTOCOL) | ||
870 | self.buffer[self.local_head : self.local_head + len(nd)] = nd | ||
871 | self.local_head = 0 | ||
872 | if self.local_tail - self.local_head > sz: | ||
873 | return True | ||
874 | return False | ||
875 | |||
876 | def WaitForSpace(self, sz): | ||
877 | if self.HasSpace(sz): | ||
878 | return | ||
879 | while True: | ||
880 | self.wait_event.clear() | ||
881 | self.local_tail = self.tail.value | ||
882 | if self.HasSpace(sz): | ||
883 | return | ||
884 | self.wait_event.wait() | ||
885 | |||
886 | def AddToBuffer(self, obj): | ||
887 | d = cPickle.dumps(obj, cPickle.HIGHEST_PROTOCOL) | ||
888 | n = len(d) | ||
889 | nd = cPickle.dumps(n, cPickle.HIGHEST_PROTOCOL) | ||
890 | sz = n + glb_nsz | ||
891 | self.WaitForSpace(sz) | ||
892 | pos = self.local_head | ||
893 | self.buffer[pos : pos + len(nd)] = nd | ||
894 | self.buffer[pos + glb_nsz : pos + sz] = d | ||
895 | self.local_head += sz | ||
896 | |||
897 | def FetchBatch(self, batch_size): | ||
898 | fetched = 0 | ||
899 | while batch_size > fetched: | ||
900 | obj = self.Next() | ||
901 | if obj is None: | ||
902 | self.more = False | ||
903 | break | ||
904 | self.AddToBuffer(obj) | ||
905 | fetched += 1 | ||
906 | if fetched: | ||
907 | self.fetched += fetched | ||
908 | with self.fetch_count.get_lock(): | ||
909 | self.fetch_count.value += fetched | ||
910 | self.head.value = self.local_head | ||
911 | self.fetched_event.set() | ||
912 | |||
913 | def Run(self): | ||
914 | while self.more: | ||
915 | target = self.WaitForTarget() | ||
916 | if target < 0: | ||
917 | break | ||
918 | batch_size = min(glb_chunk_sz, target - self.fetched) | ||
919 | self.FetchBatch(batch_size) | ||
920 | self.fetching_done.value = True | ||
921 | self.fetched_event.set() | ||
922 | |||
923 | def SQLFetcherFn(*x): | ||
924 | process = SQLFetcherProcess(*x) | ||
925 | process.Run() | ||
926 | |||
927 | # SQL data fetcher | ||
928 | |||
929 | class SQLFetcher(QObject): | ||
930 | |||
931 | done = Signal(object) | ||
932 | |||
933 | def __init__(self, glb, sql, prep, process_data, parent=None): | ||
934 | super(SQLFetcher, self).__init__(parent) | ||
935 | self.process_data = process_data | ||
936 | self.more = True | ||
937 | self.target = 0 | ||
938 | self.last_target = 0 | ||
939 | self.fetched = 0 | ||
940 | self.buffer_size = 16 * 1024 * 1024 | ||
941 | self.buffer = Array(c_char, self.buffer_size, lock=False) | ||
942 | self.head = Value(c_longlong) | ||
943 | self.tail = Value(c_longlong) | ||
944 | self.local_tail = 0 | ||
945 | self.fetch_count = Value(c_longlong) | ||
946 | self.fetching_done = Value(c_bool) | ||
947 | self.last_count = 0 | ||
948 | self.process_target = Value(c_longlong) | ||
949 | self.wait_event = Event() | ||
950 | self.fetched_event = Event() | ||
951 | glb.AddInstanceToShutdownOnExit(self) | ||
952 | self.process = Process(target=SQLFetcherFn, args=(glb.dbref, sql, self.buffer, self.head, self.tail, self.fetch_count, self.fetching_done, self.process_target, self.wait_event, self.fetched_event, prep)) | ||
953 | self.process.start() | ||
954 | self.thread = Thread(self.Thread) | ||
955 | self.thread.done.connect(self.ProcessData, Qt.QueuedConnection) | ||
956 | self.thread.start() | ||
957 | |||
958 | def Shutdown(self): | ||
959 | # Tell the thread and process to exit | ||
960 | self.process_target.value = -1 | ||
961 | self.wait_event.set() | ||
962 | self.more = False | ||
963 | self.fetching_done.value = True | ||
964 | self.fetched_event.set() | ||
965 | |||
966 | def Thread(self): | ||
967 | if not self.more: | ||
968 | return True, 0 | ||
969 | while True: | ||
970 | self.fetched_event.clear() | ||
971 | fetch_count = self.fetch_count.value | ||
972 | if fetch_count != self.last_count: | ||
973 | break | ||
974 | if self.fetching_done.value: | ||
975 | self.more = False | ||
976 | return True, 0 | ||
977 | self.fetched_event.wait() | ||
978 | count = fetch_count - self.last_count | ||
979 | self.last_count = fetch_count | ||
980 | self.fetched += count | ||
981 | return False, count | ||
982 | |||
983 | def Fetch(self, nr): | ||
984 | if not self.more: | ||
985 | # -1 inidcates there are no more | ||
986 | return -1 | ||
987 | result = self.fetched | ||
988 | extra = result + nr - self.target | ||
989 | if extra > 0: | ||
990 | self.target += extra | ||
991 | # process_target < 0 indicates shutting down | ||
992 | if self.process_target.value >= 0: | ||
993 | self.process_target.value = self.target | ||
994 | self.wait_event.set() | ||
995 | return result | ||
996 | |||
997 | def RemoveFromBuffer(self): | ||
998 | pos = self.local_tail | ||
999 | if len(self.buffer) - pos < glb_nsz: | ||
1000 | pos = 0 | ||
1001 | n = cPickle.loads(self.buffer[pos : pos + glb_nsz]) | ||
1002 | if n == 0: | ||
1003 | pos = 0 | ||
1004 | n = cPickle.loads(self.buffer[0 : glb_nsz]) | ||
1005 | pos += glb_nsz | ||
1006 | obj = cPickle.loads(self.buffer[pos : pos + n]) | ||
1007 | self.local_tail = pos + n | ||
1008 | return obj | ||
1009 | |||
1010 | def ProcessData(self, count): | ||
1011 | for i in xrange(count): | ||
1012 | obj = self.RemoveFromBuffer() | ||
1013 | self.process_data(obj) | ||
1014 | self.tail.value = self.local_tail | ||
1015 | self.wait_event.set() | ||
1016 | self.done.emit(count) | ||
1017 | |||
1018 | # Fetch more records bar | ||
1019 | |||
1020 | class FetchMoreRecordsBar(): | ||
1021 | |||
1022 | def __init__(self, model, parent): | ||
1023 | self.model = model | ||
1024 | |||
1025 | self.label = QLabel("Number of records (x " + "{:,}".format(glb_chunk_sz) + ") to fetch:") | ||
1026 | self.label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) | ||
1027 | |||
1028 | self.fetch_count = QSpinBox() | ||
1029 | self.fetch_count.setRange(1, 1000000) | ||
1030 | self.fetch_count.setValue(10) | ||
1031 | self.fetch_count.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) | ||
1032 | |||
1033 | self.fetch = QPushButton("Go!") | ||
1034 | self.fetch.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) | ||
1035 | self.fetch.released.connect(self.FetchMoreRecords) | ||
1036 | |||
1037 | self.progress = QProgressBar() | ||
1038 | self.progress.setRange(0, 100) | ||
1039 | self.progress.hide() | ||
1040 | |||
1041 | self.done_label = QLabel("All records fetched") | ||
1042 | self.done_label.hide() | ||
1043 | |||
1044 | self.spacer = QLabel("") | ||
1045 | |||
1046 | self.close_button = QToolButton() | ||
1047 | self.close_button.setIcon(parent.style().standardIcon(QStyle.SP_DockWidgetCloseButton)) | ||
1048 | self.close_button.released.connect(self.Deactivate) | ||
1049 | |||
1050 | self.hbox = QHBoxLayout() | ||
1051 | self.hbox.setContentsMargins(0, 0, 0, 0) | ||
1052 | |||
1053 | self.hbox.addWidget(self.label) | ||
1054 | self.hbox.addWidget(self.fetch_count) | ||
1055 | self.hbox.addWidget(self.fetch) | ||
1056 | self.hbox.addWidget(self.spacer) | ||
1057 | self.hbox.addWidget(self.progress) | ||
1058 | self.hbox.addWidget(self.done_label) | ||
1059 | self.hbox.addWidget(self.close_button) | ||
1060 | |||
1061 | self.bar = QWidget() | ||
1062 | self.bar.setLayout(self.hbox); | ||
1063 | self.bar.show() | ||
1064 | |||
1065 | self.in_progress = False | ||
1066 | self.model.progress.connect(self.Progress) | ||
1067 | |||
1068 | self.done = False | ||
1069 | |||
1070 | if not model.HasMoreRecords(): | ||
1071 | self.Done() | ||
1072 | |||
1073 | def Widget(self): | ||
1074 | return self.bar | ||
1075 | |||
1076 | def Activate(self): | ||
1077 | self.bar.show() | ||
1078 | self.fetch.setFocus() | ||
1079 | |||
1080 | def Deactivate(self): | ||
1081 | self.bar.hide() | ||
1082 | |||
1083 | def Enable(self, enable): | ||
1084 | self.fetch.setEnabled(enable) | ||
1085 | self.fetch_count.setEnabled(enable) | ||
1086 | |||
1087 | def Busy(self): | ||
1088 | self.Enable(False) | ||
1089 | self.fetch.hide() | ||
1090 | self.spacer.hide() | ||
1091 | self.progress.show() | ||
1092 | |||
1093 | def Idle(self): | ||
1094 | self.in_progress = False | ||
1095 | self.Enable(True) | ||
1096 | self.progress.hide() | ||
1097 | self.fetch.show() | ||
1098 | self.spacer.show() | ||
1099 | |||
1100 | def Target(self): | ||
1101 | return self.fetch_count.value() * glb_chunk_sz | ||
1102 | |||
1103 | def Done(self): | ||
1104 | self.done = True | ||
1105 | self.Idle() | ||
1106 | self.label.hide() | ||
1107 | self.fetch_count.hide() | ||
1108 | self.fetch.hide() | ||
1109 | self.spacer.hide() | ||
1110 | self.done_label.show() | ||
1111 | |||
1112 | def Progress(self, count): | ||
1113 | if self.in_progress: | ||
1114 | if count: | ||
1115 | percent = ((count - self.start) * 100) / self.Target() | ||
1116 | if percent >= 100: | ||
1117 | self.Idle() | ||
1118 | else: | ||
1119 | self.progress.setValue(percent) | ||
1120 | if not count: | ||
1121 | # Count value of zero means no more records | ||
1122 | self.Done() | ||
1123 | |||
1124 | def FetchMoreRecords(self): | ||
1125 | if self.done: | ||
1126 | return | ||
1127 | self.progress.setValue(0) | ||
1128 | self.Busy() | ||
1129 | self.in_progress = True | ||
1130 | self.start = self.model.FetchMoreRecords(self.Target()) | ||
1131 | |||
1132 | # Brance data model level two item | ||
1133 | |||
1134 | class BranchLevelTwoItem(): | ||
1135 | |||
1136 | def __init__(self, row, text, parent_item): | ||
1137 | self.row = row | ||
1138 | self.parent_item = parent_item | ||
1139 | self.data = [""] * 8 | ||
1140 | self.data[7] = text | ||
1141 | self.level = 2 | ||
1142 | |||
1143 | def getParentItem(self): | ||
1144 | return self.parent_item | ||
1145 | |||
1146 | def getRow(self): | ||
1147 | return self.row | ||
1148 | |||
1149 | def childCount(self): | ||
1150 | return 0 | ||
1151 | |||
1152 | def hasChildren(self): | ||
1153 | return False | ||
1154 | |||
1155 | def getData(self, column): | ||
1156 | return self.data[column] | ||
1157 | |||
1158 | # Brance data model level one item | ||
1159 | |||
1160 | class BranchLevelOneItem(): | ||
1161 | |||
1162 | def __init__(self, glb, row, data, parent_item): | ||
1163 | self.glb = glb | ||
1164 | self.row = row | ||
1165 | self.parent_item = parent_item | ||
1166 | self.child_count = 0 | ||
1167 | self.child_items = [] | ||
1168 | self.data = data[1:] | ||
1169 | self.dbid = data[0] | ||
1170 | self.level = 1 | ||
1171 | self.query_done = False | ||
1172 | |||
1173 | def getChildItem(self, row): | ||
1174 | return self.child_items[row] | ||
1175 | |||
1176 | def getParentItem(self): | ||
1177 | return self.parent_item | ||
1178 | |||
1179 | def getRow(self): | ||
1180 | return self.row | ||
1181 | |||
1182 | def Select(self): | ||
1183 | self.query_done = True | ||
1184 | |||
1185 | if not self.glb.have_disassembler: | ||
1186 | return | ||
1187 | |||
1188 | query = QSqlQuery(self.glb.db) | ||
1189 | |||
1190 | QueryExec(query, "SELECT cpu, to_dso_id, to_symbol_id, to_sym_offset, short_name, long_name, build_id, sym_start, to_ip" | ||
1191 | " FROM samples" | ||
1192 | " INNER JOIN dsos ON samples.to_dso_id = dsos.id" | ||
1193 | " INNER JOIN symbols ON samples.to_symbol_id = symbols.id" | ||
1194 | " WHERE samples.id = " + str(self.dbid)) | ||
1195 | if not query.next(): | ||
1196 | return | ||
1197 | cpu = query.value(0) | ||
1198 | dso = query.value(1) | ||
1199 | sym = query.value(2) | ||
1200 | if dso == 0 or sym == 0: | ||
1201 | return | ||
1202 | off = query.value(3) | ||
1203 | short_name = query.value(4) | ||
1204 | long_name = query.value(5) | ||
1205 | build_id = query.value(6) | ||
1206 | sym_start = query.value(7) | ||
1207 | ip = query.value(8) | ||
1208 | |||
1209 | QueryExec(query, "SELECT samples.dso_id, symbol_id, sym_offset, sym_start" | ||
1210 | " FROM samples" | ||
1211 | " INNER JOIN symbols ON samples.symbol_id = symbols.id" | ||
1212 | " WHERE samples.id > " + str(self.dbid) + " AND cpu = " + str(cpu) + | ||
1213 | " ORDER BY samples.id" | ||
1214 | " LIMIT 1") | ||
1215 | if not query.next(): | ||
1216 | return | ||
1217 | if query.value(0) != dso: | ||
1218 | # Cannot disassemble from one dso to another | ||
1219 | return | ||
1220 | bsym = query.value(1) | ||
1221 | boff = query.value(2) | ||
1222 | bsym_start = query.value(3) | ||
1223 | if bsym == 0: | ||
1224 | return | ||
1225 | tot = bsym_start + boff + 1 - sym_start - off | ||
1226 | if tot <= 0 or tot > 16384: | ||
1227 | return | ||
1228 | |||
1229 | inst = self.glb.disassembler.Instruction() | ||
1230 | f = self.glb.FileFromNamesAndBuildId(short_name, long_name, build_id) | ||
1231 | if not f: | ||
1232 | return | ||
1233 | mode = 0 if Is64Bit(f) else 1 | ||
1234 | self.glb.disassembler.SetMode(inst, mode) | ||
1235 | |||
1236 | buf_sz = tot + 16 | ||
1237 | buf = create_string_buffer(tot + 16) | ||
1238 | f.seek(sym_start + off) | ||
1239 | buf.value = f.read(buf_sz) | ||
1240 | buf_ptr = addressof(buf) | ||
1241 | i = 0 | ||
1242 | while tot > 0: | ||
1243 | cnt, text = self.glb.disassembler.DisassembleOne(inst, buf_ptr, buf_sz, ip) | ||
1244 | if cnt: | ||
1245 | byte_str = tohex(ip).rjust(16) | ||
1246 | for k in xrange(cnt): | ||
1247 | byte_str += " %02x" % ord(buf[i]) | ||
1248 | i += 1 | ||
1249 | while k < 15: | ||
1250 | byte_str += " " | ||
1251 | k += 1 | ||
1252 | self.child_items.append(BranchLevelTwoItem(0, byte_str + " " + text, self)) | ||
1253 | self.child_count += 1 | ||
1254 | else: | ||
1255 | return | ||
1256 | buf_ptr += cnt | ||
1257 | tot -= cnt | ||
1258 | buf_sz -= cnt | ||
1259 | ip += cnt | ||
1260 | |||
1261 | def childCount(self): | ||
1262 | if not self.query_done: | ||
1263 | self.Select() | ||
1264 | if not self.child_count: | ||
1265 | return -1 | ||
1266 | return self.child_count | ||
1267 | |||
1268 | def hasChildren(self): | ||
1269 | if not self.query_done: | ||
1270 | return True | ||
1271 | return self.child_count > 0 | ||
1272 | |||
1273 | def getData(self, column): | ||
1274 | return self.data[column] | ||
1275 | |||
1276 | # Brance data model root item | ||
1277 | |||
1278 | class BranchRootItem(): | ||
1279 | |||
1280 | def __init__(self): | ||
1281 | self.child_count = 0 | ||
1282 | self.child_items = [] | ||
1283 | self.level = 0 | ||
1284 | |||
1285 | def getChildItem(self, row): | ||
1286 | return self.child_items[row] | ||
1287 | |||
1288 | def getParentItem(self): | ||
1289 | return None | ||
1290 | |||
1291 | def getRow(self): | ||
1292 | return 0 | ||
1293 | |||
1294 | def childCount(self): | ||
1295 | return self.child_count | ||
1296 | |||
1297 | def hasChildren(self): | ||
1298 | return self.child_count > 0 | ||
1299 | |||
1300 | def getData(self, column): | ||
1301 | return "" | ||
1302 | |||
1303 | # Branch data preparation | ||
1304 | |||
1305 | def BranchDataPrep(query): | ||
1306 | data = [] | ||
1307 | for i in xrange(0, 8): | ||
1308 | data.append(query.value(i)) | ||
1309 | data.append(tohex(query.value(8)).rjust(16) + " " + query.value(9) + offstr(query.value(10)) + | ||
1310 | " (" + dsoname(query.value(11)) + ")" + " -> " + | ||
1311 | tohex(query.value(12)) + " " + query.value(13) + offstr(query.value(14)) + | ||
1312 | " (" + dsoname(query.value(15)) + ")") | ||
1313 | return data | ||
1314 | |||
1315 | # Branch data model | ||
1316 | |||
1317 | class BranchModel(TreeModel): | ||
1318 | |||
1319 | progress = Signal(object) | ||
1320 | |||
1321 | def __init__(self, glb, event_id, where_clause, parent=None): | ||
1322 | super(BranchModel, self).__init__(BranchRootItem(), parent) | ||
1323 | self.glb = glb | ||
1324 | self.event_id = event_id | ||
1325 | self.more = True | ||
1326 | self.populated = 0 | ||
1327 | sql = ("SELECT samples.id, time, cpu, comm, pid, tid, branch_types.name," | ||
1328 | " CASE WHEN in_tx = '0' THEN 'No' ELSE 'Yes' END," | ||
1329 | " ip, symbols.name, sym_offset, dsos.short_name," | ||
1330 | " to_ip, to_symbols.name, to_sym_offset, to_dsos.short_name" | ||
1331 | " FROM samples" | ||
1332 | " INNER JOIN comms ON comm_id = comms.id" | ||
1333 | " INNER JOIN threads ON thread_id = threads.id" | ||
1334 | " INNER JOIN branch_types ON branch_type = branch_types.id" | ||
1335 | " INNER JOIN symbols ON symbol_id = symbols.id" | ||
1336 | " INNER JOIN symbols to_symbols ON to_symbol_id = to_symbols.id" | ||
1337 | " INNER JOIN dsos ON samples.dso_id = dsos.id" | ||
1338 | " INNER JOIN dsos AS to_dsos ON samples.to_dso_id = to_dsos.id" | ||
1339 | " WHERE samples.id > $$last_id$$" + where_clause + | ||
1340 | " AND evsel_id = " + str(self.event_id) + | ||
1341 | " ORDER BY samples.id" | ||
1342 | " LIMIT " + str(glb_chunk_sz)) | ||
1343 | self.fetcher = SQLFetcher(glb, sql, BranchDataPrep, self.AddSample) | ||
1344 | self.fetcher.done.connect(self.Update) | ||
1345 | self.fetcher.Fetch(glb_chunk_sz) | ||
1346 | |||
1347 | def columnCount(self, parent=None): | ||
1348 | return 8 | ||
1349 | |||
1350 | def columnHeader(self, column): | ||
1351 | return ("Time", "CPU", "Command", "PID", "TID", "Branch Type", "In Tx", "Branch")[column] | ||
1352 | |||
1353 | def columnFont(self, column): | ||
1354 | if column != 7: | ||
1355 | return None | ||
1356 | return QFont("Monospace") | ||
1357 | |||
1358 | def DisplayData(self, item, index): | ||
1359 | if item.level == 1: | ||
1360 | self.FetchIfNeeded(item.row) | ||
1361 | return item.getData(index.column()) | ||
1362 | |||
1363 | def AddSample(self, data): | ||
1364 | child = BranchLevelOneItem(self.glb, self.populated, data, self.root) | ||
1365 | self.root.child_items.append(child) | ||
1366 | self.populated += 1 | ||
1367 | |||
1368 | def Update(self, fetched): | ||
1369 | if not fetched: | ||
1370 | self.more = False | ||
1371 | self.progress.emit(0) | ||
1372 | child_count = self.root.child_count | ||
1373 | count = self.populated - child_count | ||
1374 | if count > 0: | ||
1375 | parent = QModelIndex() | ||
1376 | self.beginInsertRows(parent, child_count, child_count + count - 1) | ||
1377 | self.insertRows(child_count, count, parent) | ||
1378 | self.root.child_count += count | ||
1379 | self.endInsertRows() | ||
1380 | self.progress.emit(self.root.child_count) | ||
1381 | |||
1382 | def FetchMoreRecords(self, count): | ||
1383 | current = self.root.child_count | ||
1384 | if self.more: | ||
1385 | self.fetcher.Fetch(count) | ||
1386 | else: | ||
1387 | self.progress.emit(0) | ||
1388 | return current | ||
1389 | |||
1390 | def HasMoreRecords(self): | ||
1391 | return self.more | ||
1392 | |||
1393 | # Branch window | ||
1394 | |||
1395 | class BranchWindow(QMdiSubWindow): | ||
1396 | |||
1397 | def __init__(self, glb, event_id, name, where_clause, parent=None): | ||
1398 | super(BranchWindow, self).__init__(parent) | ||
1399 | |||
1400 | model_name = "Branch Events " + str(event_id) | ||
1401 | if len(where_clause): | ||
1402 | model_name = where_clause + " " + model_name | ||
1403 | |||
1404 | self.model = LookupCreateModel(model_name, lambda: BranchModel(glb, event_id, where_clause)) | ||
1405 | |||
1406 | self.view = QTreeView() | ||
1407 | self.view.setUniformRowHeights(True) | ||
1408 | self.view.setModel(self.model) | ||
1409 | |||
1410 | self.ResizeColumnsToContents() | ||
1411 | |||
1412 | self.find_bar = FindBar(self, self, True) | ||
1413 | |||
1414 | self.finder = ChildDataItemFinder(self.model.root) | ||
1415 | |||
1416 | self.fetch_bar = FetchMoreRecordsBar(self.model, self) | ||
1417 | |||
1418 | self.vbox = VBox(self.view, self.find_bar.Widget(), self.fetch_bar.Widget()) | ||
1419 | |||
1420 | self.setWidget(self.vbox.Widget()) | ||
1421 | |||
1422 | AddSubWindow(glb.mainwindow.mdi_area, self, name + " Branch Events") | ||
1423 | |||
1424 | def ResizeColumnToContents(self, column, n): | ||
1425 | # Using the view's resizeColumnToContents() here is extrememly slow | ||
1426 | # so implement a crude alternative | ||
1427 | mm = "MM" if column else "MMMM" | ||
1428 | font = self.view.font() | ||
1429 | metrics = QFontMetrics(font) | ||
1430 | max = 0 | ||
1431 | for row in xrange(n): | ||
1432 | val = self.model.root.child_items[row].data[column] | ||
1433 | len = metrics.width(str(val) + mm) | ||
1434 | max = len if len > max else max | ||
1435 | val = self.model.columnHeader(column) | ||
1436 | len = metrics.width(str(val) + mm) | ||
1437 | max = len if len > max else max | ||
1438 | self.view.setColumnWidth(column, max) | ||
1439 | |||
1440 | def ResizeColumnsToContents(self): | ||
1441 | n = min(self.model.root.child_count, 100) | ||
1442 | if n < 1: | ||
1443 | # No data yet, so connect a signal to notify when there is | ||
1444 | self.model.rowsInserted.connect(self.UpdateColumnWidths) | ||
1445 | return | ||
1446 | columns = self.model.columnCount() | ||
1447 | for i in xrange(columns): | ||
1448 | self.ResizeColumnToContents(i, n) | ||
1449 | |||
1450 | def UpdateColumnWidths(self, *x): | ||
1451 | # This only needs to be done once, so disconnect the signal now | ||
1452 | self.model.rowsInserted.disconnect(self.UpdateColumnWidths) | ||
1453 | self.ResizeColumnsToContents() | ||
1454 | |||
1455 | def Find(self, value, direction, pattern, context): | ||
1456 | self.view.setFocus() | ||
1457 | self.find_bar.Busy() | ||
1458 | self.finder.Find(value, direction, pattern, context, self.FindDone) | ||
1459 | |||
1460 | def FindDone(self, row): | ||
1461 | self.find_bar.Idle() | ||
1462 | if row >= 0: | ||
1463 | self.view.setCurrentIndex(self.model.index(row, 0, QModelIndex())) | ||
1464 | else: | ||
1465 | self.find_bar.NotFound() | ||
1466 | |||
1467 | # Event list | ||
1468 | |||
1469 | def GetEventList(db): | ||
1470 | events = [] | ||
1471 | query = QSqlQuery(db) | ||
1472 | QueryExec(query, "SELECT name FROM selected_events WHERE id > 0 ORDER BY id") | ||
1473 | while query.next(): | ||
1474 | events.append(query.value(0)) | ||
1475 | return events | ||
1476 | |||
1477 | # SQL data preparation | ||
1478 | |||
1479 | def SQLTableDataPrep(query, count): | ||
1480 | data = [] | ||
1481 | for i in xrange(count): | ||
1482 | data.append(query.value(i)) | ||
1483 | return data | ||
1484 | |||
1485 | # SQL table data model item | ||
1486 | |||
1487 | class SQLTableItem(): | ||
1488 | |||
1489 | def __init__(self, row, data): | ||
1490 | self.row = row | ||
1491 | self.data = data | ||
1492 | |||
1493 | def getData(self, column): | ||
1494 | return self.data[column] | ||
1495 | |||
1496 | # SQL table data model | ||
1497 | |||
1498 | class SQLTableModel(TableModel): | ||
1499 | |||
1500 | progress = Signal(object) | ||
1501 | |||
1502 | def __init__(self, glb, sql, column_count, parent=None): | ||
1503 | super(SQLTableModel, self).__init__(parent) | ||
1504 | self.glb = glb | ||
1505 | self.more = True | ||
1506 | self.populated = 0 | ||
1507 | self.fetcher = SQLFetcher(glb, sql, lambda x, y=column_count: SQLTableDataPrep(x, y), self.AddSample) | ||
1508 | self.fetcher.done.connect(self.Update) | ||
1509 | self.fetcher.Fetch(glb_chunk_sz) | ||
1510 | |||
1511 | def DisplayData(self, item, index): | ||
1512 | self.FetchIfNeeded(item.row) | ||
1513 | return item.getData(index.column()) | ||
1514 | |||
1515 | def AddSample(self, data): | ||
1516 | child = SQLTableItem(self.populated, data) | ||
1517 | self.child_items.append(child) | ||
1518 | self.populated += 1 | ||
1519 | |||
1520 | def Update(self, fetched): | ||
1521 | if not fetched: | ||
1522 | self.more = False | ||
1523 | self.progress.emit(0) | ||
1524 | child_count = self.child_count | ||
1525 | count = self.populated - child_count | ||
1526 | if count > 0: | ||
1527 | parent = QModelIndex() | ||
1528 | self.beginInsertRows(parent, child_count, child_count + count - 1) | ||
1529 | self.insertRows(child_count, count, parent) | ||
1530 | self.child_count += count | ||
1531 | self.endInsertRows() | ||
1532 | self.progress.emit(self.child_count) | ||
1533 | |||
1534 | def FetchMoreRecords(self, count): | ||
1535 | current = self.child_count | ||
1536 | if self.more: | ||
1537 | self.fetcher.Fetch(count) | ||
1538 | else: | ||
1539 | self.progress.emit(0) | ||
1540 | return current | ||
1541 | |||
1542 | def HasMoreRecords(self): | ||
1543 | return self.more | ||
1544 | |||
1545 | # SQL automatic table data model | ||
1546 | |||
1547 | class SQLAutoTableModel(SQLTableModel): | ||
1548 | |||
1549 | def __init__(self, glb, table_name, parent=None): | ||
1550 | sql = "SELECT * FROM " + table_name + " WHERE id > $$last_id$$ ORDER BY id LIMIT " + str(glb_chunk_sz) | ||
1551 | if table_name == "comm_threads_view": | ||
1552 | # For now, comm_threads_view has no id column | ||
1553 | sql = "SELECT * FROM " + table_name + " WHERE comm_id > $$last_id$$ ORDER BY comm_id LIMIT " + str(glb_chunk_sz) | ||
1554 | self.column_headers = [] | ||
1555 | query = QSqlQuery(glb.db) | ||
1556 | if glb.dbref.is_sqlite3: | ||
1557 | QueryExec(query, "PRAGMA table_info(" + table_name + ")") | ||
1558 | while query.next(): | ||
1559 | self.column_headers.append(query.value(1)) | ||
1560 | if table_name == "sqlite_master": | ||
1561 | sql = "SELECT * FROM " + table_name | ||
1562 | else: | ||
1563 | if table_name[:19] == "information_schema.": | ||
1564 | sql = "SELECT * FROM " + table_name | ||
1565 | select_table_name = table_name[19:] | ||
1566 | schema = "information_schema" | ||
1567 | else: | ||
1568 | select_table_name = table_name | ||
1569 | schema = "public" | ||
1570 | QueryExec(query, "SELECT column_name FROM information_schema.columns WHERE table_schema = '" + schema + "' and table_name = '" + select_table_name + "'") | ||
1571 | while query.next(): | ||
1572 | self.column_headers.append(query.value(0)) | ||
1573 | super(SQLAutoTableModel, self).__init__(glb, sql, len(self.column_headers), parent) | ||
1574 | |||
1575 | def columnCount(self, parent=None): | ||
1576 | return len(self.column_headers) | ||
1577 | |||
1578 | def columnHeader(self, column): | ||
1579 | return self.column_headers[column] | ||
1580 | |||
1581 | # Base class for custom ResizeColumnsToContents | ||
1582 | |||
1583 | class ResizeColumnsToContentsBase(QObject): | ||
1584 | |||
1585 | def __init__(self, parent=None): | ||
1586 | super(ResizeColumnsToContentsBase, self).__init__(parent) | ||
1587 | |||
1588 | def ResizeColumnToContents(self, column, n): | ||
1589 | # Using the view's resizeColumnToContents() here is extrememly slow | ||
1590 | # so implement a crude alternative | ||
1591 | font = self.view.font() | ||
1592 | metrics = QFontMetrics(font) | ||
1593 | max = 0 | ||
1594 | for row in xrange(n): | ||
1595 | val = self.data_model.child_items[row].data[column] | ||
1596 | len = metrics.width(str(val) + "MM") | ||
1597 | max = len if len > max else max | ||
1598 | val = self.data_model.columnHeader(column) | ||
1599 | len = metrics.width(str(val) + "MM") | ||
1600 | max = len if len > max else max | ||
1601 | self.view.setColumnWidth(column, max) | ||
1602 | |||
1603 | def ResizeColumnsToContents(self): | ||
1604 | n = min(self.data_model.child_count, 100) | ||
1605 | if n < 1: | ||
1606 | # No data yet, so connect a signal to notify when there is | ||
1607 | self.data_model.rowsInserted.connect(self.UpdateColumnWidths) | ||
1608 | return | ||
1609 | columns = self.data_model.columnCount() | ||
1610 | for i in xrange(columns): | ||
1611 | self.ResizeColumnToContents(i, n) | ||
1612 | |||
1613 | def UpdateColumnWidths(self, *x): | ||
1614 | # This only needs to be done once, so disconnect the signal now | ||
1615 | self.data_model.rowsInserted.disconnect(self.UpdateColumnWidths) | ||
1616 | self.ResizeColumnsToContents() | ||
1617 | |||
1618 | # Table window | ||
1619 | |||
1620 | class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase): | ||
1621 | |||
1622 | def __init__(self, glb, table_name, parent=None): | ||
1623 | super(TableWindow, self).__init__(parent) | ||
1624 | |||
1625 | self.data_model = LookupCreateModel(table_name + " Table", lambda: SQLAutoTableModel(glb, table_name)) | ||
1626 | |||
1627 | self.model = QSortFilterProxyModel() | ||
1628 | self.model.setSourceModel(self.data_model) | ||
1629 | |||
1630 | self.view = QTableView() | ||
1631 | self.view.setModel(self.model) | ||
1632 | self.view.setEditTriggers(QAbstractItemView.NoEditTriggers) | ||
1633 | self.view.verticalHeader().setVisible(False) | ||
1634 | self.view.sortByColumn(-1, Qt.AscendingOrder) | ||
1635 | self.view.setSortingEnabled(True) | ||
1636 | |||
1637 | self.ResizeColumnsToContents() | ||
1638 | |||
1639 | self.find_bar = FindBar(self, self, True) | ||
1640 | |||
1641 | self.finder = ChildDataItemFinder(self.data_model) | ||
1642 | |||
1643 | self.fetch_bar = FetchMoreRecordsBar(self.data_model, self) | ||
1644 | |||
1645 | self.vbox = VBox(self.view, self.find_bar.Widget(), self.fetch_bar.Widget()) | ||
1646 | |||
1647 | self.setWidget(self.vbox.Widget()) | ||
1648 | |||
1649 | AddSubWindow(glb.mainwindow.mdi_area, self, table_name + " Table") | ||
1650 | |||
1651 | def Find(self, value, direction, pattern, context): | ||
1652 | self.view.setFocus() | ||
1653 | self.find_bar.Busy() | ||
1654 | self.finder.Find(value, direction, pattern, context, self.FindDone) | ||
1655 | |||
1656 | def FindDone(self, row): | ||
1657 | self.find_bar.Idle() | ||
1658 | if row >= 0: | ||
1659 | self.view.setCurrentIndex(self.model.index(row, 0, QModelIndex())) | ||
1660 | else: | ||
1661 | self.find_bar.NotFound() | ||
1662 | |||
1663 | # Table list | ||
1664 | |||
1665 | def GetTableList(glb): | ||
1666 | tables = [] | ||
1667 | query = QSqlQuery(glb.db) | ||
1668 | if glb.dbref.is_sqlite3: | ||
1669 | QueryExec(query, "SELECT name FROM sqlite_master WHERE type IN ( 'table' , 'view' ) ORDER BY name") | ||
1670 | else: | ||
1671 | QueryExec(query, "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_type IN ( 'BASE TABLE' , 'VIEW' ) ORDER BY table_name") | ||
1672 | while query.next(): | ||
1673 | tables.append(query.value(0)) | ||
1674 | if glb.dbref.is_sqlite3: | ||
1675 | tables.append("sqlite_master") | ||
1676 | else: | ||
1677 | tables.append("information_schema.tables") | ||
1678 | tables.append("information_schema.views") | ||
1679 | tables.append("information_schema.columns") | ||
1680 | return tables | ||
1681 | |||
1682 | # Action Definition | ||
1683 | |||
1684 | def CreateAction(label, tip, callback, parent=None, shortcut=None): | ||
1685 | action = QAction(label, parent) | ||
1686 | if shortcut != None: | ||
1687 | action.setShortcuts(shortcut) | ||
1688 | action.setStatusTip(tip) | ||
1689 | action.triggered.connect(callback) | ||
1690 | return action | ||
1691 | |||
1692 | # Typical application actions | ||
1693 | |||
1694 | def CreateExitAction(app, parent=None): | ||
1695 | return CreateAction("&Quit", "Exit the application", app.closeAllWindows, parent, QKeySequence.Quit) | ||
1696 | |||
1697 | # Typical MDI actions | ||
1698 | |||
1699 | def CreateCloseActiveWindowAction(mdi_area): | ||
1700 | return CreateAction("Cl&ose", "Close the active window", mdi_area.closeActiveSubWindow, mdi_area) | ||
1701 | |||
1702 | def CreateCloseAllWindowsAction(mdi_area): | ||
1703 | return CreateAction("Close &All", "Close all the windows", mdi_area.closeAllSubWindows, mdi_area) | ||
1704 | |||
1705 | def CreateTileWindowsAction(mdi_area): | ||
1706 | return CreateAction("&Tile", "Tile the windows", mdi_area.tileSubWindows, mdi_area) | ||
1707 | |||
1708 | def CreateCascadeWindowsAction(mdi_area): | ||
1709 | return CreateAction("&Cascade", "Cascade the windows", mdi_area.cascadeSubWindows, mdi_area) | ||
1710 | |||
1711 | def CreateNextWindowAction(mdi_area): | ||
1712 | return CreateAction("Ne&xt", "Move the focus to the next window", mdi_area.activateNextSubWindow, mdi_area, QKeySequence.NextChild) | ||
1713 | |||
1714 | def CreatePreviousWindowAction(mdi_area): | ||
1715 | return CreateAction("Pre&vious", "Move the focus to the previous window", mdi_area.activatePreviousSubWindow, mdi_area, QKeySequence.PreviousChild) | ||
1716 | |||
1717 | # Typical MDI window menu | ||
1718 | |||
1719 | class WindowMenu(): | ||
1720 | |||
1721 | def __init__(self, mdi_area, menu): | ||
1722 | self.mdi_area = mdi_area | ||
1723 | self.window_menu = menu.addMenu("&Windows") | ||
1724 | self.close_active_window = CreateCloseActiveWindowAction(mdi_area) | ||
1725 | self.close_all_windows = CreateCloseAllWindowsAction(mdi_area) | ||
1726 | self.tile_windows = CreateTileWindowsAction(mdi_area) | ||
1727 | self.cascade_windows = CreateCascadeWindowsAction(mdi_area) | ||
1728 | self.next_window = CreateNextWindowAction(mdi_area) | ||
1729 | self.previous_window = CreatePreviousWindowAction(mdi_area) | ||
1730 | self.window_menu.aboutToShow.connect(self.Update) | ||
1731 | |||
1732 | def Update(self): | ||
1733 | self.window_menu.clear() | ||
1734 | sub_window_count = len(self.mdi_area.subWindowList()) | ||
1735 | have_sub_windows = sub_window_count != 0 | ||
1736 | self.close_active_window.setEnabled(have_sub_windows) | ||
1737 | self.close_all_windows.setEnabled(have_sub_windows) | ||
1738 | self.tile_windows.setEnabled(have_sub_windows) | ||
1739 | self.cascade_windows.setEnabled(have_sub_windows) | ||
1740 | self.next_window.setEnabled(have_sub_windows) | ||
1741 | self.previous_window.setEnabled(have_sub_windows) | ||
1742 | self.window_menu.addAction(self.close_active_window) | ||
1743 | self.window_menu.addAction(self.close_all_windows) | ||
1744 | self.window_menu.addSeparator() | ||
1745 | self.window_menu.addAction(self.tile_windows) | ||
1746 | self.window_menu.addAction(self.cascade_windows) | ||
1747 | self.window_menu.addSeparator() | ||
1748 | self.window_menu.addAction(self.next_window) | ||
1749 | self.window_menu.addAction(self.previous_window) | ||
1750 | if sub_window_count == 0: | ||
1751 | return | ||
1752 | self.window_menu.addSeparator() | ||
1753 | nr = 1 | ||
1754 | for sub_window in self.mdi_area.subWindowList(): | ||
1755 | label = str(nr) + " " + sub_window.name | ||
1756 | if nr < 10: | ||
1757 | label = "&" + label | ||
1758 | action = self.window_menu.addAction(label) | ||
1759 | action.setCheckable(True) | ||
1760 | action.setChecked(sub_window == self.mdi_area.activeSubWindow()) | ||
1761 | action.triggered.connect(lambda x=nr: self.setActiveSubWindow(x)) | ||
1762 | self.window_menu.addAction(action) | ||
1763 | nr += 1 | ||
1764 | |||
1765 | def setActiveSubWindow(self, nr): | ||
1766 | self.mdi_area.setActiveSubWindow(self.mdi_area.subWindowList()[nr - 1]) | ||
1767 | |||
1768 | # Font resize | ||
1769 | |||
1770 | def ResizeFont(widget, diff): | ||
1771 | font = widget.font() | ||
1772 | sz = font.pointSize() | ||
1773 | font.setPointSize(sz + diff) | ||
1774 | widget.setFont(font) | ||
1775 | |||
1776 | def ShrinkFont(widget): | ||
1777 | ResizeFont(widget, -1) | ||
1778 | |||
1779 | def EnlargeFont(widget): | ||
1780 | ResizeFont(widget, 1) | ||
1781 | |||
1782 | # Unique name for sub-windows | ||
1783 | |||
1784 | def NumberedWindowName(name, nr): | ||
1785 | if nr > 1: | ||
1786 | name += " <" + str(nr) + ">" | ||
1787 | return name | ||
1788 | |||
1789 | def UniqueSubWindowName(mdi_area, name): | ||
1790 | nr = 1 | ||
1791 | while True: | ||
1792 | unique_name = NumberedWindowName(name, nr) | ||
1793 | ok = True | ||
1794 | for sub_window in mdi_area.subWindowList(): | ||
1795 | if sub_window.name == unique_name: | ||
1796 | ok = False | ||
1797 | break | ||
1798 | if ok: | ||
1799 | return unique_name | ||
1800 | nr += 1 | ||
1801 | |||
1802 | # Add a sub-window | ||
1803 | |||
1804 | def AddSubWindow(mdi_area, sub_window, name): | ||
1805 | unique_name = UniqueSubWindowName(mdi_area, name) | ||
1806 | sub_window.setMinimumSize(200, 100) | ||
1807 | sub_window.resize(800, 600) | ||
1808 | sub_window.setWindowTitle(unique_name) | ||
1809 | sub_window.setAttribute(Qt.WA_DeleteOnClose) | ||
1810 | sub_window.setWindowIcon(sub_window.style().standardIcon(QStyle.SP_FileIcon)) | ||
1811 | sub_window.name = unique_name | ||
1812 | mdi_area.addSubWindow(sub_window) | ||
1813 | sub_window.show() | ||
1814 | |||
1815 | # Main window | ||
1816 | |||
1817 | class MainWindow(QMainWindow): | ||
1818 | |||
1819 | def __init__(self, glb, parent=None): | ||
1820 | super(MainWindow, self).__init__(parent) | ||
1821 | |||
1822 | self.glb = glb | ||
1823 | |||
1824 | self.setWindowTitle("Exported SQL Viewer: " + glb.dbname) | ||
1825 | self.setWindowIcon(self.style().standardIcon(QStyle.SP_ComputerIcon)) | ||
1826 | self.setMinimumSize(200, 100) | ||
1827 | |||
1828 | self.mdi_area = QMdiArea() | ||
1829 | self.mdi_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) | ||
1830 | self.mdi_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) | ||
1831 | |||
1832 | self.setCentralWidget(self.mdi_area) | ||
1833 | |||
1834 | menu = self.menuBar() | ||
1835 | |||
1836 | file_menu = menu.addMenu("&File") | ||
1837 | file_menu.addAction(CreateExitAction(glb.app, self)) | ||
1838 | |||
1839 | edit_menu = menu.addMenu("&Edit") | ||
1840 | edit_menu.addAction(CreateAction("&Find...", "Find items", self.Find, self, QKeySequence.Find)) | ||
1841 | edit_menu.addAction(CreateAction("Fetch &more records...", "Fetch more records", self.FetchMoreRecords, self, [QKeySequence(Qt.Key_F8)])) | ||
1842 | edit_menu.addAction(CreateAction("&Shrink Font", "Make text smaller", self.ShrinkFont, self, [QKeySequence("Ctrl+-")])) | ||
1843 | edit_menu.addAction(CreateAction("&Enlarge Font", "Make text bigger", self.EnlargeFont, self, [QKeySequence("Ctrl++")])) | ||
1844 | |||
1845 | reports_menu = menu.addMenu("&Reports") | ||
1846 | reports_menu.addAction(CreateAction("Context-Sensitive Call &Graph", "Create a new window containing a context-sensitive call graph", self.NewCallGraph, self)) | ||
1847 | |||
1848 | self.EventMenu(GetEventList(glb.db), reports_menu) | ||
1849 | |||
1850 | self.TableMenu(GetTableList(glb), menu) | ||
1851 | |||
1852 | self.window_menu = WindowMenu(self.mdi_area, menu) | ||
1853 | |||
1854 | def Find(self): | ||
1855 | win = self.mdi_area.activeSubWindow() | ||
1856 | if win: | ||
1857 | try: | ||
1858 | win.find_bar.Activate() | ||
1859 | except: | ||
1860 | pass | ||
1861 | |||
1862 | def FetchMoreRecords(self): | ||
1863 | win = self.mdi_area.activeSubWindow() | ||
1864 | if win: | ||
1865 | try: | ||
1866 | win.fetch_bar.Activate() | ||
1867 | except: | ||
1868 | pass | ||
1869 | |||
1870 | def ShrinkFont(self): | ||
1871 | win = self.mdi_area.activeSubWindow() | ||
1872 | ShrinkFont(win.view) | ||
1873 | |||
1874 | def EnlargeFont(self): | ||
1875 | win = self.mdi_area.activeSubWindow() | ||
1876 | EnlargeFont(win.view) | ||
1877 | |||
1878 | def EventMenu(self, events, reports_menu): | ||
1879 | branches_events = 0 | ||
1880 | for event in events: | ||
1881 | event = event.split(":")[0] | ||
1882 | if event == "branches": | ||
1883 | branches_events += 1 | ||
1884 | dbid = 0 | ||
1885 | for event in events: | ||
1886 | dbid += 1 | ||
1887 | event = event.split(":")[0] | ||
1888 | if event == "branches": | ||
1889 | label = "All branches" if branches_events == 1 else "All branches " + "(id=" + dbid + ")" | ||
1890 | reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewBranchView(x), self)) | ||
1891 | |||
1892 | def TableMenu(self, tables, menu): | ||
1893 | table_menu = menu.addMenu("&Tables") | ||
1894 | for table in tables: | ||
1895 | table_menu.addAction(CreateAction(table, "Create a new window containing a table view", lambda t=table: self.NewTableView(t), self)) | ||
1896 | |||
1897 | def NewCallGraph(self): | ||
1898 | CallGraphWindow(self.glb, self) | ||
1899 | |||
1900 | def NewBranchView(self, event_id): | ||
1901 | BranchWindow(self.glb, event_id, "", "", self) | ||
1902 | |||
1903 | def NewTableView(self, table_name): | ||
1904 | TableWindow(self.glb, table_name, self) | ||
1905 | |||
1906 | # XED Disassembler | ||
1907 | |||
1908 | class xed_state_t(Structure): | ||
1909 | |||
1910 | _fields_ = [ | ||
1911 | ("mode", c_int), | ||
1912 | ("width", c_int) | ||
1913 | ] | ||
1914 | |||
1915 | class XEDInstruction(): | ||
1916 | |||
1917 | def __init__(self, libxed): | ||
1918 | # Current xed_decoded_inst_t structure is 192 bytes. Use 512 to allow for future expansion | ||
1919 | xedd_t = c_byte * 512 | ||
1920 | self.xedd = xedd_t() | ||
1921 | self.xedp = addressof(self.xedd) | ||
1922 | libxed.xed_decoded_inst_zero(self.xedp) | ||
1923 | self.state = xed_state_t() | ||
1924 | self.statep = addressof(self.state) | ||
1925 | # Buffer for disassembled instruction text | ||
1926 | self.buffer = create_string_buffer(256) | ||
1927 | self.bufferp = addressof(self.buffer) | ||
1928 | |||
1929 | class LibXED(): | ||
1930 | |||
1931 | def __init__(self): | ||
1932 | self.libxed = CDLL("libxed.so") | ||
1933 | |||
1934 | self.xed_tables_init = self.libxed.xed_tables_init | ||
1935 | self.xed_tables_init.restype = None | ||
1936 | self.xed_tables_init.argtypes = [] | ||
1937 | |||
1938 | self.xed_decoded_inst_zero = self.libxed.xed_decoded_inst_zero | ||
1939 | self.xed_decoded_inst_zero.restype = None | ||
1940 | self.xed_decoded_inst_zero.argtypes = [ c_void_p ] | ||
1941 | |||
1942 | self.xed_operand_values_set_mode = self.libxed.xed_operand_values_set_mode | ||
1943 | self.xed_operand_values_set_mode.restype = None | ||
1944 | self.xed_operand_values_set_mode.argtypes = [ c_void_p, c_void_p ] | ||
1945 | |||
1946 | self.xed_decoded_inst_zero_keep_mode = self.libxed.xed_decoded_inst_zero_keep_mode | ||
1947 | self.xed_decoded_inst_zero_keep_mode.restype = None | ||
1948 | self.xed_decoded_inst_zero_keep_mode.argtypes = [ c_void_p ] | ||
1949 | |||
1950 | self.xed_decode = self.libxed.xed_decode | ||
1951 | self.xed_decode.restype = c_int | ||
1952 | self.xed_decode.argtypes = [ c_void_p, c_void_p, c_uint ] | ||
1953 | |||
1954 | self.xed_format_context = self.libxed.xed_format_context | ||
1955 | self.xed_format_context.restype = c_uint | ||
1956 | self.xed_format_context.argtypes = [ c_int, c_void_p, c_void_p, c_int, c_ulonglong, c_void_p, c_void_p ] | ||
1957 | |||
1958 | self.xed_tables_init() | ||
1959 | |||
1960 | def Instruction(self): | ||
1961 | return XEDInstruction(self) | ||
1962 | |||
1963 | def SetMode(self, inst, mode): | ||
1964 | if mode: | ||
1965 | inst.state.mode = 4 # 32-bit | ||
1966 | inst.state.width = 4 # 4 bytes | ||
1967 | else: | ||
1968 | inst.state.mode = 1 # 64-bit | ||
1969 | inst.state.width = 8 # 8 bytes | ||
1970 | self.xed_operand_values_set_mode(inst.xedp, inst.statep) | ||
1971 | |||
1972 | def DisassembleOne(self, inst, bytes_ptr, bytes_cnt, ip): | ||
1973 | self.xed_decoded_inst_zero_keep_mode(inst.xedp) | ||
1974 | err = self.xed_decode(inst.xedp, bytes_ptr, bytes_cnt) | ||
1975 | if err: | ||
1976 | return 0, "" | ||
1977 | # Use AT&T mode (2), alternative is Intel (3) | ||
1978 | ok = self.xed_format_context(2, inst.xedp, inst.bufferp, sizeof(inst.buffer), ip, 0, 0) | ||
1979 | if not ok: | ||
1980 | return 0, "" | ||
1981 | # Return instruction length and the disassembled instruction text | ||
1982 | # For now, assume the length is in byte 166 | ||
1983 | return inst.xedd[166], inst.buffer.value | ||
1984 | |||
1985 | def TryOpen(file_name): | ||
1986 | try: | ||
1987 | return open(file_name, "rb") | ||
1988 | except: | ||
1989 | return None | ||
1990 | |||
1991 | def Is64Bit(f): | ||
1992 | result = sizeof(c_void_p) | ||
1993 | # ELF support only | ||
1994 | pos = f.tell() | ||
1995 | f.seek(0) | ||
1996 | header = f.read(7) | ||
1997 | f.seek(pos) | ||
1998 | magic = header[0:4] | ||
1999 | eclass = ord(header[4]) | ||
2000 | encoding = ord(header[5]) | ||
2001 | version = ord(header[6]) | ||
2002 | if magic == chr(127) + "ELF" and eclass > 0 and eclass < 3 and encoding > 0 and encoding < 3 and version == 1: | ||
2003 | result = True if eclass == 2 else False | ||
2004 | return result | ||
2005 | |||
2006 | # Global data | ||
2007 | |||
2008 | class Glb(): | ||
2009 | |||
2010 | def __init__(self, dbref, db, dbname): | ||
2011 | self.dbref = dbref | ||
2012 | self.db = db | ||
2013 | self.dbname = dbname | ||
2014 | self.home_dir = os.path.expanduser("~") | ||
2015 | self.buildid_dir = os.getenv("PERF_BUILDID_DIR") | ||
2016 | if self.buildid_dir: | ||
2017 | self.buildid_dir += "/.build-id/" | ||
2018 | else: | ||
2019 | self.buildid_dir = self.home_dir + "/.debug/.build-id/" | ||
2020 | self.app = None | ||
2021 | self.mainwindow = None | ||
2022 | self.instances_to_shutdown_on_exit = weakref.WeakSet() | ||
2023 | try: | ||
2024 | self.disassembler = LibXED() | ||
2025 | self.have_disassembler = True | ||
2026 | except: | ||
2027 | self.have_disassembler = False | ||
2028 | |||
2029 | def FileFromBuildId(self, build_id): | ||
2030 | file_name = self.buildid_dir + build_id[0:2] + "/" + build_id[2:] + "/elf" | ||
2031 | return TryOpen(file_name) | ||
2032 | |||
2033 | def FileFromNamesAndBuildId(self, short_name, long_name, build_id): | ||
2034 | # Assume current machine i.e. no support for virtualization | ||
2035 | if short_name[0:7] == "[kernel" and os.path.basename(long_name) == "kcore": | ||
2036 | file_name = os.getenv("PERF_KCORE") | ||
2037 | f = TryOpen(file_name) if file_name else None | ||
2038 | if f: | ||
2039 | return f | ||
2040 | # For now, no special handling if long_name is /proc/kcore | ||
2041 | f = TryOpen(long_name) | ||
2042 | if f: | ||
2043 | return f | ||
2044 | f = self.FileFromBuildId(build_id) | ||
2045 | if f: | ||
2046 | return f | ||
2047 | return None | ||
2048 | |||
2049 | def AddInstanceToShutdownOnExit(self, instance): | ||
2050 | self.instances_to_shutdown_on_exit.add(instance) | ||
2051 | |||
2052 | # Shutdown any background processes or threads | ||
2053 | def ShutdownInstances(self): | ||
2054 | for x in self.instances_to_shutdown_on_exit: | ||
2055 | try: | ||
2056 | x.Shutdown() | ||
2057 | except: | ||
2058 | pass | ||
2059 | |||
2060 | # Database reference | ||
2061 | |||
2062 | class DBRef(): | ||
2063 | |||
2064 | def __init__(self, is_sqlite3, dbname): | ||
2065 | self.is_sqlite3 = is_sqlite3 | ||
2066 | self.dbname = dbname | ||
2067 | |||
2068 | def Open(self, connection_name): | ||
2069 | dbname = self.dbname | ||
2070 | if self.is_sqlite3: | ||
2071 | db = QSqlDatabase.addDatabase("QSQLITE", connection_name) | ||
2072 | else: | ||
2073 | db = QSqlDatabase.addDatabase("QPSQL", connection_name) | ||
2074 | opts = dbname.split() | ||
2075 | for opt in opts: | ||
2076 | if "=" in opt: | ||
2077 | opt = opt.split("=") | ||
2078 | if opt[0] == "hostname": | ||
2079 | db.setHostName(opt[1]) | ||
2080 | elif opt[0] == "port": | ||
2081 | db.setPort(int(opt[1])) | ||
2082 | elif opt[0] == "username": | ||
2083 | db.setUserName(opt[1]) | ||
2084 | elif opt[0] == "password": | ||
2085 | db.setPassword(opt[1]) | ||
2086 | elif opt[0] == "dbname": | ||
2087 | dbname = opt[1] | ||
2088 | else: | ||
2089 | dbname = opt | ||
2090 | |||
2091 | db.setDatabaseName(dbname) | ||
2092 | if not db.open(): | ||
2093 | raise Exception("Failed to open database " + dbname + " error: " + db.lastError().text()) | ||
2094 | return db, dbname | ||
2095 | |||
2096 | # Main | ||
2097 | |||
2098 | def Main(): | ||
2099 | if (len(sys.argv) < 2): | ||
2100 | print >> sys.stderr, "Usage is: exported-sql-viewer.py <database name>" | ||
2101 | raise Exception("Too few arguments") | ||
2102 | |||
2103 | dbname = sys.argv[1] | ||
2104 | |||
2105 | is_sqlite3 = False | ||
2106 | try: | ||
2107 | f = open(dbname) | ||
2108 | if f.read(15) == "SQLite format 3": | ||
2109 | is_sqlite3 = True | ||
2110 | f.close() | ||
2111 | except: | ||
2112 | pass | ||
2113 | |||
2114 | dbref = DBRef(is_sqlite3, dbname) | ||
2115 | db, dbname = dbref.Open("main") | ||
2116 | glb = Glb(dbref, db, dbname) | ||
2117 | app = QApplication(sys.argv) | ||
2118 | glb.app = app | ||
2119 | mainwindow = MainWindow(glb) | ||
2120 | glb.mainwindow = mainwindow | ||
2121 | mainwindow.show() | ||
2122 | err = app.exec_() | ||
2123 | glb.ShutdownInstances() | ||
2124 | db.close() | ||
2125 | sys.exit(err) | ||
2126 | |||
2127 | if __name__ == "__main__": | ||
2128 | Main() | ||
diff --git a/tools/perf/trace/beauty/Build b/tools/perf/trace/beauty/Build index c3b0afd67760..304313073242 100644 --- a/tools/perf/trace/beauty/Build +++ b/tools/perf/trace/beauty/Build | |||
@@ -5,6 +5,7 @@ ifeq ($(SRCARCH),$(filter $(SRCARCH),x86)) | |||
5 | libperf-y += ioctl.o | 5 | libperf-y += ioctl.o |
6 | endif | 6 | endif |
7 | libperf-y += kcmp.o | 7 | libperf-y += kcmp.o |
8 | libperf-y += mount_flags.o | ||
8 | libperf-y += pkey_alloc.o | 9 | libperf-y += pkey_alloc.o |
9 | libperf-y += prctl.o | 10 | libperf-y += prctl.o |
10 | libperf-y += sockaddr.o | 11 | libperf-y += sockaddr.o |
diff --git a/tools/perf/trace/beauty/beauty.h b/tools/perf/trace/beauty/beauty.h index 2570152d3909..039c29039b2c 100644 --- a/tools/perf/trace/beauty/beauty.h +++ b/tools/perf/trace/beauty/beauty.h | |||
@@ -24,6 +24,7 @@ struct strarray { | |||
24 | } | 24 | } |
25 | 25 | ||
26 | size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, int val); | 26 | size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, int val); |
27 | size_t strarray__scnprintf_flags(struct strarray *sa, char *bf, size_t size, unsigned long flags); | ||
27 | 28 | ||
28 | struct trace; | 29 | struct trace; |
29 | struct thread; | 30 | struct thread; |
@@ -122,6 +123,12 @@ size_t syscall_arg__scnprintf_kcmp_type(char *bf, size_t size, struct syscall_ar | |||
122 | size_t syscall_arg__scnprintf_kcmp_idx(char *bf, size_t size, struct syscall_arg *arg); | 123 | size_t syscall_arg__scnprintf_kcmp_idx(char *bf, size_t size, struct syscall_arg *arg); |
123 | #define SCA_KCMP_IDX syscall_arg__scnprintf_kcmp_idx | 124 | #define SCA_KCMP_IDX syscall_arg__scnprintf_kcmp_idx |
124 | 125 | ||
126 | unsigned long syscall_arg__mask_val_mount_flags(struct syscall_arg *arg, unsigned long flags); | ||
127 | #define SCAMV_MOUNT_FLAGS syscall_arg__mask_val_mount_flags | ||
128 | |||
129 | size_t syscall_arg__scnprintf_mount_flags(char *bf, size_t size, struct syscall_arg *arg); | ||
130 | #define SCA_MOUNT_FLAGS syscall_arg__scnprintf_mount_flags | ||
131 | |||
125 | size_t syscall_arg__scnprintf_pkey_alloc_access_rights(char *bf, size_t size, struct syscall_arg *arg); | 132 | size_t syscall_arg__scnprintf_pkey_alloc_access_rights(char *bf, size_t size, struct syscall_arg *arg); |
126 | #define SCA_PKEY_ALLOC_ACCESS_RIGHTS syscall_arg__scnprintf_pkey_alloc_access_rights | 133 | #define SCA_PKEY_ALLOC_ACCESS_RIGHTS syscall_arg__scnprintf_pkey_alloc_access_rights |
127 | 134 | ||
diff --git a/tools/perf/trace/beauty/clone.c b/tools/perf/trace/beauty/clone.c index d64d049ab991..010406500c30 100644 --- a/tools/perf/trace/beauty/clone.c +++ b/tools/perf/trace/beauty/clone.c | |||
@@ -1,9 +1,8 @@ | |||
1 | // SPDX-License-Identifier: LGPL-2.1 | ||
1 | /* | 2 | /* |
2 | * trace/beauty/cone.c | 3 | * trace/beauty/cone.c |
3 | * | 4 | * |
4 | * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | 5 | * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> |
5 | * | ||
6 | * Released under the GPL v2. (and only v2, not any later version) | ||
7 | */ | 6 | */ |
8 | 7 | ||
9 | #include "trace/beauty/beauty.h" | 8 | #include "trace/beauty/beauty.h" |
diff --git a/tools/perf/trace/beauty/drm_ioctl.sh b/tools/perf/trace/beauty/drm_ioctl.sh index 9d3816815e60..9aa94fd523a9 100755 --- a/tools/perf/trace/beauty/drm_ioctl.sh +++ b/tools/perf/trace/beauty/drm_ioctl.sh | |||
@@ -1,4 +1,5 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | # SPDX-License-Identifier: LGPL-2.1 | ||
2 | 3 | ||
3 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/drm/ | 4 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/drm/ |
4 | 5 | ||
diff --git a/tools/perf/trace/beauty/eventfd.c b/tools/perf/trace/beauty/eventfd.c index 5d6a477a6400..db5b9b492113 100644 --- a/tools/perf/trace/beauty/eventfd.c +++ b/tools/perf/trace/beauty/eventfd.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
2 | #ifndef EFD_SEMAPHORE | 2 | #ifndef EFD_SEMAPHORE |
3 | #define EFD_SEMAPHORE 1 | 3 | #define EFD_SEMAPHORE 1 |
4 | #endif | 4 | #endif |
diff --git a/tools/perf/trace/beauty/fcntl.c b/tools/perf/trace/beauty/fcntl.c index 9e8900c13cb1..e6de31674e24 100644 --- a/tools/perf/trace/beauty/fcntl.c +++ b/tools/perf/trace/beauty/fcntl.c | |||
@@ -1,9 +1,8 @@ | |||
1 | // SPDX-License-Identifier: LGPL-2.1 | ||
1 | /* | 2 | /* |
2 | * trace/beauty/fcntl.c | 3 | * trace/beauty/fcntl.c |
3 | * | 4 | * |
4 | * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | 5 | * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> |
5 | * | ||
6 | * Released under the GPL v2. (and only v2, not any later version) | ||
7 | */ | 6 | */ |
8 | 7 | ||
9 | #include "trace/beauty/beauty.h" | 8 | #include "trace/beauty/beauty.h" |
diff --git a/tools/perf/trace/beauty/flock.c b/tools/perf/trace/beauty/flock.c index c4ff6ad30b06..cf02ae5f0ba6 100644 --- a/tools/perf/trace/beauty/flock.c +++ b/tools/perf/trace/beauty/flock.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
2 | 2 | ||
3 | #include "trace/beauty/beauty.h" | 3 | #include "trace/beauty/beauty.h" |
4 | #include <linux/kernel.h> | 4 | #include <linux/kernel.h> |
diff --git a/tools/perf/trace/beauty/futex_op.c b/tools/perf/trace/beauty/futex_op.c index 61850fbc85ff..1136bde56406 100644 --- a/tools/perf/trace/beauty/futex_op.c +++ b/tools/perf/trace/beauty/futex_op.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
2 | #include <linux/futex.h> | 2 | #include <linux/futex.h> |
3 | 3 | ||
4 | #ifndef FUTEX_WAIT_BITSET | 4 | #ifndef FUTEX_WAIT_BITSET |
diff --git a/tools/perf/trace/beauty/futex_val3.c b/tools/perf/trace/beauty/futex_val3.c index 26f6b3253511..138b7d588a70 100644 --- a/tools/perf/trace/beauty/futex_val3.c +++ b/tools/perf/trace/beauty/futex_val3.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
2 | #include <linux/futex.h> | 2 | #include <linux/futex.h> |
3 | 3 | ||
4 | #ifndef FUTEX_BITSET_MATCH_ANY | 4 | #ifndef FUTEX_BITSET_MATCH_ANY |
diff --git a/tools/perf/trace/beauty/ioctl.c b/tools/perf/trace/beauty/ioctl.c index 1be3b4cf0827..5d2a7fd8d407 100644 --- a/tools/perf/trace/beauty/ioctl.c +++ b/tools/perf/trace/beauty/ioctl.c | |||
@@ -1,9 +1,8 @@ | |||
1 | // SPDX-License-Identifier: LGPL-2.1 | ||
1 | /* | 2 | /* |
2 | * trace/beauty/ioctl.c | 3 | * trace/beauty/ioctl.c |
3 | * | 4 | * |
4 | * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | 5 | * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> |
5 | * | ||
6 | * Released under the GPL v2. (and only v2, not any later version) | ||
7 | */ | 6 | */ |
8 | 7 | ||
9 | #include "trace/beauty/beauty.h" | 8 | #include "trace/beauty/beauty.h" |
diff --git a/tools/perf/trace/beauty/kcmp.c b/tools/perf/trace/beauty/kcmp.c index f62040eb9d5c..b276a274f203 100644 --- a/tools/perf/trace/beauty/kcmp.c +++ b/tools/perf/trace/beauty/kcmp.c | |||
@@ -1,9 +1,8 @@ | |||
1 | // SPDX-License-Identifier: LGPL-2.1 | ||
1 | /* | 2 | /* |
2 | * trace/beauty/kcmp.c | 3 | * trace/beauty/kcmp.c |
3 | * | 4 | * |
4 | * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | 5 | * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> |
5 | * | ||
6 | * Released under the GPL v2. (and only v2, not any later version) | ||
7 | */ | 6 | */ |
8 | 7 | ||
9 | #include "trace/beauty/beauty.h" | 8 | #include "trace/beauty/beauty.h" |
diff --git a/tools/perf/trace/beauty/kcmp_type.sh b/tools/perf/trace/beauty/kcmp_type.sh index a3c304caa336..df8b17486d57 100755 --- a/tools/perf/trace/beauty/kcmp_type.sh +++ b/tools/perf/trace/beauty/kcmp_type.sh | |||
@@ -1,4 +1,5 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | # SPDX-License-Identifier: LGPL-2.1 | ||
2 | 3 | ||
3 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ | 4 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ |
4 | 5 | ||
diff --git a/tools/perf/trace/beauty/kvm_ioctl.sh b/tools/perf/trace/beauty/kvm_ioctl.sh index c4699fd46bb6..4ce54f5bf756 100755 --- a/tools/perf/trace/beauty/kvm_ioctl.sh +++ b/tools/perf/trace/beauty/kvm_ioctl.sh | |||
@@ -1,4 +1,5 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | # SPDX-License-Identifier: LGPL-2.1 | ||
2 | 3 | ||
3 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ | 4 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ |
4 | 5 | ||
diff --git a/tools/perf/trace/beauty/madvise_behavior.sh b/tools/perf/trace/beauty/madvise_behavior.sh index 431639eb4d29..4527d290cdfc 100755 --- a/tools/perf/trace/beauty/madvise_behavior.sh +++ b/tools/perf/trace/beauty/madvise_behavior.sh | |||
@@ -1,4 +1,5 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | # SPDX-License-Identifier: LGPL-2.1 | ||
2 | 3 | ||
3 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/asm-generic/ | 4 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/asm-generic/ |
4 | 5 | ||
diff --git a/tools/perf/trace/beauty/mmap.c b/tools/perf/trace/beauty/mmap.c index 9f68077b241b..c534bd96ef5c 100644 --- a/tools/perf/trace/beauty/mmap.c +++ b/tools/perf/trace/beauty/mmap.c | |||
@@ -1,5 +1,6 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
2 | #include <uapi/linux/mman.h> | 2 | #include <uapi/linux/mman.h> |
3 | #include <linux/log2.h> | ||
3 | 4 | ||
4 | static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, | 5 | static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, |
5 | struct syscall_arg *arg) | 6 | struct syscall_arg *arg) |
@@ -30,50 +31,23 @@ static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, | |||
30 | 31 | ||
31 | #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot | 32 | #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot |
32 | 33 | ||
34 | static size_t mmap__scnprintf_flags(unsigned long flags, char *bf, size_t size) | ||
35 | { | ||
36 | #include "trace/beauty/generated/mmap_flags_array.c" | ||
37 | static DEFINE_STRARRAY(mmap_flags); | ||
38 | |||
39 | return strarray__scnprintf_flags(&strarray__mmap_flags, bf, size, flags); | ||
40 | } | ||
41 | |||
33 | static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, | 42 | static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, |
34 | struct syscall_arg *arg) | 43 | struct syscall_arg *arg) |
35 | { | 44 | { |
36 | int printed = 0, flags = arg->val; | 45 | unsigned long flags = arg->val; |
37 | 46 | ||
38 | if (flags & MAP_ANONYMOUS) | 47 | if (flags & MAP_ANONYMOUS) |
39 | arg->mask |= (1 << 4) | (1 << 5); /* Mask 4th ('fd') and 5th ('offset') args, ignored */ | 48 | arg->mask |= (1 << 4) | (1 << 5); /* Mask 4th ('fd') and 5th ('offset') args, ignored */ |
40 | 49 | ||
41 | #define P_MMAP_FLAG(n) \ | 50 | return mmap__scnprintf_flags(flags, bf, size); |
42 | if (flags & MAP_##n) { \ | ||
43 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
44 | flags &= ~MAP_##n; \ | ||
45 | } | ||
46 | |||
47 | P_MMAP_FLAG(SHARED); | ||
48 | P_MMAP_FLAG(PRIVATE); | ||
49 | #ifdef MAP_32BIT | ||
50 | P_MMAP_FLAG(32BIT); | ||
51 | #endif | ||
52 | P_MMAP_FLAG(ANONYMOUS); | ||
53 | P_MMAP_FLAG(DENYWRITE); | ||
54 | P_MMAP_FLAG(EXECUTABLE); | ||
55 | P_MMAP_FLAG(FILE); | ||
56 | P_MMAP_FLAG(FIXED); | ||
57 | #ifdef MAP_FIXED_NOREPLACE | ||
58 | P_MMAP_FLAG(FIXED_NOREPLACE); | ||
59 | #endif | ||
60 | P_MMAP_FLAG(GROWSDOWN); | ||
61 | P_MMAP_FLAG(HUGETLB); | ||
62 | P_MMAP_FLAG(LOCKED); | ||
63 | P_MMAP_FLAG(NONBLOCK); | ||
64 | P_MMAP_FLAG(NORESERVE); | ||
65 | P_MMAP_FLAG(POPULATE); | ||
66 | P_MMAP_FLAG(STACK); | ||
67 | P_MMAP_FLAG(UNINITIALIZED); | ||
68 | #ifdef MAP_SYNC | ||
69 | P_MMAP_FLAG(SYNC); | ||
70 | #endif | ||
71 | #undef P_MMAP_FLAG | ||
72 | |||
73 | if (flags) | ||
74 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
75 | |||
76 | return printed; | ||
77 | } | 51 | } |
78 | 52 | ||
79 | #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags | 53 | #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags |
diff --git a/tools/perf/trace/beauty/mmap_flags.sh b/tools/perf/trace/beauty/mmap_flags.sh new file mode 100755 index 000000000000..22c3fdca8975 --- /dev/null +++ b/tools/perf/trace/beauty/mmap_flags.sh | |||
@@ -0,0 +1,32 @@ | |||
1 | #!/bin/sh | ||
2 | # SPDX-License-Identifier: LGPL-2.1 | ||
3 | |||
4 | if [ $# -ne 2 ] ; then | ||
5 | [ $# -eq 1 ] && hostarch=$1 || hostarch=`uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/` | ||
6 | header_dir=tools/include/uapi/asm-generic | ||
7 | arch_header_dir=tools/arch/${hostarch}/include/uapi/asm | ||
8 | else | ||
9 | header_dir=$1 | ||
10 | arch_header_dir=$2 | ||
11 | fi | ||
12 | |||
13 | arch_mman=${arch_header_dir}/mman.h | ||
14 | |||
15 | # those in egrep -vw are flags, we want just the bits | ||
16 | |||
17 | printf "static const char *mmap_flags[] = {\n" | ||
18 | regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MAP_([[:alnum:]_]+)[[:space:]]+(0x[[:xdigit:]]+)[[:space:]]*.*' | ||
19 | egrep -q $regex ${arch_mman} && \ | ||
20 | (egrep $regex ${arch_mman} | \ | ||
21 | sed -r "s/$regex/\2 \1/g" | \ | ||
22 | xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n") | ||
23 | egrep -q '#[[:space:]]*include[[:space:]]+<uapi/asm-generic/mman.*' ${arch_mman} && | ||
24 | (egrep $regex ${header_dir}/mman-common.h | \ | ||
25 | egrep -vw 'MAP_(UNINITIALIZED|TYPE|SHARED_VALIDATE)' | \ | ||
26 | sed -r "s/$regex/\2 \1/g" | \ | ||
27 | xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n") | ||
28 | egrep -q '#[[:space:]]*include[[:space:]]+<uapi/asm-generic/mman.h>.*' ${arch_mman} && | ||
29 | (egrep $regex ${header_dir}/mman.h | \ | ||
30 | sed -r "s/$regex/\2 \1/g" | \ | ||
31 | xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n") | ||
32 | printf "};\n" | ||
diff --git a/tools/perf/trace/beauty/mode_t.c b/tools/perf/trace/beauty/mode_t.c index d929ad7dd97b..6879d36d3004 100644 --- a/tools/perf/trace/beauty/mode_t.c +++ b/tools/perf/trace/beauty/mode_t.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
2 | #include <sys/types.h> | 2 | #include <sys/types.h> |
3 | #include <sys/stat.h> | 3 | #include <sys/stat.h> |
4 | #include <unistd.h> | 4 | #include <unistd.h> |
diff --git a/tools/perf/trace/beauty/mount_flags.c b/tools/perf/trace/beauty/mount_flags.c new file mode 100644 index 000000000000..712935c6620a --- /dev/null +++ b/tools/perf/trace/beauty/mount_flags.c | |||
@@ -0,0 +1,43 @@ | |||
1 | // SPDX-License-Identifier: LGPL-2.1 | ||
2 | /* | ||
3 | * trace/beauty/mount_flags.c | ||
4 | * | ||
5 | * Copyright (C) 2018, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | ||
6 | */ | ||
7 | |||
8 | #include "trace/beauty/beauty.h" | ||
9 | #include <linux/compiler.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/log2.h> | ||
12 | #include <sys/mount.h> | ||
13 | |||
14 | static size_t mount__scnprintf_flags(unsigned long flags, char *bf, size_t size) | ||
15 | { | ||
16 | #include "trace/beauty/generated/mount_flags_array.c" | ||
17 | static DEFINE_STRARRAY(mount_flags); | ||
18 | |||
19 | return strarray__scnprintf_flags(&strarray__mount_flags, bf, size, flags); | ||
20 | } | ||
21 | |||
22 | unsigned long syscall_arg__mask_val_mount_flags(struct syscall_arg *arg __maybe_unused, unsigned long flags) | ||
23 | { | ||
24 | // do_mount in fs/namespace.c: | ||
25 | /* | ||
26 | * Pre-0.97 versions of mount() didn't have a flags word. When the | ||
27 | * flags word was introduced its top half was required to have the | ||
28 | * magic value 0xC0ED, and this remained so until 2.4.0-test9. | ||
29 | * Therefore, if this magic number is present, it carries no | ||
30 | * information and must be discarded. | ||
31 | */ | ||
32 | if ((flags & MS_MGC_MSK) == MS_MGC_VAL) | ||
33 | flags &= ~MS_MGC_MSK; | ||
34 | |||
35 | return flags; | ||
36 | } | ||
37 | |||
38 | size_t syscall_arg__scnprintf_mount_flags(char *bf, size_t size, struct syscall_arg *arg) | ||
39 | { | ||
40 | unsigned long flags = arg->val; | ||
41 | |||
42 | return mount__scnprintf_flags(flags, bf, size); | ||
43 | } | ||
diff --git a/tools/perf/trace/beauty/mount_flags.sh b/tools/perf/trace/beauty/mount_flags.sh new file mode 100755 index 000000000000..45547573a1db --- /dev/null +++ b/tools/perf/trace/beauty/mount_flags.sh | |||
@@ -0,0 +1,15 @@ | |||
1 | #!/bin/sh | ||
2 | # SPDX-License-Identifier: LGPL-2.1 | ||
3 | |||
4 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ | ||
5 | |||
6 | printf "static const char *mount_flags[] = {\n" | ||
7 | regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MS_([[:alnum:]_]+)[[:space:]]+([[:digit:]]+)[[:space:]]*.*' | ||
8 | egrep $regex ${header_dir}/fs.h | egrep -v '(MSK|VERBOSE|MGC_VAL)\>' | \ | ||
9 | sed -r "s/$regex/\2 \2 \1/g" | sort -n | \ | ||
10 | xargs printf "\t[%s ? (ilog2(%s) + 1) : 0] = \"%s\",\n" | ||
11 | regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MS_([[:alnum:]_]+)[[:space:]]+\(1<<([[:digit:]]+)\)[[:space:]]*.*' | ||
12 | egrep $regex ${header_dir}/fs.h | \ | ||
13 | sed -r "s/$regex/\2 \1/g" | \ | ||
14 | xargs printf "\t[%s + 1] = \"%s\",\n" | ||
15 | printf "};\n" | ||
diff --git a/tools/perf/trace/beauty/msg_flags.c b/tools/perf/trace/beauty/msg_flags.c index c064d6aae659..1b9d6306d274 100644 --- a/tools/perf/trace/beauty/msg_flags.c +++ b/tools/perf/trace/beauty/msg_flags.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
2 | #include <sys/types.h> | 2 | #include <sys/types.h> |
3 | #include <sys/socket.h> | 3 | #include <sys/socket.h> |
4 | 4 | ||
diff --git a/tools/perf/trace/beauty/open_flags.c b/tools/perf/trace/beauty/open_flags.c index 6aec6178a99d..cc673fec9184 100644 --- a/tools/perf/trace/beauty/open_flags.c +++ b/tools/perf/trace/beauty/open_flags.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
2 | #include <sys/types.h> | 2 | #include <sys/types.h> |
3 | #include <sys/stat.h> | 3 | #include <sys/stat.h> |
4 | #include <fcntl.h> | 4 | #include <fcntl.h> |
diff --git a/tools/perf/trace/beauty/perf_event_open.c b/tools/perf/trace/beauty/perf_event_open.c index 2bafd7c995ff..981185c1974b 100644 --- a/tools/perf/trace/beauty/perf_event_open.c +++ b/tools/perf/trace/beauty/perf_event_open.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
2 | #ifndef PERF_FLAG_FD_NO_GROUP | 2 | #ifndef PERF_FLAG_FD_NO_GROUP |
3 | # define PERF_FLAG_FD_NO_GROUP (1UL << 0) | 3 | # define PERF_FLAG_FD_NO_GROUP (1UL << 0) |
4 | #endif | 4 | #endif |
diff --git a/tools/perf/trace/beauty/perf_ioctl.sh b/tools/perf/trace/beauty/perf_ioctl.sh index 6492c74df928..9aabd9743ef6 100755 --- a/tools/perf/trace/beauty/perf_ioctl.sh +++ b/tools/perf/trace/beauty/perf_ioctl.sh | |||
@@ -1,4 +1,5 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | # SPDX-License-Identifier: LGPL-2.1 | ||
2 | 3 | ||
3 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ | 4 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ |
4 | 5 | ||
diff --git a/tools/perf/trace/beauty/pid.c b/tools/perf/trace/beauty/pid.c index 0313df342830..1a6acc46807b 100644 --- a/tools/perf/trace/beauty/pid.c +++ b/tools/perf/trace/beauty/pid.c | |||
@@ -1,4 +1,5 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
2 | |||
2 | size_t syscall_arg__scnprintf_pid(char *bf, size_t size, struct syscall_arg *arg) | 3 | size_t syscall_arg__scnprintf_pid(char *bf, size_t size, struct syscall_arg *arg) |
3 | { | 4 | { |
4 | int pid = arg->val; | 5 | int pid = arg->val; |
diff --git a/tools/perf/trace/beauty/pkey_alloc.c b/tools/perf/trace/beauty/pkey_alloc.c index 2ba784a3734a..1b8ed4cac815 100644 --- a/tools/perf/trace/beauty/pkey_alloc.c +++ b/tools/perf/trace/beauty/pkey_alloc.c | |||
@@ -1,40 +1,36 @@ | |||
1 | // SPDX-License-Identifier: LGPL-2.1 | ||
1 | /* | 2 | /* |
2 | * trace/beauty/pkey_alloc.c | 3 | * trace/beauty/pkey_alloc.c |
3 | * | 4 | * |
4 | * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | 5 | * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> |
5 | * | ||
6 | * Released under the GPL v2. (and only v2, not any later version) | ||
7 | */ | 6 | */ |
8 | 7 | ||
9 | #include "trace/beauty/beauty.h" | 8 | #include "trace/beauty/beauty.h" |
10 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
11 | #include <linux/log2.h> | 10 | #include <linux/log2.h> |
12 | 11 | ||
13 | static size_t pkey_alloc__scnprintf_access_rights(int access_rights, char *bf, size_t size) | 12 | size_t strarray__scnprintf_flags(struct strarray *sa, char *bf, size_t size, unsigned long flags) |
14 | { | 13 | { |
15 | int i, printed = 0; | 14 | int i, printed = 0; |
16 | 15 | ||
17 | #include "trace/beauty/generated/pkey_alloc_access_rights_array.c" | 16 | if (flags == 0) { |
18 | static DEFINE_STRARRAY(pkey_alloc_access_rights); | 17 | const char *s = sa->entries[0]; |
19 | |||
20 | if (access_rights == 0) { | ||
21 | const char *s = strarray__pkey_alloc_access_rights.entries[0]; | ||
22 | if (s) | 18 | if (s) |
23 | return scnprintf(bf, size, "%s", s); | 19 | return scnprintf(bf, size, "%s", s); |
24 | return scnprintf(bf, size, "%d", 0); | 20 | return scnprintf(bf, size, "%d", 0); |
25 | } | 21 | } |
26 | 22 | ||
27 | for (i = 1; i < strarray__pkey_alloc_access_rights.nr_entries; ++i) { | 23 | for (i = 1; i < sa->nr_entries; ++i) { |
28 | int bit = 1 << (i - 1); | 24 | unsigned long bit = 1UL << (i - 1); |
29 | 25 | ||
30 | if (!(access_rights & bit)) | 26 | if (!(flags & bit)) |
31 | continue; | 27 | continue; |
32 | 28 | ||
33 | if (printed != 0) | 29 | if (printed != 0) |
34 | printed += scnprintf(bf + printed, size - printed, "|"); | 30 | printed += scnprintf(bf + printed, size - printed, "|"); |
35 | 31 | ||
36 | if (strarray__pkey_alloc_access_rights.entries[i] != NULL) | 32 | if (sa->entries[i] != NULL) |
37 | printed += scnprintf(bf + printed, size - printed, "%s", strarray__pkey_alloc_access_rights.entries[i]); | 33 | printed += scnprintf(bf + printed, size - printed, "%s", sa->entries[i]); |
38 | else | 34 | else |
39 | printed += scnprintf(bf + printed, size - printed, "0x%#", bit); | 35 | printed += scnprintf(bf + printed, size - printed, "0x%#", bit); |
40 | } | 36 | } |
@@ -42,6 +38,14 @@ static size_t pkey_alloc__scnprintf_access_rights(int access_rights, char *bf, s | |||
42 | return printed; | 38 | return printed; |
43 | } | 39 | } |
44 | 40 | ||
41 | static size_t pkey_alloc__scnprintf_access_rights(int access_rights, char *bf, size_t size) | ||
42 | { | ||
43 | #include "trace/beauty/generated/pkey_alloc_access_rights_array.c" | ||
44 | static DEFINE_STRARRAY(pkey_alloc_access_rights); | ||
45 | |||
46 | return strarray__scnprintf_flags(&strarray__pkey_alloc_access_rights, bf, size, access_rights); | ||
47 | } | ||
48 | |||
45 | size_t syscall_arg__scnprintf_pkey_alloc_access_rights(char *bf, size_t size, struct syscall_arg *arg) | 49 | size_t syscall_arg__scnprintf_pkey_alloc_access_rights(char *bf, size_t size, struct syscall_arg *arg) |
46 | { | 50 | { |
47 | unsigned long cmd = arg->val; | 51 | unsigned long cmd = arg->val; |
diff --git a/tools/perf/trace/beauty/pkey_alloc_access_rights.sh b/tools/perf/trace/beauty/pkey_alloc_access_rights.sh index e0a51aeb20b2..f8f1b560cf8a 100755 --- a/tools/perf/trace/beauty/pkey_alloc_access_rights.sh +++ b/tools/perf/trace/beauty/pkey_alloc_access_rights.sh | |||
@@ -1,4 +1,5 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | # SPDX-License-Identifier: LGPL-2.1 | ||
2 | 3 | ||
3 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/asm-generic/ | 4 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/asm-generic/ |
4 | 5 | ||
diff --git a/tools/perf/trace/beauty/prctl.c b/tools/perf/trace/beauty/prctl.c index 246130dad6c4..be7a5d395975 100644 --- a/tools/perf/trace/beauty/prctl.c +++ b/tools/perf/trace/beauty/prctl.c | |||
@@ -1,9 +1,8 @@ | |||
1 | // SPDX-License-Identifier: LGPL-2.1 | ||
1 | /* | 2 | /* |
2 | * trace/beauty/prctl.c | 3 | * trace/beauty/prctl.c |
3 | * | 4 | * |
4 | * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | 5 | * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> |
5 | * | ||
6 | * Released under the GPL v2. (and only v2, not any later version) | ||
7 | */ | 6 | */ |
8 | 7 | ||
9 | #include "trace/beauty/beauty.h" | 8 | #include "trace/beauty/beauty.h" |
diff --git a/tools/perf/trace/beauty/prctl_option.sh b/tools/perf/trace/beauty/prctl_option.sh index f24722146ebe..d32f8f1124af 100755 --- a/tools/perf/trace/beauty/prctl_option.sh +++ b/tools/perf/trace/beauty/prctl_option.sh | |||
@@ -1,4 +1,5 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | # SPDX-License-Identifier: LGPL-2.1 | ||
2 | 3 | ||
3 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ | 4 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ |
4 | 5 | ||
diff --git a/tools/perf/trace/beauty/sched_policy.c b/tools/perf/trace/beauty/sched_policy.c index ba5096ae76b6..48f2b5c9aa3e 100644 --- a/tools/perf/trace/beauty/sched_policy.c +++ b/tools/perf/trace/beauty/sched_policy.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
2 | #include <sched.h> | 2 | #include <sched.h> |
3 | 3 | ||
4 | /* | 4 | /* |
diff --git a/tools/perf/trace/beauty/seccomp.c b/tools/perf/trace/beauty/seccomp.c index b7097fd5fed9..e36156b19c70 100644 --- a/tools/perf/trace/beauty/seccomp.c +++ b/tools/perf/trace/beauty/seccomp.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
2 | #ifndef SECCOMP_SET_MODE_STRICT | 2 | #ifndef SECCOMP_SET_MODE_STRICT |
3 | #define SECCOMP_SET_MODE_STRICT 0 | 3 | #define SECCOMP_SET_MODE_STRICT 0 |
4 | #endif | 4 | #endif |
diff --git a/tools/perf/trace/beauty/signum.c b/tools/perf/trace/beauty/signum.c index bde18a53f090..587fec545b8a 100644 --- a/tools/perf/trace/beauty/signum.c +++ b/tools/perf/trace/beauty/signum.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
2 | #include <signal.h> | 2 | #include <signal.h> |
3 | 3 | ||
4 | static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg) | 4 | static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg) |
diff --git a/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh b/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh index eb511bb5fbd3..e0803b957593 100755 --- a/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh +++ b/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh | |||
@@ -1,4 +1,5 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | # SPDX-License-Identifier: LGPL-2.1 | ||
2 | 3 | ||
3 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/sound/ | 4 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/sound/ |
4 | 5 | ||
diff --git a/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh b/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh index 6818392968b2..7a464a7bf913 100755 --- a/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh +++ b/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh | |||
@@ -1,4 +1,5 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | # SPDX-License-Identifier: LGPL-2.1 | ||
2 | 3 | ||
3 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/sound/ | 4 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/sound/ |
4 | 5 | ||
diff --git a/tools/perf/trace/beauty/sockaddr.c b/tools/perf/trace/beauty/sockaddr.c index 71a79f72d9d9..9410ad230f10 100644 --- a/tools/perf/trace/beauty/sockaddr.c +++ b/tools/perf/trace/beauty/sockaddr.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
2 | // Copyright (C) 2018, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | 2 | // Copyright (C) 2018, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> |
3 | 3 | ||
4 | #include "trace/beauty/beauty.h" | 4 | #include "trace/beauty/beauty.h" |
diff --git a/tools/perf/trace/beauty/socket.c b/tools/perf/trace/beauty/socket.c index 65227269384b..d971a2596417 100644 --- a/tools/perf/trace/beauty/socket.c +++ b/tools/perf/trace/beauty/socket.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
2 | /* | 2 | /* |
3 | * trace/beauty/socket.c | 3 | * trace/beauty/socket.c |
4 | * | 4 | * |
diff --git a/tools/perf/trace/beauty/socket_ipproto.sh b/tools/perf/trace/beauty/socket_ipproto.sh index a3cc24633bec..de0f2f29017f 100755 --- a/tools/perf/trace/beauty/socket_ipproto.sh +++ b/tools/perf/trace/beauty/socket_ipproto.sh | |||
@@ -1,4 +1,5 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | # SPDX-License-Identifier: LGPL-2.1 | ||
2 | 3 | ||
3 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ | 4 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ |
4 | 5 | ||
diff --git a/tools/perf/trace/beauty/socket_type.c b/tools/perf/trace/beauty/socket_type.c index bca26aef4a77..a63a9a332aa0 100644 --- a/tools/perf/trace/beauty/socket_type.c +++ b/tools/perf/trace/beauty/socket_type.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
2 | #include <sys/types.h> | 2 | #include <sys/types.h> |
3 | #include <sys/socket.h> | 3 | #include <sys/socket.h> |
4 | 4 | ||
diff --git a/tools/perf/trace/beauty/statx.c b/tools/perf/trace/beauty/statx.c index 5643b692af4c..630f2760dd66 100644 --- a/tools/perf/trace/beauty/statx.c +++ b/tools/perf/trace/beauty/statx.c | |||
@@ -1,9 +1,8 @@ | |||
1 | // SPDX-License-Identifier: LGPL-2.1 | ||
1 | /* | 2 | /* |
2 | * trace/beauty/statx.c | 3 | * trace/beauty/statx.c |
3 | * | 4 | * |
4 | * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | 5 | * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> |
5 | * | ||
6 | * Released under the GPL v2. (and only v2, not any later version) | ||
7 | */ | 6 | */ |
8 | 7 | ||
9 | #include "trace/beauty/beauty.h" | 8 | #include "trace/beauty/beauty.h" |
diff --git a/tools/perf/trace/beauty/vhost_virtio_ioctl.sh b/tools/perf/trace/beauty/vhost_virtio_ioctl.sh index 0f6a5197d0be..439773daaf77 100755 --- a/tools/perf/trace/beauty/vhost_virtio_ioctl.sh +++ b/tools/perf/trace/beauty/vhost_virtio_ioctl.sh | |||
@@ -1,4 +1,5 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | # SPDX-License-Identifier: LGPL-2.1 | ||
2 | 3 | ||
3 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ | 4 | [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ |
4 | 5 | ||
diff --git a/tools/perf/trace/beauty/waitid_options.c b/tools/perf/trace/beauty/waitid_options.c index 8465281a093d..42ff58ad613b 100644 --- a/tools/perf/trace/beauty/waitid_options.c +++ b/tools/perf/trace/beauty/waitid_options.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
2 | #include <sys/types.h> | 2 | #include <sys/types.h> |
3 | #include <sys/wait.h> | 3 | #include <sys/wait.h> |
4 | 4 | ||
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 28cd6a17491b..6936daf89ddd 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -139,6 +139,7 @@ static int arch__associate_ins_ops(struct arch* arch, const char *name, struct i | |||
139 | #include "arch/x86/annotate/instructions.c" | 139 | #include "arch/x86/annotate/instructions.c" |
140 | #include "arch/powerpc/annotate/instructions.c" | 140 | #include "arch/powerpc/annotate/instructions.c" |
141 | #include "arch/s390/annotate/instructions.c" | 141 | #include "arch/s390/annotate/instructions.c" |
142 | #include "arch/sparc/annotate/instructions.c" | ||
142 | 143 | ||
143 | static struct arch architectures[] = { | 144 | static struct arch architectures[] = { |
144 | { | 145 | { |
@@ -170,6 +171,13 @@ static struct arch architectures[] = { | |||
170 | .comment_char = '#', | 171 | .comment_char = '#', |
171 | }, | 172 | }, |
172 | }, | 173 | }, |
174 | { | ||
175 | .name = "sparc", | ||
176 | .init = sparc__annotate_init, | ||
177 | .objdump = { | ||
178 | .comment_char = '#', | ||
179 | }, | ||
180 | }, | ||
173 | }; | 181 | }; |
174 | 182 | ||
175 | static void ins__delete(struct ins_operands *ops) | 183 | static void ins__delete(struct ins_operands *ops) |
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index c4617bcfd521..72d5ba2479bf 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c | |||
@@ -962,16 +962,23 @@ s64 perf_event__process_auxtrace(struct perf_session *session, | |||
962 | #define PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ 64 | 962 | #define PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ 64 |
963 | #define PERF_ITRACE_MAX_LAST_BRANCH_SZ 1024 | 963 | #define PERF_ITRACE_MAX_LAST_BRANCH_SZ 1024 |
964 | 964 | ||
965 | void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts) | 965 | void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts, |
966 | bool no_sample) | ||
966 | { | 967 | { |
967 | synth_opts->instructions = true; | ||
968 | synth_opts->branches = true; | 968 | synth_opts->branches = true; |
969 | synth_opts->transactions = true; | 969 | synth_opts->transactions = true; |
970 | synth_opts->ptwrites = true; | 970 | synth_opts->ptwrites = true; |
971 | synth_opts->pwr_events = true; | 971 | synth_opts->pwr_events = true; |
972 | synth_opts->errors = true; | 972 | synth_opts->errors = true; |
973 | synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; | 973 | if (no_sample) { |
974 | synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; | 974 | synth_opts->period_type = PERF_ITRACE_PERIOD_INSTRUCTIONS; |
975 | synth_opts->period = 1; | ||
976 | synth_opts->calls = true; | ||
977 | } else { | ||
978 | synth_opts->instructions = true; | ||
979 | synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; | ||
980 | synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; | ||
981 | } | ||
975 | synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; | 982 | synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; |
976 | synth_opts->last_branch_sz = PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; | 983 | synth_opts->last_branch_sz = PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; |
977 | synth_opts->initial_skip = 0; | 984 | synth_opts->initial_skip = 0; |
@@ -999,7 +1006,7 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str, | |||
999 | } | 1006 | } |
1000 | 1007 | ||
1001 | if (!str) { | 1008 | if (!str) { |
1002 | itrace_synth_opts__set_default(synth_opts); | 1009 | itrace_synth_opts__set_default(synth_opts, false); |
1003 | return 0; | 1010 | return 0; |
1004 | } | 1011 | } |
1005 | 1012 | ||
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index d88f6e9eb461..8e50f96d4b23 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h | |||
@@ -58,6 +58,7 @@ enum itrace_period_type { | |||
58 | /** | 58 | /** |
59 | * struct itrace_synth_opts - AUX area tracing synthesis options. | 59 | * struct itrace_synth_opts - AUX area tracing synthesis options. |
60 | * @set: indicates whether or not options have been set | 60 | * @set: indicates whether or not options have been set |
61 | * @default_no_sample: Default to no sampling. | ||
61 | * @inject: indicates the event (not just the sample) must be fully synthesized | 62 | * @inject: indicates the event (not just the sample) must be fully synthesized |
62 | * because 'perf inject' will write it out | 63 | * because 'perf inject' will write it out |
63 | * @instructions: whether to synthesize 'instructions' events | 64 | * @instructions: whether to synthesize 'instructions' events |
@@ -82,6 +83,7 @@ enum itrace_period_type { | |||
82 | */ | 83 | */ |
83 | struct itrace_synth_opts { | 84 | struct itrace_synth_opts { |
84 | bool set; | 85 | bool set; |
86 | bool default_no_sample; | ||
85 | bool inject; | 87 | bool inject; |
86 | bool instructions; | 88 | bool instructions; |
87 | bool branches; | 89 | bool branches; |
@@ -528,7 +530,8 @@ int perf_event__process_auxtrace_error(struct perf_session *session, | |||
528 | union perf_event *event); | 530 | union perf_event *event); |
529 | int itrace_parse_synth_opts(const struct option *opt, const char *str, | 531 | int itrace_parse_synth_opts(const struct option *opt, const char *str, |
530 | int unset); | 532 | int unset); |
531 | void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts); | 533 | void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts, |
534 | bool no_sample); | ||
532 | 535 | ||
533 | size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp); | 536 | size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp); |
534 | void perf_session__auxtrace_error_inc(struct perf_session *session, | 537 | void perf_session__auxtrace_error_inc(struct perf_session *session, |
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 2ae640257fdb..73430b73570d 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c | |||
@@ -244,6 +244,27 @@ static void cs_etm__free(struct perf_session *session) | |||
244 | zfree(&aux); | 244 | zfree(&aux); |
245 | } | 245 | } |
246 | 246 | ||
247 | static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address) | ||
248 | { | ||
249 | struct machine *machine; | ||
250 | |||
251 | machine = etmq->etm->machine; | ||
252 | |||
253 | if (address >= etmq->etm->kernel_start) { | ||
254 | if (machine__is_host(machine)) | ||
255 | return PERF_RECORD_MISC_KERNEL; | ||
256 | else | ||
257 | return PERF_RECORD_MISC_GUEST_KERNEL; | ||
258 | } else { | ||
259 | if (machine__is_host(machine)) | ||
260 | return PERF_RECORD_MISC_USER; | ||
261 | else if (perf_guest) | ||
262 | return PERF_RECORD_MISC_GUEST_USER; | ||
263 | else | ||
264 | return PERF_RECORD_MISC_HYPERVISOR; | ||
265 | } | ||
266 | } | ||
267 | |||
247 | static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u64 address, | 268 | static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u64 address, |
248 | size_t size, u8 *buffer) | 269 | size_t size, u8 *buffer) |
249 | { | 270 | { |
@@ -258,10 +279,7 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u64 address, | |||
258 | return -1; | 279 | return -1; |
259 | 280 | ||
260 | machine = etmq->etm->machine; | 281 | machine = etmq->etm->machine; |
261 | if (address >= etmq->etm->kernel_start) | 282 | cpumode = cs_etm__cpu_mode(etmq, address); |
262 | cpumode = PERF_RECORD_MISC_KERNEL; | ||
263 | else | ||
264 | cpumode = PERF_RECORD_MISC_USER; | ||
265 | 283 | ||
266 | thread = etmq->thread; | 284 | thread = etmq->thread; |
267 | if (!thread) { | 285 | if (!thread) { |
@@ -653,7 +671,7 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq, | |||
653 | struct perf_sample sample = {.ip = 0,}; | 671 | struct perf_sample sample = {.ip = 0,}; |
654 | 672 | ||
655 | event->sample.header.type = PERF_RECORD_SAMPLE; | 673 | event->sample.header.type = PERF_RECORD_SAMPLE; |
656 | event->sample.header.misc = PERF_RECORD_MISC_USER; | 674 | event->sample.header.misc = cs_etm__cpu_mode(etmq, addr); |
657 | event->sample.header.size = sizeof(struct perf_event_header); | 675 | event->sample.header.size = sizeof(struct perf_event_header); |
658 | 676 | ||
659 | sample.ip = addr; | 677 | sample.ip = addr; |
@@ -665,7 +683,7 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq, | |||
665 | sample.cpu = etmq->packet->cpu; | 683 | sample.cpu = etmq->packet->cpu; |
666 | sample.flags = 0; | 684 | sample.flags = 0; |
667 | sample.insn_len = 1; | 685 | sample.insn_len = 1; |
668 | sample.cpumode = event->header.misc; | 686 | sample.cpumode = event->sample.header.misc; |
669 | 687 | ||
670 | if (etm->synth_opts.last_branch) { | 688 | if (etm->synth_opts.last_branch) { |
671 | cs_etm__copy_last_branch_rb(etmq); | 689 | cs_etm__copy_last_branch_rb(etmq); |
@@ -706,12 +724,15 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq) | |||
706 | u64 nr; | 724 | u64 nr; |
707 | struct branch_entry entries; | 725 | struct branch_entry entries; |
708 | } dummy_bs; | 726 | } dummy_bs; |
727 | u64 ip; | ||
728 | |||
729 | ip = cs_etm__last_executed_instr(etmq->prev_packet); | ||
709 | 730 | ||
710 | event->sample.header.type = PERF_RECORD_SAMPLE; | 731 | event->sample.header.type = PERF_RECORD_SAMPLE; |
711 | event->sample.header.misc = PERF_RECORD_MISC_USER; | 732 | event->sample.header.misc = cs_etm__cpu_mode(etmq, ip); |
712 | event->sample.header.size = sizeof(struct perf_event_header); | 733 | event->sample.header.size = sizeof(struct perf_event_header); |
713 | 734 | ||
714 | sample.ip = cs_etm__last_executed_instr(etmq->prev_packet); | 735 | sample.ip = ip; |
715 | sample.pid = etmq->pid; | 736 | sample.pid = etmq->pid; |
716 | sample.tid = etmq->tid; | 737 | sample.tid = etmq->tid; |
717 | sample.addr = cs_etm__first_executed_instr(etmq->packet); | 738 | sample.addr = cs_etm__first_executed_instr(etmq->packet); |
@@ -720,7 +741,7 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq) | |||
720 | sample.period = 1; | 741 | sample.period = 1; |
721 | sample.cpu = etmq->packet->cpu; | 742 | sample.cpu = etmq->packet->cpu; |
722 | sample.flags = 0; | 743 | sample.flags = 0; |
723 | sample.cpumode = PERF_RECORD_MISC_USER; | 744 | sample.cpumode = event->sample.header.misc; |
724 | 745 | ||
725 | /* | 746 | /* |
726 | * perf report cannot handle events without a branch stack | 747 | * perf report cannot handle events without a branch stack |
@@ -1432,7 +1453,8 @@ int cs_etm__process_auxtrace_info(union perf_event *event, | |||
1432 | if (session->itrace_synth_opts && session->itrace_synth_opts->set) { | 1453 | if (session->itrace_synth_opts && session->itrace_synth_opts->set) { |
1433 | etm->synth_opts = *session->itrace_synth_opts; | 1454 | etm->synth_opts = *session->itrace_synth_opts; |
1434 | } else { | 1455 | } else { |
1435 | itrace_synth_opts__set_default(&etm->synth_opts); | 1456 | itrace_synth_opts__set_default(&etm->synth_opts, |
1457 | session->itrace_synth_opts->default_no_sample); | ||
1436 | etm->synth_opts.callchain = false; | 1458 | etm->synth_opts.callchain = false; |
1437 | } | 1459 | } |
1438 | 1460 | ||
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index 1f3ccc368530..d01b8355f4ca 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h | |||
@@ -63,6 +63,7 @@ struct perf_env { | |||
63 | struct numa_node *numa_nodes; | 63 | struct numa_node *numa_nodes; |
64 | struct memory_node *memory_nodes; | 64 | struct memory_node *memory_nodes; |
65 | unsigned long long memory_bsize; | 65 | unsigned long long memory_bsize; |
66 | u64 clockid_res_ns; | ||
66 | }; | 67 | }; |
67 | 68 | ||
68 | extern struct perf_env perf_env; | 69 | extern struct perf_env perf_env; |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index bc646185f8d9..e9c108a6b1c3 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -308,6 +308,7 @@ static int perf_event__synthesize_fork(struct perf_tool *tool, | |||
308 | event->fork.pid = tgid; | 308 | event->fork.pid = tgid; |
309 | event->fork.tid = pid; | 309 | event->fork.tid = pid; |
310 | event->fork.header.type = PERF_RECORD_FORK; | 310 | event->fork.header.type = PERF_RECORD_FORK; |
311 | event->fork.header.misc = PERF_RECORD_MISC_FORK_EXEC; | ||
311 | 312 | ||
312 | event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size); | 313 | event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size); |
313 | 314 | ||
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index be440df29615..e88e6f9b1463 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -358,7 +358,7 @@ void perf_evlist__disable(struct perf_evlist *evlist) | |||
358 | struct perf_evsel *pos; | 358 | struct perf_evsel *pos; |
359 | 359 | ||
360 | evlist__for_each_entry(evlist, pos) { | 360 | evlist__for_each_entry(evlist, pos) { |
361 | if (!perf_evsel__is_group_leader(pos) || !pos->fd) | 361 | if (pos->disabled || !perf_evsel__is_group_leader(pos) || !pos->fd) |
362 | continue; | 362 | continue; |
363 | perf_evsel__disable(pos); | 363 | perf_evsel__disable(pos); |
364 | } | 364 | } |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 29d7b97f66fb..6d187059a373 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -232,6 +232,7 @@ void perf_evsel__init(struct perf_evsel *evsel, | |||
232 | evsel->leader = evsel; | 232 | evsel->leader = evsel; |
233 | evsel->unit = ""; | 233 | evsel->unit = ""; |
234 | evsel->scale = 1.0; | 234 | evsel->scale = 1.0; |
235 | evsel->max_events = ULONG_MAX; | ||
235 | evsel->evlist = NULL; | 236 | evsel->evlist = NULL; |
236 | evsel->bpf_fd = -1; | 237 | evsel->bpf_fd = -1; |
237 | INIT_LIST_HEAD(&evsel->node); | 238 | INIT_LIST_HEAD(&evsel->node); |
@@ -793,6 +794,9 @@ static void apply_config_terms(struct perf_evsel *evsel, | |||
793 | case PERF_EVSEL__CONFIG_TERM_MAX_STACK: | 794 | case PERF_EVSEL__CONFIG_TERM_MAX_STACK: |
794 | max_stack = term->val.max_stack; | 795 | max_stack = term->val.max_stack; |
795 | break; | 796 | break; |
797 | case PERF_EVSEL__CONFIG_TERM_MAX_EVENTS: | ||
798 | evsel->max_events = term->val.max_events; | ||
799 | break; | ||
796 | case PERF_EVSEL__CONFIG_TERM_INHERIT: | 800 | case PERF_EVSEL__CONFIG_TERM_INHERIT: |
797 | /* | 801 | /* |
798 | * attr->inherit should has already been set by | 802 | * attr->inherit should has already been set by |
@@ -1203,16 +1207,27 @@ int perf_evsel__append_addr_filter(struct perf_evsel *evsel, const char *filter) | |||
1203 | 1207 | ||
1204 | int perf_evsel__enable(struct perf_evsel *evsel) | 1208 | int perf_evsel__enable(struct perf_evsel *evsel) |
1205 | { | 1209 | { |
1206 | return perf_evsel__run_ioctl(evsel, | 1210 | int err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, 0); |
1207 | PERF_EVENT_IOC_ENABLE, | 1211 | |
1208 | 0); | 1212 | if (!err) |
1213 | evsel->disabled = false; | ||
1214 | |||
1215 | return err; | ||
1209 | } | 1216 | } |
1210 | 1217 | ||
1211 | int perf_evsel__disable(struct perf_evsel *evsel) | 1218 | int perf_evsel__disable(struct perf_evsel *evsel) |
1212 | { | 1219 | { |
1213 | return perf_evsel__run_ioctl(evsel, | 1220 | int err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, 0); |
1214 | PERF_EVENT_IOC_DISABLE, | 1221 | /* |
1215 | 0); | 1222 | * We mark it disabled here so that tools that disable a event can |
1223 | * ignore events after they disable it. I.e. the ring buffer may have | ||
1224 | * already a few more events queued up before the kernel got the stop | ||
1225 | * request. | ||
1226 | */ | ||
1227 | if (!err) | ||
1228 | evsel->disabled = true; | ||
1229 | |||
1230 | return err; | ||
1216 | } | 1231 | } |
1217 | 1232 | ||
1218 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) | 1233 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 4107c39f4a54..3147ca76c6fc 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -46,6 +46,7 @@ enum term_type { | |||
46 | PERF_EVSEL__CONFIG_TERM_STACK_USER, | 46 | PERF_EVSEL__CONFIG_TERM_STACK_USER, |
47 | PERF_EVSEL__CONFIG_TERM_INHERIT, | 47 | PERF_EVSEL__CONFIG_TERM_INHERIT, |
48 | PERF_EVSEL__CONFIG_TERM_MAX_STACK, | 48 | PERF_EVSEL__CONFIG_TERM_MAX_STACK, |
49 | PERF_EVSEL__CONFIG_TERM_MAX_EVENTS, | ||
49 | PERF_EVSEL__CONFIG_TERM_OVERWRITE, | 50 | PERF_EVSEL__CONFIG_TERM_OVERWRITE, |
50 | PERF_EVSEL__CONFIG_TERM_DRV_CFG, | 51 | PERF_EVSEL__CONFIG_TERM_DRV_CFG, |
51 | PERF_EVSEL__CONFIG_TERM_BRANCH, | 52 | PERF_EVSEL__CONFIG_TERM_BRANCH, |
@@ -65,6 +66,7 @@ struct perf_evsel_config_term { | |||
65 | bool inherit; | 66 | bool inherit; |
66 | bool overwrite; | 67 | bool overwrite; |
67 | char *branch; | 68 | char *branch; |
69 | unsigned long max_events; | ||
68 | } val; | 70 | } val; |
69 | bool weak; | 71 | bool weak; |
70 | }; | 72 | }; |
@@ -99,6 +101,8 @@ struct perf_evsel { | |||
99 | struct perf_counts *prev_raw_counts; | 101 | struct perf_counts *prev_raw_counts; |
100 | int idx; | 102 | int idx; |
101 | u32 ids; | 103 | u32 ids; |
104 | unsigned long max_events; | ||
105 | unsigned long nr_events_printed; | ||
102 | char *name; | 106 | char *name; |
103 | double scale; | 107 | double scale; |
104 | const char *unit; | 108 | const char *unit; |
@@ -119,6 +123,7 @@ struct perf_evsel { | |||
119 | bool snapshot; | 123 | bool snapshot; |
120 | bool supported; | 124 | bool supported; |
121 | bool needs_swap; | 125 | bool needs_swap; |
126 | bool disabled; | ||
122 | bool no_aux_samples; | 127 | bool no_aux_samples; |
123 | bool immediate; | 128 | bool immediate; |
124 | bool system_wide; | 129 | bool system_wide; |
diff --git a/tools/perf/util/genelf.h b/tools/perf/util/genelf.h index de322d51c7fe..b72440bf9a79 100644 --- a/tools/perf/util/genelf.h +++ b/tools/perf/util/genelf.h | |||
@@ -29,6 +29,12 @@ int jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_ent | |||
29 | #elif defined(__powerpc__) | 29 | #elif defined(__powerpc__) |
30 | #define GEN_ELF_ARCH EM_PPC | 30 | #define GEN_ELF_ARCH EM_PPC |
31 | #define GEN_ELF_CLASS ELFCLASS32 | 31 | #define GEN_ELF_CLASS ELFCLASS32 |
32 | #elif defined(__sparc__) && defined(__arch64__) | ||
33 | #define GEN_ELF_ARCH EM_SPARCV9 | ||
34 | #define GEN_ELF_CLASS ELFCLASS64 | ||
35 | #elif defined(__sparc__) | ||
36 | #define GEN_ELF_ARCH EM_SPARC | ||
37 | #define GEN_ELF_CLASS ELFCLASS32 | ||
32 | #else | 38 | #else |
33 | #error "unsupported architecture" | 39 | #error "unsupported architecture" |
34 | #endif | 40 | #endif |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 1ec1d9bc2d63..4fd45be95a43 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -1034,6 +1034,13 @@ static int write_auxtrace(struct feat_fd *ff, | |||
1034 | return err; | 1034 | return err; |
1035 | } | 1035 | } |
1036 | 1036 | ||
1037 | static int write_clockid(struct feat_fd *ff, | ||
1038 | struct perf_evlist *evlist __maybe_unused) | ||
1039 | { | ||
1040 | return do_write(ff, &ff->ph->env.clockid_res_ns, | ||
1041 | sizeof(ff->ph->env.clockid_res_ns)); | ||
1042 | } | ||
1043 | |||
1037 | static int cpu_cache_level__sort(const void *a, const void *b) | 1044 | static int cpu_cache_level__sort(const void *a, const void *b) |
1038 | { | 1045 | { |
1039 | struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a; | 1046 | struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a; |
@@ -1508,6 +1515,12 @@ static void print_cpu_topology(struct feat_fd *ff, FILE *fp) | |||
1508 | fprintf(fp, "# Core ID and Socket ID information is not available\n"); | 1515 | fprintf(fp, "# Core ID and Socket ID information is not available\n"); |
1509 | } | 1516 | } |
1510 | 1517 | ||
1518 | static void print_clockid(struct feat_fd *ff, FILE *fp) | ||
1519 | { | ||
1520 | fprintf(fp, "# clockid frequency: %"PRIu64" MHz\n", | ||
1521 | ff->ph->env.clockid_res_ns * 1000); | ||
1522 | } | ||
1523 | |||
1511 | static void free_event_desc(struct perf_evsel *events) | 1524 | static void free_event_desc(struct perf_evsel *events) |
1512 | { | 1525 | { |
1513 | struct perf_evsel *evsel; | 1526 | struct perf_evsel *evsel; |
@@ -2531,6 +2544,15 @@ out: | |||
2531 | return ret; | 2544 | return ret; |
2532 | } | 2545 | } |
2533 | 2546 | ||
2547 | static int process_clockid(struct feat_fd *ff, | ||
2548 | void *data __maybe_unused) | ||
2549 | { | ||
2550 | if (do_read_u64(ff, &ff->ph->env.clockid_res_ns)) | ||
2551 | return -1; | ||
2552 | |||
2553 | return 0; | ||
2554 | } | ||
2555 | |||
2534 | struct feature_ops { | 2556 | struct feature_ops { |
2535 | int (*write)(struct feat_fd *ff, struct perf_evlist *evlist); | 2557 | int (*write)(struct feat_fd *ff, struct perf_evlist *evlist); |
2536 | void (*print)(struct feat_fd *ff, FILE *fp); | 2558 | void (*print)(struct feat_fd *ff, FILE *fp); |
@@ -2590,6 +2612,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { | |||
2590 | FEAT_OPN(CACHE, cache, true), | 2612 | FEAT_OPN(CACHE, cache, true), |
2591 | FEAT_OPR(SAMPLE_TIME, sample_time, false), | 2613 | FEAT_OPR(SAMPLE_TIME, sample_time, false), |
2592 | FEAT_OPR(MEM_TOPOLOGY, mem_topology, true), | 2614 | FEAT_OPR(MEM_TOPOLOGY, mem_topology, true), |
2615 | FEAT_OPR(CLOCKID, clockid, false) | ||
2593 | }; | 2616 | }; |
2594 | 2617 | ||
2595 | struct header_print_data { | 2618 | struct header_print_data { |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index e17903caa71d..0d553ddca0a3 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -38,6 +38,7 @@ enum { | |||
38 | HEADER_CACHE, | 38 | HEADER_CACHE, |
39 | HEADER_SAMPLE_TIME, | 39 | HEADER_SAMPLE_TIME, |
40 | HEADER_MEM_TOPOLOGY, | 40 | HEADER_MEM_TOPOLOGY, |
41 | HEADER_CLOCKID, | ||
41 | HEADER_LAST_FEATURE, | 42 | HEADER_LAST_FEATURE, |
42 | HEADER_FEAT_BITS = 256, | 43 | HEADER_FEAT_BITS = 256, |
43 | }; | 44 | }; |
diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c index 7f0c83b6332b..7b27d77306c2 100644 --- a/tools/perf/util/intel-bts.c +++ b/tools/perf/util/intel-bts.c | |||
@@ -269,6 +269,13 @@ static int intel_bts_do_fix_overlap(struct auxtrace_queue *queue, | |||
269 | return 0; | 269 | return 0; |
270 | } | 270 | } |
271 | 271 | ||
272 | static inline u8 intel_bts_cpumode(struct intel_bts *bts, uint64_t ip) | ||
273 | { | ||
274 | return machine__kernel_ip(bts->machine, ip) ? | ||
275 | PERF_RECORD_MISC_KERNEL : | ||
276 | PERF_RECORD_MISC_USER; | ||
277 | } | ||
278 | |||
272 | static int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq, | 279 | static int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq, |
273 | struct branch *branch) | 280 | struct branch *branch) |
274 | { | 281 | { |
@@ -281,12 +288,8 @@ static int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq, | |||
281 | bts->num_events++ <= bts->synth_opts.initial_skip) | 288 | bts->num_events++ <= bts->synth_opts.initial_skip) |
282 | return 0; | 289 | return 0; |
283 | 290 | ||
284 | event.sample.header.type = PERF_RECORD_SAMPLE; | ||
285 | event.sample.header.misc = PERF_RECORD_MISC_USER; | ||
286 | event.sample.header.size = sizeof(struct perf_event_header); | ||
287 | |||
288 | sample.cpumode = PERF_RECORD_MISC_USER; | ||
289 | sample.ip = le64_to_cpu(branch->from); | 291 | sample.ip = le64_to_cpu(branch->from); |
292 | sample.cpumode = intel_bts_cpumode(bts, sample.ip); | ||
290 | sample.pid = btsq->pid; | 293 | sample.pid = btsq->pid; |
291 | sample.tid = btsq->tid; | 294 | sample.tid = btsq->tid; |
292 | sample.addr = le64_to_cpu(branch->to); | 295 | sample.addr = le64_to_cpu(branch->to); |
@@ -298,6 +301,10 @@ static int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq, | |||
298 | sample.insn_len = btsq->intel_pt_insn.length; | 301 | sample.insn_len = btsq->intel_pt_insn.length; |
299 | memcpy(sample.insn, btsq->intel_pt_insn.buf, INTEL_PT_INSN_BUF_SZ); | 302 | memcpy(sample.insn, btsq->intel_pt_insn.buf, INTEL_PT_INSN_BUF_SZ); |
300 | 303 | ||
304 | event.sample.header.type = PERF_RECORD_SAMPLE; | ||
305 | event.sample.header.misc = sample.cpumode; | ||
306 | event.sample.header.size = sizeof(struct perf_event_header); | ||
307 | |||
301 | if (bts->synth_opts.inject) { | 308 | if (bts->synth_opts.inject) { |
302 | event.sample.header.size = bts->branches_event_size; | 309 | event.sample.header.size = bts->branches_event_size; |
303 | ret = perf_event__synthesize_sample(&event, | 310 | ret = perf_event__synthesize_sample(&event, |
@@ -910,7 +917,8 @@ int intel_bts_process_auxtrace_info(union perf_event *event, | |||
910 | if (session->itrace_synth_opts && session->itrace_synth_opts->set) { | 917 | if (session->itrace_synth_opts && session->itrace_synth_opts->set) { |
911 | bts->synth_opts = *session->itrace_synth_opts; | 918 | bts->synth_opts = *session->itrace_synth_opts; |
912 | } else { | 919 | } else { |
913 | itrace_synth_opts__set_default(&bts->synth_opts); | 920 | itrace_synth_opts__set_default(&bts->synth_opts, |
921 | session->itrace_synth_opts->default_no_sample); | ||
914 | if (session->itrace_synth_opts) | 922 | if (session->itrace_synth_opts) |
915 | bts->synth_opts.thread_stack = | 923 | bts->synth_opts.thread_stack = |
916 | session->itrace_synth_opts->thread_stack; | 924 | session->itrace_synth_opts->thread_stack; |
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 48c1d415c6b0..86cc9a64e982 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c | |||
@@ -407,6 +407,13 @@ intel_pt_cache_lookup(struct dso *dso, struct machine *machine, u64 offset) | |||
407 | return auxtrace_cache__lookup(dso->auxtrace_cache, offset); | 407 | return auxtrace_cache__lookup(dso->auxtrace_cache, offset); |
408 | } | 408 | } |
409 | 409 | ||
410 | static inline u8 intel_pt_cpumode(struct intel_pt *pt, uint64_t ip) | ||
411 | { | ||
412 | return ip >= pt->kernel_start ? | ||
413 | PERF_RECORD_MISC_KERNEL : | ||
414 | PERF_RECORD_MISC_USER; | ||
415 | } | ||
416 | |||
410 | static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, | 417 | static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, |
411 | uint64_t *insn_cnt_ptr, uint64_t *ip, | 418 | uint64_t *insn_cnt_ptr, uint64_t *ip, |
412 | uint64_t to_ip, uint64_t max_insn_cnt, | 419 | uint64_t to_ip, uint64_t max_insn_cnt, |
@@ -429,10 +436,7 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, | |||
429 | if (to_ip && *ip == to_ip) | 436 | if (to_ip && *ip == to_ip) |
430 | goto out_no_cache; | 437 | goto out_no_cache; |
431 | 438 | ||
432 | if (*ip >= ptq->pt->kernel_start) | 439 | cpumode = intel_pt_cpumode(ptq->pt, *ip); |
433 | cpumode = PERF_RECORD_MISC_KERNEL; | ||
434 | else | ||
435 | cpumode = PERF_RECORD_MISC_USER; | ||
436 | 440 | ||
437 | thread = ptq->thread; | 441 | thread = ptq->thread; |
438 | if (!thread) { | 442 | if (!thread) { |
@@ -759,7 +763,8 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, | |||
759 | if (pt->synth_opts.callchain) { | 763 | if (pt->synth_opts.callchain) { |
760 | size_t sz = sizeof(struct ip_callchain); | 764 | size_t sz = sizeof(struct ip_callchain); |
761 | 765 | ||
762 | sz += pt->synth_opts.callchain_sz * sizeof(u64); | 766 | /* Add 1 to callchain_sz for callchain context */ |
767 | sz += (pt->synth_opts.callchain_sz + 1) * sizeof(u64); | ||
763 | ptq->chain = zalloc(sz); | 768 | ptq->chain = zalloc(sz); |
764 | if (!ptq->chain) | 769 | if (!ptq->chain) |
765 | goto out_free; | 770 | goto out_free; |
@@ -1058,15 +1063,11 @@ static void intel_pt_prep_b_sample(struct intel_pt *pt, | |||
1058 | union perf_event *event, | 1063 | union perf_event *event, |
1059 | struct perf_sample *sample) | 1064 | struct perf_sample *sample) |
1060 | { | 1065 | { |
1061 | event->sample.header.type = PERF_RECORD_SAMPLE; | ||
1062 | event->sample.header.misc = PERF_RECORD_MISC_USER; | ||
1063 | event->sample.header.size = sizeof(struct perf_event_header); | ||
1064 | |||
1065 | if (!pt->timeless_decoding) | 1066 | if (!pt->timeless_decoding) |
1066 | sample->time = tsc_to_perf_time(ptq->timestamp, &pt->tc); | 1067 | sample->time = tsc_to_perf_time(ptq->timestamp, &pt->tc); |
1067 | 1068 | ||
1068 | sample->cpumode = PERF_RECORD_MISC_USER; | ||
1069 | sample->ip = ptq->state->from_ip; | 1069 | sample->ip = ptq->state->from_ip; |
1070 | sample->cpumode = intel_pt_cpumode(pt, sample->ip); | ||
1070 | sample->pid = ptq->pid; | 1071 | sample->pid = ptq->pid; |
1071 | sample->tid = ptq->tid; | 1072 | sample->tid = ptq->tid; |
1072 | sample->addr = ptq->state->to_ip; | 1073 | sample->addr = ptq->state->to_ip; |
@@ -1075,6 +1076,10 @@ static void intel_pt_prep_b_sample(struct intel_pt *pt, | |||
1075 | sample->flags = ptq->flags; | 1076 | sample->flags = ptq->flags; |
1076 | sample->insn_len = ptq->insn_len; | 1077 | sample->insn_len = ptq->insn_len; |
1077 | memcpy(sample->insn, ptq->insn, INTEL_PT_INSN_BUF_SZ); | 1078 | memcpy(sample->insn, ptq->insn, INTEL_PT_INSN_BUF_SZ); |
1079 | |||
1080 | event->sample.header.type = PERF_RECORD_SAMPLE; | ||
1081 | event->sample.header.misc = sample->cpumode; | ||
1082 | event->sample.header.size = sizeof(struct perf_event_header); | ||
1078 | } | 1083 | } |
1079 | 1084 | ||
1080 | static int intel_pt_inject_event(union perf_event *event, | 1085 | static int intel_pt_inject_event(union perf_event *event, |
@@ -1160,7 +1165,8 @@ static void intel_pt_prep_sample(struct intel_pt *pt, | |||
1160 | 1165 | ||
1161 | if (pt->synth_opts.callchain) { | 1166 | if (pt->synth_opts.callchain) { |
1162 | thread_stack__sample(ptq->thread, ptq->chain, | 1167 | thread_stack__sample(ptq->thread, ptq->chain, |
1163 | pt->synth_opts.callchain_sz, sample->ip); | 1168 | pt->synth_opts.callchain_sz + 1, |
1169 | sample->ip, pt->kernel_start); | ||
1164 | sample->callchain = ptq->chain; | 1170 | sample->callchain = ptq->chain; |
1165 | } | 1171 | } |
1166 | 1172 | ||
@@ -2559,7 +2565,8 @@ int intel_pt_process_auxtrace_info(union perf_event *event, | |||
2559 | if (session->itrace_synth_opts && session->itrace_synth_opts->set) { | 2565 | if (session->itrace_synth_opts && session->itrace_synth_opts->set) { |
2560 | pt->synth_opts = *session->itrace_synth_opts; | 2566 | pt->synth_opts = *session->itrace_synth_opts; |
2561 | } else { | 2567 | } else { |
2562 | itrace_synth_opts__set_default(&pt->synth_opts); | 2568 | itrace_synth_opts__set_default(&pt->synth_opts, |
2569 | session->itrace_synth_opts->default_no_sample); | ||
2563 | if (use_browser != -1) { | 2570 | if (use_browser != -1) { |
2564 | pt->synth_opts.branches = false; | 2571 | pt->synth_opts.branches = false; |
2565 | pt->synth_opts.callchain = true; | 2572 | pt->synth_opts.callchain = true; |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 111ae858cbcb..8f36ce813bc5 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -1708,6 +1708,7 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event | |||
1708 | struct thread *parent = machine__findnew_thread(machine, | 1708 | struct thread *parent = machine__findnew_thread(machine, |
1709 | event->fork.ppid, | 1709 | event->fork.ppid, |
1710 | event->fork.ptid); | 1710 | event->fork.ptid); |
1711 | bool do_maps_clone = true; | ||
1711 | int err = 0; | 1712 | int err = 0; |
1712 | 1713 | ||
1713 | if (dump_trace) | 1714 | if (dump_trace) |
@@ -1736,9 +1737,25 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event | |||
1736 | 1737 | ||
1737 | thread = machine__findnew_thread(machine, event->fork.pid, | 1738 | thread = machine__findnew_thread(machine, event->fork.pid, |
1738 | event->fork.tid); | 1739 | event->fork.tid); |
1740 | /* | ||
1741 | * When synthesizing FORK events, we are trying to create thread | ||
1742 | * objects for the already running tasks on the machine. | ||
1743 | * | ||
1744 | * Normally, for a kernel FORK event, we want to clone the parent's | ||
1745 | * maps because that is what the kernel just did. | ||
1746 | * | ||
1747 | * But when synthesizing, this should not be done. If we do, we end up | ||
1748 | * with overlapping maps as we process the sythesized MMAP2 events that | ||
1749 | * get delivered shortly thereafter. | ||
1750 | * | ||
1751 | * Use the FORK event misc flags in an internal way to signal this | ||
1752 | * situation, so we can elide the map clone when appropriate. | ||
1753 | */ | ||
1754 | if (event->fork.header.misc & PERF_RECORD_MISC_FORK_EXEC) | ||
1755 | do_maps_clone = false; | ||
1739 | 1756 | ||
1740 | if (thread == NULL || parent == NULL || | 1757 | if (thread == NULL || parent == NULL || |
1741 | thread__fork(thread, parent, sample->time) < 0) { | 1758 | thread__fork(thread, parent, sample->time, do_maps_clone) < 0) { |
1742 | dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); | 1759 | dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); |
1743 | err = -1; | 1760 | err = -1; |
1744 | } | 1761 | } |
@@ -2140,6 +2157,27 @@ static int resolve_lbr_callchain_sample(struct thread *thread, | |||
2140 | return 0; | 2157 | return 0; |
2141 | } | 2158 | } |
2142 | 2159 | ||
2160 | static int find_prev_cpumode(struct ip_callchain *chain, struct thread *thread, | ||
2161 | struct callchain_cursor *cursor, | ||
2162 | struct symbol **parent, | ||
2163 | struct addr_location *root_al, | ||
2164 | u8 *cpumode, int ent) | ||
2165 | { | ||
2166 | int err = 0; | ||
2167 | |||
2168 | while (--ent >= 0) { | ||
2169 | u64 ip = chain->ips[ent]; | ||
2170 | |||
2171 | if (ip >= PERF_CONTEXT_MAX) { | ||
2172 | err = add_callchain_ip(thread, cursor, parent, | ||
2173 | root_al, cpumode, ip, | ||
2174 | false, NULL, NULL, 0); | ||
2175 | break; | ||
2176 | } | ||
2177 | } | ||
2178 | return err; | ||
2179 | } | ||
2180 | |||
2143 | static int thread__resolve_callchain_sample(struct thread *thread, | 2181 | static int thread__resolve_callchain_sample(struct thread *thread, |
2144 | struct callchain_cursor *cursor, | 2182 | struct callchain_cursor *cursor, |
2145 | struct perf_evsel *evsel, | 2183 | struct perf_evsel *evsel, |
@@ -2246,6 +2284,12 @@ static int thread__resolve_callchain_sample(struct thread *thread, | |||
2246 | } | 2284 | } |
2247 | 2285 | ||
2248 | check_calls: | 2286 | check_calls: |
2287 | if (callchain_param.order != ORDER_CALLEE) { | ||
2288 | err = find_prev_cpumode(chain, thread, cursor, parent, root_al, | ||
2289 | &cpumode, chain->nr - first_call); | ||
2290 | if (err) | ||
2291 | return (err < 0) ? err : 0; | ||
2292 | } | ||
2249 | for (i = first_call, nr_entries = 0; | 2293 | for (i = first_call, nr_entries = 0; |
2250 | i < chain_nr && nr_entries < max_stack; i++) { | 2294 | i < chain_nr && nr_entries < max_stack; i++) { |
2251 | u64 ip; | 2295 | u64 ip; |
@@ -2260,9 +2304,15 @@ check_calls: | |||
2260 | continue; | 2304 | continue; |
2261 | #endif | 2305 | #endif |
2262 | ip = chain->ips[j]; | 2306 | ip = chain->ips[j]; |
2263 | |||
2264 | if (ip < PERF_CONTEXT_MAX) | 2307 | if (ip < PERF_CONTEXT_MAX) |
2265 | ++nr_entries; | 2308 | ++nr_entries; |
2309 | else if (callchain_param.order != ORDER_CALLEE) { | ||
2310 | err = find_prev_cpumode(chain, thread, cursor, parent, | ||
2311 | root_al, &cpumode, j); | ||
2312 | if (err) | ||
2313 | return (err < 0) ? err : 0; | ||
2314 | continue; | ||
2315 | } | ||
2266 | 2316 | ||
2267 | err = add_callchain_ip(thread, cursor, parent, | 2317 | err = add_callchain_ip(thread, cursor, parent, |
2268 | root_al, &cpumode, ip, | 2318 | root_al, &cpumode, ip, |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index f8cd3e7c9186..59be3466d64d 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -926,6 +926,7 @@ static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = { | |||
926 | [PARSE_EVENTS__TERM_TYPE_NOINHERIT] = "no-inherit", | 926 | [PARSE_EVENTS__TERM_TYPE_NOINHERIT] = "no-inherit", |
927 | [PARSE_EVENTS__TERM_TYPE_INHERIT] = "inherit", | 927 | [PARSE_EVENTS__TERM_TYPE_INHERIT] = "inherit", |
928 | [PARSE_EVENTS__TERM_TYPE_MAX_STACK] = "max-stack", | 928 | [PARSE_EVENTS__TERM_TYPE_MAX_STACK] = "max-stack", |
929 | [PARSE_EVENTS__TERM_TYPE_MAX_EVENTS] = "nr", | ||
929 | [PARSE_EVENTS__TERM_TYPE_OVERWRITE] = "overwrite", | 930 | [PARSE_EVENTS__TERM_TYPE_OVERWRITE] = "overwrite", |
930 | [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE] = "no-overwrite", | 931 | [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE] = "no-overwrite", |
931 | [PARSE_EVENTS__TERM_TYPE_DRV_CFG] = "driver-config", | 932 | [PARSE_EVENTS__TERM_TYPE_DRV_CFG] = "driver-config", |
@@ -1037,6 +1038,9 @@ do { \ | |||
1037 | case PARSE_EVENTS__TERM_TYPE_MAX_STACK: | 1038 | case PARSE_EVENTS__TERM_TYPE_MAX_STACK: |
1038 | CHECK_TYPE_VAL(NUM); | 1039 | CHECK_TYPE_VAL(NUM); |
1039 | break; | 1040 | break; |
1041 | case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: | ||
1042 | CHECK_TYPE_VAL(NUM); | ||
1043 | break; | ||
1040 | default: | 1044 | default: |
1041 | err->str = strdup("unknown term"); | 1045 | err->str = strdup("unknown term"); |
1042 | err->idx = term->err_term; | 1046 | err->idx = term->err_term; |
@@ -1084,6 +1088,7 @@ static int config_term_tracepoint(struct perf_event_attr *attr, | |||
1084 | case PARSE_EVENTS__TERM_TYPE_INHERIT: | 1088 | case PARSE_EVENTS__TERM_TYPE_INHERIT: |
1085 | case PARSE_EVENTS__TERM_TYPE_NOINHERIT: | 1089 | case PARSE_EVENTS__TERM_TYPE_NOINHERIT: |
1086 | case PARSE_EVENTS__TERM_TYPE_MAX_STACK: | 1090 | case PARSE_EVENTS__TERM_TYPE_MAX_STACK: |
1091 | case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: | ||
1087 | case PARSE_EVENTS__TERM_TYPE_OVERWRITE: | 1092 | case PARSE_EVENTS__TERM_TYPE_OVERWRITE: |
1088 | case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: | 1093 | case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: |
1089 | return config_term_common(attr, term, err); | 1094 | return config_term_common(attr, term, err); |
@@ -1162,6 +1167,9 @@ do { \ | |||
1162 | case PARSE_EVENTS__TERM_TYPE_MAX_STACK: | 1167 | case PARSE_EVENTS__TERM_TYPE_MAX_STACK: |
1163 | ADD_CONFIG_TERM(MAX_STACK, max_stack, term->val.num); | 1168 | ADD_CONFIG_TERM(MAX_STACK, max_stack, term->val.num); |
1164 | break; | 1169 | break; |
1170 | case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: | ||
1171 | ADD_CONFIG_TERM(MAX_EVENTS, max_events, term->val.num); | ||
1172 | break; | ||
1165 | case PARSE_EVENTS__TERM_TYPE_OVERWRITE: | 1173 | case PARSE_EVENTS__TERM_TYPE_OVERWRITE: |
1166 | ADD_CONFIG_TERM(OVERWRITE, overwrite, term->val.num ? 1 : 0); | 1174 | ADD_CONFIG_TERM(OVERWRITE, overwrite, term->val.num ? 1 : 0); |
1167 | break; | 1175 | break; |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 4473dac27aee..5ed035cbcbb7 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -71,6 +71,7 @@ enum { | |||
71 | PARSE_EVENTS__TERM_TYPE_NOINHERIT, | 71 | PARSE_EVENTS__TERM_TYPE_NOINHERIT, |
72 | PARSE_EVENTS__TERM_TYPE_INHERIT, | 72 | PARSE_EVENTS__TERM_TYPE_INHERIT, |
73 | PARSE_EVENTS__TERM_TYPE_MAX_STACK, | 73 | PARSE_EVENTS__TERM_TYPE_MAX_STACK, |
74 | PARSE_EVENTS__TERM_TYPE_MAX_EVENTS, | ||
74 | PARSE_EVENTS__TERM_TYPE_NOOVERWRITE, | 75 | PARSE_EVENTS__TERM_TYPE_NOOVERWRITE, |
75 | PARSE_EVENTS__TERM_TYPE_OVERWRITE, | 76 | PARSE_EVENTS__TERM_TYPE_OVERWRITE, |
76 | PARSE_EVENTS__TERM_TYPE_DRV_CFG, | 77 | PARSE_EVENTS__TERM_TYPE_DRV_CFG, |
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 5f761f3ed0f3..7805c71aaae2 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l | |||
@@ -269,6 +269,7 @@ time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); } | |||
269 | call-graph { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CALLGRAPH); } | 269 | call-graph { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CALLGRAPH); } |
270 | stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); } | 270 | stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); } |
271 | max-stack { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_STACK); } | 271 | max-stack { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_STACK); } |
272 | nr { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_EVENTS); } | ||
272 | inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); } | 273 | inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); } |
273 | no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } | 274 | no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } |
274 | overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_OVERWRITE); } | 275 | overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_OVERWRITE); } |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 0281d5e2cd67..66a84d5846c8 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -324,7 +324,17 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss) | |||
324 | plt_entry_size = 16; | 324 | plt_entry_size = 16; |
325 | break; | 325 | break; |
326 | 326 | ||
327 | default: /* FIXME: s390/alpha/mips/parisc/poperpc/sh/sparc/xtensa need to be checked */ | 327 | case EM_SPARC: |
328 | plt_header_size = 48; | ||
329 | plt_entry_size = 12; | ||
330 | break; | ||
331 | |||
332 | case EM_SPARCV9: | ||
333 | plt_header_size = 128; | ||
334 | plt_entry_size = 32; | ||
335 | break; | ||
336 | |||
337 | default: /* FIXME: s390/alpha/mips/parisc/poperpc/sh/xtensa need to be checked */ | ||
328 | plt_header_size = shdr_plt.sh_entsize; | 338 | plt_header_size = shdr_plt.sh_entsize; |
329 | plt_entry_size = shdr_plt.sh_entsize; | 339 | plt_entry_size = shdr_plt.sh_entsize; |
330 | break; | 340 | break; |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 20f49779116b..d026d215bdc6 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -123,7 +123,8 @@ struct symbol_conf { | |||
123 | const char *vmlinux_name, | 123 | const char *vmlinux_name, |
124 | *kallsyms_name, | 124 | *kallsyms_name, |
125 | *source_prefix, | 125 | *source_prefix, |
126 | *field_sep; | 126 | *field_sep, |
127 | *graph_function; | ||
127 | const char *default_guest_vmlinux_name, | 128 | const char *default_guest_vmlinux_name, |
128 | *default_guest_kallsyms, | 129 | *default_guest_kallsyms, |
129 | *default_guest_modules; | 130 | *default_guest_modules; |
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c index c091635bf7dc..61a4286a74dc 100644 --- a/tools/perf/util/thread-stack.c +++ b/tools/perf/util/thread-stack.c | |||
@@ -310,20 +310,46 @@ void thread_stack__free(struct thread *thread) | |||
310 | } | 310 | } |
311 | } | 311 | } |
312 | 312 | ||
313 | static inline u64 callchain_context(u64 ip, u64 kernel_start) | ||
314 | { | ||
315 | return ip < kernel_start ? PERF_CONTEXT_USER : PERF_CONTEXT_KERNEL; | ||
316 | } | ||
317 | |||
313 | void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, | 318 | void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, |
314 | size_t sz, u64 ip) | 319 | size_t sz, u64 ip, u64 kernel_start) |
315 | { | 320 | { |
316 | size_t i; | 321 | u64 context = callchain_context(ip, kernel_start); |
322 | u64 last_context; | ||
323 | size_t i, j; | ||
317 | 324 | ||
318 | if (!thread || !thread->ts) | 325 | if (sz < 2) { |
319 | chain->nr = 1; | 326 | chain->nr = 0; |
320 | else | 327 | return; |
321 | chain->nr = min(sz, thread->ts->cnt + 1); | 328 | } |
322 | 329 | ||
323 | chain->ips[0] = ip; | 330 | chain->ips[0] = context; |
331 | chain->ips[1] = ip; | ||
332 | |||
333 | if (!thread || !thread->ts) { | ||
334 | chain->nr = 2; | ||
335 | return; | ||
336 | } | ||
337 | |||
338 | last_context = context; | ||
339 | |||
340 | for (i = 2, j = 1; i < sz && j <= thread->ts->cnt; i++, j++) { | ||
341 | ip = thread->ts->stack[thread->ts->cnt - j].ret_addr; | ||
342 | context = callchain_context(ip, kernel_start); | ||
343 | if (context != last_context) { | ||
344 | if (i >= sz - 1) | ||
345 | break; | ||
346 | chain->ips[i++] = context; | ||
347 | last_context = context; | ||
348 | } | ||
349 | chain->ips[i] = ip; | ||
350 | } | ||
324 | 351 | ||
325 | for (i = 1; i < chain->nr; i++) | 352 | chain->nr = i; |
326 | chain->ips[i] = thread->ts->stack[thread->ts->cnt - i].ret_addr; | ||
327 | } | 353 | } |
328 | 354 | ||
329 | struct call_return_processor * | 355 | struct call_return_processor * |
diff --git a/tools/perf/util/thread-stack.h b/tools/perf/util/thread-stack.h index b7e41c4ebfdd..f97c00a8c251 100644 --- a/tools/perf/util/thread-stack.h +++ b/tools/perf/util/thread-stack.h | |||
@@ -84,7 +84,7 @@ int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip, | |||
84 | u64 to_ip, u16 insn_len, u64 trace_nr); | 84 | u64 to_ip, u16 insn_len, u64 trace_nr); |
85 | void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr); | 85 | void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr); |
86 | void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, | 86 | void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, |
87 | size_t sz, u64 ip); | 87 | size_t sz, u64 ip, u64 kernel_start); |
88 | int thread_stack__flush(struct thread *thread); | 88 | int thread_stack__flush(struct thread *thread); |
89 | void thread_stack__free(struct thread *thread); | 89 | void thread_stack__free(struct thread *thread); |
90 | size_t thread_stack__depth(struct thread *thread); | 90 | size_t thread_stack__depth(struct thread *thread); |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 2048d393ece6..3d9ed7d0e281 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -330,7 +330,8 @@ static int thread__prepare_access(struct thread *thread) | |||
330 | } | 330 | } |
331 | 331 | ||
332 | static int thread__clone_map_groups(struct thread *thread, | 332 | static int thread__clone_map_groups(struct thread *thread, |
333 | struct thread *parent) | 333 | struct thread *parent, |
334 | bool do_maps_clone) | ||
334 | { | 335 | { |
335 | /* This is new thread, we share map groups for process. */ | 336 | /* This is new thread, we share map groups for process. */ |
336 | if (thread->pid_ == parent->pid_) | 337 | if (thread->pid_ == parent->pid_) |
@@ -341,15 +342,11 @@ static int thread__clone_map_groups(struct thread *thread, | |||
341 | thread->pid_, thread->tid, parent->pid_, parent->tid); | 342 | thread->pid_, thread->tid, parent->pid_, parent->tid); |
342 | return 0; | 343 | return 0; |
343 | } | 344 | } |
344 | |||
345 | /* But this one is new process, copy maps. */ | 345 | /* But this one is new process, copy maps. */ |
346 | if (map_groups__clone(thread, parent->mg) < 0) | 346 | return do_maps_clone ? map_groups__clone(thread, parent->mg) : 0; |
347 | return -ENOMEM; | ||
348 | |||
349 | return 0; | ||
350 | } | 347 | } |
351 | 348 | ||
352 | int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) | 349 | int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp, bool do_maps_clone) |
353 | { | 350 | { |
354 | if (parent->comm_set) { | 351 | if (parent->comm_set) { |
355 | const char *comm = thread__comm_str(parent); | 352 | const char *comm = thread__comm_str(parent); |
@@ -362,7 +359,7 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) | |||
362 | } | 359 | } |
363 | 360 | ||
364 | thread->ppid = parent->tid; | 361 | thread->ppid = parent->tid; |
365 | return thread__clone_map_groups(thread, parent); | 362 | return thread__clone_map_groups(thread, parent, do_maps_clone); |
366 | } | 363 | } |
367 | 364 | ||
368 | void thread__find_cpumode_addr_location(struct thread *thread, u64 addr, | 365 | void thread__find_cpumode_addr_location(struct thread *thread, u64 addr, |
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 07606aa6998d..30e2b4c165fe 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
@@ -42,6 +42,8 @@ struct thread { | |||
42 | void *addr_space; | 42 | void *addr_space; |
43 | struct unwind_libunwind_ops *unwind_libunwind_ops; | 43 | struct unwind_libunwind_ops *unwind_libunwind_ops; |
44 | #endif | 44 | #endif |
45 | bool filter; | ||
46 | int filter_entry_depth; | ||
45 | }; | 47 | }; |
46 | 48 | ||
47 | struct machine; | 49 | struct machine; |
@@ -87,7 +89,7 @@ struct comm *thread__comm(const struct thread *thread); | |||
87 | struct comm *thread__exec_comm(const struct thread *thread); | 89 | struct comm *thread__exec_comm(const struct thread *thread); |
88 | const char *thread__comm_str(const struct thread *thread); | 90 | const char *thread__comm_str(const struct thread *thread); |
89 | int thread__insert_map(struct thread *thread, struct map *map); | 91 | int thread__insert_map(struct thread *thread, struct map *map); |
90 | int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp); | 92 | int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp, bool do_maps_clone); |
91 | size_t thread__fprintf(struct thread *thread, FILE *fp); | 93 | size_t thread__fprintf(struct thread *thread, FILE *fp); |
92 | 94 | ||
93 | struct thread *thread__main_thread(struct machine *machine, struct thread *thread); | 95 | struct thread *thread__main_thread(struct machine *machine, struct thread *thread); |
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index 6f318b15950e..5eff9bfc5758 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c | |||
@@ -45,13 +45,13 @@ static int __report_module(struct addr_location *al, u64 ip, | |||
45 | Dwarf_Addr s; | 45 | Dwarf_Addr s; |
46 | 46 | ||
47 | dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL); | 47 | dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL); |
48 | if (s != al->map->start) | 48 | if (s != al->map->start - al->map->pgoff) |
49 | mod = 0; | 49 | mod = 0; |
50 | } | 50 | } |
51 | 51 | ||
52 | if (!mod) | 52 | if (!mod) |
53 | mod = dwfl_report_elf(ui->dwfl, dso->short_name, | 53 | mod = dwfl_report_elf(ui->dwfl, dso->short_name, |
54 | (dso->symsrc_filename ? dso->symsrc_filename : dso->long_name), -1, al->map->start, | 54 | (dso->symsrc_filename ? dso->symsrc_filename : dso->long_name), -1, al->map->start - al->map->pgoff, |
55 | false); | 55 | false); |
56 | 56 | ||
57 | return mod && dwfl_addrmodule(ui->dwfl, ip) == mod ? 0 : -1; | 57 | return mod && dwfl_addrmodule(ui->dwfl, ip) == mod ? 0 : -1; |