]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge tag 'perf-core-for-mingo-4.12-20170331' of git://git.kernel.org/pub/scm/linux...
authorIngo Molnar <mingo@kernel.org>
Sat, 1 Apr 2017 10:43:40 +0000 (12:43 +0200)
committerIngo Molnar <mingo@kernel.org>
Sat, 1 Apr 2017 10:43:40 +0000 (12:43 +0200)
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>
24 files changed:
tools/include/linux/types.h
tools/include/uapi/linux/fcntl.h [new file with mode: 0644]
tools/include/uapi/linux/stat.h [new file with mode: 0644]
tools/perf/Build
tools/perf/MANIFEST
tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
tools/perf/arch/x86/util/perf_regs.c
tools/perf/builtin-help.c
tools/perf/builtin-trace.c
tools/perf/check-headers.sh
tools/perf/perf.c
tools/perf/trace/beauty/Build [new file with mode: 0644]
tools/perf/trace/beauty/beauty.h [new file with mode: 0644]
tools/perf/trace/beauty/statx.c [new file with mode: 0644]
tools/perf/util/Build
tools/perf/util/alias.c [deleted file]
tools/perf/util/cache.h
tools/perf/util/callchain.c
tools/perf/util/config.c
tools/perf/util/help-unknown-cmd.c
tools/perf/util/hist.c
tools/perf/util/perf_regs.c
tools/perf/util/perf_regs.h
tools/perf/util/probe-file.c

index c24b3e3ae29691d404ad36bc56bdea3497ea0de7..77a28a26a6709fe3fe90026acfd9936849824890 100644 (file)
@@ -7,6 +7,7 @@
 
 #define __SANE_USERSPACE_TYPES__       /* For PPC64, to get LL64 types */
 #include <asm/types.h>
+#include <asm/posix_types.h>
 
 struct page;
 struct kmem_cache;
