Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf updates and fixes from Ingo Molnar:
"These are almost all tooling updates: 'perf top', 'perf trace' and
'perf script' fixes and updates, an UAPI header sync with the merge
window versions, license marker updates, much improved Sparc support
from David Miller, and a number of fixes"

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (66 commits)
perf intel-pt/bts: Calculate cpumode for synthesized samples
perf intel-pt: Insert callchain context into synthesized callchains
perf tools: Don't clone maps from parent when synthesizing forks
perf top: Start display thread earlier
tools headers uapi: Update linux/if_link.h header copy
tools headers uapi: Update linux/netlink.h header copy
tools headers: Sync the various kvm.h header copies
tools include uapi: Update linux/mmap.h copy
perf trace beauty: Use the mmap flags table generated from headers
perf beauty: Wire up the mmap flags table generator to the Makefile
perf beauty: Add a generator for MAP_ mmap's flag constants
tools include uapi: Update asound.h copy
tools arch uapi: Update asm-generic/unistd.h and arm64 unistd.h copies
tools include uapi: Update linux/fs.h copy
perf callchain: Honour the ordering of PERF_CONTEXT_{USER,KERNEL,etc}
perf cs-etm: Correct CPU mode for samples
perf unwind: Take pgoff into account when reporting elf to libdwfl
perf top: Do not use overwrite mode by default
perf top: Allow disabling the overwrite mode
perf trace: Beautify mount's first pathname arg
...

