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