diff --git a/tools/include/uapi/linux/fcntl.h b/tools/include/uapi/linux/fcntl.h
new file mode 100644 (file)
index 0000000..813afd6
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef _UAPI_LINUX_FCNTL_H
+#define _UAPI_LINUX_FCNTL_H
+
+#include <asm/fcntl.h>
+
+#define F_SETLEASE     (F_LINUX_SPECIFIC_BASE + 0)
+#define F_GETLEASE     (F_LINUX_SPECIFIC_BASE + 1)
+
+/*
+ * Cancel a blocking posix lock; internal use only until we expose an
+ * asynchronous lock api to userspace:
+ */
+#define F_CANCELLK     (F_LINUX_SPECIFIC_BASE + 5)
+
+/* Create a file descriptor with FD_CLOEXEC set. */
+#define F_DUPFD_CLOEXEC        (F_LINUX_SPECIFIC_BASE + 6)
+
+/*
+ * Request nofications on a directory.
+ * See below for events that may be notified.
+ */
+#define F_NOTIFY       (F_LINUX_SPECIFIC_BASE+2)
+
+/*
+ * Set and get of pipe page size array
+ */
+#define F_SETPIPE_SZ   (F_LINUX_SPECIFIC_BASE + 7)
+#define F_GETPIPE_SZ   (F_LINUX_SPECIFIC_BASE + 8)
+
+/*
+ * Set/Get seals
+ */
+#define F_ADD_SEALS    (F_LINUX_SPECIFIC_BASE + 9)
+#define F_GET_SEALS    (F_LINUX_SPECIFIC_BASE + 10)
+
+/*
+ * Types of seals
+ */
+#define F_SEAL_SEAL    0x0001  /* prevent further seals from being set */
+#define F_SEAL_SHRINK  0x0002  /* prevent file from shrinking */
+#define F_SEAL_GROW    0x0004  /* prevent file from growing */
+#define F_SEAL_WRITE   0x0008  /* prevent writes */
+/* (1U << 31) is reserved for signed error codes */
+
+/*
+ * Types of directory notifications that may be requested.
+ */
+#define DN_ACCESS      0x00000001      /* File accessed */
+#define DN_MODIFY      0x00000002      /* File modified */
+#define DN_CREATE      0x00000004      /* File created */
+#define DN_DELETE      0x00000008      /* File removed */
+#define DN_RENAME      0x00000010      /* File renamed */
+#define DN_ATTRIB      0x00000020      /* File changed attibutes */
+#define DN_MULTISHOT   0x80000000      /* Don't remove notifier */
+
+#define AT_FDCWD               -100    /* Special value used to indicate
+                                           openat should use the current
+                                           working directory. */
+#define AT_SYMLINK_NOFOLLOW    0x100   /* Do not follow symbolic links.  */
+#define AT_REMOVEDIR           0x200   /* Remove directory instead of
+                                           unlinking file.  */
+#define AT_SYMLINK_FOLLOW      0x400   /* Follow symbolic links.  */
+#define AT_NO_AUTOMOUNT                0x800   /* Suppress terminal automount traversal */
+#define AT_EMPTY_PATH          0x1000  /* Allow empty relative pathname */
+
+#define AT_STATX_SYNC_TYPE     0x6000  /* Type of synchronisation required from statx() */
+#define AT_STATX_SYNC_AS_STAT  0x0000  /* - Do whatever stat() does */
+#define AT_STATX_FORCE_SYNC    0x2000  /* - Force the attributes to be sync'd with the server */
+#define AT_STATX_DONT_SYNC     0x4000  /* - Don't sync attributes with the server */
+
+
+#endif /* _UAPI_LINUX_FCNTL_H */
diff --git a/tools/include/uapi/linux/stat.h b/tools/include/uapi/linux/stat.h
new file mode 100644 (file)
index 0000000..51a6b86
--- /dev/null
@@ -0,0 +1,176 @@
+#ifndef _UAPI_LINUX_STAT_H
+#define _UAPI_LINUX_STAT_H
+
+#include <linux/types.h>
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
+#define S_IFMT  00170000
+#define S_IFSOCK 0140000
+#define S_IFLNK         0120000
+#define S_IFREG  0100000
+#define S_IFBLK  0060000
+#define S_IFDIR  0040000
+#define S_IFCHR  0020000
+#define S_IFIFO  0010000
+#define S_ISUID  0004000
+#define S_ISGID  0002000
+#define S_ISVTX  0001000
+
+#define S_ISLNK(m)     (((m) & S_IFMT) == S_IFLNK)
+#define S_ISREG(m)     (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m)     (((m) & S_IFMT) == S_IFDIR)
+#define S_ISCHR(m)     (((m) & S_IFMT) == S_IFCHR)
+#define S_ISBLK(m)     (((m) & S_IFMT) == S_IFBLK)
+#define S_ISFIFO(m)    (((m) & S_IFMT) == S_IFIFO)
+#define S_ISSOCK(m)    (((m) & S_IFMT) == S_IFSOCK)
+
+#define S_IRWXU 00700
+#define S_IRUSR 00400
+#define S_IWUSR 00200
+#define S_IXUSR 00100
+
+#define S_IRWXG 00070
+#define S_IRGRP 00040
+#define S_IWGRP 00020
+#define S_IXGRP 00010
+
+#define S_IRWXO 00007
+#define S_IROTH 00004
+#define S_IWOTH 00002
+#define S_IXOTH 00001
+
+#endif
+
+/*
+ * Timestamp structure for the timestamps in struct statx.
+ *
+ * tv_sec holds the number of seconds before (negative) or after (positive)
+ * 00:00:00 1st January 1970 UTC.
+ *
+ * tv_nsec holds a number of nanoseconds before (0..-999,999,999 if tv_sec is
+ * negative) or after (0..999,999,999 if tv_sec is positive) the tv_sec time.
+ *
+ * Note that if both tv_sec and tv_nsec are non-zero, then the two values must
+ * either be both positive or both negative.
+ *
+ * __reserved is held in case we need a yet finer resolution.
+ */
+struct statx_timestamp {
+       __s64   tv_sec;
+       __s32   tv_nsec;
+       __s32   __reserved;
+};
+
+/*
+ * Structures for the extended file attribute retrieval system call
+ * (statx()).
+ *
+ * The caller passes a mask of what they're specifically interested in as a
+ * parameter to statx().  What statx() actually got will be indicated in
+ * st_mask upon return.
+ *
+ * For each bit in the mask argument:
+ *
+ * - if the datum is not supported:
+ *
+ *   - the bit will be cleared, and
+ *
+ *   - the datum will be set to an appropriate fabricated value if one is
+ *     available (eg. CIFS can take a default uid and gid), otherwise
+ *
+ *   - the field will be cleared;
+ *
+ * - otherwise, if explicitly requested:
+ *
+ *   - the datum will be synchronised to the server if AT_STATX_FORCE_SYNC is
+ *     set or if the datum is considered out of date, and
+ *
+ *   - the field will be filled in and the bit will be set;
+ *
+ * - otherwise, if not requested, but available in approximate form without any
+ *   effort, it will be filled in anyway, and the bit will be set upon return
+ *   (it might not be up to date, however, and no attempt will be made to
+ *   synchronise the internal state first);
+ *
+ * - otherwise the field and the bit will be cleared before returning.
+ *
+ * Items in STATX_BASIC_STATS may be marked unavailable on return, but they
+ * will have values installed for compatibility purposes so that stat() and
+ * co. can be emulated in userspace.
+ */
+struct statx {
+       /* 0x00 */
+       __u32   stx_mask;       /* What results were written [uncond] */
+       __u32   stx_blksize;    /* Preferred general I/O size [uncond] */
+       __u64   stx_attributes; /* Flags conveying information about the file [uncond] */
+       /* 0x10 */
+       __u32   stx_nlink;      /* Number of hard links */
+       __u32   stx_uid;        /* User ID of owner */
+       __u32   stx_gid;        /* Group ID of owner */
+       __u16   stx_mode;       /* File mode */
+       __u16   __spare0[1];
+       /* 0x20 */
+       __u64   stx_ino;        /* Inode number */
+       __u64   stx_size;       /* File size */
+       __u64   stx_blocks;     /* Number of 512-byte blocks allocated */
+       __u64   __spare1[1];
+       /* 0x40 */
+       struct statx_timestamp  stx_atime;      /* Last access time */
+       struct statx_timestamp  stx_btime;      /* File creation time */
+       struct statx_timestamp  stx_ctime;      /* Last attribute change time */
+       struct statx_timestamp  stx_mtime;      /* Last data modification time */
+       /* 0x80 */
+       __u32   stx_rdev_major; /* Device ID of special file [if bdev/cdev] */
+       __u32   stx_rdev_minor;
+       __u32   stx_dev_major;  /* ID of device containing file [uncond] */
+       __u32   stx_dev_minor;
+       /* 0x90 */
+       __u64   __spare2[14];   /* Spare space for future expansion */
+       /* 0x100 */
+};
+
+/*
+ * Flags to be stx_mask
+ *
+ * Query request/result mask for statx() and struct statx::stx_mask.
+ *
+ * These bits should be set in the mask argument of statx() to request
+ * particular items when calling statx().
+ */
+#define STATX_TYPE             0x00000001U     /* Want/got stx_mode & S_IFMT */
+#define STATX_MODE             0x00000002U     /* Want/got stx_mode & ~S_IFMT */
+#define STATX_NLINK            0x00000004U     /* Want/got stx_nlink */
+#define STATX_UID              0x00000008U     /* Want/got stx_uid */
+#define STATX_GID              0x00000010U     /* Want/got stx_gid */
+#define STATX_ATIME            0x00000020U     /* Want/got stx_atime */
+#define STATX_MTIME            0x00000040U     /* Want/got stx_mtime */
+#define STATX_CTIME            0x00000080U     /* Want/got stx_ctime */
+#define STATX_INO              0x00000100U     /* Want/got stx_ino */
+#define STATX_SIZE             0x00000200U     /* Want/got stx_size */
+#define STATX_BLOCKS           0x00000400U     /* Want/got stx_blocks */
+#define STATX_BASIC_STATS      0x000007ffU     /* The stuff in the normal stat struct */
+#define STATX_BTIME            0x00000800U     /* Want/got stx_btime */
+#define STATX_ALL              0x00000fffU     /* All currently supported flags */
+
+/*
+ * Attributes to be found in stx_attributes
+ *
+ * These give information about the features or the state of a file that might
+ * be of use to ordinary userspace programs such as GUIs or ls rather than
+ * specialised tools.
+ *
+ * Note that the flags marked [I] correspond to generic FS_IOC_FLAGS
+ * semantically.  Where possible, the numerical value is picked to correspond
+ * also.
+ */
+#define STATX_ATTR_COMPRESSED          0x00000004 /* [I] File is compressed by the fs */
+#define STATX_ATTR_IMMUTABLE           0x00000010 /* [I] File is marked immutable */
+#define STATX_ATTR_APPEND              0x00000020 /* [I] File is append-only */
+#define STATX_ATTR_NODUMP              0x00000040 /* [I] File is not to be dumped */
+#define STATX_ATTR_ENCRYPTED           0x00000800 /* [I] File requires key to decrypt in fs */
+
+#define STATX_ATTR_AUTOMOUNT           0x00001000 /* Dir: Automount trigger */
+
+
+#endif /* _UAPI_LINUX_STAT_H */
index 9b79f8d7db50e3dafcbe200ad8f3b47230ead69b..bd8eeb60533cdee3311dd6277b728990e4e70042 100644 (file)
@@ -50,5 +50,6 @@ libperf-y += util/
 libperf-y += arch/
 libperf-y += ui/
 libperf-y += scripts/
+libperf-y += trace/beauty/
 
 gtk-y += ui/gtk/
index 28648c09dcd683c11b381661f270fcc1ed36c0a9..89018c7311a4f8689403367a23021862f37f582e 100644 (file)
@@ -73,9 +73,11 @@ tools/include/uapi/asm-generic/mman-common.h
 tools/include/uapi/asm-generic/mman.h
 tools/include/uapi/linux/bpf.h
 tools/include/uapi/linux/bpf_common.h
+tools/include/uapi/linux/fcntl.h
 tools/include/uapi/linux/hw_breakpoint.h
 tools/include/uapi/linux/mman.h
 tools/include/uapi/linux/perf_event.h
+tools/include/uapi/linux/stat.h
 tools/include/linux/poison.h
 tools/include/linux/rbtree.h
 tools/include/linux/rbtree_augmented.h
