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

Merge tag 'perf-core-for-mingo-4.12-20170331' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

New features:

- Beautify the statx syscall arguments in 'perf trace' (Arnaldo Carvalho de Melo)

e.g.:

System wide strace like session:

# trace -e statx
16612.967 ( 0.028 ms): statx/4562 statx(dfd: CWD, filename: /tmp/statx, flags: SYMLINK_NOFOLLOW, mask: TYPE|MODE|NLINK|UID|GID|ATIME|MTIME|CTIME|INO|SIZE|BLOCKS|BTIME, buffer: 0x7ffef195d660) = 0
36050.891 ( 0.007 ms): statx/4576 statx(dfd: CWD, filename: /etc/passwd, flags: SYMLINK_NOFOLLOW|STATX_DONT_SYNC, mask: BTIME, buffer: 0x7ffda9bf50f0) = 0
^C#

User visible changes:

- Handle unpaired raw_syscalls:sys_exit events in 'perf trace', i.e. we
shouldn't try to calculate duration or print the timestamp for a missing
matching raw_syscalls:sys_enter (Arnaldo Carvalho de Melo)

- Do not print "cycles: 0" in perf report LBR lines in platforms not
supporting 'cycles', such as Intel's Broadwell (Jin Yao)

- Handle missing $HOME env var (Jiri Olsa)

- Map 8-bit registers (al, bl, etc), not supported in uprobes_events, to
the next best thing (ax, bx, etc) supported (Ravi Bangoria)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>