+3617 -540
+2
include/uapi/linux/perf_event.h
··· 646 646 * 647 647 * PERF_RECORD_MISC_MMAP_DATA - PERF_RECORD_MMAP* events 648 648 * PERF_RECORD_MISC_COMM_EXEC - PERF_RECORD_COMM event 649 + * PERF_RECORD_MISC_FORK_EXEC - PERF_RECORD_FORK event (perf internal) 649 650 * PERF_RECORD_MISC_SWITCH_OUT - PERF_RECORD_SWITCH* events 650 651 */ 651 652 #define PERF_RECORD_MISC_MMAP_DATA (1 << 13) 652 653 #define PERF_RECORD_MISC_COMM_EXEC (1 << 13) 654 + #define PERF_RECORD_MISC_FORK_EXEC (1 << 13) 653 655 #define PERF_RECORD_MISC_SWITCH_OUT (1 << 13) 654 656 /* 655 657 * These PERF_RECORD_MISC_* flags below are safely reused
+1 -1
kernel/events/core.c
··· 750 750 /* 751 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 754 __update_cgrp_time(event->cgrp); 755 755 } 756 756
+1
tools/arch/arm64/include/uapi/asm/unistd.h
··· 16 16 */ 17 17 18 18 #define __ARCH_WANT_RENAMEAT 19 + #define __ARCH_WANT_NEW_STAT 19 20 20 21 #include <asm-generic/unistd.h>
+1
tools/arch/powerpc/include/uapi/asm/kvm.h
··· 634 634 635 635 #define KVM_REG_PPC_DEC_EXPIRY (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbe) 636 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 639 /* Transactional Memory checkpointed state: 639 640 * This is all GPRs, all VSX regs and a subset of SPRs
+2
tools/arch/s390/include/uapi/asm/kvm.h
··· 160 160 #define KVM_S390_VM_CRYPTO_ENABLE_DEA_KW 1 161 161 #define KVM_S390_VM_CRYPTO_DISABLE_AES_KW 2 162 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 166 /* kvm attributes for migration mode */ 165 167 #define KVM_S390_VM_MIGRATION_STOP 0
+2 -4
tools/arch/x86/include/uapi/asm/kvm.h
··· 300 300 __u8 injected; 301 301 __u8 nr; 302 302 __u8 has_error_code; 303 - union { 304 - __u8 pad; 305 - __u8 pending; 306 - }; 303 + __u8 pending; 307 304 __u32 error_code; 308 305 } exception; 309 306 struct { ··· 384 387 385 388 #define KVM_STATE_NESTED_GUEST_MODE 0x00000001 386 389 #define KVM_STATE_NESTED_RUN_PENDING 0x00000002 390 + #define KVM_STATE_NESTED_EVMCS 0x00000004 387 391 388 392 #define KVM_STATE_NESTED_SMM_GUEST_MODE 0x00000001 389 393 #define KVM_STATE_NESTED_SMM_VMXON 0x00000002
+2
tools/include/uapi/asm-generic/unistd.h
··· 242 242 /* fs/stat.c */ 243 243 #define __NR_readlinkat 78 244 244 __SYSCALL(__NR_readlinkat, sys_readlinkat) 245 + #if defined(__ARCH_WANT_NEW_STAT) || defined(__ARCH_WANT_STAT64) 245 246 #define __NR3264_fstatat 79 246 247 __SC_3264(__NR3264_fstatat, sys_fstatat64, sys_newfstatat) 247 248 #define __NR3264_fstat 80 248 249 __SC_3264(__NR3264_fstat, sys_fstat64, sys_newfstat) 250 + #endif 249 251 250 252 /* fs/sync.c */ 251 253 #define __NR_sync 81
+393
tools/include/uapi/linux/fs.h
··· 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 */
+1
tools/include/uapi/linux/if_link.h
··· 287 287 IFLA_BR_MCAST_STATS_ENABLED, 288 288 IFLA_BR_MCAST_IGMP_VERSION, 289 289 IFLA_BR_MCAST_MLD_VERSION, 290 + IFLA_BR_VLAN_STATS_PER_PORT, 290 291 __IFLA_BR_MAX, 291 292 }; 292 293
+19 -2
tools/include/uapi/linux/kvm.h
··· 420 420 struct kvm_coalesced_mmio_zone { 421 421 __u64 addr; 422 422 __u32 size; 423 - __u32 pad; 423 + union { 424 + __u32 pad; 425 + __u32 pio; 426 + }; 424 427 }; 425 428 426 429 struct kvm_coalesced_mmio { 427 430 __u64 phys_addr; 428 431 __u32 len; 429 - __u32 pad; 432 + union { 433 + __u32 pad; 434 + __u32 pio; 435 + }; 430 436 __u8 data[8]; 431 437 }; 432 438 ··· 758 752 #define KVM_S390_SIE_PAGE_OFFSET 1 759 753 760 754 /* 755 + * On arm64, machine type can be used to request the physical 756 + * address size for the VM. Bits[7-0] are reserved for the guest 757 + * PA size shift (i.e, log2(PA_Size)). For backward compatibility, 758 + * value 0 implies the default IPA size, 40bits. 759 + */ 760 + #define KVM_VM_TYPE_ARM_IPA_SIZE_MASK 0xffULL 761 + #define KVM_VM_TYPE_ARM_IPA_SIZE(x) \ 762 + ((x) & KVM_VM_TYPE_ARM_IPA_SIZE_MASK) 763 + /* 761 764 * ioctls for /dev/kvm fds: 762 765 */ 763 766 #define KVM_GET_API_VERSION _IO(KVMIO, 0x00) ··· 973 958 #define KVM_CAP_HYPERV_SEND_IPI 161 974 959 #define KVM_CAP_COALESCED_PIO 162 975 960 #define KVM_CAP_HYPERV_ENLIGHTENED_VMCS 163 961 + #define KVM_CAP_EXCEPTION_PAYLOAD 164 962 + #define KVM_CAP_ARM_VM_IPA_SIZE 165 976 963 977 964 #ifdef KVM_CAP_IRQ_ROUTING 978 965
+2
tools/include/uapi/linux/mman.h
··· 28 28 #define MAP_HUGE_2MB HUGETLB_FLAG_ENCODE_2MB 29 29 #define MAP_HUGE_8MB HUGETLB_FLAG_ENCODE_8MB 30 30 #define MAP_HUGE_16MB HUGETLB_FLAG_ENCODE_16MB 31 + #define MAP_HUGE_32MB HUGETLB_FLAG_ENCODE_32MB 31 32 #define MAP_HUGE_256MB HUGETLB_FLAG_ENCODE_256MB 33 + #define MAP_HUGE_512MB HUGETLB_FLAG_ENCODE_512MB 32 34 #define MAP_HUGE_1GB HUGETLB_FLAG_ENCODE_1GB 33 35 #define MAP_HUGE_2GB HUGETLB_FLAG_ENCODE_2GB 34 36 #define MAP_HUGE_16GB HUGETLB_FLAG_ENCODE_16GB
+1
tools/include/uapi/linux/netlink.h
··· 155 155 #define NETLINK_LIST_MEMBERSHIPS 9 156 156 #define NETLINK_CAP_ACK 10 157 157 #define NETLINK_EXT_ACK 11 158 + #define NETLINK_DUMP_STRICT_CHK 12 158 159 159 160 struct nl_pktinfo { 160 161 __u32 group;
+2
tools/include/uapi/linux/perf_event.h
··· 646 646 * 647 647 * PERF_RECORD_MISC_MMAP_DATA - PERF_RECORD_MMAP* events 648 648 * PERF_RECORD_MISC_COMM_EXEC - PERF_RECORD_COMM event 649 + * PERF_RECORD_MISC_FORK_EXEC - PERF_RECORD_FORK event (perf internal) 649 650 * PERF_RECORD_MISC_SWITCH_OUT - PERF_RECORD_SWITCH* events 650 651 */ 651 652 #define PERF_RECORD_MISC_MMAP_DATA (1 << 13) 652 653 #define PERF_RECORD_MISC_COMM_EXEC (1 << 13) 654 + #define PERF_RECORD_MISC_FORK_EXEC (1 << 13) 653 655 #define PERF_RECORD_MISC_SWITCH_OUT (1 << 13) 654 656 /* 655 657 * These PERF_RECORD_MISC_* flags below are safely reused
+1 -1
tools/include/uapi/sound/asound.h
··· 752 752 #define SNDRV_TIMER_PSFLG_EARLY_EVENT (1<<2) /* write early event to the poll queue */ 753 753 754 754 struct snd_timer_params { 755 - unsigned int flags; /* flags - SNDRV_MIXER_PSFLG_* */ 755 + unsigned int flags; /* flags - SNDRV_TIMER_PSFLG_* */ 756 756 unsigned int ticks; /* requested resolution in ticks */ 757 757 unsigned int queue_size; /* total size of queue (32-1024) */ 758 758 unsigned int reserved0; /* reserved, was: failure locations */
+19
tools/lib/subcmd/parse-options.c
··· 116 116 case OPTION_INTEGER: 117 117 case OPTION_UINTEGER: 118 118 case OPTION_LONG: 119 + case OPTION_ULONG: 119 120 case OPTION_U64: 120 121 default: 121 122 break; ··· 167 166 case OPTION_INTEGER: 168 167 case OPTION_UINTEGER: 169 168 case OPTION_LONG: 169 + case OPTION_ULONG: 170 170 case OPTION_U64: 171 171 default: 172 172 break; ··· 293 291 if (get_arg(p, opt, flags, &arg)) 294 292 return -1; 295 293 *(long *)opt->value = strtol(arg, (char **)&s, 10); 294 + if (*s) 295 + return opterror(opt, "expects a numerical value", flags); 296 + return 0; 297 + 298 + case OPTION_ULONG: 299 + if (unset) { 300 + *(unsigned long *)opt->value = 0; 301 + return 0; 302 + } 303 + if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 304 + *(unsigned long *)opt->value = opt->defval; 305 + return 0; 306 + } 307 + if (get_arg(p, opt, flags, &arg)) 308 + return -1; 309 + *(unsigned long *)opt->value = strtoul(arg, (char **)&s, 10); 296 310 if (*s) 297 311 return opterror(opt, "expects a numerical value", flags); 298 312 return 0; ··· 721 703 case OPTION_ARGUMENT: 722 704 break; 723 705 case OPTION_LONG: 706 + case OPTION_ULONG: 724 707 case OPTION_U64: 725 708 case OPTION_INTEGER: 726 709 case OPTION_UINTEGER:
+2
tools/lib/subcmd/parse-options.h
··· 25 25 OPTION_STRING, 26 26 OPTION_INTEGER, 27 27 OPTION_LONG, 28 + OPTION_ULONG, 28 29 OPTION_CALLBACK, 29 30 OPTION_U64, 30 31 OPTION_UINTEGER, ··· 134 133 #define OPT_INTEGER(s, l, v, h) { .type = OPTION_INTEGER, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) } 135 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) } 136 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_ULONG(s, l, v, h) { .type = OPTION_ULONG, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned long *), .help = (h) } 137 137 #define OPT_U64(s, l, v, h) { .type = OPTION_U64, .short_name = (s), .long_name = (l), .value = check_vtype(v, u64 *), .help = (h) } 138 138 #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 139 #define OPT_STRING_OPTARG(s, l, v, a, h, d) \
+19
tools/perf/Documentation/build-xed.txt
··· 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 + $
+1 -1
tools/perf/Documentation/intel-pt.txt
··· 106 106 While it is possible to create scripts to analyze the data, an alternative 107 107 approach is available to export the data to a sqlite or postgresql database. 108 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 111 There is also script intel-pt-events.py which provides an example of how to 112 112 unpack the raw data for power events and PTWRITE.
+4 -3
tools/perf/Documentation/itrace.txt
··· 11 11 l synthesize last branch entries (use with i or x) 12 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 - can be specified in units of: 17 + In addition, the period (default 100000, except for perf script where it is 1) 18 + for instructions events can be specified in units of: 18 19 19 20 i instructions 20 21 t ticks
+18
tools/perf/Documentation/perf-script.txt
··· 383 383 will be printed. Each entry has function name and file/line. Enabled by 384 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 404 SEE ALSO 387 405 -------- 388 406 linkperf:perf-record[1], linkperf:perf-script-perl[1],
+10
tools/perf/Documentation/perf-top.txt
··· 242 242 --hierarchy:: 243 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 255 --force:: 246 256 Don't do ownership validation. 247 257
+67
tools/perf/Documentation/perf-trace.txt
··· 171 171 --kernel-syscall-graph:: 172 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 179 --max-stack:: 175 180 Set the stack depth limit when parsing the callchain, anything 176 181 beyond the specified depth will be ignored. Note that at this point ··· 242 237 243 238 As you can see, there was major pagefault in python process, from 244 239 CRYPTO_push_info_ routine which faulted somewhere in libcrypto.so. 240 + 241 + Trace the first 4 open, openat or open_by_handle_at syscalls (in the future more syscalls may match here): 242 + 243 + $ perf trace -e open* --max-events 4 244 + [root@jouet perf]# trace -e open* --max-events 4 245 + 2272.992 ( 0.037 ms): gnome-shell/1370 openat(dfd: CWD, filename: /proc/self/stat) = 31 246 + 2277.481 ( 0.139 ms): gnome-shell/3039 openat(dfd: CWD, filename: /proc/self/stat) = 65 247 + 3026.398 ( 0.076 ms): gnome-shell/3039 openat(dfd: CWD, filename: /proc/self/stat) = 65 248 + 4294.665 ( 0.015 ms): sed/15879 openat(dfd: CWD, filename: /etc/ld.so.cache, flags: CLOEXEC) = 3 249 + $ 250 + 251 + Trace the first minor page fault when running a workload: 252 + 253 + # perf trace -F min --max-stack=7 --max-events 1 sleep 1 254 + 0.000 ( 0.000 ms): sleep/18006 minfault [__clear_user+0x1a] => 0x5626efa56080 (?k) 255 + __clear_user ([kernel.kallsyms]) 256 + load_elf_binary ([kernel.kallsyms]) 257 + search_binary_handler ([kernel.kallsyms]) 258 + __do_execve_file.isra.33 ([kernel.kallsyms]) 259 + __x64_sys_execve ([kernel.kallsyms]) 260 + do_syscall_64 ([kernel.kallsyms]) 261 + entry_SYSCALL_64 ([kernel.kallsyms]) 262 + # 263 + 264 + Trace the next min page page fault to take place on the first CPU: 265 + 266 + # perf trace -F min --call-graph=dwarf --max-events 1 --cpu 0 267 + 0.000 ( 0.000 ms): Web Content/17136 minfault [js::gc::Chunk::fetchNextDecommittedArena+0x4b] => 0x7fbe6181b000 (?.) 268 + js::gc::FreeSpan::initAsEmpty (inlined) 269 + js::gc::Arena::setAsNotAllocated (inlined) 270 + js::gc::Chunk::fetchNextDecommittedArena (/usr/lib64/firefox/libxul.so) 271 + js::gc::Chunk::allocateArena (/usr/lib64/firefox/libxul.so) 272 + js::gc::GCRuntime::allocateArena (/usr/lib64/firefox/libxul.so) 273 + js::gc::ArenaLists::allocateFromArena (/usr/lib64/firefox/libxul.so) 274 + js::gc::GCRuntime::tryNewTenuredThing<JSString, (js::AllowGC)1> (inlined) 275 + js::AllocateString<JSString, (js::AllowGC)1> (/usr/lib64/firefox/libxul.so) 276 + js::Allocate<JSThinInlineString, (js::AllowGC)1> (inlined) 277 + JSThinInlineString::new_<(js::AllowGC)1> (inlined) 278 + AllocateInlineString<(js::AllowGC)1, unsigned char> (inlined) 279 + js::ConcatStrings<(js::AllowGC)1> (/usr/lib64/firefox/libxul.so) 280 + [0x18b26e6bc2bd] (/tmp/perf-17136.map) 281 + # 282 + 283 + Trace the next two sched:sched_switch events, four block:*_plug events, the 284 + next block:*_unplug and the next three net:*dev_queue events, this last one 285 + with a backtrace of at most 16 entries, system wide: 286 + 287 + # perf trace -e sched:*switch/nr=2/,block:*_plug/nr=4/,block:*_unplug/nr=1/,net:*dev_queue/nr=3,max-stack=16/ 288 + 0.000 :0/0 sched:sched_switch:swapper/2:0 [120] S ==> rcu_sched:10 [120] 289 + 0.015 rcu_sched/10 sched:sched_switch:rcu_sched:10 [120] R ==> swapper/2:0 [120] 290 + 254.198 irq/50-iwlwifi/680 net:net_dev_queue:dev=wlp3s0 skbaddr=0xffff93498051f600 len=66 291 + __dev_queue_xmit ([kernel.kallsyms]) 292 + 273.977 :0/0 net:net_dev_queue:dev=wlp3s0 skbaddr=0xffff93498051f600 len=78 293 + __dev_queue_xmit ([kernel.kallsyms]) 294 + 274.007 :0/0 net:net_dev_queue:dev=wlp3s0 skbaddr=0xffff93498051ff00 len=78 295 + __dev_queue_xmit ([kernel.kallsyms]) 296 + 2930.140 kworker/u16:58/2722 block:block_plug:[kworker/u16:58] 297 + 2930.162 kworker/u16:58/2722 block:block_unplug:[kworker/u16:58] 1 298 + 4466.094 jbd2/dm-2-8/748 block:block_plug:[jbd2/dm-2-8] 299 + 8050.123 kworker/u16:30/2694 block:block_plug:[kworker/u16:30] 300 + 8050.271 kworker/u16:30/2694 block:block_plug:[kworker/u16:30] 301 + # 245 302 246 303 SEE ALSO 247 304 --------
+19
tools/perf/Makefile.perf
··· 1 1 include ../scripts/Makefile.include 2 + include ../scripts/Makefile.arch 2 3 3 4 # The default target of this Makefile is... 4 5 all: ··· 386 385 SHELL = $(SHELL_PATH) 387 386 388 387 linux_uapi_dir := $(srctree)/tools/include/uapi/linux 388 + asm_generic_uapi_dir := $(srctree)/tools/include/uapi/asm-generic 389 + arch_asm_uapi_dir := $(srctree)/tools/arch/$(ARCH)/include/uapi/asm/ 389 390 390 391 beauty_outdir := $(OUTPUT)trace/beauty/generated 391 392 beauty_ioctl_outdir := $(beauty_outdir)/ioctl ··· 462 459 463 460 $(madvise_behavior_array): $(madvise_hdr_dir)/mman-common.h $(madvise_behavior_tbl) 464 461 $(Q)$(SHELL) '$(madvise_behavior_tbl)' $(madvise_hdr_dir) > $@ 462 + 463 + mmap_flags_array := $(beauty_outdir)/mmap_flags_array.c 464 + mmap_flags_tbl := $(srctree)/tools/perf/trace/beauty/mmap_flags.sh 465 + 466 + $(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) 467 + $(Q)$(SHELL) '$(mmap_flags_tbl)' $(asm_generic_uapi_dir) $(arch_asm_uapi_dir) > $@ 468 + 469 + mount_flags_array := $(beauty_outdir)/mount_flags_array.c 470 + mount_flags_tbl := $(srctree)/tools/perf/trace/beauty/mount_flags.sh 471 + 472 + $(mount_flags_array): $(linux_uapi_dir)/fs.h $(mount_flags_tbl) 473 + $(Q)$(SHELL) '$(mount_flags_tbl)' $(linux_uapi_dir) > $@ 465 474 466 475 prctl_option_array := $(beauty_outdir)/prctl_option_array.c 467 476 prctl_hdr_dir := $(srctree)/tools/include/uapi/linux/ ··· 592 577 $(socket_ipproto_array) \ 593 578 $(vhost_virtio_ioctl_array) \ 594 579 $(madvise_behavior_array) \ 580 + $(mmap_flags_array) \ 581 + $(mount_flags_array) \ 595 582 $(perf_ioctl_array) \ 596 583 $(prctl_option_array) \ 597 584 $(arch_errno_name_array) ··· 880 863 $(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c \ 881 864 $(OUTPUT)pmu-events/pmu-events.c \ 882 865 $(OUTPUT)$(madvise_behavior_array) \ 866 + $(OUTPUT)$(mmap_flags_array) \ 867 + $(OUTPUT)$(mount_flags_array) \ 883 868 $(OUTPUT)$(drm_ioctl_array) \ 884 869 $(OUTPUT)$(pkey_alloc_access_rights_array) \ 885 870 $(OUTPUT)$(sndrv_ctl_ioctl_array) \
+1 -1
tools/perf/arch/arm64/entry/syscalls/mksyscalltbl
··· 23 23 { 24 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
+2
tools/perf/arch/sparc/Makefile
··· 1 1 ifndef NO_DWARF 2 2 PERF_HAVE_DWARF_REGS := 1 3 3 endif 4 + 5 + PERF_HAVE_JITDUMP := 1
+169
tools/perf/arch/sparc/annotate/instructions.c
··· 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 + }
+22 -2
tools/perf/builtin-record.c
··· 592 592 if (!rec->opts.full_auxtrace) 593 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 598 perf_header__clear_feat(&session->header, HEADER_STAT); 596 599 } 597 600 ··· 899 896 rec->session = session; 900 897 901 898 record__init_features(rec); 899 + 900 + if (rec->opts.use_clockid && rec->opts.clockid_res_ns) 901 + session->header.env.clockid_res_ns = rec->opts.clockid_res_ns; 902 902 903 903 if (forks) { 904 904 err = perf_evlist__prepare_workload(rec->evlist, &opts->target, ··· 1343 1337 CLOCKID_END, 1344 1338 }; 1345 1339 1340 + static int get_clockid_res(clockid_t clk_id, u64 *res_ns) 1341 + { 1342 + struct timespec res; 1343 + 1344 + *res_ns = 0; 1345 + if (!clock_getres(clk_id, &res)) 1346 + *res_ns = res.tv_nsec + res.tv_sec * NSEC_PER_SEC; 1347 + else 1348 + pr_warning("WARNING: Failed to determine specified clock resolution.\n"); 1349 + 1350 + return 0; 1351 + } 1352 + 1346 1353 static int parse_clockid(const struct option *opt, const char *str, int unset) 1347 1354 { 1348 1355 struct record_opts *opts = (struct record_opts *)opt->value; ··· 1379 1360 1380 1361 /* if its a number, we're done */ 1381 1362 if (sscanf(str, "%d", &opts->clockid) == 1) 1382 - return 0; 1363 + return get_clockid_res(opts->clockid, &opts->clockid_res_ns); 1383 1364 1384 1365 /* allow a "CLOCK_" prefix to the name */ 1385 1366 if (!strncasecmp(str, "CLOCK_", 6)) ··· 1388 1369 for (cm = clockids; cm->name; cm++) { 1389 1370 if (!strcasecmp(str, cm->name)) { 1390 1371 opts->clockid = cm->clockid; 1391 - return 0; 1372 + return get_clockid_res(opts->clockid, 1373 + &opts->clockid_res_ns); 1392 1374 } 1393 1375 } 1394 1376
+142 -24
tools/perf/builtin-script.c
··· 44 44 #include <sys/stat.h> 45 45 #include <fcntl.h> 46 46 #include <unistd.h> 47 + #include <subcmd/pager.h> 47 48 48 49 #include "sane_ctype.h" 49 50 ··· 913 912 914 913 static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en, 915 914 struct perf_insn *x, u8 *inbuf, int len, 916 - int insn, FILE *fp) 915 + int insn, FILE *fp, int *total_cycles) 917 916 { 918 917 int printed = fprintf(fp, "\t%016" PRIx64 "\t%-30s\t#%s%s%s%s", ip, 919 918 dump_insn(x, ip, inbuf, len, NULL), ··· 922 921 en->flags.in_tx ? " INTX" : "", 923 922 en->flags.abort ? " ABORT" : ""); 924 923 if (en->flags.cycles) { 925 - printed += fprintf(fp, " %d cycles", en->flags.cycles); 924 + *total_cycles += en->flags.cycles; 925 + printed += fprintf(fp, " %d cycles [%d]", en->flags.cycles, *total_cycles); 926 926 if (insn) 927 927 printed += fprintf(fp, " %.2f IPC", (float)insn / en->flags.cycles); 928 928 } ··· 980 978 u8 buffer[MAXBB]; 981 979 unsigned off; 982 980 struct symbol *lastsym = NULL; 981 + int total_cycles = 0; 983 982 984 983 if (!(br && br->nr)) 985 984 return 0; ··· 1001 998 printed += ip__fprintf_sym(br->entries[nr - 1].from, thread, 1002 999 x.cpumode, x.cpu, &lastsym, attr, fp); 1003 1000 printed += ip__fprintf_jump(br->entries[nr - 1].from, &br->entries[nr - 1], 1004 - &x, buffer, len, 0, fp); 1001 + &x, buffer, len, 0, fp, &total_cycles); 1005 1002 } 1006 1003 1007 1004 /* Print all blocks */ ··· 1029 1026 1030 1027 printed += ip__fprintf_sym(ip, thread, x.cpumode, x.cpu, &lastsym, attr, fp); 1031 1028 if (ip == end) { 1032 - printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn, fp); 1029 + printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn, fp, 1030 + &total_cycles); 1033 1031 break; 1034 1032 } else { 1035 1033 printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", ip, ··· 1108 1104 return printed; 1109 1105 } 1110 1106 1107 + static const char *resolve_branch_sym(struct perf_sample *sample, 1108 + struct perf_evsel *evsel, 1109 + struct thread *thread, 1110 + struct addr_location *al, 1111 + u64 *ip) 1112 + { 1113 + struct addr_location addr_al; 1114 + struct perf_event_attr *attr = &evsel->attr; 1115 + const char *name = NULL; 1116 + 1117 + if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) { 1118 + if (sample_addr_correlates_sym(attr)) { 1119 + thread__resolve(thread, &addr_al, sample); 1120 + if (addr_al.sym) 1121 + name = addr_al.sym->name; 1122 + else 1123 + *ip = sample->addr; 1124 + } else { 1125 + *ip = sample->addr; 1126 + } 1127 + } else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) { 1128 + if (al->sym) 1129 + name = al->sym->name; 1130 + else 1131 + *ip = sample->ip; 1132 + } 1133 + return name; 1134 + } 1135 + 1111 1136 static int perf_sample__fprintf_callindent(struct perf_sample *sample, 1112 1137 struct perf_evsel *evsel, 1113 1138 struct thread *thread, ··· 1144 1111 { 1145 1112 struct perf_event_attr *attr = &evsel->attr; 1146 1113 size_t depth = thread_stack__depth(thread); 1147 - struct addr_location addr_al; 1148 1114 const char *name = NULL; 1149 1115 static int spacing; 1150 1116 int len = 0; ··· 1157 1125 if (thread->ts && sample->flags & PERF_IP_FLAG_RETURN) 1158 1126 depth += 1; 1159 1127 1160 - if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) { 1161 - if (sample_addr_correlates_sym(attr)) { 1162 - thread__resolve(thread, &addr_al, sample); 1163 - if (addr_al.sym) 1164 - name = addr_al.sym->name; 1165 - else 1166 - ip = sample->addr; 1167 - } else { 1168 - ip = sample->addr; 1169 - } 1170 - } else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) { 1171 - if (al->sym) 1172 - name = al->sym->name; 1173 - else 1174 - ip = sample->ip; 1175 - } 1128 + name = resolve_branch_sym(sample, evsel, thread, al, &ip); 1176 1129 1177 1130 if (PRINT_FIELD(DSO) && !(PRINT_FIELD(IP) || PRINT_FIELD(ADDR))) { 1178 1131 dlen += fprintf(fp, "("); ··· 1663 1646 } 1664 1647 } 1665 1648 1649 + static bool show_event(struct perf_sample *sample, 1650 + struct perf_evsel *evsel, 1651 + struct thread *thread, 1652 + struct addr_location *al) 1653 + { 1654 + int depth = thread_stack__depth(thread); 1655 + 1656 + if (!symbol_conf.graph_function) 1657 + return true; 1658 + 1659 + if (thread->filter) { 1660 + if (depth <= thread->filter_entry_depth) { 1661 + thread->filter = false; 1662 + return false; 1663 + } 1664 + return true; 1665 + } else { 1666 + const char *s = symbol_conf.graph_function; 1667 + u64 ip; 1668 + const char *name = resolve_branch_sym(sample, evsel, thread, al, 1669 + &ip); 1670 + unsigned nlen; 1671 + 1672 + if (!name) 1673 + return false; 1674 + nlen = strlen(name); 1675 + while (*s) { 1676 + unsigned len = strcspn(s, ","); 1677 + if (nlen == len && !strncmp(name, s, len)) { 1678 + thread->filter = true; 1679 + thread->filter_entry_depth = depth; 1680 + return true; 1681 + } 1682 + s += len; 1683 + if (*s == ',') 1684 + s++; 1685 + } 1686 + return false; 1687 + } 1688 + } 1689 + 1666 1690 static void process_event(struct perf_script *script, 1667 1691 struct perf_sample *sample, struct perf_evsel *evsel, 1668 1692 struct addr_location *al, ··· 1716 1658 FILE *fp = es->fp; 1717 1659 1718 1660 if (output[type].fields == 0) 1661 + return; 1662 + 1663 + if (!show_event(sample, evsel, thread, al)) 1719 1664 return; 1720 1665 1721 1666 ++es->samples; ··· 1798 1737 1799 1738 if (PRINT_FIELD(METRIC)) 1800 1739 perf_sample__fprint_metric(script, thread, evsel, sample, fp); 1740 + 1741 + if (verbose) 1742 + fflush(fp); 1801 1743 } 1802 1744 1803 1745 static struct scripting_ops *scripting_ops; ··· 3164 3100 #define perf_script__process_auxtrace_info 0 3165 3101 #endif 3166 3102 3103 + static int parse_insn_trace(const struct option *opt __maybe_unused, 3104 + const char *str __maybe_unused, 3105 + int unset __maybe_unused) 3106 + { 3107 + parse_output_fields(NULL, "+insn,-event,-period", 0); 3108 + itrace_parse_synth_opts(opt, "i0ns", 0); 3109 + nanosecs = true; 3110 + return 0; 3111 + } 3112 + 3113 + static int parse_xed(const struct option *opt __maybe_unused, 3114 + const char *str __maybe_unused, 3115 + int unset __maybe_unused) 3116 + { 3117 + force_pager("xed -F insn: -A -64 | less"); 3118 + return 0; 3119 + } 3120 + 3121 + static int parse_call_trace(const struct option *opt __maybe_unused, 3122 + const char *str __maybe_unused, 3123 + int unset __maybe_unused) 3124 + { 3125 + parse_output_fields(NULL, "-ip,-addr,-event,-period,+callindent", 0); 3126 + itrace_parse_synth_opts(opt, "cewp", 0); 3127 + nanosecs = true; 3128 + return 0; 3129 + } 3130 + 3131 + static int parse_callret_trace(const struct option *opt __maybe_unused, 3132 + const char *str __maybe_unused, 3133 + int unset __maybe_unused) 3134 + { 3135 + parse_output_fields(NULL, "-ip,-addr,-event,-period,+callindent,+flags", 0); 3136 + itrace_parse_synth_opts(opt, "crewp", 0); 3137 + nanosecs = true; 3138 + return 0; 3139 + } 3140 + 3167 3141 int cmd_script(int argc, const char **argv) 3168 3142 { 3169 3143 bool show_full_info = false; ··· 3211 3109 char *rec_script_path = NULL; 3212 3110 char *rep_script_path = NULL; 3213 3111 struct perf_session *session; 3214 - struct itrace_synth_opts itrace_synth_opts = { .set = false, }; 3112 + struct itrace_synth_opts itrace_synth_opts = { 3113 + .set = false, 3114 + .default_no_sample = true, 3115 + }; 3215 3116 char *script_path = NULL; 3216 3117 const char **__argv; 3217 3118 int i, j, err = 0; ··· 3289 3184 "system-wide collection from all CPUs"), 3290 3185 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", 3291 3186 "only consider these symbols"), 3187 + OPT_CALLBACK_OPTARG(0, "insn-trace", &itrace_synth_opts, NULL, NULL, 3188 + "Decode instructions from itrace", parse_insn_trace), 3189 + OPT_CALLBACK_OPTARG(0, "xed", NULL, NULL, NULL, 3190 + "Run xed disassembler on output", parse_xed), 3191 + OPT_CALLBACK_OPTARG(0, "call-trace", &itrace_synth_opts, NULL, NULL, 3192 + "Decode calls from from itrace", parse_call_trace), 3193 + OPT_CALLBACK_OPTARG(0, "call-ret-trace", &itrace_synth_opts, NULL, NULL, 3194 + "Decode calls and returns from itrace", parse_callret_trace), 3195 + OPT_STRING(0, "graph-function", &symbol_conf.graph_function, "symbol[,symbol...]", 3196 + "Only print symbols and callees with --call-trace/--call-ret-trace"), 3292 3197 OPT_STRING(0, "stop-bt", &symbol_conf.bt_stop_list_str, "symbol[,symbol...]", 3293 3198 "Stop display of callgraph at these symbols"), 3294 3199 OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), ··· 3532 3417 exit(-1); 3533 3418 } 3534 3419 3535 - if (!script_name) 3420 + if (!script_name) { 3536 3421 setup_pager(); 3422 + use_browser = 0; 3423 + } 3537 3424 3538 3425 session = perf_session__new(&data, false, &script.tool); 3539 3426 if (session == NULL) ··· 3556 3439 script.session = session; 3557 3440 script__setup_sample_type(&script); 3558 3441 3559 - if (output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT) 3442 + if ((output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT) || 3443 + symbol_conf.graph_function) 3560 3444 itrace_synth_opts.thread_stack = true; 3561 3445 3562 3446 session->itrace_synth_opts = &itrace_synth_opts;
+24
tools/perf/builtin-stat.c
··· 409 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 434 static int __run_perf_stat(int argc, const char **argv, int run_idx) 413 435 { 414 436 int interval = stat_config.interval; ··· 601 579 enable_counters(); 602 580 while (!done) { 603 581 nanosleep(&ts, NULL); 582 + if (!is_target_alive(&target, evsel_list->threads)) 583 + break; 604 584 if (timeout) 605 585 break; 606 586 if (interval) {
+15 -6
tools/perf/builtin-top.c
··· 1134 1134 if (!target__none(&opts->target)) 1135 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 1137 ret = -1; 1143 1138 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : 1144 1139 display_thread), top)) { ··· 1150 1155 goto out_join; 1151 1156 } 1152 1157 } 1158 + 1159 + /* Wait for a minimal set of events before starting the snapshot */ 1160 + perf_evlist__poll(top->evlist, 100); 1161 + 1162 + perf_top__mmap_read(top); 1153 1163 1154 1164 while (!done) { 1155 1165 u64 hits = top->samples; ··· 1257 1257 .uses_mmap = true, 1258 1258 }, 1259 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 1269 .max_stack = sysctl__max_stack(), 1263 1270 .annotation_opts = annotation__default_options, ··· 1379 1372 "Show raw trace event output (do not use print fmt or plugins)"), 1380 1373 OPT_BOOLEAN(0, "hierarchy", &symbol_conf.report_hierarchy, 1381 1374 "Show entries in a hierarchy"), 1375 + OPT_BOOLEAN(0, "overwrite", &top.record_opts.overwrite, 1376 + "Use a backward ring buffer, default: no"), 1382 1377 OPT_BOOLEAN(0, "force", &symbol_conf.force, "don't complain, do it"), 1383 1378 OPT_UINTEGER(0, "num-thread-synthesize", &top.nr_threads_synthesize, 1384 1379 "number of thread to run event synthesize"),
+90 -8
tools/perf/builtin-trace.c
··· 89 89 u64 base_time; 90 90 FILE *output; 91 91 unsigned long nr_events; 92 + unsigned long nr_events_printed; 93 + unsigned long max_events; 92 94 struct strlist *ev_qualifier; 93 95 struct { 94 96 size_t nr; ··· 614 612 615 613 struct syscall_arg_fmt { 616 614 size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg); 615 + unsigned long (*mask_val)(struct syscall_arg *arg, unsigned long val); 617 616 void *parm; 618 617 const char *name; 619 618 bool show_zero; ··· 726 723 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, 727 724 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, 728 725 [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, }, 726 + { .name = "mount", 727 + .arg = { [0] = { .scnprintf = SCA_FILENAME, /* dev_name */ }, 728 + [3] = { .scnprintf = SCA_MOUNT_FLAGS, /* flags */ 729 + .mask_val = SCAMV_MOUNT_FLAGS, /* flags */ }, }, }, 729 730 { .name = "mprotect", 730 731 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ }, 731 732 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, }, ··· 839 832 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, 840 833 { .name = "tkill", 841 834 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, 842 - { .name = "umount2", .alias = "umount", }, 835 + { .name = "umount2", .alias = "umount", 836 + .arg = { [0] = { .scnprintf = SCA_FILENAME, /* name */ }, }, }, 843 837 { .name = "uname", .alias = "newuname", }, 844 838 { .name = "unlinkat", 845 839 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, ··· 862 854 { 863 855 const int nmemb = ARRAY_SIZE(syscall_fmts); 864 856 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp); 857 + } 858 + 859 + static struct syscall_fmt *syscall_fmt__find_by_alias(const char *alias) 860 + { 861 + int i, nmemb = ARRAY_SIZE(syscall_fmts); 862 + 863 + for (i = 0; i < nmemb; ++i) { 864 + if (syscall_fmts[i].alias && strcmp(syscall_fmts[i].alias, alias) == 0) 865 + return &syscall_fmts[i]; 866 + } 867 + 868 + return NULL; 865 869 } 866 870 867 871 /* ··· 1505 1485 return scnprintf(bf, size, "arg%d: ", arg->idx); 1506 1486 } 1507 1487 1488 + /* 1489 + * Check if the value is in fact zero, i.e. mask whatever needs masking, such 1490 + * as mount 'flags' argument that needs ignoring some magic flag, see comment 1491 + * in tools/perf/trace/beauty/mount_flags.c 1492 + */ 1493 + static unsigned long syscall__mask_val(struct syscall *sc, struct syscall_arg *arg, unsigned long val) 1494 + { 1495 + if (sc->arg_fmt && sc->arg_fmt[arg->idx].mask_val) 1496 + return sc->arg_fmt[arg->idx].mask_val(arg, val); 1497 + 1498 + return val; 1499 + } 1500 + 1508 1501 static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size, 1509 1502 struct syscall_arg *arg, unsigned long val) 1510 1503 { ··· 1566 1533 continue; 1567 1534 1568 1535 val = syscall_arg__val(&arg, arg.idx); 1536 + /* 1537 + * Some syscall args need some mask, most don't and 1538 + * return val untouched. 1539 + */ 1540 + val = syscall__mask_val(sc, &arg, val); 1569 1541 1570 1542 /* 1571 1543 * Suppress this argument if its value is zero and ··· 1701 1663 printed = trace__fprintf_entry_head(trace, trace->current, 0, false, ttrace->entry_time, trace->output); 1702 1664 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str); 1703 1665 ttrace->entry_pending = false; 1666 + 1667 + ++trace->nr_events_printed; 1704 1668 1705 1669 return printed; 1706 1670 } ··· 1850 1810 int max_stack = evsel->attr.sample_max_stack ? 1851 1811 evsel->attr.sample_max_stack : 1852 1812 trace->max_stack; 1813 + int err; 1853 1814 1854 - if (machine__resolve(trace->host, &al, sample) < 0 || 1855 - thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack)) 1815 + if (machine__resolve(trace->host, &al, sample) < 0) 1856 1816 return -1; 1857 1817 1858 - return 0; 1818 + err = thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack); 1819 + addr_location__put(&al); 1820 + return err; 1859 1821 } 1860 1822 1861 1823 static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample) ··· 1981 1939 goto signed_print; 1982 1940 1983 1941 fputc('\n', trace->output); 1942 + 1943 + /* 1944 + * We only consider an 'event' for the sake of --max-events a non-filtered 1945 + * sys_enter + sys_exit and other tracepoint events. 1946 + */ 1947 + if (++trace->nr_events_printed == trace->max_events && trace->max_events != ULONG_MAX) 1948 + interrupted = true; 1984 1949 1985 1950 if (callchain_ret > 0) 1986 1951 trace__fprintf_callchain(trace, sample); ··· 2121 2072 { 2122 2073 binary__fprintf(sample->raw_data, sample->raw_size, 8, 2123 2074 bpf_output__printer, NULL, trace->output); 2075 + ++trace->nr_events_printed; 2124 2076 } 2125 2077 2126 2078 static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, 2127 2079 union perf_event *event __maybe_unused, 2128 2080 struct perf_sample *sample) 2129 2081 { 2130 - struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); 2082 + struct thread *thread; 2131 2083 int callchain_ret = 0; 2084 + /* 2085 + * Check if we called perf_evsel__disable(evsel) due to, for instance, 2086 + * this event's max_events having been hit and this is an entry coming 2087 + * from the ring buffer that we should discard, since the max events 2088 + * have already been considered/printed. 2089 + */ 2090 + if (evsel->disabled) 2091 + return 0; 2092 + 2093 + thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); 2132 2094 2133 2095 if (sample->callchain) { 2134 2096 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor); ··· 2187 2127 event_format__fprintf(evsel->tp_format, sample->cpu, 2188 2128 sample->raw_data, sample->raw_size, 2189 2129 trace->output); 2130 + ++trace->nr_events_printed; 2131 + 2132 + if (evsel->max_events != ULONG_MAX && ++evsel->nr_events_printed == evsel->max_events) { 2133 + perf_evsel__disable(evsel); 2134 + perf_evsel__close(evsel); 2135 + } 2190 2136 } 2191 2137 } 2192 2138 ··· 2203 2137 trace__fprintf_callchain(trace, sample); 2204 2138 else if (callchain_ret < 0) 2205 2139 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel)); 2206 - thread__put(thread); 2207 2140 out: 2141 + thread__put(thread); 2208 2142 return 0; 2209 2143 } 2210 2144 ··· 2291 2225 trace__fprintf_callchain(trace, sample); 2292 2226 else if (callchain_ret < 0) 2293 2227 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel)); 2228 + 2229 + ++trace->nr_events_printed; 2294 2230 out: 2295 2231 err = 0; 2296 2232 out_put: ··· 2470 2402 tracepoint_handler handler = evsel->handler; 2471 2403 handler(trace, evsel, event, sample); 2472 2404 } 2405 + 2406 + if (trace->nr_events_printed >= trace->max_events && trace->max_events != ULONG_MAX) 2407 + interrupted = true; 2473 2408 } 2474 2409 2475 2410 static int trace__add_syscall_newtp(struct trace *trace) ··· 2777 2706 int timeout = done ? 100 : -1; 2778 2707 2779 2708 if (!draining && perf_evlist__poll(evlist, timeout) > 0) { 2780 - if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0) 2709 + if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP | POLLNVAL) == 0) 2781 2710 draining = true; 2782 2711 2783 2712 goto again; ··· 3209 3138 int len = strlen(str) + 1, err = -1, list, idx; 3210 3139 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR); 3211 3140 char group_name[PATH_MAX]; 3141 + struct syscall_fmt *fmt; 3212 3142 3213 3143 if (strace_groups_dir == NULL) 3214 3144 return -1; ··· 3227 3155 if (syscalltbl__id(trace->sctbl, s) >= 0 || 3228 3156 syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) { 3229 3157 list = 1; 3158 + goto do_concat; 3159 + } 3160 + 3161 + fmt = syscall_fmt__find_by_alias(s); 3162 + if (fmt != NULL) { 3163 + list = 1; 3164 + s = fmt->name; 3230 3165 } else { 3231 3166 path__join(group_name, sizeof(group_name), strace_groups_dir, s); 3232 3167 if (access(group_name, R_OK) == 0) 3233 3168 list = 1; 3234 3169 } 3235 - 3170 + do_concat: 3236 3171 if (lists[list]) { 3237 3172 sprintf(lists[list] + strlen(lists[list]), ",%s", s); 3238 3173 } else { ··· 3328 3249 .trace_syscalls = false, 3329 3250 .kernel_syscallchains = false, 3330 3251 .max_stack = UINT_MAX, 3252 + .max_events = ULONG_MAX, 3331 3253 }; 3332 3254 const char *output_name = NULL; 3333 3255 const struct option trace_options[] = { ··· 3381 3301 &record_parse_callchain_opt), 3382 3302 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains, 3383 3303 "Show the kernel callchains on the syscall exit path"), 3304 + OPT_ULONG(0, "max-events", &trace.max_events, 3305 + "Set the maximum number of events to print, exit after that is reached. "), 3384 3306 OPT_UINTEGER(0, "min-stack", &trace.min_stack, 3385 3307 "Set the minimum stack depth when parsing the callchain, " 3386 3308 "anything below the specified depth will be ignored."),
+1
tools/perf/check-headers.sh
··· 5 5 include/uapi/drm/drm.h 6 6 include/uapi/drm/i915_drm.h 7 7 include/uapi/linux/fcntl.h 8 + include/uapi/linux/fs.h 8 9 include/uapi/linux/kcmp.h 9 10 include/uapi/linux/kvm.h 10 11 include/uapi/linux/in.h
+1
tools/perf/perf.h
··· 81 81 unsigned initial_delay; 82 82 bool use_clockid; 83 83 clockid_t clockid; 84 + u64 clockid_res_ns; 84 85 unsigned int proc_map_timeout; 85 86 }; 86 87
-339
tools/perf/scripts/python/call-graph-from-sql.py
··· 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)
+1 -1
tools/perf/scripts/python/export-to-postgresql.py
··· 59 59 # pt_example=# \q 60 60 # 61 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 64 # Tables: 65 65 #
+1 -1
tools/perf/scripts/python/export-to-sqlite.py
··· 40 40 # sqlite> .quit 41 41 # 42 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 45 # The database structure is practically the same as created by the script 46 46 # export-to-postgresql.py. Refer to that script for details. A notable
+2128
tools/perf/scripts/python/exported-sql-viewer.py
··· 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()
+1
tools/perf/trace/beauty/Build
··· 5 5 libperf-y += ioctl.o 6 6 endif 7 7 libperf-y += kcmp.o 8 + libperf-y += mount_flags.o 8 9 libperf-y += pkey_alloc.o 9 10 libperf-y += prctl.o 10 11 libperf-y += sockaddr.o
+7
tools/perf/trace/beauty/beauty.h
··· 24 24 } 25 25 26 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 29 struct trace; 29 30 struct thread; ··· 122 121 123 122 size_t syscall_arg__scnprintf_kcmp_idx(char *bf, size_t size, struct syscall_arg *arg); 124 123 #define SCA_KCMP_IDX syscall_arg__scnprintf_kcmp_idx 124 + 125 + unsigned long syscall_arg__mask_val_mount_flags(struct syscall_arg *arg, unsigned long flags); 126 + #define SCAMV_MOUNT_FLAGS syscall_arg__mask_val_mount_flags 127 + 128 + size_t syscall_arg__scnprintf_mount_flags(char *bf, size_t size, struct syscall_arg *arg); 129 + #define SCA_MOUNT_FLAGS syscall_arg__scnprintf_mount_flags 125 130 126 131 size_t syscall_arg__scnprintf_pkey_alloc_access_rights(char *bf, size_t size, struct syscall_arg *arg); 127 132 #define SCA_PKEY_ALLOC_ACCESS_RIGHTS syscall_arg__scnprintf_pkey_alloc_access_rights
+1 -2
tools/perf/trace/beauty/clone.c
··· 1 + // SPDX-License-Identifier: LGPL-2.1 1 2 /* 2 3 * trace/beauty/cone.c 3 4 * 4 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 8 #include "trace/beauty/beauty.h"
+1
tools/perf/trace/beauty/drm_ioctl.sh
··· 1 1 #!/bin/sh 2 + # SPDX-License-Identifier: LGPL-2.1 2 3 3 4 [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/drm/ 4 5
+1 -1
tools/perf/trace/beauty/eventfd.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 1 + // SPDX-License-Identifier: LGPL-2.1 2 2 #ifndef EFD_SEMAPHORE 3 3 #define EFD_SEMAPHORE 1 4 4 #endif
+1 -2
tools/perf/trace/beauty/fcntl.c
··· 1 + // SPDX-License-Identifier: LGPL-2.1 1 2 /* 2 3 * trace/beauty/fcntl.c 3 4 * 4 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 8 #include "trace/beauty/beauty.h"
+1 -1
tools/perf/trace/beauty/flock.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 1 + // SPDX-License-Identifier: LGPL-2.1 2 2 3 3 #include "trace/beauty/beauty.h" 4 4 #include <linux/kernel.h>
+1 -1
tools/perf/trace/beauty/futex_op.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 1 + // SPDX-License-Identifier: LGPL-2.1 2 2 #include <linux/futex.h> 3 3 4 4 #ifndef FUTEX_WAIT_BITSET
+1 -1
tools/perf/trace/beauty/futex_val3.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 1 + // SPDX-License-Identifier: LGPL-2.1 2 2 #include <linux/futex.h> 3 3 4 4 #ifndef FUTEX_BITSET_MATCH_ANY
+1 -2
tools/perf/trace/beauty/ioctl.c
··· 1 + // SPDX-License-Identifier: LGPL-2.1 1 2 /* 2 3 * trace/beauty/ioctl.c 3 4 * 4 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 8 #include "trace/beauty/beauty.h"
+1 -2
tools/perf/trace/beauty/kcmp.c
··· 1 + // SPDX-License-Identifier: LGPL-2.1 1 2 /* 2 3 * trace/beauty/kcmp.c 3 4 * 4 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 8 #include "trace/beauty/beauty.h"
+1
tools/perf/trace/beauty/kcmp_type.sh
··· 1 1 #!/bin/sh 2 + # SPDX-License-Identifier: LGPL-2.1 2 3 3 4 [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ 4 5
+1
tools/perf/trace/beauty/kvm_ioctl.sh
··· 1 1 #!/bin/sh 2 + # SPDX-License-Identifier: LGPL-2.1 2 3 3 4 [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ 4 5
+1
tools/perf/trace/beauty/madvise_behavior.sh
··· 1 1 #!/bin/sh 2 + # SPDX-License-Identifier: LGPL-2.1 2 3 3 4 [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/asm-generic/ 4 5
+12 -38
tools/perf/trace/beauty/mmap.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 1 + // SPDX-License-Identifier: LGPL-2.1 2 2 #include <uapi/linux/mman.h> 3 + #include <linux/log2.h> 3 4 4 5 static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, 5 6 struct syscall_arg *arg) ··· 31 30 32 31 #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot 33 32 33 + static size_t mmap__scnprintf_flags(unsigned long flags, char *bf, size_t size) 34 + { 35 + #include "trace/beauty/generated/mmap_flags_array.c" 36 + static DEFINE_STRARRAY(mmap_flags); 37 + 38 + return strarray__scnprintf_flags(&strarray__mmap_flags, bf, size, flags); 39 + } 40 + 34 41 static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, 35 42 struct syscall_arg *arg) 36 43 { 37 - int printed = 0, flags = arg->val; 44 + unsigned long flags = arg->val; 38 45 39 46 if (flags & MAP_ANONYMOUS) 40 47 arg->mask |= (1 << 4) | (1 << 5); /* Mask 4th ('fd') and 5th ('offset') args, ignored */ 41 48 42 - #define P_MMAP_FLAG(n) \ 43 - if (flags & MAP_##n) { \ 44 - printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ 45 - flags &= ~MAP_##n; \ 46 - } 47 - 48 - P_MMAP_FLAG(SHARED); 49 - P_MMAP_FLAG(PRIVATE); 50 - #ifdef MAP_32BIT 51 - P_MMAP_FLAG(32BIT); 52 - #endif 53 - P_MMAP_FLAG(ANONYMOUS); 54 - P_MMAP_FLAG(DENYWRITE); 55 - P_MMAP_FLAG(EXECUTABLE); 56 - P_MMAP_FLAG(FILE); 57 - P_MMAP_FLAG(FIXED); 58 - #ifdef MAP_FIXED_NOREPLACE 59 - P_MMAP_FLAG(FIXED_NOREPLACE); 60 - #endif 61 - P_MMAP_FLAG(GROWSDOWN); 62 - P_MMAP_FLAG(HUGETLB); 63 - P_MMAP_FLAG(LOCKED); 64 - P_MMAP_FLAG(NONBLOCK); 65 - P_MMAP_FLAG(NORESERVE); 66 - P_MMAP_FLAG(POPULATE); 67 - P_MMAP_FLAG(STACK); 68 - P_MMAP_FLAG(UNINITIALIZED); 69 - #ifdef MAP_SYNC 70 - P_MMAP_FLAG(SYNC); 71 - #endif 72 - #undef P_MMAP_FLAG 73 - 74 - if (flags) 75 - printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); 76 - 77 - return printed; 49 + return mmap__scnprintf_flags(flags, bf, size); 78 50 } 79 51 80 52 #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
+32
tools/perf/trace/beauty/mmap_flags.sh
··· 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"
+1 -1
tools/perf/trace/beauty/mode_t.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 1 + // SPDX-License-Identifier: LGPL-2.1 2 2 #include <sys/types.h> 3 3 #include <sys/stat.h> 4 4 #include <unistd.h>
+43
tools/perf/trace/beauty/mount_flags.c
··· 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 + }
+15
tools/perf/trace/beauty/mount_flags.sh
··· 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"
+1 -1
tools/perf/trace/beauty/msg_flags.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 1 + // SPDX-License-Identifier: LGPL-2.1 2 2 #include <sys/types.h> 3 3 #include <sys/socket.h> 4 4
+1 -1
tools/perf/trace/beauty/open_flags.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 1 + // SPDX-License-Identifier: LGPL-2.1 2 2 #include <sys/types.h> 3 3 #include <sys/stat.h> 4 4 #include <fcntl.h>
+1 -1
tools/perf/trace/beauty/perf_event_open.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 1 + // SPDX-License-Identifier: LGPL-2.1 2 2 #ifndef PERF_FLAG_FD_NO_GROUP 3 3 # define PERF_FLAG_FD_NO_GROUP (1UL << 0) 4 4 #endif
+1
tools/perf/trace/beauty/perf_ioctl.sh
··· 1 1 #!/bin/sh 2 + # SPDX-License-Identifier: LGPL-2.1 2 3 3 4 [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ 4 5
+2 -1
tools/perf/trace/beauty/pid.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 1 + // SPDX-License-Identifier: LGPL-2.1 2 + 2 3 size_t syscall_arg__scnprintf_pid(char *bf, size_t size, struct syscall_arg *arg) 3 4 { 4 5 int pid = arg->val;
+17 -13
tools/perf/trace/beauty/pkey_alloc.c
··· 1 + // SPDX-License-Identifier: LGPL-2.1 1 2 /* 2 3 * trace/beauty/pkey_alloc.c 3 4 * 4 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 8 #include "trace/beauty/beauty.h" 10 9 #include <linux/kernel.h> 11 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 14 int i, printed = 0; 16 15 17 - #include "trace/beauty/generated/pkey_alloc_access_rights_array.c" 18 - static DEFINE_STRARRAY(pkey_alloc_access_rights); 19 - 20 - if (access_rights == 0) { 21 - const char *s = strarray__pkey_alloc_access_rights.entries[0]; 16 + if (flags == 0) { 17 + const char *s = sa->entries[0]; 22 18 if (s) 23 19 return scnprintf(bf, size, "%s", s); 24 20 return scnprintf(bf, size, "%d", 0); 25 21 } 26 22 27 - for (i = 1; i < strarray__pkey_alloc_access_rights.nr_entries; ++i) { 28 - int bit = 1 << (i - 1); 23 + for (i = 1; i < sa->nr_entries; ++i) { 24 + unsigned long bit = 1UL << (i - 1); 29 25 30 - if (!(access_rights & bit)) 26 + if (!(flags & bit)) 31 27 continue; 32 28 33 29 if (printed != 0) 34 30 printed += scnprintf(bf + printed, size - printed, "|"); 35 31 36 - if (strarray__pkey_alloc_access_rights.entries[i] != NULL) 37 - printed += scnprintf(bf + printed, size - printed, "%s", strarray__pkey_alloc_access_rights.entries[i]); 32 + if (sa->entries[i] != NULL) 33 + printed += scnprintf(bf + printed, size - printed, "%s", sa->entries[i]); 38 34 else 39 35 printed += scnprintf(bf + printed, size - printed, "0x%#", bit); 40 36 } 41 37 42 38 return printed; 39 + } 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); 43 47 } 44 48 45 49 size_t syscall_arg__scnprintf_pkey_alloc_access_rights(char *bf, size_t size, struct syscall_arg *arg)
+1
tools/perf/trace/beauty/pkey_alloc_access_rights.sh
··· 1 1 #!/bin/sh 2 + # SPDX-License-Identifier: LGPL-2.1 2 3 3 4 [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/asm-generic/ 4 5
+1 -2
tools/perf/trace/beauty/prctl.c
··· 1 + // SPDX-License-Identifier: LGPL-2.1 1 2 /* 2 3 * trace/beauty/prctl.c 3 4 * 4 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 8 #include "trace/beauty/beauty.h"
+1
tools/perf/trace/beauty/prctl_option.sh
··· 1 1 #!/bin/sh 2 + # SPDX-License-Identifier: LGPL-2.1 2 3 3 4 [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ 4 5
+1 -1
tools/perf/trace/beauty/sched_policy.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 1 + // SPDX-License-Identifier: LGPL-2.1 2 2 #include <sched.h> 3 3 4 4 /*
+1 -1
tools/perf/trace/beauty/seccomp.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 1 + // SPDX-License-Identifier: LGPL-2.1 2 2 #ifndef SECCOMP_SET_MODE_STRICT 3 3 #define SECCOMP_SET_MODE_STRICT 0 4 4 #endif
+1 -1
tools/perf/trace/beauty/signum.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 1 + // SPDX-License-Identifier: LGPL-2.1 2 2 #include <signal.h> 3 3 4 4 static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
+1
tools/perf/trace/beauty/sndrv_ctl_ioctl.sh
··· 1 1 #!/bin/sh 2 + # SPDX-License-Identifier: LGPL-2.1 2 3 3 4 [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/sound/ 4 5
+1
tools/perf/trace/beauty/sndrv_pcm_ioctl.sh
··· 1 1 #!/bin/sh 2 + # SPDX-License-Identifier: LGPL-2.1 2 3 3 4 [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/sound/ 4 5
+1 -1
tools/perf/trace/beauty/sockaddr.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 1 + // SPDX-License-Identifier: LGPL-2.1 2 2 // Copyright (C) 2018, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> 3 3 4 4 #include "trace/beauty/beauty.h"
+1 -1
tools/perf/trace/beauty/socket.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 1 + // SPDX-License-Identifier: LGPL-2.1 2 2 /* 3 3 * trace/beauty/socket.c 4 4 *
+1
tools/perf/trace/beauty/socket_ipproto.sh
··· 1 1 #!/bin/sh 2 + # SPDX-License-Identifier: LGPL-2.1 2 3 3 4 [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ 4 5
+1 -1
tools/perf/trace/beauty/socket_type.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 1 + // SPDX-License-Identifier: LGPL-2.1 2 2 #include <sys/types.h> 3 3 #include <sys/socket.h> 4 4
+1 -2
tools/perf/trace/beauty/statx.c
··· 1 + // SPDX-License-Identifier: LGPL-2.1 1 2 /* 2 3 * trace/beauty/statx.c 3 4 * 4 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 8 #include "trace/beauty/beauty.h"
+1
tools/perf/trace/beauty/vhost_virtio_ioctl.sh
··· 1 1 #!/bin/sh 2 + # SPDX-License-Identifier: LGPL-2.1 2 3 3 4 [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ 4 5
+1 -1
tools/perf/trace/beauty/waitid_options.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 1 + // SPDX-License-Identifier: LGPL-2.1 2 2 #include <sys/types.h> 3 3 #include <sys/wait.h> 4 4
+8
tools/perf/util/annotate.c
··· 139 139 #include "arch/x86/annotate/instructions.c" 140 140 #include "arch/powerpc/annotate/instructions.c" 141 141 #include "arch/s390/annotate/instructions.c" 142 + #include "arch/sparc/annotate/instructions.c" 142 143 143 144 static struct arch architectures[] = { 144 145 { ··· 168 167 .name = "s390", 169 168 .init = s390__annotate_init, 170 169 .objdump = { 170 + .comment_char = '#', 171 + }, 172 + }, 173 + { 174 + .name = "sparc", 175 + .init = sparc__annotate_init, 176 + .objdump = { 171 177 .comment_char = '#', 172 178 }, 173 179 },
+12 -5
tools/perf/util/auxtrace.c
··· 962 962 #define PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ 64 963 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 968 synth_opts->branches = true; 969 969 synth_opts->transactions = true; 970 970 synth_opts->ptwrites = true; 971 971 synth_opts->pwr_events = true; 972 972 synth_opts->errors = true; 973 - synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; 974 - synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; 973 + if (no_sample) { 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 982 synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; 976 983 synth_opts->last_branch_sz = PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; 977 984 synth_opts->initial_skip = 0; ··· 1006 999 } 1007 1000 1008 1001 if (!str) { 1009 - itrace_synth_opts__set_default(synth_opts); 1002 + itrace_synth_opts__set_default(synth_opts, false); 1010 1003 return 0; 1011 1004 } 1012 1005
+4 -1
tools/perf/util/auxtrace.h
··· 58 58 /** 59 59 * struct itrace_synth_opts - AUX area tracing synthesis options. 60 60 * @set: indicates whether or not options have been set 61 + * @default_no_sample: Default to no sampling. 61 62 * @inject: indicates the event (not just the sample) must be fully synthesized 62 63 * because 'perf inject' will write it out 63 64 * @instructions: whether to synthesize 'instructions' events ··· 83 82 */ 84 83 struct itrace_synth_opts { 85 84 bool set; 85 + bool default_no_sample; 86 86 bool inject; 87 87 bool instructions; 88 88 bool branches; ··· 530 528 union perf_event *event); 531 529 int itrace_parse_synth_opts(const struct option *opt, const char *str, 532 530 int unset); 533 - void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts); 531 + void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts, 532 + bool no_sample); 534 533 535 534 size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp); 536 535 void perf_session__auxtrace_error_inc(struct perf_session *session,
+32 -10
tools/perf/util/cs-etm.c
··· 244 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 268 static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u64 address, 248 269 size_t size, u8 *buffer) 249 270 { ··· 279 258 return -1; 280 259 281 260 machine = etmq->etm->machine; 282 - if (address >= etmq->etm->kernel_start) 283 - cpumode = PERF_RECORD_MISC_KERNEL; 284 - else 285 - cpumode = PERF_RECORD_MISC_USER; 261 + cpumode = cs_etm__cpu_mode(etmq, address); 286 262 287 263 thread = etmq->thread; 288 264 if (!thread) { ··· 671 653 struct perf_sample sample = {.ip = 0,}; 672 654 673 655 event->sample.header.type = PERF_RECORD_SAMPLE; 674 - event->sample.header.misc = PERF_RECORD_MISC_USER; 656 + event->sample.header.misc = cs_etm__cpu_mode(etmq, addr); 675 657 event->sample.header.size = sizeof(struct perf_event_header); 676 658 677 659 sample.ip = addr; ··· 683 665 sample.cpu = etmq->packet->cpu; 684 666 sample.flags = 0; 685 667 sample.insn_len = 1; 686 - sample.cpumode = event->header.misc; 668 + sample.cpumode = event->sample.header.misc; 687 669 688 670 if (etm->synth_opts.last_branch) { 689 671 cs_etm__copy_last_branch_rb(etmq); ··· 724 706 u64 nr; 725 707 struct branch_entry entries; 726 708 } dummy_bs; 709 + u64 ip; 710 + 711 + ip = cs_etm__last_executed_instr(etmq->prev_packet); 727 712 728 713 event->sample.header.type = PERF_RECORD_SAMPLE; 729 - event->sample.header.misc = PERF_RECORD_MISC_USER; 714 + event->sample.header.misc = cs_etm__cpu_mode(etmq, ip); 730 715 event->sample.header.size = sizeof(struct perf_event_header); 731 716 732 - sample.ip = cs_etm__last_executed_instr(etmq->prev_packet); 717 + sample.ip = ip; 733 718 sample.pid = etmq->pid; 734 719 sample.tid = etmq->tid; 735 720 sample.addr = cs_etm__first_executed_instr(etmq->packet); ··· 741 720 sample.period = 1; 742 721 sample.cpu = etmq->packet->cpu; 743 722 sample.flags = 0; 744 - sample.cpumode = PERF_RECORD_MISC_USER; 723 + sample.cpumode = event->sample.header.misc; 745 724 746 725 /* 747 726 * perf report cannot handle events without a branch stack ··· 1453 1432 if (session->itrace_synth_opts && session->itrace_synth_opts->set) { 1454 1433 etm->synth_opts = *session->itrace_synth_opts; 1455 1434 } else { 1456 - itrace_synth_opts__set_default(&etm->synth_opts); 1435 + itrace_synth_opts__set_default(&etm->synth_opts, 1436 + session->itrace_synth_opts->default_no_sample); 1457 1437 etm->synth_opts.callchain = false; 1458 1438 } 1459 1439
+1
tools/perf/util/env.h
··· 63 63 struct numa_node *numa_nodes; 64 64 struct memory_node *memory_nodes; 65 65 unsigned long long memory_bsize; 66 + u64 clockid_res_ns; 66 67 }; 67 68 68 69 extern struct perf_env perf_env;
+1
tools/perf/util/event.c
··· 308 308 event->fork.pid = tgid; 309 309 event->fork.tid = pid; 310 310 event->fork.header.type = PERF_RECORD_FORK; 311 + event->fork.header.misc = PERF_RECORD_MISC_FORK_EXEC; 311 312 312 313 event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size); 313 314
+1 -1
tools/perf/util/evlist.c
··· 358 358 struct perf_evsel *pos; 359 359 360 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 362 continue; 363 363 perf_evsel__disable(pos); 364 364 }
+21 -6
tools/perf/util/evsel.c
··· 232 232 evsel->leader = evsel; 233 233 evsel->unit = ""; 234 234 evsel->scale = 1.0; 235 + evsel->max_events = ULONG_MAX; 235 236 evsel->evlist = NULL; 236 237 evsel->bpf_fd = -1; 237 238 INIT_LIST_HEAD(&evsel->node); ··· 794 793 case PERF_EVSEL__CONFIG_TERM_MAX_STACK: 795 794 max_stack = term->val.max_stack; 796 795 break; 796 + case PERF_EVSEL__CONFIG_TERM_MAX_EVENTS: 797 + evsel->max_events = term->val.max_events; 798 + break; 797 799 case PERF_EVSEL__CONFIG_TERM_INHERIT: 798 800 /* 799 801 * attr->inherit should has already been set by ··· 1207 1203 1208 1204 int perf_evsel__enable(struct perf_evsel *evsel) 1209 1205 { 1210 - return perf_evsel__run_ioctl(evsel, 1211 - PERF_EVENT_IOC_ENABLE, 1212 - 0); 1206 + int err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, 0); 1207 + 1208 + if (!err) 1209 + evsel->disabled = false; 1210 + 1211 + return err; 1213 1212 } 1214 1213 1215 1214 int perf_evsel__disable(struct perf_evsel *evsel) 1216 1215 { 1217 - return perf_evsel__run_ioctl(evsel, 1218 - PERF_EVENT_IOC_DISABLE, 1219 - 0); 1216 + int err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, 0); 1217 + /* 1218 + * We mark it disabled here so that tools that disable a event can 1219 + * ignore events after they disable it. I.e. the ring buffer may have 1220 + * already a few more events queued up before the kernel got the stop 1221 + * request. 1222 + */ 1223 + if (!err) 1224 + evsel->disabled = true; 1225 + 1226 + return err; 1220 1227 } 1221 1228 1222 1229 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
+5
tools/perf/util/evsel.h
··· 46 46 PERF_EVSEL__CONFIG_TERM_STACK_USER, 47 47 PERF_EVSEL__CONFIG_TERM_INHERIT, 48 48 PERF_EVSEL__CONFIG_TERM_MAX_STACK, 49 + PERF_EVSEL__CONFIG_TERM_MAX_EVENTS, 49 50 PERF_EVSEL__CONFIG_TERM_OVERWRITE, 50 51 PERF_EVSEL__CONFIG_TERM_DRV_CFG, 51 52 PERF_EVSEL__CONFIG_TERM_BRANCH, ··· 66 65 bool inherit; 67 66 bool overwrite; 68 67 char *branch; 68 + unsigned long max_events; 69 69 } val; 70 70 bool weak; 71 71 }; ··· 101 99 struct perf_counts *prev_raw_counts; 102 100 int idx; 103 101 u32 ids; 102 + unsigned long max_events; 103 + unsigned long nr_events_printed; 104 104 char *name; 105 105 double scale; 106 106 const char *unit; ··· 123 119 bool snapshot; 124 120 bool supported; 125 121 bool needs_swap; 122 + bool disabled; 126 123 bool no_aux_samples; 127 124 bool immediate; 128 125 bool system_wide;
+6
tools/perf/util/genelf.h
··· 29 29 #elif defined(__powerpc__) 30 30 #define GEN_ELF_ARCH EM_PPC 31 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 38 #else 33 39 #error "unsupported architecture" 34 40 #endif
+23
tools/perf/util/header.c
··· 1034 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 1044 static int cpu_cache_level__sort(const void *a, const void *b) 1038 1045 { 1039 1046 struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a; ··· 1513 1506 ph->env.cpu[i].core_id, ph->env.cpu[i].socket_id); 1514 1507 } else 1515 1508 fprintf(fp, "# Core ID and Socket ID information is not available\n"); 1509 + } 1510 + 1511 + static void print_clockid(struct feat_fd *ff, FILE *fp) 1512 + { 1513 + fprintf(fp, "# clockid frequency: %"PRIu64" MHz\n", 1514 + ff->ph->env.clockid_res_ns * 1000); 1516 1515 } 1517 1516 1518 1517 static void free_event_desc(struct perf_evsel *events) ··· 2544 2531 return ret; 2545 2532 } 2546 2533 2534 + static int process_clockid(struct feat_fd *ff, 2535 + void *data __maybe_unused) 2536 + { 2537 + if (do_read_u64(ff, &ff->ph->env.clockid_res_ns)) 2538 + return -1; 2539 + 2540 + return 0; 2541 + } 2542 + 2547 2543 struct feature_ops { 2548 2544 int (*write)(struct feat_fd *ff, struct perf_evlist *evlist); 2549 2545 void (*print)(struct feat_fd *ff, FILE *fp); ··· 2612 2590 FEAT_OPN(CACHE, cache, true), 2613 2591 FEAT_OPR(SAMPLE_TIME, sample_time, false), 2614 2592 FEAT_OPR(MEM_TOPOLOGY, mem_topology, true), 2593 + FEAT_OPR(CLOCKID, clockid, false) 2615 2594 }; 2616 2595 2617 2596 struct header_print_data {
+1
tools/perf/util/header.h
··· 38 38 HEADER_CACHE, 39 39 HEADER_SAMPLE_TIME, 40 40 HEADER_MEM_TOPOLOGY, 41 + HEADER_CLOCKID, 41 42 HEADER_LAST_FEATURE, 42 43 HEADER_FEAT_BITS = 256, 43 44 };
+14 -6
tools/perf/util/intel-bts.c
··· 269 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 279 static int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq, 273 280 struct branch *branch) 274 281 { ··· 288 281 bts->num_events++ <= bts->synth_opts.initial_skip) 289 282 return 0; 290 283 291 - event.sample.header.type = PERF_RECORD_SAMPLE; 292 - event.sample.header.misc = PERF_RECORD_MISC_USER; 293 - event.sample.header.size = sizeof(struct perf_event_header); 294 - 295 - sample.cpumode = PERF_RECORD_MISC_USER; 296 284 sample.ip = le64_to_cpu(branch->from); 285 + sample.cpumode = intel_bts_cpumode(bts, sample.ip); 297 286 sample.pid = btsq->pid; 298 287 sample.tid = btsq->tid; 299 288 sample.addr = le64_to_cpu(branch->to); ··· 300 297 sample.flags = btsq->sample_flags; 301 298 sample.insn_len = btsq->intel_pt_insn.length; 302 299 memcpy(sample.insn, btsq->intel_pt_insn.buf, INTEL_PT_INSN_BUF_SZ); 300 + 301 + event.sample.header.type = PERF_RECORD_SAMPLE; 302 + event.sample.header.misc = sample.cpumode; 303 + event.sample.header.size = sizeof(struct perf_event_header); 303 304 304 305 if (bts->synth_opts.inject) { 305 306 event.sample.header.size = bts->branches_event_size; ··· 917 910 if (session->itrace_synth_opts && session->itrace_synth_opts->set) { 918 911 bts->synth_opts = *session->itrace_synth_opts; 919 912 } else { 920 - itrace_synth_opts__set_default(&bts->synth_opts); 913 + itrace_synth_opts__set_default(&bts->synth_opts, 914 + session->itrace_synth_opts->default_no_sample); 921 915 if (session->itrace_synth_opts) 922 916 bts->synth_opts.thread_stack = 923 917 session->itrace_synth_opts->thread_stack;
+19 -12
tools/perf/util/intel-pt.c
··· 407 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 417 static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, 411 418 uint64_t *insn_cnt_ptr, uint64_t *ip, 412 419 uint64_t to_ip, uint64_t max_insn_cnt, ··· 436 429 if (to_ip && *ip == to_ip) 437 430 goto out_no_cache; 438 431 439 - if (*ip >= ptq->pt->kernel_start) 440 - cpumode = PERF_RECORD_MISC_KERNEL; 441 - else 442 - cpumode = PERF_RECORD_MISC_USER; 432 + cpumode = intel_pt_cpumode(ptq->pt, *ip); 443 433 444 434 thread = ptq->thread; 445 435 if (!thread) { ··· 763 759 if (pt->synth_opts.callchain) { 764 760 size_t sz = sizeof(struct ip_callchain); 765 761 766 - sz += pt->synth_opts.callchain_sz * sizeof(u64); 762 + /* Add 1 to callchain_sz for callchain context */ 763 + sz += (pt->synth_opts.callchain_sz + 1) * sizeof(u64); 767 764 ptq->chain = zalloc(sz); 768 765 if (!ptq->chain) 769 766 goto out_free; ··· 1063 1058 union perf_event *event, 1064 1059 struct perf_sample *sample) 1065 1060 { 1066 - event->sample.header.type = PERF_RECORD_SAMPLE; 1067 - event->sample.header.misc = PERF_RECORD_MISC_USER; 1068 - event->sample.header.size = sizeof(struct perf_event_header); 1069 - 1070 1061 if (!pt->timeless_decoding) 1071 1062 sample->time = tsc_to_perf_time(ptq->timestamp, &pt->tc); 1072 1063 1073 - sample->cpumode = PERF_RECORD_MISC_USER; 1074 1064 sample->ip = ptq->state->from_ip; 1065 + sample->cpumode = intel_pt_cpumode(pt, sample->ip); 1075 1066 sample->pid = ptq->pid; 1076 1067 sample->tid = ptq->tid; 1077 1068 sample->addr = ptq->state->to_ip; ··· 1076 1075 sample->flags = ptq->flags; 1077 1076 sample->insn_len = ptq->insn_len; 1078 1077 memcpy(sample->insn, ptq->insn, INTEL_PT_INSN_BUF_SZ); 1078 + 1079 + event->sample.header.type = PERF_RECORD_SAMPLE; 1080 + event->sample.header.misc = sample->cpumode; 1081 + event->sample.header.size = sizeof(struct perf_event_header); 1079 1082 } 1080 1083 1081 1084 static int intel_pt_inject_event(union perf_event *event, ··· 1165 1160 1166 1161 if (pt->synth_opts.callchain) { 1167 1162 thread_stack__sample(ptq->thread, ptq->chain, 1168 - pt->synth_opts.callchain_sz, sample->ip); 1163 + pt->synth_opts.callchain_sz + 1, 1164 + sample->ip, pt->kernel_start); 1169 1165 sample->callchain = ptq->chain; 1170 1166 } 1171 1167 ··· 2565 2559 if (session->itrace_synth_opts && session->itrace_synth_opts->set) { 2566 2560 pt->synth_opts = *session->itrace_synth_opts; 2567 2561 } else { 2568 - itrace_synth_opts__set_default(&pt->synth_opts); 2562 + itrace_synth_opts__set_default(&pt->synth_opts, 2563 + session->itrace_synth_opts->default_no_sample); 2569 2564 if (use_browser != -1) { 2570 2565 pt->synth_opts.branches = false; 2571 2566 pt->synth_opts.callchain = true;
+52 -2
tools/perf/util/machine.c
··· 1708 1708 struct thread *parent = machine__findnew_thread(machine, 1709 1709 event->fork.ppid, 1710 1710 event->fork.ptid); 1711 + bool do_maps_clone = true; 1711 1712 int err = 0; 1712 1713 1713 1714 if (dump_trace) ··· 1737 1736 1738 1737 thread = machine__findnew_thread(machine, event->fork.pid, 1739 1738 event->fork.tid); 1739 + /* 1740 + * When synthesizing FORK events, we are trying to create thread 1741 + * objects for the already running tasks on the machine. 1742 + * 1743 + * Normally, for a kernel FORK event, we want to clone the parent's 1744 + * maps because that is what the kernel just did. 1745 + * 1746 + * But when synthesizing, this should not be done. If we do, we end up 1747 + * with overlapping maps as we process the sythesized MMAP2 events that 1748 + * get delivered shortly thereafter. 1749 + * 1750 + * Use the FORK event misc flags in an internal way to signal this 1751 + * situation, so we can elide the map clone when appropriate. 1752 + */ 1753 + if (event->fork.header.misc & PERF_RECORD_MISC_FORK_EXEC) 1754 + do_maps_clone = false; 1740 1755 1741 1756 if (thread == NULL || parent == NULL || 1742 - thread__fork(thread, parent, sample->time) < 0) { 1757 + thread__fork(thread, parent, sample->time, do_maps_clone) < 0) { 1743 1758 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); 1744 1759 err = -1; 1745 1760 } ··· 2157 2140 return 0; 2158 2141 } 2159 2142 2143 + static int find_prev_cpumode(struct ip_callchain *chain, struct thread *thread, 2144 + struct callchain_cursor *cursor, 2145 + struct symbol **parent, 2146 + struct addr_location *root_al, 2147 + u8 *cpumode, int ent) 2148 + { 2149 + int err = 0; 2150 + 2151 + while (--ent >= 0) { 2152 + u64 ip = chain->ips[ent]; 2153 + 2154 + if (ip >= PERF_CONTEXT_MAX) { 2155 + err = add_callchain_ip(thread, cursor, parent, 2156 + root_al, cpumode, ip, 2157 + false, NULL, NULL, 0); 2158 + break; 2159 + } 2160 + } 2161 + return err; 2162 + } 2163 + 2160 2164 static int thread__resolve_callchain_sample(struct thread *thread, 2161 2165 struct callchain_cursor *cursor, 2162 2166 struct perf_evsel *evsel, ··· 2284 2246 } 2285 2247 2286 2248 check_calls: 2249 + if (callchain_param.order != ORDER_CALLEE) { 2250 + err = find_prev_cpumode(chain, thread, cursor, parent, root_al, 2251 + &cpumode, chain->nr - first_call); 2252 + if (err) 2253 + return (err < 0) ? err : 0; 2254 + } 2287 2255 for (i = first_call, nr_entries = 0; 2288 2256 i < chain_nr && nr_entries < max_stack; i++) { 2289 2257 u64 ip; ··· 2304 2260 continue; 2305 2261 #endif 2306 2262 ip = chain->ips[j]; 2307 - 2308 2263 if (ip < PERF_CONTEXT_MAX) 2309 2264 ++nr_entries; 2265 + else if (callchain_param.order != ORDER_CALLEE) { 2266 + err = find_prev_cpumode(chain, thread, cursor, parent, 2267 + root_al, &cpumode, j); 2268 + if (err) 2269 + return (err < 0) ? err : 0; 2270 + continue; 2271 + } 2310 2272 2311 2273 err = add_callchain_ip(thread, cursor, parent, 2312 2274 root_al, &cpumode, ip,
+8
tools/perf/util/parse-events.c
··· 926 926 [PARSE_EVENTS__TERM_TYPE_NOINHERIT] = "no-inherit", 927 927 [PARSE_EVENTS__TERM_TYPE_INHERIT] = "inherit", 928 928 [PARSE_EVENTS__TERM_TYPE_MAX_STACK] = "max-stack", 929 + [PARSE_EVENTS__TERM_TYPE_MAX_EVENTS] = "nr", 929 930 [PARSE_EVENTS__TERM_TYPE_OVERWRITE] = "overwrite", 930 931 [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE] = "no-overwrite", 931 932 [PARSE_EVENTS__TERM_TYPE_DRV_CFG] = "driver-config", ··· 1038 1037 case PARSE_EVENTS__TERM_TYPE_MAX_STACK: 1039 1038 CHECK_TYPE_VAL(NUM); 1040 1039 break; 1040 + case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: 1041 + CHECK_TYPE_VAL(NUM); 1042 + break; 1041 1043 default: 1042 1044 err->str = strdup("unknown term"); 1043 1045 err->idx = term->err_term; ··· 1088 1084 case PARSE_EVENTS__TERM_TYPE_INHERIT: 1089 1085 case PARSE_EVENTS__TERM_TYPE_NOINHERIT: 1090 1086 case PARSE_EVENTS__TERM_TYPE_MAX_STACK: 1087 + case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: 1091 1088 case PARSE_EVENTS__TERM_TYPE_OVERWRITE: 1092 1089 case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: 1093 1090 return config_term_common(attr, term, err); ··· 1166 1161 break; 1167 1162 case PARSE_EVENTS__TERM_TYPE_MAX_STACK: 1168 1163 ADD_CONFIG_TERM(MAX_STACK, max_stack, term->val.num); 1164 + break; 1165 + case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: 1166 + ADD_CONFIG_TERM(MAX_EVENTS, max_events, term->val.num); 1169 1167 break; 1170 1168 case PARSE_EVENTS__TERM_TYPE_OVERWRITE: 1171 1169 ADD_CONFIG_TERM(OVERWRITE, overwrite, term->val.num ? 1 : 0);
+1
tools/perf/util/parse-events.h
··· 71 71 PARSE_EVENTS__TERM_TYPE_NOINHERIT, 72 72 PARSE_EVENTS__TERM_TYPE_INHERIT, 73 73 PARSE_EVENTS__TERM_TYPE_MAX_STACK, 74 + PARSE_EVENTS__TERM_TYPE_MAX_EVENTS, 74 75 PARSE_EVENTS__TERM_TYPE_NOOVERWRITE, 75 76 PARSE_EVENTS__TERM_TYPE_OVERWRITE, 76 77 PARSE_EVENTS__TERM_TYPE_DRV_CFG,
+1
tools/perf/util/parse-events.l
··· 269 269 call-graph { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CALLGRAPH); } 270 270 stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); } 271 271 max-stack { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_STACK); } 272 + nr { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_EVENTS); } 272 273 inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); } 273 274 no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } 274 275 overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_OVERWRITE); }
+11 -1
tools/perf/util/symbol-elf.c
··· 324 324 plt_entry_size = 16; 325 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 338 plt_header_size = shdr_plt.sh_entsize; 329 339 plt_entry_size = shdr_plt.sh_entsize; 330 340 break;
+2 -1
tools/perf/util/symbol.h
··· 123 123 const char *vmlinux_name, 124 124 *kallsyms_name, 125 125 *source_prefix, 126 - *field_sep; 126 + *field_sep, 127 + *graph_function; 127 128 const char *default_guest_vmlinux_name, 128 129 *default_guest_kallsyms, 129 130 *default_guest_modules;
+36 -10
tools/perf/util/thread-stack.c
··· 310 310 } 311 311 } 312 312 313 - void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, 314 - size_t sz, u64 ip) 313 + static inline u64 callchain_context(u64 ip, u64 kernel_start) 315 314 { 316 - size_t i; 315 + return ip < kernel_start ? PERF_CONTEXT_USER : PERF_CONTEXT_KERNEL; 316 + } 317 317 318 - if (!thread || !thread->ts) 319 - chain->nr = 1; 320 - else 321 - chain->nr = min(sz, thread->ts->cnt + 1); 318 + void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, 319 + size_t sz, u64 ip, u64 kernel_start) 320 + { 321 + u64 context = callchain_context(ip, kernel_start); 322 + u64 last_context; 323 + size_t i, j; 322 324 323 - chain->ips[0] = ip; 325 + if (sz < 2) { 326 + chain->nr = 0; 327 + return; 328 + } 324 329 325 - for (i = 1; i < chain->nr; i++) 326 - chain->ips[i] = thread->ts->stack[thread->ts->cnt - i].ret_addr; 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 + } 351 + 352 + chain->nr = i; 327 353 } 328 354 329 355 struct call_return_processor *
+1 -1
tools/perf/util/thread-stack.h
··· 84 84 u64 to_ip, u16 insn_len, u64 trace_nr); 85 85 void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr); 86 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 88 int thread_stack__flush(struct thread *thread); 89 89 void thread_stack__free(struct thread *thread); 90 90 size_t thread_stack__depth(struct thread *thread);
+5 -8
tools/perf/util/thread.c
··· 330 330 } 331 331 332 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 336 /* This is new thread, we share map groups for process. */ 336 337 if (thread->pid_ == parent->pid_) ··· 342 341 thread->pid_, thread->tid, parent->pid_, parent->tid); 343 342 return 0; 344 343 } 345 - 346 344 /* But this one is new process, copy maps. */ 347 - if (map_groups__clone(thread, parent->mg) < 0) 348 - return -ENOMEM; 349 - 350 - return 0; 345 + return do_maps_clone ? map_groups__clone(thread, parent->mg) : 0; 351 346 } 352 347 353 - int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) 348 + int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp, bool do_maps_clone) 354 349 { 355 350 if (parent->comm_set) { 356 351 const char *comm = thread__comm_str(parent); ··· 359 362 } 360 363 361 364 thread->ppid = parent->tid; 362 - return thread__clone_map_groups(thread, parent); 365 + return thread__clone_map_groups(thread, parent, do_maps_clone); 363 366 } 364 367 365 368 void thread__find_cpumode_addr_location(struct thread *thread, u64 addr,
+3 -1
tools/perf/util/thread.h
··· 42 42 void *addr_space; 43 43 struct unwind_libunwind_ops *unwind_libunwind_ops; 44 44 #endif 45 + bool filter; 46 + int filter_entry_depth; 45 47 }; 46 48 47 49 struct machine; ··· 89 87 struct comm *thread__exec_comm(const struct thread *thread); 90 88 const char *thread__comm_str(const struct thread *thread); 91 89 int thread__insert_map(struct thread *thread, struct map *map); 92 - int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp); 90 + int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp, bool do_maps_clone); 93 91 size_t thread__fprintf(struct thread *thread, FILE *fp); 94 92 95 93 struct thread *thread__main_thread(struct machine *machine, struct thread *thread);
+2 -2
tools/perf/util/unwind-libdw.c
··· 45 45 Dwarf_Addr s; 46 46 47 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 49 mod = 0; 50 50 } 51 51 52 52 if (!mod) 53 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 55 false); 56 56 57 57 return mod && dwfl_addrmodule(ui->dwfl, ip) == mod ? 0 : -1;