index e93ef0b38db8e16a38f83e2e3f08dfb8d5fff4a0..5aef183e2f85c5f6c45e44d4e9a68c9ea62c0d74 100644 (file)
 329    common  pkey_mprotect           sys_pkey_mprotect
 330    common  pkey_alloc              sys_pkey_alloc
 331    common  pkey_free               sys_pkey_free
+332    common  statx                   sys_statx
 
 #
 # x32-specific system call numbers start at 512 to avoid cache impact
index d8a8dcf761f7c5e85e1f2e6621f5cb4412deac34..3bf3548c5e2d1960fd18d39eb2a8edecd651b32c 100644 (file)
@@ -1,8 +1,10 @@
 #include <string.h>
+#include <regex.h>
 
 #include "../../perf.h"
 #include "../../util/util.h"
 #include "../../util/perf_regs.h"
+#include "../../util/debug.h"
 
 const struct sample_reg sample_reg_masks[] = {
        SMPL_REG(AX, PERF_REG_X86_AX),
@@ -37,15 +39,23 @@ struct sdt_name_reg {
 #define SDT_NAME_REG(n, m) {.sdt_name = "%" #n, .uprobe_name = "%" #m}
 #define SDT_NAME_REG_END {.sdt_name = NULL, .uprobe_name = NULL}
 
-static const struct sdt_name_reg sdt_reg_renamings[] = {
+static const struct sdt_name_reg sdt_reg_tbl[] = {
        SDT_NAME_REG(eax, ax),
        SDT_NAME_REG(rax, ax),
+       SDT_NAME_REG(al,  ax),
+       SDT_NAME_REG(ah,  ax),
        SDT_NAME_REG(ebx, bx),
        SDT_NAME_REG(rbx, bx),
+       SDT_NAME_REG(bl,  bx),
+       SDT_NAME_REG(bh,  bx),
        SDT_NAME_REG(ecx, cx),
        SDT_NAME_REG(rcx, cx),
+       SDT_NAME_REG(cl,  cx),
+       SDT_NAME_REG(ch,  cx),
        SDT_NAME_REG(edx, dx),
        SDT_NAME_REG(rdx, dx),
+       SDT_NAME_REG(dl,  dx),
+       SDT_NAME_REG(dh,  dx),
        SDT_NAME_REG(esi, si),
        SDT_NAME_REG(rsi, si),
        SDT_NAME_REG(sil, si),
@@ -87,45 +97,158 @@ static const struct sdt_name_reg sdt_reg_renamings[] = {
        SDT_NAME_REG_END,
 };
 
-int sdt_rename_register(char **pdesc, char *old_name)
+/*
+ * Perf only supports OP which is in  +/-NUM(REG)  form.
+ * Here plus-minus sign, NUM and parenthesis are optional,
+ * only REG is mandatory.
+ *
+ * SDT events also supports indirect addressing mode with a
+ * symbol as offset, scaled mode and constants in OP. But
+ * perf does not support them yet. Below are few examples.
+ *
+ * OP with scaled mode:
+ *     (%rax,%rsi,8)
+ *     10(%ras,%rsi,8)
+ *
+ * OP with indirect addressing mode:
+ *     check_action(%rip)
+ *     mp_+52(%rip)
+ *     44+mp_(%rip)
+ *
+ * OP with constant values:
+ *     $0
+ *     $123
+ *     $-1
+ */
+#define SDT_OP_REGEX  "^([+\\-]?)([0-9]*)(\\(?)(%[a-z][a-z0-9]+)(\\)?)$"
+
+static regex_t sdt_op_regex;
+
+static int sdt_init_op_regex(void)
 {
-       const struct sdt_name_reg *rnames = sdt_reg_renamings;
-       char *new_desc, *old_desc = *pdesc;
-       size_t prefix_len, sdt_len, uprobe_len, old_desc_len, offset;
-       int ret = -1;
-
-       while (ret != 0 && rnames->sdt_name != NULL) {
-               sdt_len = strlen(rnames->sdt_name);
-               ret = strncmp(old_name, rnames->sdt_name, sdt_len);
-               rnames += !!ret;
-       }
+       static int initialized;
+       int ret = 0;
 
-       if (rnames->sdt_name == NULL)
+       if (initialized)
                return 0;
 
-       sdt_len = strlen(rnames->sdt_name);
-       uprobe_len = strlen(rnames->uprobe_name);
-       old_desc_len = strlen(old_desc) + 1;
+       ret = regcomp(&sdt_op_regex, SDT_OP_REGEX, REG_EXTENDED);
+       if (ret < 0) {
+               pr_debug4("Regex compilation error.\n");
+               return ret;
+       }
 
-       new_desc = zalloc(old_desc_len + uprobe_len - sdt_len);
-       if (new_desc == NULL)
-               return -1;
+       initialized = 1;
+       return 0;
+}
 
-       /* Copy the chars before the register name (at least '%') */
-       prefix_len = old_name - old_desc;
-       memcpy(new_desc, old_desc, prefix_len);
+/*
+ * Max x86 register name length is 5(ex: %r15d). So, 6th char
+ * should always contain NULL. This helps to find register name
+ * length using strlen, insted of maintaing one more variable.
+ */
+#define SDT_REG_NAME_SIZE  6
 
-       /* Copy the new register name */
-       memcpy(new_desc + prefix_len, rnames->uprobe_name, uprobe_len);
+/*
+ * The uprobe parser does not support all gas register names;
+ * so, we have to replace them (ex. for x86_64: %rax -> %ax).
+ * Note: If register does not require renaming, just copy
+ * paste as it is, but don't leave it empty.
+ */
+static void sdt_rename_register(char *sdt_reg, int sdt_len, char *uprobe_reg)
+{
+       int i = 0;
 
-       /* Copy the chars after the register name (if need be) */
-       offset = prefix_len + sdt_len;
-       if (offset < old_desc_len)
-               memcpy(new_desc + prefix_len + uprobe_len,
-                       old_desc + offset, old_desc_len - offset);
+       for (i = 0; sdt_reg_tbl[i].sdt_name != NULL; i++) {
+               if (!strncmp(sdt_reg_tbl[i].sdt_name, sdt_reg, sdt_len)) {
+                       strcpy(uprobe_reg, sdt_reg_tbl[i].uprobe_name);
+                       return;
+               }
+       }
 
-       free(old_desc);
-       *pdesc = new_desc;
+       strncpy(uprobe_reg, sdt_reg, sdt_len);
+}
 
-       return 0;
+int arch_sdt_arg_parse_op(char *old_op, char **new_op)
+{
+       char new_reg[SDT_REG_NAME_SIZE] = {0};
+       int new_len = 0, ret;
+       /*
+        * rm[0]:  +/-NUM(REG)
+        * rm[1]:  +/-
+        * rm[2]:  NUM
+        * rm[3]:  (
+        * rm[4]:  REG
+        * rm[5]:  )
+        */
+       regmatch_t rm[6];
+       /*
+        * Max prefix length is 2 as it may contains sign(+/-)
+        * and displacement 0 (Both sign and displacement 0 are
+        * optional so it may be empty). Use one more character
+        * to hold last NULL so that strlen can be used to find
+        * prefix length, instead of maintaing one more variable.
+        */
+       char prefix[3] = {0};
+
+       ret = sdt_init_op_regex();
+       if (ret < 0)
+               return ret;
+
+       /*
+        * If unsupported OR does not match with regex OR
+        * register name too long, skip it.
+        */
+       if (strchr(old_op, ',') || strchr(old_op, '$') ||
+           regexec(&sdt_op_regex, old_op, 6, rm, 0)   ||
+           rm[4].rm_eo - rm[4].rm_so > SDT_REG_NAME_SIZE) {
+               pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
+               return SDT_ARG_SKIP;
+       }
+
+       /*
+        * Prepare prefix.
+        * If SDT OP has parenthesis but does not provide
+        * displacement, add 0 for displacement.
+        *     SDT         Uprobe     Prefix
+        *     -----------------------------
+        *     +24(%rdi)   +24(%di)   +
+        *     24(%rdi)    +24(%di)   +
+        *     %rdi        %di
+        *     (%rdi)      +0(%di)    +0
+        *     -80(%rbx)   -80(%bx)   -
+        */
+       if (rm[3].rm_so != rm[3].rm_eo) {
+               if (rm[1].rm_so != rm[1].rm_eo)
+                       prefix[0] = *(old_op + rm[1].rm_so);
+               else if (rm[2].rm_so != rm[2].rm_eo)
+                       prefix[0] = '+';
+               else
+                       strncpy(prefix, "+0", 2);
+       }
+
+       /* Rename register */
+       sdt_rename_register(old_op + rm[4].rm_so, rm[4].rm_eo - rm[4].rm_so,
+                           new_reg);
+
+       /* Prepare final OP which should be valid for uprobe_events */
+       new_len = strlen(prefix)              +
+                 (rm[2].rm_eo - rm[2].rm_so) +
+                 (rm[3].rm_eo - rm[3].rm_so) +
+                 strlen(new_reg)             +
+                 (rm[5].rm_eo - rm[5].rm_so) +
+                 1;                                    /* NULL */
+
+       *new_op = zalloc(new_len);
+       if (!*new_op)
+               return -ENOMEM;
+
+       scnprintf(*new_op, new_len, "%.*s%.*s%.*s%.*s%.*s",
+                 strlen(prefix), prefix,
+                 (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so,
+                 (int)(rm[3].rm_eo - rm[3].rm_so), old_op + rm[3].rm_so,
+                 strlen(new_reg), new_reg,
+                 (int)(rm[5].rm_eo - rm[5].rm_so), old_op + rm[5].rm_so);
+
+       return SDT_ARG_VALID;
 }
index 7ae238929e9545cf779540f9b192d35118bbcba2..1eec96a0fa675350fed9e55e1bbef85bfd266171 100644 (file)
@@ -301,12 +301,6 @@ void list_common_cmds_help(void)
        }
 }
 
-static int is_perf_command(const char *s)
-{
-       return is_in_cmdlist(&main_cmds, s) ||
-               is_in_cmdlist(&other_cmds, s);
-}
-
 static const char *cmd_to_page(const char *perf_cmd)
 {
        char *s;
@@ -446,7 +440,6 @@ int cmd_help(int argc, const char **argv)
                "perf help [--all] [--man|--web|--info] [command]",
                NULL
        };
-       const char *alias;
        int rc;
 
        load_command_list("perf-", &main_cmds, &other_cmds);
@@ -472,12 +465,6 @@ int cmd_help(int argc, const char **argv)
                return 0;
        }
 
-       alias = alias_lookup(argv[0]);
-       if (alias && !is_perf_command(argv[0])) {
-               printf("`perf %s' is aliased to `%s'\n", argv[0], alias);
-               return 0;
-       }
-
        switch (help_format) {
        case HELP_FORMAT_MAN:
                rc = show_man_page(argv[0]);
index c88f9f215e6f7bf68a7f62d7a98eb27c605dc55f..fce278d5fadad20c42500242894d48f1c7d47156 100644 (file)
@@ -31,6 +31,7 @@
 #include "util/intlist.h"
 #include "util/thread_map.h"
 #include "util/stat.h"
+#include "trace/beauty/beauty.h"
 #include "trace-event.h"
 #include "util/parse-events.h"
 #include "util/bpf-loader.h"
@@ -267,15 +268,6 @@ out_delete:
        ({ struct syscall_tp *fields = evsel->priv; \
           fields->name.pointer(&fields->name, sample); })
 
-struct syscall_arg {
-       unsigned long val;
-       struct thread *thread;
-       struct trace  *trace;
-       void          *parm;
-       u8            idx;
-       u8            mask;
-};
-
 struct strarray {
        int         offset;
        int         nr_entries;
@@ -771,6 +763,10 @@ static struct syscall_fmt {
          .arg_parm      = { [0] = &strarray__socket_families, /* family */ }, },
        { .name     = "stat",       .errmsg = true, .alias = "newstat", },
        { .name     = "statfs",     .errmsg = true, },
+       { .name     = "statx",      .errmsg = true,
+         .arg_scnprintf = { [0] = SCA_FDAT, /* flags */
+                            [2] = SCA_STATX_FLAGS, /* flags */
+                            [3] = SCA_STATX_MASK, /* mask */ }, },
        { .name     = "swapoff",    .errmsg = true,
          .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
        { .name     = "swapon",     .errmsg = true,
@@ -821,12 +817,21 @@ struct syscall {
        void                **arg_parm;
 };
 
-static size_t fprintf_duration(unsigned long t, FILE *fp)
+/*
+ * We need to have this 'calculated' boolean because in some cases we really
+ * don't know what is the duration of a syscall, for instance, when we start
+ * a session and some threads are waiting for a syscall to finish, say 'poll',
+ * in which case all we can do is to print "( ? ) for duration and for the
+ * start timestamp.
+ */
+static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
 {
        double duration = (double)t / NSEC_PER_MSEC;
        size_t printed = fprintf(fp, "(");
 
-       if (duration >= 1.0)
+       if (!calculated)
+               printed += fprintf(fp, "     ?   ");
+       else if (duration >= 1.0)
                printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
        else if (duration >= 0.01)
                printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
@@ -1028,13 +1033,27 @@ static bool trace__filter_duration(struct trace *trace, double t)
        return t < (trace->duration_filter * NSEC_PER_MSEC);
 }
 
-static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
+static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
 {
        double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
 
        return fprintf(fp, "%10.3f ", ts);
 }
 
+/*
+ * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
+ * using ttrace->entry_time for a thread that receives a sys_exit without
+ * first having received a sys_enter ("poll" issued before tracing session
+ * starts, lost sys_enter exit due to ring buffer overflow).
+ */
+static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
+{
+       if (tstamp > 0)
+               return __trace__fprintf_tstamp(trace, tstamp, fp);
+
+       return fprintf(fp, "         ? ");
+}
+
 static bool done = false;
 static bool interrupted = false;
 
@@ -1045,10 +1064,10 @@ static void sig_handler(int sig)
 }
 
 static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
-                                       u64 duration, u64 tstamp, FILE *fp)
+                                       u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
 {
        size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
-       printed += fprintf_duration(duration, fp);
+       printed += fprintf_duration(duration, duration_calculated, fp);
 
        if (trace->multiple_threads) {
                if (trace->show_comm)
@@ -1450,7 +1469,7 @@ static int trace__printf_interrupted_entry(struct trace *trace, struct perf_samp
 
        duration = sample->time - ttrace->entry_time;
 
-       printed  = trace__fprintf_entry_head(trace, trace->current, duration, ttrace->entry_time, trace->output);
+       printed  = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
        printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
        ttrace->entry_pending = false;
 
@@ -1497,7 +1516,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
 
        if (sc->is_exit) {
                if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
-                       trace__fprintf_entry_head(trace, thread, 1, ttrace->entry_time, trace->output);
+                       trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
                        fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
                }
        } else {
@@ -1545,6 +1564,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
 {
        long ret;
        u64 duration = 0;
+       bool duration_calculated = false;
        struct thread *thread;
        int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
        struct syscall *sc = trace__syscall_info(trace, evsel, id);
@@ -1573,6 +1593,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
                duration = sample->time - ttrace->entry_time;
                if (trace__filter_duration(trace, duration))
                        goto out;
+               duration_calculated = true;
        } else if (trace->duration_filter)
                goto out;
 
@@ -1588,7 +1609,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
        if (trace->summary_only)
                goto out;
 
-       trace__fprintf_entry_head(trace, thread, duration, ttrace->entry_time, trace->output);
+       trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
 
        if (ttrace->entry_pending) {
                fprintf(trace->output, "%-70s", ttrace->entry_str);
@@ -1855,7 +1876,7 @@ static int trace__pgfault(struct trace *trace,
        thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
                              sample->ip, &al);
 
-       trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
+       trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
 
        fprintf(trace->output, "%sfault [",
                evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
index c747bfd7f14da88e5478692a00cb30d587852a08..83fe2202382eda0cd95eafc15a726cb9022527d8 100755 (executable)
@@ -1,7 +1,9 @@
 #!/bin/sh
 
 HEADERS='
+include/uapi/linux/fcntl.h
 include/uapi/linux/perf_event.h
+include/uapi/linux/stat.h
 include/linux/hash.h
 include/uapi/linux/hw_breakpoint.h
 arch/x86/include/asm/disabled-features.h
index 4b283d18e158f3b7f56985d38f9cf65b9b950b14..9217f2227f3d2eb053245d92eddec05b9db2fb83 100644 (file)
@@ -267,71 +267,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
        return handled;
 }
 
-static int handle_alias(int *argcp, const char ***argv)
-{
-       int envchanged = 0, ret = 0, saved_errno = errno;
-       int count, option_count;
-       const char **new_argv;
-       const char *alias_command;
-       char *alias_string;
-
-       alias_command = (*argv)[0];
-       alias_string = alias_lookup(alias_command);
-       if (alias_string) {
-               if (alias_string[0] == '!') {
-                       if (*argcp > 1) {
-                               struct strbuf buf;
-
-                               if (strbuf_init(&buf, PATH_MAX) < 0 ||
-                                   strbuf_addstr(&buf, alias_string) < 0 ||
-                                   sq_quote_argv(&buf, (*argv) + 1,
-                                                 PATH_MAX) < 0)
-                                       die("Failed to allocate memory.");
-                               free(alias_string);
-                               alias_string = buf.buf;
-                       }
-                       ret = system(alias_string + 1);
-                       if (ret >= 0 && WIFEXITED(ret) &&
-                           WEXITSTATUS(ret) != 127)
-                               exit(WEXITSTATUS(ret));
-                       die("Failed to run '%s' when expanding alias '%s'",
-                           alias_string + 1, alias_command);
-               }
-               count = split_cmdline(alias_string, &new_argv);
-               if (count < 0)
-                       die("Bad alias.%s string", alias_command);
-               option_count = handle_options(&new_argv, &count, &envchanged);
-               if (envchanged)
-                       die("alias '%s' changes environment variables\n"
-                                "You can use '!perf' in the alias to do this.",
-                                alias_command);
-               memmove(new_argv - option_count, new_argv,
-                               count * sizeof(char *));
-               new_argv -= option_count;
-
-               if (count < 1)
-                       die("empty alias for %s", alias_command);
-
-               if (!strcmp(alias_command, new_argv[0]))
-                       die("recursive alias: %s", alias_command);
-
-               new_argv = realloc(new_argv, sizeof(char *) *
-                                   (count + *argcp + 1));
-               /* insert after command name */
-               memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp);
-               new_argv[count + *argcp] = NULL;
-
-               *argv = new_argv;
-               *argcp += count - 1;
-
-               ret = 1;
-       }
-
-       errno = saved_errno;
-
-       return ret;
-}
-
 #define RUN_SETUP      (1<<0)
 #define USE_PAGER      (1<<1)
 
@@ -455,25 +390,12 @@ do_die:
 
 static int run_argv(int *argcp, const char ***argv)
 {
-       int done_alias = 0;
-
-       while (1) {
-               /* See if it's an internal command */
-               handle_internal_command(*argcp, *argv);
-
-               /* .. then try the external ones */
-               execv_dashed_external(*argv);
+       /* See if it's an internal command */
+       handle_internal_command(*argcp, *argv);
 
-               /* It could be an alias -- this works around the insanity
-                * of overriding "perf log" with "perf show" by having
-                * alias.log = show
-                */
-               if (done_alias || !handle_alias(argcp, argv))
-                       break;
-               done_alias = 1;
-       }
-
-       return done_alias;
+       /* .. then try the external ones */
+       execv_dashed_external(*argv);
+       return 0;
 }
 
 static void pthread__block_sigwinch(void)
@@ -606,17 +528,12 @@ int main(int argc, const char **argv)
 
        while (1) {
                static int done_help;
-               int was_alias = run_argv(&argc, &argv);
+
+               run_argv(&argc, &argv);
 
                if (errno != ENOENT)
                        break;
 
-               if (was_alias) {
-                       fprintf(stderr, "Expansion of alias '%s' failed; "
-                               "'%s' is not a perf-command\n",
-                               cmd, argv[0]);
-                       goto out;
-               }
                if (!done_help) {
                        cmd = argv[0] = help_unknown_cmd(cmd);
                        done_help = 1;
diff --git a/tools/perf/trace/beauty/Build b/tools/perf/trace/beauty/Build
new file mode 100644 (file)
index 0000000..be95ac6
--- /dev/null
@@ -0,0 +1 @@
+libperf-y += statx.o
diff --git a/tools/perf/trace/beauty/beauty.h b/tools/perf/trace/beauty/beauty.h
new file mode 100644 (file)
index 0000000..cf50be3
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _PERF_TRACE_BEAUTY_H
+#define _PERF_TRACE_BEAUTY_H
+
+#include <linux/types.h>
+
+struct trace;
+struct thread;
+
+struct syscall_arg {
+       unsigned long val;
+       struct thread *thread;
+       struct trace  *trace;
+       void          *parm;
+       u8            idx;
+       u8            mask;
+};
+
+size_t syscall_arg__scnprintf_statx_flags(char *bf, size_t size, struct syscall_arg *arg);
+#define SCA_STATX_FLAGS syscall_arg__scnprintf_statx_flags
+
+size_t syscall_arg__scnprintf_statx_mask(char *bf, size_t size, struct syscall_arg *arg);
+#define SCA_STATX_MASK syscall_arg__scnprintf_statx_mask
+
+#endif /* _PERF_TRACE_BEAUTY_H */
diff --git a/tools/perf/trace/beauty/statx.c b/tools/perf/trace/beauty/statx.c
new file mode 100644 (file)
index 0000000..5643b69
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * trace/beauty/statx.c
+ *
+ *  Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Released under the GPL v2. (and only v2, not any later version)
+ */
+
+#include "trace/beauty/beauty.h"
+#include <linux/kernel.h>
+#include <sys/types.h>
+#include <uapi/linux/fcntl.h>
+#include <uapi/linux/stat.h>
+
+size_t syscall_arg__scnprintf_statx_flags(char *bf, size_t size, struct syscall_arg *arg)
+{
+       int printed = 0, flags = arg->val;
+
+       if (flags == 0)
+               return scnprintf(bf, size, "SYNC_AS_STAT");
+#define        P_FLAG(n) \
+       if (flags & AT_##n) { \
+               printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
+               flags &= ~AT_##n; \
+       }
+
+       P_FLAG(SYMLINK_NOFOLLOW);
+       P_FLAG(REMOVEDIR);
+       P_FLAG(SYMLINK_FOLLOW);
+       P_FLAG(NO_AUTOMOUNT);
+       P_FLAG(EMPTY_PATH);
+       P_FLAG(STATX_FORCE_SYNC);
+       P_FLAG(STATX_DONT_SYNC);
+
+#undef P_FLAG
+
+       if (flags)
+               printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
+
+       return printed;
+}
+
+size_t syscall_arg__scnprintf_statx_mask(char *bf, size_t size, struct syscall_arg *arg)
+{
+       int printed = 0, flags = arg->val;
+
+#define        P_FLAG(n) \
+       if (flags & STATX_##n) { \
+               printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
+               flags &= ~STATX_##n; \
+       }
+
+       P_FLAG(TYPE);
+       P_FLAG(MODE);
+       P_FLAG(NLINK);
+       P_FLAG(UID);
+       P_FLAG(GID);
+       P_FLAG(ATIME);
+       P_FLAG(MTIME);
+       P_FLAG(CTIME);
+       P_FLAG(INO);
+       P_FLAG(SIZE);
+       P_FLAG(BLOCKS);
+       P_FLAG(BTIME);
+
+#undef P_FLAG
+
+       if (flags)
+               printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
+
+       return printed;
+}
index 2ae92da613dd61ad1d6302c7ff4b1ccdc033e6df..5c0ea11a8f0a12af168b20bfce589661370173cd 100644 (file)
@@ -1,4 +1,3 @@
-libperf-y += alias.o
 libperf-y += annotate.o
 libperf-y += block-range.o
 libperf-y += build-id.o
diff --git a/tools/perf/util/alias.c b/tools/perf/util/alias.c
deleted file mode 100644 (file)
index 6455471..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#include "cache.h"
-#include "util.h"
-#include "config.h"
-
-static const char *alias_key;
-static char *alias_val;
-
-static int alias_lookup_cb(const char *k, const char *v,
-                          void *cb __maybe_unused)
-{
-       if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) {
-               if (!v)
-                       return config_error_nonbool(k);
-               alias_val = strdup(v);
-               return 0;
-       }
-       return 0;
-}
-
-char *alias_lookup(const char *alias)
-{
-       alias_key = alias;
-       alias_val = NULL;
-       perf_config(alias_lookup_cb, NULL);
-       return alias_val;
-}
-
-int split_cmdline(char *cmdline, const char ***argv)
-{
-       int src, dst, count = 0, size = 16;
-       char quoted = 0;
-
-       *argv = malloc(sizeof(char*) * size);
-
-       /* split alias_string */
-       (*argv)[count++] = cmdline;
-       for (src = dst = 0; cmdline[src];) {
-               char c = cmdline[src];
-               if (!quoted && isspace(c)) {
-                       cmdline[dst++] = 0;
-                       while (cmdline[++src]
-                                       && isspace(cmdline[src]))
-                               ; /* skip */
-                       if (count >= size) {
-                               size += 16;
-                               *argv = realloc(*argv, sizeof(char*) * size);
-                       }
-                       (*argv)[count++] = cmdline + dst;
-               } else if (!quoted && (c == '\'' || c == '"')) {
-                       quoted = c;
-                       src++;
-               } else if (c == quoted) {
-                       quoted = 0;
-                       src++;
-               } else {
-                       if (c == '\\' && quoted != '\'') {
-                               src++;
-                               c = cmdline[src];
-                               if (!c) {
-                                       zfree(argv);
-                                       return error("cmdline ends with \\");
-                               }
-                       }
-                       cmdline[dst++] = c;
-                       src++;
-               }
-       }
-
-       cmdline[dst] = 0;
-
-       if (quoted) {
-               zfree(argv);
-               return error("unclosed quote");
-       }
-
-       return count;
-}
-
index 512c0c83fbc6a9a9ed2a9c996de74ff6fb45eb62..0328f297a748380d7e128e69b204e42001c3e8c1 100644 (file)
@@ -15,7 +15,6 @@
 #define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
 #define PERF_PAGER_ENVIRONMENT "PERF_PAGER"
 
-char *alias_lookup(const char *alias);
 int split_cmdline(char *cmdline, const char ***argv);
 
 #define alloc_nr(x) (((x)+16)*3/2)
index d78776a20e8002da76ff0195e243769df2444e49..3cea1fb5404b3ab787c4ad8682c0ece66e975387 100644 (file)
@@ -1105,63 +1105,100 @@ int callchain_branch_counts(struct callchain_root *root,
                                                  cycles_count);
 }
 
-static int callchain_counts_printf(FILE *fp, char *bf, int bfsize,
-                                  u64 branch_count, u64 predicted_count,
-                                  u64 abort_count, u64 cycles_count,
-                                  u64 iter_count, u64 samples_count)
+static int counts_str_build(char *bf, int bfsize,
+                            u64 branch_count, u64 predicted_count,
+                            u64 abort_count, u64 cycles_count,
+                            u64 iter_count, u64 samples_count)
 {
        double predicted_percent = 0.0;
        const char *null_str = "";
        char iter_str[32];
-       char *str;
-       u64 cycles = 0;
-
-       if (branch_count == 0) {
-               if (fp)
-                       return fprintf(fp, " (calltrace)");
+       char cycle_str[32];
+       char *istr, *cstr;
+       u64 cycles;
 
+       if (branch_count == 0)
                return scnprintf(bf, bfsize, " (calltrace)");
-       }
+
+       cycles = cycles_count / branch_count;
 
        if (iter_count && samples_count) {
-               scnprintf(iter_str, sizeof(iter_str),
-                        ", iterations:%" PRId64 "",
-                        iter_count / samples_count);
-               str = iter_str;
+               if (cycles > 0)
+                       scnprintf(iter_str, sizeof(iter_str),
+                                " iterations:%" PRId64 "",
+                                iter_count / samples_count);
+               else
+                       scnprintf(iter_str, sizeof(iter_str),
+                                "iterations:%" PRId64 "",
+                                iter_count / samples_count);
+               istr = iter_str;
+       } else
+               istr = (char *)null_str;
+
+       if (cycles > 0) {
+               scnprintf(cycle_str, sizeof(cycle_str),
+                         "cycles:%" PRId64 "", cycles);
+               cstr = cycle_str;
        } else
-               str = (char *)null_str;
+               cstr = (char *)null_str;
 
        predicted_percent = predicted_count * 100.0 / branch_count;
-       cycles = cycles_count / branch_count;
 
-       if ((predicted_percent >= 100.0) && (abort_count == 0)) {
-               if (fp)
-                       return fprintf(fp, " (cycles:%" PRId64 "%s)",
-                                      cycles, str);
+       if ((predicted_count == branch_count) && (abort_count == 0)) {
+               if ((cycles > 0) || (istr != (char *)null_str))
+                       return scnprintf(bf, bfsize, " (%s%s)", cstr, istr);
+               else
+                       return scnprintf(bf, bfsize, "%s", (char *)null_str);
+       }
 
-               return scnprintf(bf, bfsize, " (cycles:%" PRId64 "%s)",
-                                cycles, str);
+       if ((predicted_count < branch_count) && (abort_count == 0)) {
+               if ((cycles > 0) || (istr != (char *)null_str))
+                       return scnprintf(bf, bfsize,
+                               " (predicted:%.1f%% %s%s)",
+                               predicted_percent, cstr, istr);
+               else {
+                       return scnprintf(bf, bfsize,
+                               " (predicted:%.1f%%)",
+                               predicted_percent);
+               }
        }
 
-       if ((predicted_percent < 100.0) && (abort_count == 0)) {
-               if (fp)
-                       return fprintf(fp,
-                               " (predicted:%.1f%%, cycles:%" PRId64 "%s)",
-                               predicted_percent, cycles, str);
+       if ((predicted_count == branch_count) && (abort_count > 0)) {
+               if ((cycles > 0) || (istr != (char *)null_str))
+                       return scnprintf(bf, bfsize,
+                               " (abort:%" PRId64 " %s%s)",
+                               abort_count, cstr, istr);
+               else
+                       return scnprintf(bf, bfsize,
+                               " (abort:%" PRId64 ")",
+                               abort_count);
+       }
 
+       if ((cycles > 0) || (istr != (char *)null_str))
                return scnprintf(bf, bfsize,
-                       " (predicted:%.1f%%, cycles:%" PRId64 "%s)",
-                       predicted_percent, cycles, str);
-       }
+                       " (predicted:%.1f%% abort:%" PRId64 " %s%s)",
+                       predicted_percent, abort_count, cstr, istr);
+
+       return scnprintf(bf, bfsize,
+                       " (predicted:%.1f%% abort:%" PRId64 ")",
+                       predicted_percent, abort_count);
+}
+
+static int callchain_counts_printf(FILE *fp, char *bf, int bfsize,
+                                  u64 branch_count, u64 predicted_count,
+                                  u64 abort_count, u64 cycles_count,
+                                  u64 iter_count, u64 samples_count)
+{
+       char str[128];
+
+       counts_str_build(str, sizeof(str), branch_count,
+                        predicted_count, abort_count, cycles_count,
+                        iter_count, samples_count);
 
        if (fp)
-               return fprintf(fp,
-               " (predicted:%.1f%%, abort:%" PRId64 ", cycles:%" PRId64 "%s)",
-                       predicted_percent, abort_count, cycles, str);
+               return fprintf(fp, "%s", str);
 
-       return scnprintf(bf, bfsize,
-               " (predicted:%.1f%%, abort:%" PRId64 ", cycles:%" PRId64 "%s)",
-               predicted_percent, abort_count, cycles, str);
+       return scnprintf(bf, bfsize, "%s", str);
 }
 
 int callchain_list_counts__printf_value(struct callchain_node *node,
index 0c7d5a4975cd4a8f798533cbd15660c058652d37..7b01d59076d3a68247e2115b3fe59c85547c0a92 100644 (file)
@@ -627,6 +627,8 @@ static int perf_config_set__init(struct perf_config_set *set)
 {
        int ret = -1;
        const char *home = NULL;
+       char *user_config;
+       struct stat st;
 
        /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
        if (config_exclusive_filename)
@@ -637,35 +639,41 @@ static int perf_config_set__init(struct perf_config_set *set)
        }
 
        home = getenv("HOME");
-       if (perf_config_global() && home) {
-               char *user_config = strdup(mkpath("%s/.perfconfig", home));
-               struct stat st;
 
-               if (user_config == NULL) {
-                       warning("Not enough memory to process %s/.perfconfig, "
-                               "ignoring it.", home);
-                       goto out;
-               }
+       /*
+        * Skip reading user config if:
+        *   - there is no place to read it from (HOME)
+        *   - we are asked not to (PERF_CONFIG_NOGLOBAL=1)
+        */
+       if (!home || !*home || !perf_config_global())
+               return 0;
 
-               if (stat(user_config, &st) < 0) {
-                       if (errno == ENOENT)
-                               ret = 0;
-                       goto out_free;
-               }
+       user_config = strdup(mkpath("%s/.perfconfig", home));
+       if (user_config == NULL) {
+               warning("Not enough memory to process %s/.perfconfig, "
+                       "ignoring it.", home);
+               goto out;
+       }
+
+       if (stat(user_config, &st) < 0) {
+               if (errno == ENOENT)
+                       ret = 0;
+               goto out_free;
+       }
 
-               ret = 0;
+       ret = 0;
 
-               if (st.st_uid && (st.st_uid != geteuid())) {
-                       warning("File %s not owned by current user or root, "
-                               "ignoring it.", user_config);
-                       goto out_free;
-               }
+       if (st.st_uid && (st.st_uid != geteuid())) {
+               warning("File %s not owned by current user or root, "
+                       "ignoring it.", user_config);
+               goto out_free;
+       }
+
+       if (st.st_size)
+               ret = perf_config_from_file(collect_config, user_config, set);
 
-               if (st.st_size)
-                       ret = perf_config_from_file(collect_config, user_config, set);
 out_free:
-               free(user_config);
-       }
+       free(user_config);
 out:
        return ret;
 }
index 2821f8d77e5208116cbd5832f9b9833d0764221e..34201440ac03dca697c0c28eeced7344ac747f5d 100644 (file)
@@ -6,16 +6,12 @@
 #include "levenshtein.h"
 
 static int autocorrect;
-static struct cmdnames aliases;
 
 static int perf_unknown_cmd_config(const char *var, const char *value,
                                   void *cb __maybe_unused)
 {
        if (!strcmp(var, "help.autocorrect"))
                autocorrect = perf_config_int(var,value);
-       /* Also use aliases for command lookup */
-       if (!prefixcmp(var, "alias."))
-               add_cmdname(&aliases, var + 6, strlen(var + 6));
 
        return 0;
 }
@@ -59,14 +55,12 @@ const char *help_unknown_cmd(const char *cmd)
 
        memset(&main_cmds, 0, sizeof(main_cmds));
        memset(&other_cmds, 0, sizeof(main_cmds));
-       memset(&aliases, 0, sizeof(aliases));
 
        perf_config(perf_unknown_cmd_config, NULL);
 
        load_command_list("perf-", &main_cmds, &other_cmds);
 
-       if (add_cmd_list(&main_cmds, &aliases) < 0 ||
-           add_cmd_list(&main_cmds, &other_cmds) < 0) {
+       if (add_cmd_list(&main_cmds, &other_cmds) < 0) {
                fprintf(stderr, "ERROR: Failed to allocate command list for unknown command.\n");
                goto end;
        }
index 3c4d4d00cb2cd1ba4cabcab34b19ca6b19536f77..61bf304206fd50a5775bf0cddb313fb75686db5f 100644 (file)
@@ -2459,7 +2459,7 @@ int parse_filter_percentage(const struct option *opt __maybe_unused,
        else if (!strcmp(arg, "absolute"))
                symbol_conf.filter_relative = false;
        else {
-               pr_debug("Invalud percentage: %s\n", arg);
+               pr_debug("Invalid percentage: %s\n", arg);
                return -1;
        }
 
index a37e5934aa2aa9020fa5cfab08298e1880b1a6f4..b2ae039eff85c4c7166fecaa713704edf952956c 100644 (file)
@@ -6,10 +6,10 @@ const struct sample_reg __weak sample_reg_masks[] = {
        SMPL_REG_END
 };
 
-int __weak sdt_rename_register(char **pdesc __maybe_unused,
-                       char *old_name __maybe_unused)
+int __weak arch_sdt_arg_parse_op(char *old_op __maybe_unused,
+                                char **new_op __maybe_unused)
 {
-       return 0;
+       return SDT_ARG_SKIP;
 }
 
 #ifdef HAVE_PERF_REGS_SUPPORT
index 7544a157e15951739e5806d79683336c3d2726d1..32b37d19dcc34b4bffffcdb0f755d4ea14cab55f 100644 (file)
@@ -15,11 +15,12 @@ struct sample_reg {
 
 extern const struct sample_reg sample_reg_masks[];
 
-/*
- * The table sdt_reg_renamings is used for adjusting gcc/gas-generated
- * registers before filling the uprobe tracer interface.
- */
-int sdt_rename_register(char **pdesc, char *old_name);
+enum {
+       SDT_ARG_VALID = 0,
+       SDT_ARG_SKIP,
+};
+
+int arch_sdt_arg_parse_op(char *old_op, char **new_op);
 
 #ifdef HAVE_PERF_REGS_SUPPORT
 #include <perf_regs.h>
index d741634cbfc03d6063e71ace5f6cd69dfecf86eb..88714dec891223f10e41dd794e08ab8180bcdc52 100644 (file)
@@ -694,10 +694,29 @@ static const char * const type_to_suffix[] = {
        "", ":u8", ":u16", "", ":u32", "", "", "", ":u64"
 };
 
+/*
+ * Isolate the string number and convert it into a decimal value;
+ * this will be an index to get suffix of the uprobe name (defining
+ * the type)
+ */
+static int sdt_arg_parse_size(char *n_ptr, const char **suffix)
+{
+       long type_idx;
+
+       type_idx = strtol(n_ptr, NULL, 10);
+       if (type_idx < -8 || type_idx > 8) {
+               pr_debug4("Failed to get a valid sdt type\n");
+               return -1;
+       }
+
+       *suffix = type_to_suffix[type_idx + 8];
+       return 0;
+}
+
 static int synthesize_sdt_probe_arg(struct strbuf *buf, int i, const char *arg)
 {
-       char *tmp, *desc = strdup(arg);
-       const char *prefix = "", *suffix = "";
+       char *op, *desc = strdup(arg), *new_op = NULL;
+       const char *suffix = "";
        int ret = -1;
 
        if (desc == NULL) {
@@ -705,112 +724,37 @@ static int synthesize_sdt_probe_arg(struct strbuf *buf, int i, const char *arg)
                return ret;
        }
 
-       tmp = strchr(desc, '@');
-       if (tmp) {
-               long type_idx;
-               /*
-                * Isolate the string number and convert it into a
-                * binary value; this will be an index to get suffix
-                * of the uprobe name (defining the type)
-                */
-               tmp[0] = '\0';
-               type_idx = strtol(desc, NULL, 10);
-               /* Check that the conversion went OK */
-               if (type_idx == LONG_MIN || type_idx == LONG_MAX) {
-                       pr_debug4("Failed to parse sdt type\n");
-                       goto error;
-               }
-               /* Check that the converted value is OK */
-               if (type_idx < -8 || type_idx > 8) {
-                       pr_debug4("Failed to get a valid sdt type\n");
-                       goto error;
-               }
-               suffix = type_to_suffix[type_idx + 8];
-               /* Get rid of the sdt prefix which is now useless */
-               tmp++;
-               memmove(desc, tmp, strlen(tmp) + 1);
-       }
-
        /*
-        * The uprobe tracer format does not support all the
-        * addressing modes (notably: in x86 the scaled mode); so, we
-        * detect ',' characters, if there is just one, there is no
-        * use converting the sdt arg into a uprobe one.
+        * Argument is in N@OP format. N is size of the argument and OP is
+        * the actual assembly operand. N can be omitted; in that case
+        * argument is just OP(without @).
         */
-       if (strchr(desc, ',')) {
-               pr_debug4("Skipping unsupported SDT argument; %s\n", desc);
-               goto out;
-       }
+       op = strchr(desc, '@');
+       if (op) {
+               op[0] = '\0';
+               op++;
 
-       /*
-        * If the argument addressing mode is indirect, we must check
-        * a few things...
-        */
-       tmp = strchr(desc, '(');
-       if (tmp) {
-               int j;
-
-               /*
-                * ...if the addressing mode is indirect with a
-                * positive offset (ex.: "1608(%ax)"), we need to add
-                * a '+' prefix so as to be compliant with uprobe
-                * format.
-                */
-               if (desc[0] != '+' && desc[0] != '-')
-                       prefix = "+";
-
-               /*
-                * ...or if the addressing mode is indirect with a symbol
-                * as offset, the argument will not be supported by
-                * the uprobe tracer format; so, let's skip this one.
-                */
-               for (j = 0; j < tmp - desc; j++) {
-                       if (desc[j] != '+' && desc[j] != '-' &&
-                               !isdigit(desc[j])) {
-                               pr_debug4("Skipping unsupported SDT argument; "
-                                       "%s\n", desc);
-                               goto out;
-                       }
-               }
+               if (sdt_arg_parse_size(desc, &suffix))
+                       goto error;
+       } else {
+               op = desc;
        }
 
-       /*
-        * The uprobe tracer format does not support constants; if we
-        * find one in the current argument, let's skip the argument.
-        */
-       if (strchr(desc, '$')) {
-               pr_debug4("Skipping unsupported SDT argument; %s\n", desc);
-               goto out;
-       }
+       ret = arch_sdt_arg_parse_op(op, &new_op);
 
-       /*
-        * The uprobe parser does not support all gas register names;
-        * so, we have to replace them (ex. for x86_64: %rax -> %ax);
-        * the loop below looks for the register names (starting with
-        * a '%' and tries to perform the needed renamings.
-        */
-       tmp = strchr(desc, '%');
-       while (tmp) {
-               size_t offset = tmp - desc;
+       if (ret < 0)
+               goto error;
 
-               ret = sdt_rename_register(&desc, desc + offset);
+       if (ret == SDT_ARG_VALID) {
+               ret = strbuf_addf(buf, " arg%d=%s%s", i + 1, new_op, suffix);
                if (ret < 0)
                        goto error;
-
-               /*
-                * The desc pointer might have changed; so, let's not
-                * try to reuse tmp for next lookup
-                */
-               tmp = strchr(desc + offset + 1, '%');
        }
 
-       if (strbuf_addf(buf, " arg%d=%s%s%s", i + 1, prefix, desc, suffix) < 0)
-               goto error;
-
-out:
        ret = 0;
 error:
        free(desc);
+       free(new_op);
        return ret;
 }