+730 -426
+1
tools/include/linux/types.h
··· 7 7 8 8 #define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */ 9 9 #include <asm/types.h> 10 + #include <asm/posix_types.h> 10 11 11 12 struct page; 12 13 struct kmem_cache;
+72
tools/include/uapi/linux/fcntl.h
··· 1 + #ifndef _UAPI_LINUX_FCNTL_H 2 + #define _UAPI_LINUX_FCNTL_H 3 + 4 + #include <asm/fcntl.h> 5 + 6 + #define F_SETLEASE (F_LINUX_SPECIFIC_BASE + 0) 7 + #define F_GETLEASE (F_LINUX_SPECIFIC_BASE + 1) 8 + 9 + /* 10 + * Cancel a blocking posix lock; internal use only until we expose an 11 + * asynchronous lock api to userspace: 12 + */ 13 + #define F_CANCELLK (F_LINUX_SPECIFIC_BASE + 5) 14 + 15 + /* Create a file descriptor with FD_CLOEXEC set. */ 16 + #define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6) 17 + 18 + /* 19 + * Request nofications on a directory. 20 + * See below for events that may be notified. 21 + */ 22 + #define F_NOTIFY (F_LINUX_SPECIFIC_BASE+2) 23 + 24 + /* 25 + * Set and get of pipe page size array 26 + */ 27 + #define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7) 28 + #define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8) 29 + 30 + /* 31 + * Set/Get seals 32 + */ 33 + #define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9) 34 + #define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10) 35 + 36 + /* 37 + * Types of seals 38 + */ 39 + #define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */ 40 + #define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */ 41 + #define F_SEAL_GROW 0x0004 /* prevent file from growing */ 42 + #define F_SEAL_WRITE 0x0008 /* prevent writes */ 43 + /* (1U << 31) is reserved for signed error codes */ 44 + 45 + /* 46 + * Types of directory notifications that may be requested. 47 + */ 48 + #define DN_ACCESS 0x00000001 /* File accessed */ 49 + #define DN_MODIFY 0x00000002 /* File modified */ 50 + #define DN_CREATE 0x00000004 /* File created */ 51 + #define DN_DELETE 0x00000008 /* File removed */ 52 + #define DN_RENAME 0x00000010 /* File renamed */ 53 + #define DN_ATTRIB 0x00000020 /* File changed attibutes */ 54 + #define DN_MULTISHOT 0x80000000 /* Don't remove notifier */ 55 + 56 + #define AT_FDCWD -100 /* Special value used to indicate 57 + openat should use the current 58 + working directory. */ 59 + #define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */ 60 + #define AT_REMOVEDIR 0x200 /* Remove directory instead of 61 + unlinking file. */ 62 + #define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */ 63 + #define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */ 64 + #define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */ 65 + 66 + #define AT_STATX_SYNC_TYPE 0x6000 /* Type of synchronisation required from statx() */ 67 + #define AT_STATX_SYNC_AS_STAT 0x0000 /* - Do whatever stat() does */ 68 + #define AT_STATX_FORCE_SYNC 0x2000 /* - Force the attributes to be sync'd with the server */ 69 + #define AT_STATX_DONT_SYNC 0x4000 /* - Don't sync attributes with the server */ 70 + 71 + 72 + #endif /* _UAPI_LINUX_FCNTL_H */
+176
tools/include/uapi/linux/stat.h
··· 1 + #ifndef _UAPI_LINUX_STAT_H 2 + #define _UAPI_LINUX_STAT_H 3 + 4 + #include <linux/types.h> 5 + 6 + #if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) 7 + 8 + #define S_IFMT 00170000 9 + #define S_IFSOCK 0140000 10 + #define S_IFLNK 0120000 11 + #define S_IFREG 0100000 12 + #define S_IFBLK 0060000 13 + #define S_IFDIR 0040000 14 + #define S_IFCHR 0020000 15 + #define S_IFIFO 0010000 16 + #define S_ISUID 0004000 17 + #define S_ISGID 0002000 18 + #define S_ISVTX 0001000 19 + 20 + #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) 21 + #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) 22 + #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) 23 + #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) 24 + #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) 25 + #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) 26 + #define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) 27 + 28 + #define S_IRWXU 00700 29 + #define S_IRUSR 00400 30 + #define S_IWUSR 00200 31 + #define S_IXUSR 00100 32 + 33 + #define S_IRWXG 00070 34 + #define S_IRGRP 00040 35 + #define S_IWGRP 00020 36 + #define S_IXGRP 00010 37 + 38 + #define S_IRWXO 00007 39 + #define S_IROTH 00004 40 + #define S_IWOTH 00002 41 + #define S_IXOTH 00001 42 + 43 + #endif 44 + 45 + /* 46 + * Timestamp structure for the timestamps in struct statx. 47 + * 48 + * tv_sec holds the number of seconds before (negative) or after (positive) 49 + * 00:00:00 1st January 1970 UTC. 50 + * 51 + * tv_nsec holds a number of nanoseconds before (0..-999,999,999 if tv_sec is 52 + * negative) or after (0..999,999,999 if tv_sec is positive) the tv_sec time. 53 + * 54 + * Note that if both tv_sec and tv_nsec are non-zero, then the two values must 55 + * either be both positive or both negative. 56 + * 57 + * __reserved is held in case we need a yet finer resolution. 58 + */ 59 + struct statx_timestamp { 60 + __s64 tv_sec; 61 + __s32 tv_nsec; 62 + __s32 __reserved; 63 + }; 64 + 65 + /* 66 + * Structures for the extended file attribute retrieval system call 67 + * (statx()). 68 + * 69 + * The caller passes a mask of what they're specifically interested in as a 70 + * parameter to statx(). What statx() actually got will be indicated in 71 + * st_mask upon return. 72 + * 73 + * For each bit in the mask argument: 74 + * 75 + * - if the datum is not supported: 76 + * 77 + * - the bit will be cleared, and 78 + * 79 + * - the datum will be set to an appropriate fabricated value if one is 80 + * available (eg. CIFS can take a default uid and gid), otherwise 81 + * 82 + * - the field will be cleared; 83 + * 84 + * - otherwise, if explicitly requested: 85 + * 86 + * - the datum will be synchronised to the server if AT_STATX_FORCE_SYNC is 87 + * set or if the datum is considered out of date, and 88 + * 89 + * - the field will be filled in and the bit will be set; 90 + * 91 + * - otherwise, if not requested, but available in approximate form without any 92 + * effort, it will be filled in anyway, and the bit will be set upon return 93 + * (it might not be up to date, however, and no attempt will be made to 94 + * synchronise the internal state first); 95 + * 96 + * - otherwise the field and the bit will be cleared before returning. 97 + * 98 + * Items in STATX_BASIC_STATS may be marked unavailable on return, but they 99 + * will have values installed for compatibility purposes so that stat() and 100 + * co. can be emulated in userspace. 101 + */ 102 + struct statx { 103 + /* 0x00 */ 104 + __u32 stx_mask; /* What results were written [uncond] */ 105 + __u32 stx_blksize; /* Preferred general I/O size [uncond] */ 106 + __u64 stx_attributes; /* Flags conveying information about the file [uncond] */ 107 + /* 0x10 */ 108 + __u32 stx_nlink; /* Number of hard links */ 109 + __u32 stx_uid; /* User ID of owner */ 110 + __u32 stx_gid; /* Group ID of owner */ 111 + __u16 stx_mode; /* File mode */ 112 + __u16 __spare0[1]; 113 + /* 0x20 */ 114 + __u64 stx_ino; /* Inode number */ 115 + __u64 stx_size; /* File size */ 116 + __u64 stx_blocks; /* Number of 512-byte blocks allocated */ 117 + __u64 __spare1[1]; 118 + /* 0x40 */ 119 + struct statx_timestamp stx_atime; /* Last access time */ 120 + struct statx_timestamp stx_btime; /* File creation time */ 121 + struct statx_timestamp stx_ctime; /* Last attribute change time */ 122 + struct statx_timestamp stx_mtime; /* Last data modification time */ 123 + /* 0x80 */ 124 + __u32 stx_rdev_major; /* Device ID of special file [if bdev/cdev] */ 125 + __u32 stx_rdev_minor; 126 + __u32 stx_dev_major; /* ID of device containing file [uncond] */ 127 + __u32 stx_dev_minor; 128 + /* 0x90 */ 129 + __u64 __spare2[14]; /* Spare space for future expansion */ 130 + /* 0x100 */ 131 + }; 132 + 133 + /* 134 + * Flags to be stx_mask 135 + * 136 + * Query request/result mask for statx() and struct statx::stx_mask. 137 + * 138 + * These bits should be set in the mask argument of statx() to request 139 + * particular items when calling statx(). 140 + */ 141 + #define STATX_TYPE 0x00000001U /* Want/got stx_mode & S_IFMT */ 142 + #define STATX_MODE 0x00000002U /* Want/got stx_mode & ~S_IFMT */ 143 + #define STATX_NLINK 0x00000004U /* Want/got stx_nlink */ 144 + #define STATX_UID 0x00000008U /* Want/got stx_uid */ 145 + #define STATX_GID 0x00000010U /* Want/got stx_gid */ 146 + #define STATX_ATIME 0x00000020U /* Want/got stx_atime */ 147 + #define STATX_MTIME 0x00000040U /* Want/got stx_mtime */ 148 + #define STATX_CTIME 0x00000080U /* Want/got stx_ctime */ 149 + #define STATX_INO 0x00000100U /* Want/got stx_ino */ 150 + #define STATX_SIZE 0x00000200U /* Want/got stx_size */ 151 + #define STATX_BLOCKS 0x00000400U /* Want/got stx_blocks */ 152 + #define STATX_BASIC_STATS 0x000007ffU /* The stuff in the normal stat struct */ 153 + #define STATX_BTIME 0x00000800U /* Want/got stx_btime */ 154 + #define STATX_ALL 0x00000fffU /* All currently supported flags */ 155 + 156 + /* 157 + * Attributes to be found in stx_attributes 158 + * 159 + * These give information about the features or the state of a file that might 160 + * be of use to ordinary userspace programs such as GUIs or ls rather than 161 + * specialised tools. 162 + * 163 + * Note that the flags marked [I] correspond to generic FS_IOC_FLAGS 164 + * semantically. Where possible, the numerical value is picked to correspond 165 + * also. 166 + */ 167 + #define STATX_ATTR_COMPRESSED 0x00000004 /* [I] File is compressed by the fs */ 168 + #define STATX_ATTR_IMMUTABLE 0x00000010 /* [I] File is marked immutable */ 169 + #define STATX_ATTR_APPEND 0x00000020 /* [I] File is append-only */ 170 + #define STATX_ATTR_NODUMP 0x00000040 /* [I] File is not to be dumped */ 171 + #define STATX_ATTR_ENCRYPTED 0x00000800 /* [I] File requires key to decrypt in fs */ 172 + 173 + #define STATX_ATTR_AUTOMOUNT 0x00001000 /* Dir: Automount trigger */ 174 + 175 + 176 + #endif /* _UAPI_LINUX_STAT_H */
+1
tools/perf/Build
··· 50 50 libperf-y += arch/ 51 51 libperf-y += ui/ 52 52 libperf-y += scripts/ 53 + libperf-y += trace/beauty/ 53 54 54 55 gtk-y += ui/gtk/
+2
tools/perf/MANIFEST
··· 73 73 tools/include/uapi/asm-generic/mman.h 74 74 tools/include/uapi/linux/bpf.h 75 75 tools/include/uapi/linux/bpf_common.h 76 + tools/include/uapi/linux/fcntl.h 76 77 tools/include/uapi/linux/hw_breakpoint.h 77 78 tools/include/uapi/linux/mman.h 78 79 tools/include/uapi/linux/perf_event.h 80 + tools/include/uapi/linux/stat.h 79 81 tools/include/linux/poison.h 80 82 tools/include/linux/rbtree.h 81 83 tools/include/linux/rbtree_augmented.h
+1
tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
··· 338 338 329 common pkey_mprotect sys_pkey_mprotect 339 339 330 common pkey_alloc sys_pkey_alloc 340 340 331 common pkey_free sys_pkey_free 341 + 332 common statx sys_statx 341 342 342 343 # 343 344 # x32-specific system call numbers start at 512 to avoid cache impact
+159 -36
tools/perf/arch/x86/util/perf_regs.c
··· 1 1 #include <string.h> 2 + #include <regex.h> 2 3 3 4 #include "../../perf.h" 4 5 #include "../../util/util.h" 5 6 #include "../../util/perf_regs.h" 7 + #include "../../util/debug.h" 6 8 7 9 const struct sample_reg sample_reg_masks[] = { 8 10 SMPL_REG(AX, PERF_REG_X86_AX), ··· 39 37 #define SDT_NAME_REG(n, m) {.sdt_name = "%" #n, .uprobe_name = "%" #m} 40 38 #define SDT_NAME_REG_END {.sdt_name = NULL, .uprobe_name = NULL} 41 39 42 - static const struct sdt_name_reg sdt_reg_renamings[] = { 40 + static const struct sdt_name_reg sdt_reg_tbl[] = { 43 41 SDT_NAME_REG(eax, ax), 44 42 SDT_NAME_REG(rax, ax), 43 + SDT_NAME_REG(al, ax), 44 + SDT_NAME_REG(ah, ax), 45 45 SDT_NAME_REG(ebx, bx), 46 46 SDT_NAME_REG(rbx, bx), 47 + SDT_NAME_REG(bl, bx), 48 + SDT_NAME_REG(bh, bx), 47 49 SDT_NAME_REG(ecx, cx), 48 50 SDT_NAME_REG(rcx, cx), 51 + SDT_NAME_REG(cl, cx), 52 + SDT_NAME_REG(ch, cx), 49 53 SDT_NAME_REG(edx, dx), 50 54 SDT_NAME_REG(rdx, dx), 55 + SDT_NAME_REG(dl, dx), 56 + SDT_NAME_REG(dh, dx), 51 57 SDT_NAME_REG(esi, si), 52 58 SDT_NAME_REG(rsi, si), 53 59 SDT_NAME_REG(sil, si), ··· 97 87 SDT_NAME_REG_END, 98 88 }; 99 89 100 - int sdt_rename_register(char **pdesc, char *old_name) 90 + /* 91 + * Perf only supports OP which is in +/-NUM(REG) form. 92 + * Here plus-minus sign, NUM and parenthesis are optional, 93 + * only REG is mandatory. 94 + * 95 + * SDT events also supports indirect addressing mode with a 96 + * symbol as offset, scaled mode and constants in OP. But 97 + * perf does not support them yet. Below are few examples. 98 + * 99 + * OP with scaled mode: 100 + * (%rax,%rsi,8) 101 + * 10(%ras,%rsi,8) 102 + * 103 + * OP with indirect addressing mode: 104 + * check_action(%rip) 105 + * mp_+52(%rip) 106 + * 44+mp_(%rip) 107 + * 108 + * OP with constant values: 109 + * $0 110 + * $123 111 + * $-1 112 + */ 113 + #define SDT_OP_REGEX "^([+\\-]?)([0-9]*)(\\(?)(%[a-z][a-z0-9]+)(\\)?)$" 114 + 115 + static regex_t sdt_op_regex; 116 + 117 + static int sdt_init_op_regex(void) 101 118 { 102 - const struct sdt_name_reg *rnames = sdt_reg_renamings; 103 - char *new_desc, *old_desc = *pdesc; 104 - size_t prefix_len, sdt_len, uprobe_len, old_desc_len, offset; 105 - int ret = -1; 119 + static int initialized; 120 + int ret = 0; 106 121 107 - while (ret != 0 && rnames->sdt_name != NULL) { 108 - sdt_len = strlen(rnames->sdt_name); 109 - ret = strncmp(old_name, rnames->sdt_name, sdt_len); 110 - rnames += !!ret; 111 - } 112 - 113 - if (rnames->sdt_name == NULL) 122 + if (initialized) 114 123 return 0; 115 124 116 - sdt_len = strlen(rnames->sdt_name); 117 - uprobe_len = strlen(rnames->uprobe_name); 118 - old_desc_len = strlen(old_desc) + 1; 125 + ret = regcomp(&sdt_op_regex, SDT_OP_REGEX, REG_EXTENDED); 126 + if (ret < 0) { 127 + pr_debug4("Regex compilation error.\n"); 128 + return ret; 129 + } 119 130 120 - new_desc = zalloc(old_desc_len + uprobe_len - sdt_len); 121 - if (new_desc == NULL) 122 - return -1; 123 - 124 - /* Copy the chars before the register name (at least '%') */ 125 - prefix_len = old_name - old_desc; 126 - memcpy(new_desc, old_desc, prefix_len); 127 - 128 - /* Copy the new register name */ 129 - memcpy(new_desc + prefix_len, rnames->uprobe_name, uprobe_len); 130 - 131 - /* Copy the chars after the register name (if need be) */ 132 - offset = prefix_len + sdt_len; 133 - if (offset < old_desc_len) 134 - memcpy(new_desc + prefix_len + uprobe_len, 135 - old_desc + offset, old_desc_len - offset); 136 - 137 - free(old_desc); 138 - *pdesc = new_desc; 139 - 131 + initialized = 1; 140 132 return 0; 133 + } 134 + 135 + /* 136 + * Max x86 register name length is 5(ex: %r15d). So, 6th char 137 + * should always contain NULL. This helps to find register name 138 + * length using strlen, insted of maintaing one more variable. 139 + */ 140 + #define SDT_REG_NAME_SIZE 6 141 + 142 + /* 143 + * The uprobe parser does not support all gas register names; 144 + * so, we have to replace them (ex. for x86_64: %rax -> %ax). 145 + * Note: If register does not require renaming, just copy 146 + * paste as it is, but don't leave it empty. 147 + */ 148 + static void sdt_rename_register(char *sdt_reg, int sdt_len, char *uprobe_reg) 149 + { 150 + int i = 0; 151 + 152 + for (i = 0; sdt_reg_tbl[i].sdt_name != NULL; i++) { 153 + if (!strncmp(sdt_reg_tbl[i].sdt_name, sdt_reg, sdt_len)) { 154 + strcpy(uprobe_reg, sdt_reg_tbl[i].uprobe_name); 155 + return; 156 + } 157 + } 158 + 159 + strncpy(uprobe_reg, sdt_reg, sdt_len); 160 + } 161 + 162 + int arch_sdt_arg_parse_op(char *old_op, char **new_op) 163 + { 164 + char new_reg[SDT_REG_NAME_SIZE] = {0}; 165 + int new_len = 0, ret; 166 + /* 167 + * rm[0]: +/-NUM(REG) 168 + * rm[1]: +/- 169 + * rm[2]: NUM 170 + * rm[3]: ( 171 + * rm[4]: REG 172 + * rm[5]: ) 173 + */ 174 + regmatch_t rm[6]; 175 + /* 176 + * Max prefix length is 2 as it may contains sign(+/-) 177 + * and displacement 0 (Both sign and displacement 0 are 178 + * optional so it may be empty). Use one more character 179 + * to hold last NULL so that strlen can be used to find 180 + * prefix length, instead of maintaing one more variable. 181 + */ 182 + char prefix[3] = {0}; 183 + 184 + ret = sdt_init_op_regex(); 185 + if (ret < 0) 186 + return ret; 187 + 188 + /* 189 + * If unsupported OR does not match with regex OR 190 + * register name too long, skip it. 191 + */ 192 + if (strchr(old_op, ',') || strchr(old_op, '$') || 193 + regexec(&sdt_op_regex, old_op, 6, rm, 0) || 194 + rm[4].rm_eo - rm[4].rm_so > SDT_REG_NAME_SIZE) { 195 + pr_debug4("Skipping unsupported SDT argument: %s\n", old_op); 196 + return SDT_ARG_SKIP; 197 + } 198 + 199 + /* 200 + * Prepare prefix. 201 + * If SDT OP has parenthesis but does not provide 202 + * displacement, add 0 for displacement. 203 + * SDT Uprobe Prefix 204 + * ----------------------------- 205 + * +24(%rdi) +24(%di) + 206 + * 24(%rdi) +24(%di) + 207 + * %rdi %di 208 + * (%rdi) +0(%di) +0 209 + * -80(%rbx) -80(%bx) - 210 + */ 211 + if (rm[3].rm_so != rm[3].rm_eo) { 212 + if (rm[1].rm_so != rm[1].rm_eo) 213 + prefix[0] = *(old_op + rm[1].rm_so); 214 + else if (rm[2].rm_so != rm[2].rm_eo) 215 + prefix[0] = '+'; 216 + else 217 + strncpy(prefix, "+0", 2); 218 + } 219 + 220 + /* Rename register */ 221 + sdt_rename_register(old_op + rm[4].rm_so, rm[4].rm_eo - rm[4].rm_so, 222 + new_reg); 223 + 224 + /* Prepare final OP which should be valid for uprobe_events */ 225 + new_len = strlen(prefix) + 226 + (rm[2].rm_eo - rm[2].rm_so) + 227 + (rm[3].rm_eo - rm[3].rm_so) + 228 + strlen(new_reg) + 229 + (rm[5].rm_eo - rm[5].rm_so) + 230 + 1; /* NULL */ 231 + 232 + *new_op = zalloc(new_len); 233 + if (!*new_op) 234 + return -ENOMEM; 235 + 236 + scnprintf(*new_op, new_len, "%.*s%.*s%.*s%.*s%.*s", 237 + strlen(prefix), prefix, 238 + (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so, 239 + (int)(rm[3].rm_eo - rm[3].rm_so), old_op + rm[3].rm_so, 240 + strlen(new_reg), new_reg, 241 + (int)(rm[5].rm_eo - rm[5].rm_so), old_op + rm[5].rm_so); 242 + 243 + return SDT_ARG_VALID; 141 244 }
-13
tools/perf/builtin-help.c
··· 301 301 } 302 302 } 303 303 304 - static int is_perf_command(const char *s) 305 - { 306 - return is_in_cmdlist(&main_cmds, s) || 307 - is_in_cmdlist(&other_cmds, s); 308 - } 309 - 310 304 static const char *cmd_to_page(const char *perf_cmd) 311 305 { 312 306 char *s; ··· 440 446 "perf help [--all] [--man|--web|--info] [command]", 441 447 NULL 442 448 }; 443 - const char *alias; 444 449 int rc; 445 450 446 451 load_command_list("perf-", &main_cmds, &other_cmds); ··· 462 469 printf("\n usage: %s\n\n", perf_usage_string); 463 470 list_common_cmds_help(); 464 471 printf("\n %s\n\n", perf_more_info_string); 465 - return 0; 466 - } 467 - 468 - alias = alias_lookup(argv[0]); 469 - if (alias && !is_perf_command(argv[0])) { 470 - printf("`perf %s' is aliased to `%s'\n", argv[0], alias); 471 472 return 0; 472 473 } 473 474
+39 -18
tools/perf/builtin-trace.c
··· 31 31 #include "util/intlist.h" 32 32 #include "util/thread_map.h" 33 33 #include "util/stat.h" 34 + #include "trace/beauty/beauty.h" 34 35 #include "trace-event.h" 35 36 #include "util/parse-events.h" 36 37 #include "util/bpf-loader.h" ··· 267 266 #define perf_evsel__sc_tp_ptr(evsel, name, sample) \ 268 267 ({ struct syscall_tp *fields = evsel->priv; \ 269 268 fields->name.pointer(&fields->name, sample); }) 270 - 271 - struct syscall_arg { 272 - unsigned long val; 273 - struct thread *thread; 274 - struct trace *trace; 275 - void *parm; 276 - u8 idx; 277 - u8 mask; 278 - }; 279 269 280 270 struct strarray { 281 271 int offset; ··· 763 771 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, }, 764 772 { .name = "stat", .errmsg = true, .alias = "newstat", }, 765 773 { .name = "statfs", .errmsg = true, }, 774 + { .name = "statx", .errmsg = true, 775 + .arg_scnprintf = { [0] = SCA_FDAT, /* flags */ 776 + [2] = SCA_STATX_FLAGS, /* flags */ 777 + [3] = SCA_STATX_MASK, /* mask */ }, }, 766 778 { .name = "swapoff", .errmsg = true, 767 779 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, }, 768 780 { .name = "swapon", .errmsg = true, ··· 817 821 void **arg_parm; 818 822 }; 819 823 820 - static size_t fprintf_duration(unsigned long t, FILE *fp) 824 + /* 825 + * We need to have this 'calculated' boolean because in some cases we really 826 + * don't know what is the duration of a syscall, for instance, when we start 827 + * a session and some threads are waiting for a syscall to finish, say 'poll', 828 + * in which case all we can do is to print "( ? ) for duration and for the 829 + * start timestamp. 830 + */ 831 + static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp) 821 832 { 822 833 double duration = (double)t / NSEC_PER_MSEC; 823 834 size_t printed = fprintf(fp, "("); 824 835 825 - if (duration >= 1.0) 836 + if (!calculated) 837 + printed += fprintf(fp, " ? "); 838 + else if (duration >= 1.0) 826 839 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration); 827 840 else if (duration >= 0.01) 828 841 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration); ··· 1033 1028 return t < (trace->duration_filter * NSEC_PER_MSEC); 1034 1029 } 1035 1030 1036 - static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp) 1031 + static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp) 1037 1032 { 1038 1033 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC; 1039 1034 1040 1035 return fprintf(fp, "%10.3f ", ts); 1036 + } 1037 + 1038 + /* 1039 + * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are 1040 + * using ttrace->entry_time for a thread that receives a sys_exit without 1041 + * first having received a sys_enter ("poll" issued before tracing session 1042 + * starts, lost sys_enter exit due to ring buffer overflow). 1043 + */ 1044 + static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp) 1045 + { 1046 + if (tstamp > 0) 1047 + return __trace__fprintf_tstamp(trace, tstamp, fp); 1048 + 1049 + return fprintf(fp, " ? "); 1041 1050 } 1042 1051 1043 1052 static bool done = false; ··· 1064 1045 } 1065 1046 1066 1047 static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread, 1067 - u64 duration, u64 tstamp, FILE *fp) 1048 + u64 duration, bool duration_calculated, u64 tstamp, FILE *fp) 1068 1049 { 1069 1050 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp); 1070 - printed += fprintf_duration(duration, fp); 1051 + printed += fprintf_duration(duration, duration_calculated, fp); 1071 1052 1072 1053 if (trace->multiple_threads) { 1073 1054 if (trace->show_comm) ··· 1469 1450 1470 1451 duration = sample->time - ttrace->entry_time; 1471 1452 1472 - printed = trace__fprintf_entry_head(trace, trace->current, duration, ttrace->entry_time, trace->output); 1453 + printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output); 1473 1454 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str); 1474 1455 ttrace->entry_pending = false; 1475 1456 ··· 1516 1497 1517 1498 if (sc->is_exit) { 1518 1499 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) { 1519 - trace__fprintf_entry_head(trace, thread, 1, ttrace->entry_time, trace->output); 1500 + trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output); 1520 1501 fprintf(trace->output, "%-70s)\n", ttrace->entry_str); 1521 1502 } 1522 1503 } else { ··· 1564 1545 { 1565 1546 long ret; 1566 1547 u64 duration = 0; 1548 + bool duration_calculated = false; 1567 1549 struct thread *thread; 1568 1550 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0; 1569 1551 struct syscall *sc = trace__syscall_info(trace, evsel, id); ··· 1593 1573 duration = sample->time - ttrace->entry_time; 1594 1574 if (trace__filter_duration(trace, duration)) 1595 1575 goto out; 1576 + duration_calculated = true; 1596 1577 } else if (trace->duration_filter) 1597 1578 goto out; 1598 1579 ··· 1609 1588 if (trace->summary_only) 1610 1589 goto out; 1611 1590 1612 - trace__fprintf_entry_head(trace, thread, duration, ttrace->entry_time, trace->output); 1591 + trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output); 1613 1592 1614 1593 if (ttrace->entry_pending) { 1615 1594 fprintf(trace->output, "%-70s", ttrace->entry_str); ··· 1876 1855 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION, 1877 1856 sample->ip, &al); 1878 1857 1879 - trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output); 1858 + trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output); 1880 1859 1881 1860 fprintf(trace->output, "%sfault [", 1882 1861 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
+2
tools/perf/check-headers.sh
··· 1 1 #!/bin/sh 2 2 3 3 HEADERS=' 4 + include/uapi/linux/fcntl.h 4 5 include/uapi/linux/perf_event.h 6 + include/uapi/linux/stat.h 5 7 include/linux/hash.h 6 8 include/uapi/linux/hw_breakpoint.h 7 9 arch/x86/include/asm/disabled-features.h
+7 -90
tools/perf/perf.c
··· 267 267 return handled; 268 268 } 269 269 270 - static int handle_alias(int *argcp, const char ***argv) 271 - { 272 - int envchanged = 0, ret = 0, saved_errno = errno; 273 - int count, option_count; 274 - const char **new_argv; 275 - const char *alias_command; 276 - char *alias_string; 277 - 278 - alias_command = (*argv)[0]; 279 - alias_string = alias_lookup(alias_command); 280 - if (alias_string) { 281 - if (alias_string[0] == '!') { 282 - if (*argcp > 1) { 283 - struct strbuf buf; 284 - 285 - if (strbuf_init(&buf, PATH_MAX) < 0 || 286 - strbuf_addstr(&buf, alias_string) < 0 || 287 - sq_quote_argv(&buf, (*argv) + 1, 288 - PATH_MAX) < 0) 289 - die("Failed to allocate memory."); 290 - free(alias_string); 291 - alias_string = buf.buf; 292 - } 293 - ret = system(alias_string + 1); 294 - if (ret >= 0 && WIFEXITED(ret) && 295 - WEXITSTATUS(ret) != 127) 296 - exit(WEXITSTATUS(ret)); 297 - die("Failed to run '%s' when expanding alias '%s'", 298 - alias_string + 1, alias_command); 299 - } 300 - count = split_cmdline(alias_string, &new_argv); 301 - if (count < 0) 302 - die("Bad alias.%s string", alias_command); 303 - option_count = handle_options(&new_argv, &count, &envchanged); 304 - if (envchanged) 305 - die("alias '%s' changes environment variables\n" 306 - "You can use '!perf' in the alias to do this.", 307 - alias_command); 308 - memmove(new_argv - option_count, new_argv, 309 - count * sizeof(char *)); 310 - new_argv -= option_count; 311 - 312 - if (count < 1) 313 - die("empty alias for %s", alias_command); 314 - 315 - if (!strcmp(alias_command, new_argv[0])) 316 - die("recursive alias: %s", alias_command); 317 - 318 - new_argv = realloc(new_argv, sizeof(char *) * 319 - (count + *argcp + 1)); 320 - /* insert after command name */ 321 - memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp); 322 - new_argv[count + *argcp] = NULL; 323 - 324 - *argv = new_argv; 325 - *argcp += count - 1; 326 - 327 - ret = 1; 328 - } 329 - 330 - errno = saved_errno; 331 - 332 - return ret; 333 - } 334 - 335 270 #define RUN_SETUP (1<<0) 336 271 #define USE_PAGER (1<<1) 337 272 ··· 390 455 391 456 static int run_argv(int *argcp, const char ***argv) 392 457 { 393 - int done_alias = 0; 458 + /* See if it's an internal command */ 459 + handle_internal_command(*argcp, *argv); 394 460 395 - while (1) { 396 - /* See if it's an internal command */ 397 - handle_internal_command(*argcp, *argv); 398 - 399 - /* .. then try the external ones */ 400 - execv_dashed_external(*argv); 401 - 402 - /* It could be an alias -- this works around the insanity 403 - * of overriding "perf log" with "perf show" by having 404 - * alias.log = show 405 - */ 406 - if (done_alias || !handle_alias(argcp, argv)) 407 - break; 408 - done_alias = 1; 409 - } 410 - 411 - return done_alias; 461 + /* .. then try the external ones */ 462 + execv_dashed_external(*argv); 463 + return 0; 412 464 } 413 465 414 466 static void pthread__block_sigwinch(void) ··· 528 606 529 607 while (1) { 530 608 static int done_help; 531 - int was_alias = run_argv(&argc, &argv); 609 + 610 + run_argv(&argc, &argv); 532 611 533 612 if (errno != ENOENT) 534 613 break; 535 614 536 - if (was_alias) { 537 - fprintf(stderr, "Expansion of alias '%s' failed; " 538 - "'%s' is not a perf-command\n", 539 - cmd, argv[0]); 540 - goto out; 541 - } 542 615 if (!done_help) { 543 616 cmd = argv[0] = help_unknown_cmd(cmd); 544 617 done_help = 1;
+1
tools/perf/trace/beauty/Build
··· 1 + libperf-y += statx.o
+24
tools/perf/trace/beauty/beauty.h
··· 1 + #ifndef _PERF_TRACE_BEAUTY_H 2 + #define _PERF_TRACE_BEAUTY_H 3 + 4 + #include <linux/types.h> 5 + 6 + struct trace; 7 + struct thread; 8 + 9 + struct syscall_arg { 10 + unsigned long val; 11 + struct thread *thread; 12 + struct trace *trace; 13 + void *parm; 14 + u8 idx; 15 + u8 mask; 16 + }; 17 + 18 + size_t syscall_arg__scnprintf_statx_flags(char *bf, size_t size, struct syscall_arg *arg); 19 + #define SCA_STATX_FLAGS syscall_arg__scnprintf_statx_flags 20 + 21 + size_t syscall_arg__scnprintf_statx_mask(char *bf, size_t size, struct syscall_arg *arg); 22 + #define SCA_STATX_MASK syscall_arg__scnprintf_statx_mask 23 + 24 + #endif /* _PERF_TRACE_BEAUTY_H */
+72
tools/perf/trace/beauty/statx.c
··· 1 + /* 2 + * trace/beauty/statx.c 3 + * 4 + * 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 + */ 8 + 9 + #include "trace/beauty/beauty.h" 10 + #include <linux/kernel.h> 11 + #include <sys/types.h> 12 + #include <uapi/linux/fcntl.h> 13 + #include <uapi/linux/stat.h> 14 + 15 + size_t syscall_arg__scnprintf_statx_flags(char *bf, size_t size, struct syscall_arg *arg) 16 + { 17 + int printed = 0, flags = arg->val; 18 + 19 + if (flags == 0) 20 + return scnprintf(bf, size, "SYNC_AS_STAT"); 21 + #define P_FLAG(n) \ 22 + if (flags & AT_##n) { \ 23 + printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ 24 + flags &= ~AT_##n; \ 25 + } 26 + 27 + P_FLAG(SYMLINK_NOFOLLOW); 28 + P_FLAG(REMOVEDIR); 29 + P_FLAG(SYMLINK_FOLLOW); 30 + P_FLAG(NO_AUTOMOUNT); 31 + P_FLAG(EMPTY_PATH); 32 + P_FLAG(STATX_FORCE_SYNC); 33 + P_FLAG(STATX_DONT_SYNC); 34 + 35 + #undef P_FLAG 36 + 37 + if (flags) 38 + printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); 39 + 40 + return printed; 41 + } 42 + 43 + size_t syscall_arg__scnprintf_statx_mask(char *bf, size_t size, struct syscall_arg *arg) 44 + { 45 + int printed = 0, flags = arg->val; 46 + 47 + #define P_FLAG(n) \ 48 + if (flags & STATX_##n) { \ 49 + printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ 50 + flags &= ~STATX_##n; \ 51 + } 52 + 53 + P_FLAG(TYPE); 54 + P_FLAG(MODE); 55 + P_FLAG(NLINK); 56 + P_FLAG(UID); 57 + P_FLAG(GID); 58 + P_FLAG(ATIME); 59 + P_FLAG(MTIME); 60 + P_FLAG(CTIME); 61 + P_FLAG(INO); 62 + P_FLAG(SIZE); 63 + P_FLAG(BLOCKS); 64 + P_FLAG(BTIME); 65 + 66 + #undef P_FLAG 67 + 68 + if (flags) 69 + printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); 70 + 71 + return printed; 72 + }
-1
tools/perf/util/Build
··· 1 - libperf-y += alias.o 2 1 libperf-y += annotate.o 3 2 libperf-y += block-range.o 4 3 libperf-y += build-id.o
-78
tools/perf/util/alias.c
··· 1 - #include "cache.h" 2 - #include "util.h" 3 - #include "config.h" 4 - 5 - static const char *alias_key; 6 - static char *alias_val; 7 - 8 - static int alias_lookup_cb(const char *k, const char *v, 9 - void *cb __maybe_unused) 10 - { 11 - if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) { 12 - if (!v) 13 - return config_error_nonbool(k); 14 - alias_val = strdup(v); 15 - return 0; 16 - } 17 - return 0; 18 - } 19 - 20 - char *alias_lookup(const char *alias) 21 - { 22 - alias_key = alias; 23 - alias_val = NULL; 24 - perf_config(alias_lookup_cb, NULL); 25 - return alias_val; 26 - } 27 - 28 - int split_cmdline(char *cmdline, const char ***argv) 29 - { 30 - int src, dst, count = 0, size = 16; 31 - char quoted = 0; 32 - 33 - *argv = malloc(sizeof(char*) * size); 34 - 35 - /* split alias_string */ 36 - (*argv)[count++] = cmdline; 37 - for (src = dst = 0; cmdline[src];) { 38 - char c = cmdline[src]; 39 - if (!quoted && isspace(c)) { 40 - cmdline[dst++] = 0; 41 - while (cmdline[++src] 42 - && isspace(cmdline[src])) 43 - ; /* skip */ 44 - if (count >= size) { 45 - size += 16; 46 - *argv = realloc(*argv, sizeof(char*) * size); 47 - } 48 - (*argv)[count++] = cmdline + dst; 49 - } else if (!quoted && (c == '\'' || c == '"')) { 50 - quoted = c; 51 - src++; 52 - } else if (c == quoted) { 53 - quoted = 0; 54 - src++; 55 - } else { 56 - if (c == '\\' && quoted != '\'') { 57 - src++; 58 - c = cmdline[src]; 59 - if (!c) { 60 - zfree(argv); 61 - return error("cmdline ends with \\"); 62 - } 63 - } 64 - cmdline[dst++] = c; 65 - src++; 66 - } 67 - } 68 - 69 - cmdline[dst] = 0; 70 - 71 - if (quoted) { 72 - zfree(argv); 73 - return error("unclosed quote"); 74 - } 75 - 76 - return count; 77 - } 78 -
-1
tools/perf/util/cache.h
··· 15 15 #define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR" 16 16 #define PERF_PAGER_ENVIRONMENT "PERF_PAGER" 17 17 18 - char *alias_lookup(const char *alias); 19 18 int split_cmdline(char *cmdline, const char ***argv); 20 19 21 20 #define alloc_nr(x) (((x)+16)*3/2)
+85 -48
tools/perf/util/callchain.c
··· 1105 1105 cycles_count); 1106 1106 } 1107 1107 1108 + static int counts_str_build(char *bf, int bfsize, 1109 + u64 branch_count, u64 predicted_count, 1110 + u64 abort_count, u64 cycles_count, 1111 + u64 iter_count, u64 samples_count) 1112 + { 1113 + double predicted_percent = 0.0; 1114 + const char *null_str = ""; 1115 + char iter_str[32]; 1116 + char cycle_str[32]; 1117 + char *istr, *cstr; 1118 + u64 cycles; 1119 + 1120 + if (branch_count == 0) 1121 + return scnprintf(bf, bfsize, " (calltrace)"); 1122 + 1123 + cycles = cycles_count / branch_count; 1124 + 1125 + if (iter_count && samples_count) { 1126 + if (cycles > 0) 1127 + scnprintf(iter_str, sizeof(iter_str), 1128 + " iterations:%" PRId64 "", 1129 + iter_count / samples_count); 1130 + else 1131 + scnprintf(iter_str, sizeof(iter_str), 1132 + "iterations:%" PRId64 "", 1133 + iter_count / samples_count); 1134 + istr = iter_str; 1135 + } else 1136 + istr = (char *)null_str; 1137 + 1138 + if (cycles > 0) { 1139 + scnprintf(cycle_str, sizeof(cycle_str), 1140 + "cycles:%" PRId64 "", cycles); 1141 + cstr = cycle_str; 1142 + } else 1143 + cstr = (char *)null_str; 1144 + 1145 + predicted_percent = predicted_count * 100.0 / branch_count; 1146 + 1147 + if ((predicted_count == branch_count) && (abort_count == 0)) { 1148 + if ((cycles > 0) || (istr != (char *)null_str)) 1149 + return scnprintf(bf, bfsize, " (%s%s)", cstr, istr); 1150 + else 1151 + return scnprintf(bf, bfsize, "%s", (char *)null_str); 1152 + } 1153 + 1154 + if ((predicted_count < branch_count) && (abort_count == 0)) { 1155 + if ((cycles > 0) || (istr != (char *)null_str)) 1156 + return scnprintf(bf, bfsize, 1157 + " (predicted:%.1f%% %s%s)", 1158 + predicted_percent, cstr, istr); 1159 + else { 1160 + return scnprintf(bf, bfsize, 1161 + " (predicted:%.1f%%)", 1162 + predicted_percent); 1163 + } 1164 + } 1165 + 1166 + if ((predicted_count == branch_count) && (abort_count > 0)) { 1167 + if ((cycles > 0) || (istr != (char *)null_str)) 1168 + return scnprintf(bf, bfsize, 1169 + " (abort:%" PRId64 " %s%s)", 1170 + abort_count, cstr, istr); 1171 + else 1172 + return scnprintf(bf, bfsize, 1173 + " (abort:%" PRId64 ")", 1174 + abort_count); 1175 + } 1176 + 1177 + if ((cycles > 0) || (istr != (char *)null_str)) 1178 + return scnprintf(bf, bfsize, 1179 + " (predicted:%.1f%% abort:%" PRId64 " %s%s)", 1180 + predicted_percent, abort_count, cstr, istr); 1181 + 1182 + return scnprintf(bf, bfsize, 1183 + " (predicted:%.1f%% abort:%" PRId64 ")", 1184 + predicted_percent, abort_count); 1185 + } 1186 + 1108 1187 static int callchain_counts_printf(FILE *fp, char *bf, int bfsize, 1109 1188 u64 branch_count, u64 predicted_count, 1110 1189 u64 abort_count, u64 cycles_count, 1111 1190 u64 iter_count, u64 samples_count) 1112 1191 { 1113 - double predicted_percent = 0.0; 1114 - const char *null_str = ""; 1115 - char iter_str[32]; 1116 - char *str; 1117 - u64 cycles = 0; 1192 + char str[128]; 1118 1193 1119 - if (branch_count == 0) { 1120 - if (fp) 1121 - return fprintf(fp, " (calltrace)"); 1122 - 1123 - return scnprintf(bf, bfsize, " (calltrace)"); 1124 - } 1125 - 1126 - if (iter_count && samples_count) { 1127 - scnprintf(iter_str, sizeof(iter_str), 1128 - ", iterations:%" PRId64 "", 1129 - iter_count / samples_count); 1130 - str = iter_str; 1131 - } else 1132 - str = (char *)null_str; 1133 - 1134 - predicted_percent = predicted_count * 100.0 / branch_count; 1135 - cycles = cycles_count / branch_count; 1136 - 1137 - if ((predicted_percent >= 100.0) && (abort_count == 0)) { 1138 - if (fp) 1139 - return fprintf(fp, " (cycles:%" PRId64 "%s)", 1140 - cycles, str); 1141 - 1142 - return scnprintf(bf, bfsize, " (cycles:%" PRId64 "%s)", 1143 - cycles, str); 1144 - } 1145 - 1146 - if ((predicted_percent < 100.0) && (abort_count == 0)) { 1147 - if (fp) 1148 - return fprintf(fp, 1149 - " (predicted:%.1f%%, cycles:%" PRId64 "%s)", 1150 - predicted_percent, cycles, str); 1151 - 1152 - return scnprintf(bf, bfsize, 1153 - " (predicted:%.1f%%, cycles:%" PRId64 "%s)", 1154 - predicted_percent, cycles, str); 1155 - } 1194 + counts_str_build(str, sizeof(str), branch_count, 1195 + predicted_count, abort_count, cycles_count, 1196 + iter_count, samples_count); 1156 1197 1157 1198 if (fp) 1158 - return fprintf(fp, 1159 - " (predicted:%.1f%%, abort:%" PRId64 ", cycles:%" PRId64 "%s)", 1160 - predicted_percent, abort_count, cycles, str); 1199 + return fprintf(fp, "%s", str); 1161 1200 1162 - return scnprintf(bf, bfsize, 1163 - " (predicted:%.1f%%, abort:%" PRId64 ", cycles:%" PRId64 "%s)", 1164 - predicted_percent, abort_count, cycles, str); 1201 + return scnprintf(bf, bfsize, "%s", str); 1165 1202 } 1166 1203 1167 1204 int callchain_list_counts__printf_value(struct callchain_node *node,
+34 -26
tools/perf/util/config.c
··· 627 627 { 628 628 int ret = -1; 629 629 const char *home = NULL; 630 + char *user_config; 631 + struct stat st; 630 632 631 633 /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ 632 634 if (config_exclusive_filename) ··· 639 637 } 640 638 641 639 home = getenv("HOME"); 642 - if (perf_config_global() && home) { 643 - char *user_config = strdup(mkpath("%s/.perfconfig", home)); 644 - struct stat st; 645 640 646 - if (user_config == NULL) { 647 - warning("Not enough memory to process %s/.perfconfig, " 648 - "ignoring it.", home); 649 - goto out; 650 - } 641 + /* 642 + * Skip reading user config if: 643 + * - there is no place to read it from (HOME) 644 + * - we are asked not to (PERF_CONFIG_NOGLOBAL=1) 645 + */ 646 + if (!home || !*home || !perf_config_global()) 647 + return 0; 651 648 652 - if (stat(user_config, &st) < 0) { 653 - if (errno == ENOENT) 654 - ret = 0; 655 - goto out_free; 656 - } 657 - 658 - ret = 0; 659 - 660 - if (st.st_uid && (st.st_uid != geteuid())) { 661 - warning("File %s not owned by current user or root, " 662 - "ignoring it.", user_config); 663 - goto out_free; 664 - } 665 - 666 - if (st.st_size) 667 - ret = perf_config_from_file(collect_config, user_config, set); 668 - out_free: 669 - free(user_config); 649 + user_config = strdup(mkpath("%s/.perfconfig", home)); 650 + if (user_config == NULL) { 651 + warning("Not enough memory to process %s/.perfconfig, " 652 + "ignoring it.", home); 653 + goto out; 670 654 } 655 + 656 + if (stat(user_config, &st) < 0) { 657 + if (errno == ENOENT) 658 + ret = 0; 659 + goto out_free; 660 + } 661 + 662 + ret = 0; 663 + 664 + if (st.st_uid && (st.st_uid != geteuid())) { 665 + warning("File %s not owned by current user or root, " 666 + "ignoring it.", user_config); 667 + goto out_free; 668 + } 669 + 670 + if (st.st_size) 671 + ret = perf_config_from_file(collect_config, user_config, set); 672 + 673 + out_free: 674 + free(user_config); 671 675 out: 672 676 return ret; 673 677 }
+1 -7
tools/perf/util/help-unknown-cmd.c
··· 6 6 #include "levenshtein.h" 7 7 8 8 static int autocorrect; 9 - static struct cmdnames aliases; 10 9 11 10 static int perf_unknown_cmd_config(const char *var, const char *value, 12 11 void *cb __maybe_unused) 13 12 { 14 13 if (!strcmp(var, "help.autocorrect")) 15 14 autocorrect = perf_config_int(var,value); 16 - /* Also use aliases for command lookup */ 17 - if (!prefixcmp(var, "alias.")) 18 - add_cmdname(&aliases, var + 6, strlen(var + 6)); 19 15 20 16 return 0; 21 17 } ··· 55 59 56 60 memset(&main_cmds, 0, sizeof(main_cmds)); 57 61 memset(&other_cmds, 0, sizeof(main_cmds)); 58 - memset(&aliases, 0, sizeof(aliases)); 59 62 60 63 perf_config(perf_unknown_cmd_config, NULL); 61 64 62 65 load_command_list("perf-", &main_cmds, &other_cmds); 63 66 64 - if (add_cmd_list(&main_cmds, &aliases) < 0 || 65 - add_cmd_list(&main_cmds, &other_cmds) < 0) { 67 + if (add_cmd_list(&main_cmds, &other_cmds) < 0) { 66 68 fprintf(stderr, "ERROR: Failed to allocate command list for unknown command.\n"); 67 69 goto end; 68 70 }
+1 -1
tools/perf/util/hist.c
··· 2459 2459 else if (!strcmp(arg, "absolute")) 2460 2460 symbol_conf.filter_relative = false; 2461 2461 else { 2462 - pr_debug("Invalud percentage: %s\n", arg); 2462 + pr_debug("Invalid percentage: %s\n", arg); 2463 2463 return -1; 2464 2464 } 2465 2465
+3 -3
tools/perf/util/perf_regs.c
··· 6 6 SMPL_REG_END 7 7 }; 8 8 9 - int __weak sdt_rename_register(char **pdesc __maybe_unused, 10 - char *old_name __maybe_unused) 9 + int __weak arch_sdt_arg_parse_op(char *old_op __maybe_unused, 10 + char **new_op __maybe_unused) 11 11 { 12 - return 0; 12 + return SDT_ARG_SKIP; 13 13 } 14 14 15 15 #ifdef HAVE_PERF_REGS_SUPPORT
+6 -5
tools/perf/util/perf_regs.h
··· 15 15 16 16 extern const struct sample_reg sample_reg_masks[]; 17 17 18 - /* 19 - * The table sdt_reg_renamings is used for adjusting gcc/gas-generated 20 - * registers before filling the uprobe tracer interface. 21 - */ 22 - int sdt_rename_register(char **pdesc, char *old_name); 18 + enum { 19 + SDT_ARG_VALID = 0, 20 + SDT_ARG_SKIP, 21 + }; 22 + 23 + int arch_sdt_arg_parse_op(char *old_op, char **new_op); 23 24 24 25 #ifdef HAVE_PERF_REGS_SUPPORT 25 26 #include <perf_regs.h>
+43 -99
tools/perf/util/probe-file.c
··· 694 694 "", ":u8", ":u16", "", ":u32", "", "", "", ":u64" 695 695 }; 696 696 697 + /* 698 + * Isolate the string number and convert it into a decimal value; 699 + * this will be an index to get suffix of the uprobe name (defining 700 + * the type) 701 + */ 702 + static int sdt_arg_parse_size(char *n_ptr, const char **suffix) 703 + { 704 + long type_idx; 705 + 706 + type_idx = strtol(n_ptr, NULL, 10); 707 + if (type_idx < -8 || type_idx > 8) { 708 + pr_debug4("Failed to get a valid sdt type\n"); 709 + return -1; 710 + } 711 + 712 + *suffix = type_to_suffix[type_idx + 8]; 713 + return 0; 714 + } 715 + 697 716 static int synthesize_sdt_probe_arg(struct strbuf *buf, int i, const char *arg) 698 717 { 699 - char *tmp, *desc = strdup(arg); 700 - const char *prefix = "", *suffix = ""; 718 + char *op, *desc = strdup(arg), *new_op = NULL; 719 + const char *suffix = ""; 701 720 int ret = -1; 702 721 703 722 if (desc == NULL) { ··· 724 705 return ret; 725 706 } 726 707 727 - tmp = strchr(desc, '@'); 728 - if (tmp) { 729 - long type_idx; 730 - /* 731 - * Isolate the string number and convert it into a 732 - * binary value; this will be an index to get suffix 733 - * of the uprobe name (defining the type) 734 - */ 735 - tmp[0] = '\0'; 736 - type_idx = strtol(desc, NULL, 10); 737 - /* Check that the conversion went OK */ 738 - if (type_idx == LONG_MIN || type_idx == LONG_MAX) { 739 - pr_debug4("Failed to parse sdt type\n"); 708 + /* 709 + * Argument is in N@OP format. N is size of the argument and OP is 710 + * the actual assembly operand. N can be omitted; in that case 711 + * argument is just OP(without @). 712 + */ 713 + op = strchr(desc, '@'); 714 + if (op) { 715 + op[0] = '\0'; 716 + op++; 717 + 718 + if (sdt_arg_parse_size(desc, &suffix)) 740 719 goto error; 741 - } 742 - /* Check that the converted value is OK */ 743 - if (type_idx < -8 || type_idx > 8) { 744 - pr_debug4("Failed to get a valid sdt type\n"); 745 - goto error; 746 - } 747 - suffix = type_to_suffix[type_idx + 8]; 748 - /* Get rid of the sdt prefix which is now useless */ 749 - tmp++; 750 - memmove(desc, tmp, strlen(tmp) + 1); 720 + } else { 721 + op = desc; 751 722 } 752 723 753 - /* 754 - * The uprobe tracer format does not support all the 755 - * addressing modes (notably: in x86 the scaled mode); so, we 756 - * detect ',' characters, if there is just one, there is no 757 - * use converting the sdt arg into a uprobe one. 758 - */ 759 - if (strchr(desc, ',')) { 760 - pr_debug4("Skipping unsupported SDT argument; %s\n", desc); 761 - goto out; 762 - } 724 + ret = arch_sdt_arg_parse_op(op, &new_op); 763 725 764 - /* 765 - * If the argument addressing mode is indirect, we must check 766 - * a few things... 767 - */ 768 - tmp = strchr(desc, '('); 769 - if (tmp) { 770 - int j; 771 - 772 - /* 773 - * ...if the addressing mode is indirect with a 774 - * positive offset (ex.: "1608(%ax)"), we need to add 775 - * a '+' prefix so as to be compliant with uprobe 776 - * format. 777 - */ 778 - if (desc[0] != '+' && desc[0] != '-') 779 - prefix = "+"; 780 - 781 - /* 782 - * ...or if the addressing mode is indirect with a symbol 783 - * as offset, the argument will not be supported by 784 - * the uprobe tracer format; so, let's skip this one. 785 - */ 786 - for (j = 0; j < tmp - desc; j++) { 787 - if (desc[j] != '+' && desc[j] != '-' && 788 - !isdigit(desc[j])) { 789 - pr_debug4("Skipping unsupported SDT argument; " 790 - "%s\n", desc); 791 - goto out; 792 - } 793 - } 794 - } 795 - 796 - /* 797 - * The uprobe tracer format does not support constants; if we 798 - * find one in the current argument, let's skip the argument. 799 - */ 800 - if (strchr(desc, '$')) { 801 - pr_debug4("Skipping unsupported SDT argument; %s\n", desc); 802 - goto out; 803 - } 804 - 805 - /* 806 - * The uprobe parser does not support all gas register names; 807 - * so, we have to replace them (ex. for x86_64: %rax -> %ax); 808 - * the loop below looks for the register names (starting with 809 - * a '%' and tries to perform the needed renamings. 810 - */ 811 - tmp = strchr(desc, '%'); 812 - while (tmp) { 813 - size_t offset = tmp - desc; 814 - 815 - ret = sdt_rename_register(&desc, desc + offset); 816 - if (ret < 0) 817 - goto error; 818 - 819 - /* 820 - * The desc pointer might have changed; so, let's not 821 - * try to reuse tmp for next lookup 822 - */ 823 - tmp = strchr(desc + offset + 1, '%'); 824 - } 825 - 826 - if (strbuf_addf(buf, " arg%d=%s%s%s", i + 1, prefix, desc, suffix) < 0) 726 + if (ret < 0) 827 727 goto error; 828 728 829 - out: 729 + if (ret == SDT_ARG_VALID) { 730 + ret = strbuf_addf(buf, " arg%d=%s%s", i + 1, new_op, suffix); 731 + if (ret < 0) 732 + goto error; 733 + } 734 + 830 735 ret = 0; 831 736 error: 832 737 free(desc); 738 + free(new_op); 833 739 return ret; 834 740 } 835 741