Merge tag 'perf-core-for-mingo-5.5-20191021' of git://git.kernel.org/pub/scm/linux...
authorIngo Molnar <mingo@kernel.org>
Mon, 21 Oct 2019 23:15:45 +0000 (01:15 +0200)
committerIngo Molnar <mingo@kernel.org>
Mon, 21 Oct 2019 23:15:45 +0000 (01:15 +0200)
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

perf trace:

- Add syscall failure stats to -s/--summary and -S/--with-summary, works in
  combination with specifying just a set of syscalls, see below first with
  -s/--summary, then with -S/--with-summary just for the syscalls we saw failing
  with -s:

    # perf trace -s sleep 1

     Summary of events:

     sleep (16218), 80 events, 93.0%

       syscall     calls  errors  total      min      avg      max   stddev
                                  (msec)   (msec)   (msec)   (msec)    (%)
       ----------- -----  ------ -------- -------- -------- -------- ------
       nanosleep       1      0  1000.091 1000.091 1000.091 1000.091  0.00%
       mmap            8      0     0.045    0.005    0.006    0.008  7.09%
       mprotect        4      0     0.028    0.005    0.007    0.009 11.38%
       openat          3      0     0.021    0.005    0.007    0.009 14.07%
       munmap          1      0     0.017    0.017    0.017    0.017  0.00%
       brk             4      0     0.010    0.001    0.002    0.004 23.15%
       read            4      0     0.009    0.002    0.002    0.003  8.13%
       close           5      0     0.008    0.001    0.002    0.002 10.83%
       fstat           3      0     0.006    0.002    0.002    0.002  6.97%
       access          1      1     0.006    0.006    0.006    0.006  0.00%
       lseek           3      0     0.005    0.001    0.002    0.002  7.37%
       arch_prctl      2      1     0.004    0.001    0.002    0.002 17.64%
       execve          1      0     0.000    0.000    0.000    0.000  0.00%

    # perf trace -e access,arch_prctl -S sleep 1
         0.000 ( 0.006 ms): sleep/19503 arch_prctl(option: 0x3001, arg2: 0x7fff165996b0) = -1 EINVAL (Invalid argument)
         0.024 ( 0.006 ms): sleep/19503 access(filename: 0x2177e510, mode: R)            = -1 ENOENT (No such file or directory)
         0.136 ( 0.002 ms): sleep/19503 arch_prctl(option: SET_FS, arg2: 0x7f9421737580) = 0

     Summary of events:

     sleep (19503), 6 events, 50.0%

       syscall    calls  errors total    min    avg    max  stddev
                                (msec) (msec) (msec) (msec)    (%)
       ---------- -----  ------ ------ ------ ------ ------ ------
       arch_prctl   2       1    0.008  0.002  0.004  0.006 57.22%
       access       1       1    0.006  0.006  0.006  0.006  0.00%

    #

  - Introduce --errno-summary, to drill down a bit more in the errno stats:

    # perf trace --errno-summary -e access,arch_prctl -S sleep 1
         0.000 ( 0.006 ms): sleep/5587 arch_prctl(option: 0x3001, arg2: 0x7ffd6ba6aa00) = -1 EINVAL (Invalid argument)
         0.028 ( 0.007 ms): sleep/5587 access(filename: 0xb83d9510, mode: R)            = -1 ENOENT (No such file or directory)
         0.172 ( 0.003 ms): sleep/5587 arch_prctl(option: SET_FS, arg2: 0x7f45b8392580) = 0

     Summary of events:

     sleep (5587), 6 events, 50.0%

       syscall    calls  errors total    min    avg    max  stddev
                                (msec) (msec) (msec) (msec)   (%)
       ---------- -----  ------ ------ ------ ------ ------ ------
       arch_prctl     2     1    0.009  0.003  0.005  0.006 38.90%
   EINVAL: 1
       access         1     1    0.007  0.007  0.007  0.007  0.00%
                           ENOENT: 1
    #

  - Filter own pid to avoid a feedback look in 'perf trace record -a'

  - Add the glue for the auto generated x86 IRQ vector array.

  - Show error message when not finding a field used in a filter expression

    # perf trace --max-events=4 -e syscalls:sys_enter_write --filter="cnt>32767"
    Failed to set filter "(cnt>32767) && (common_pid != 19938 && common_pid != 8922)" on event syscalls:sys_enter_write with 22 (Invalid argument)
    #
    # perf trace --max-events=4 -e syscalls:sys_enter_write --filter="count>32767"
         0.000 python3.5/17535 syscalls:sys_enter_write(fd: 3, buf: 0x564b0dc53600, count: 172086)
        12.641 python3.5.post/17535 syscalls:sys_enter_write(fd: 3, buf: 0x564b0db63660, count: 75994)
        27.738 python3.5.post/17535 syscalls:sys_enter_write(fd: 3, buf: 0x564b0db4b1e0, count: 41635)
       136.070 python3.5.post/17535 syscalls:sys_enter_write(fd: 3, buf: 0x564b0dbab510, count: 62232)
    #

  - Add a generator for x86's IRQ vectors -> strings

  - Introduce stroul() (string -> number) methods for the strarray and
    strarrays classes, also strtoul_flags, allowing to go from both strings
    and or-ed strings to numbers, allowing things like:

    # perf trace -e syscalls:sys_enter_mmap --filter="flags==DENYWRITE|PRIVATE|FIXED" sleep 1
         0.000 sleep/22588 syscalls:sys_enter_mmap(addr: 0x7f42d2aa5000, len: 1363968, prot: READ|EXEC, flags: PRIVATE|FIXED|DENYWRITE, fd: 3, off: 0x22000)
         0.011 sleep/22588 syscalls:sys_enter_mmap(addr: 0x7f42d2bf2000, len: 311296, prot: READ, flags: PRIVATE|FIXED|DENYWRITE, fd: 3, off: 0x16f000)
         0.015 sleep/22588 syscalls:sys_enter_mmap(addr: 0x7f42d2c3f000, len: 24576, prot: READ|WRITE, flags: PRIVATE|FIXED|DENYWRITE, fd: 3, off: 0x1bb000)
    #

  Allowing to narrow down from the complete set of mmap calls for that workload:

    # perf trace -e syscalls:sys_enter_mmap sleep 1
         0.000 sleep/22695 syscalls:sys_enter_mmap(len: 134773, prot: READ, flags: PRIVATE, fd: 3)
         0.041 sleep/22695 syscalls:sys_enter_mmap(len: 8192, prot: READ|WRITE, flags: PRIVATE|ANONYMOUS)
         0.053 sleep/22695 syscalls:sys_enter_mmap(len: 1857472, prot: READ, flags: PRIVATE|DENYWRITE, fd: 3)
         0.069 sleep/22695 syscalls:sys_enter_mmap(addr: 0x7fd23ffb6000, len: 1363968, prot: READ|EXEC, flags: PRIVATE|FIXED|DENYWRITE, fd: 3, off: 0x22000)
         0.077 sleep/22695 syscalls:sys_enter_mmap(addr: 0x7fd240103000, len: 311296, prot: READ, flags: PRIVATE|FIXED|DENYWRITE, fd: 3, off: 0x16f000)
         0.083 sleep/22695 syscalls:sys_enter_mmap(addr: 0x7fd240150000, len: 24576, prot: READ|WRITE, flags: PRIVATE|FIXED|DENYWRITE, fd: 3, off: 0x1bb000)
         0.095 sleep/22695 syscalls:sys_enter_mmap(addr: 0x7fd240156000, len: 14272, prot: READ|WRITE, flags: PRIVATE|FIXED|ANONYMOUS)
         0.339 sleep/22695 syscalls:sys_enter_mmap(len: 217750512, prot: READ, flags: PRIVATE, fd: 3)
    #

  Works with all targets, so, for system wide, looking at who calls mmap with flags set to just "PRIVATE":

    # perf trace --max-events=5 -e syscalls:sys_enter_mmap --filter="flags==PRIVATE"
         0.000 pool/2242 syscalls:sys_enter_mmap(len: 756, prot: READ, flags: PRIVATE, fd: 14)
         0.050 pool/2242 syscalls:sys_enter_mmap(len: 756, prot: READ, flags: PRIVATE, fd: 14)
         0.062 pool/2242 syscalls:sys_enter_mmap(len: 756, prot: READ, flags: PRIVATE, fd: 14)
         0.145 goa-identity-s/2240 syscalls:sys_enter_mmap(len: 756, prot: READ, flags: PRIVATE, fd: 18)
         0.183 goa-identity-s/2240 syscalls:sys_enter_mmap(len: 756, prot: READ, flags: PRIVATE, fd: 18)
    #

  # perf trace --max-events=2 -e syscalls:sys_enter_lseek --filter="whence==SET && offset != 0"
         0.000 Cache2 I/O/12047 syscalls:sys_enter_lseek(fd: 277, offset: 43, whence: SET)
      1142.070 mozStorage #5/12302 syscalls:sys_enter_lseek(fd: 44</home/acme/.mozilla/firefox/ina67tev.default/cookies.sqlite-wal>, offset: 393536, whence: SET)
  #

perf annotate:

  - Fix objdump --no-show-raw-insn flag to work with goth gcc and clang.

  - Streamline objdump execution, preserving the right error codes for better
    reporting to user.

perf report:

  - Add warning when libunwind not compiled in.

perf stat:

  Jin Yao:

  - Support --all-kernel/--all-user, to match options available in 'perf record',
    asking that all the events specified work just with kernel or user events.

perf list:

  Jin Yao:

  - Hide deprecated events by default, allow showing them with --deprecated.

libbperf:

  Jiri Olsa:

  - Allow to build with -ltcmalloc.

  - Finish mmap interface, getting more stuff from tools/perf while adding
    abstractions to avoid pulling too much stuff, to get libperf to grow as
    tools needs things like auxtrace, etc.

perf scripting engines:

  Steven Rostedt (VMware):

  - Iterate on tep event arrays directly, fixing script generation with
    '-g python' when having multiple tracepoints in a perf.data file.

core:

  - Allow to build with -ltcmalloc.

perf test:

  Leo Yan:

  - Report failure for mmap events.

  - Avoid infinite loop for task exit case.

  - Remove needless headers for bp_account test.

  - Add dedicated checking helper is_supported().

  - Disable bp_signal testing for arm64.

Vendor events:

arm64:

  John Garry:

  - Fix Hisi hip08 DDRC PMU eventname.

  - Add some missing events for Hisi hip08 DDRC, L3C and HHA PMUs.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
60 files changed:
tools/arch/x86/include/asm/irq_vectors.h [new file with mode: 0644]
tools/perf/Documentation/perf-list.txt
tools/perf/Documentation/perf-stat.txt
tools/perf/Documentation/perf-trace.txt
tools/perf/Makefile.config
tools/perf/Makefile.perf
tools/perf/builtin-list.c
tools/perf/builtin-report.c
tools/perf/builtin-script.c
tools/perf/builtin-stat.c
tools/perf/builtin-trace.c
tools/perf/check-headers.sh
tools/perf/lib/Makefile
tools/perf/lib/evlist.c
tools/perf/lib/include/internal/evlist.h
tools/perf/lib/include/internal/evsel.h
tools/perf/lib/include/internal/mmap.h
tools/perf/lib/include/internal/tests.h
tools/perf/lib/include/perf/core.h
tools/perf/lib/include/perf/evlist.h
tools/perf/lib/include/perf/evsel.h
tools/perf/lib/internal.h
tools/perf/lib/libperf.map
tools/perf/lib/mmap.c
tools/perf/lib/tests/Makefile
tools/perf/lib/tests/test-cpumap.c
tools/perf/lib/tests/test-evlist.c
tools/perf/lib/tests/test-evsel.c
tools/perf/lib/tests/test-threadmap.c
tools/perf/pmu-events/arch/arm64/hisilicon/hip08/uncore-ddrc.json
tools/perf/pmu-events/arch/arm64/hisilicon/hip08/uncore-hha.json
tools/perf/pmu-events/arch/arm64/hisilicon/hip08/uncore-l3c.json
tools/perf/pmu-events/jevents.c
tools/perf/pmu-events/jevents.h
tools/perf/pmu-events/pmu-events.h
tools/perf/tests/bp_account.c
tools/perf/tests/bp_signal.c
tools/perf/tests/builtin-test.c
tools/perf/tests/task-exit.c
tools/perf/tests/tests.h
tools/perf/trace/beauty/beauty.h
tools/perf/trace/beauty/mmap.c
tools/perf/trace/beauty/tracepoints/Build
tools/perf/trace/beauty/tracepoints/x86_irq_vectors.c [new file with mode: 0644]
tools/perf/trace/beauty/tracepoints/x86_irq_vectors.sh [new file with mode: 0755]
tools/perf/util/annotate.c
tools/perf/util/evlist.c
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h
tools/perf/util/pmu.c
tools/perf/util/pmu.h
tools/perf/util/scripting-engines/trace-event-perl.c
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/stat.c
tools/perf/util/stat.h
tools/perf/util/string2.h
tools/perf/util/time-utils.c
tools/perf/util/time-utils.h
tools/perf/util/trace-event-parse.c
tools/perf/util/trace-event.h

diff --git a/tools/arch/x86/include/asm/irq_vectors.h b/tools/arch/x86/include/asm/irq_vectors.h
new file mode 100644 (file)
index 0000000..889f8b1
--- /dev/null
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_IRQ_VECTORS_H
+#define _ASM_X86_IRQ_VECTORS_H
+
+#include <linux/threads.h>
+/*
+ * Linux IRQ vector layout.
+ *
+ * There are 256 IDT entries (per CPU - each entry is 8 bytes) which can
+ * be defined by Linux. They are used as a jump table by the CPU when a
+ * given vector is triggered - by a CPU-external, CPU-internal or
+ * software-triggered event.
+ *
+ * Linux sets the kernel code address each entry jumps to early during
+ * bootup, and never changes them. This is the general layout of the
+ * IDT entries:
+ *
+ *  Vectors   0 ...  31 : system traps and exceptions - hardcoded events
+ *  Vectors  32 ... 127 : device interrupts
+ *  Vector  128         : legacy int80 syscall interface
+ *  Vectors 129 ... LOCAL_TIMER_VECTOR-1
+ *  Vectors LOCAL_TIMER_VECTOR ... 255 : special interrupts
+ *
+ * 64-bit x86 has per CPU IDT tables, 32-bit has one shared IDT table.
+ *
+ * This file enumerates the exact layout of them:
+ */
+
+#define NMI_VECTOR                     0x02
+#define MCE_VECTOR                     0x12
+
+/*
+ * IDT vectors usable for external interrupt sources start at 0x20.
+ * (0x80 is the syscall vector, 0x30-0x3f are for ISA)
+ */
+#define FIRST_EXTERNAL_VECTOR          0x20
+
+/*
+ * Reserve the lowest usable vector (and hence lowest priority)  0x20 for
+ * triggering cleanup after irq migration. 0x21-0x2f will still be used
+ * for device interrupts.
+ */
+#define IRQ_MOVE_CLEANUP_VECTOR                FIRST_EXTERNAL_VECTOR
+
+#define IA32_SYSCALL_VECTOR            0x80
+
+/*
+ * Vectors 0x30-0x3f are used for ISA interrupts.
+ *   round up to the next 16-vector boundary
+ */
+#define ISA_IRQ_VECTOR(irq)            (((FIRST_EXTERNAL_VECTOR + 16) & ~15) + irq)
+
+/*
+ * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
+ *
+ *  some of the following vectors are 'rare', they are merged
+ *  into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
+ *  TLB, reschedule and local APIC vectors are performance-critical.
+ */
+
+#define SPURIOUS_APIC_VECTOR           0xff
+/*
+ * Sanity check
+ */
+#if ((SPURIOUS_APIC_VECTOR & 0x0F) != 0x0F)
+# error SPURIOUS_APIC_VECTOR definition error
+#endif
+
+#define ERROR_APIC_VECTOR              0xfe
+#define RESCHEDULE_VECTOR              0xfd
+#define CALL_FUNCTION_VECTOR           0xfc
+#define CALL_FUNCTION_SINGLE_VECTOR    0xfb
+#define THERMAL_APIC_VECTOR            0xfa
+#define THRESHOLD_APIC_VECTOR          0xf9
+#define REBOOT_VECTOR                  0xf8
+
+/*
+ * Generic system vector for platform specific use
+ */
+#define X86_PLATFORM_IPI_VECTOR                0xf7
+
+/*
+ * IRQ work vector:
+ */
+#define IRQ_WORK_VECTOR                        0xf6
+
+#define UV_BAU_MESSAGE                 0xf5
+#define DEFERRED_ERROR_VECTOR          0xf4
+
+/* Vector on which hypervisor callbacks will be delivered */
+#define HYPERVISOR_CALLBACK_VECTOR     0xf3
+
+/* Vector for KVM to deliver posted interrupt IPI */
+#ifdef CONFIG_HAVE_KVM
+#define POSTED_INTR_VECTOR             0xf2
+#define POSTED_INTR_WAKEUP_VECTOR      0xf1
+#define POSTED_INTR_NESTED_VECTOR      0xf0
+#endif
+
+#define MANAGED_IRQ_SHUTDOWN_VECTOR    0xef
+
+#if IS_ENABLED(CONFIG_HYPERV)
+#define HYPERV_REENLIGHTENMENT_VECTOR  0xee
+#define HYPERV_STIMER0_VECTOR          0xed
+#endif
+
+#define LOCAL_TIMER_VECTOR             0xec
+
+#define NR_VECTORS                      256
+
+#ifdef CONFIG_X86_LOCAL_APIC
+#define FIRST_SYSTEM_VECTOR            LOCAL_TIMER_VECTOR
+#else
+#define FIRST_SYSTEM_VECTOR            NR_VECTORS
+#endif
+
+/*
+ * Size the maximum number of interrupts.
+ *
+ * If the irq_desc[] array has a sparse layout, we can size things
+ * generously - it scales up linearly with the maximum number of CPUs,
+ * and the maximum number of IO-APICs, whichever is higher.
+ *
+ * In other cases we size more conservatively, to not create too large
+ * static arrays.
+ */
+
+#define NR_IRQS_LEGACY                 16
+
+#define CPU_VECTOR_LIMIT               (64 * NR_CPUS)
+#define IO_APIC_VECTOR_LIMIT           (32 * MAX_IO_APICS)
+
+#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_PCI_MSI)
+#define NR_IRQS                                                \
+       (CPU_VECTOR_LIMIT > IO_APIC_VECTOR_LIMIT ?      \
+               (NR_VECTORS + CPU_VECTOR_LIMIT)  :      \
+               (NR_VECTORS + IO_APIC_VECTOR_LIMIT))
+#elif defined(CONFIG_X86_IO_APIC)
+#define        NR_IRQS                         (NR_VECTORS + IO_APIC_VECTOR_LIMIT)
+#elif defined(CONFIG_PCI_MSI)
+#define NR_IRQS                                (NR_VECTORS + CPU_VECTOR_LIMIT)
+#else
+#define NR_IRQS                                NR_IRQS_LEGACY
+#endif
+
+#endif /* _ASM_X86_IRQ_VECTORS_H */
index 18ed1b0..6345db3 100644 (file)
@@ -36,6 +36,9 @@ Enable debugging output.
 Print how named events are resolved internally into perf events, and also
 any extra expressions computed by perf stat.
 
+--deprecated::
+Print deprecated events. By default the deprecated events are hidden.
+
 [[EVENT_MODIFIERS]]
 EVENT MODIFIERS
 ---------------
index 930c51c..a9af4e4 100644 (file)
@@ -323,6 +323,12 @@ The output is SMI cycles%, equals to (aperf - unhalted core cycles) / aperf
 
 Users who wants to get the actual value can apply --no-metric-only.
 
+--all-kernel::
+Configure all used events to run in kernel space.
+
+--all-user::
+Configure all used events to run in user space.
+
 EXAMPLES
 --------
 
index 3bb89c2..abc9b5d 100644 (file)
@@ -146,6 +146,10 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
        Show all syscalls followed by a summary by thread with min, max, and
     average times (in msec) and relative stddev.
 
+--errno-summary::
+       To be used with -s or -S, to show stats for the errnos experienced by
+       syscalls, using only this option will trigger --summary.
+
 --tool_stats::
        Show tool stats such as number of times fd->pathname was discovered thru
        hooking the open syscall return + vfs_getname or via reading /proc/pid/fd, etc.
index 063202c..1783427 100644 (file)
@@ -265,6 +265,11 @@ LDFLAGS += -Wl,-z,noexecstack
 
 EXTLIBS = -lpthread -lrt -lm -ldl
 
+ifneq ($(TCMALLOC),)
+  CFLAGS += -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free
+  EXTLIBS += -ltcmalloc
+endif
+
 ifeq ($(FEATURES_DUMP),)
 include $(srctree)/tools/build/Makefile.feature
 else
index a099a8a..1cd2944 100644 (file)
@@ -114,6 +114,8 @@ include ../scripts/utilities.mak
 # Define NO_LIBZSTD if you do not want support of Zstandard based runtime
 # trace compression in record mode.
 #
+# Define TCMALLOC to enable tcmalloc heap profiling.
+#
 
 # As per kernel Makefile, avoid funny character set dependencies
 unexport LC_ALL
@@ -544,6 +546,12 @@ x86_arch_prctl_code_tbl := $(srctree)/tools/perf/trace/beauty/x86_arch_prctl.sh
 $(x86_arch_prctl_code_array): $(x86_arch_asm_uapi_dir)/prctl.h $(x86_arch_prctl_code_tbl)
        $(Q)$(SHELL) '$(x86_arch_prctl_code_tbl)' $(x86_arch_asm_uapi_dir) > $@
 
+x86_arch_irq_vectors_array := $(beauty_outdir)/x86_arch_irq_vectors_array.c
+x86_arch_irq_vectors_tbl := $(srctree)/tools/perf/trace/beauty/tracepoints/x86_irq_vectors.sh
+
+$(x86_arch_irq_vectors_array): $(x86_arch_asm_dir)/irq_vectors.h $(x86_arch_irq_vectors_tbl)
+       $(Q)$(SHELL) '$(x86_arch_irq_vectors_tbl)' $(x86_arch_asm_dir) > $@
+
 x86_arch_MSRs_array := $(beauty_outdir)/x86_arch_MSRs_array.c
 x86_arch_MSRs_tbl := $(srctree)/tools/perf/trace/beauty/tracepoints/x86_msr.sh
 
@@ -684,6 +692,7 @@ prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders $(drm_ioc
        $(perf_ioctl_array) \
        $(prctl_option_array) \
        $(usbdevfs_ioctl_array) \
+       $(x86_arch_irq_vectors_array) \
        $(x86_arch_MSRs_array) \
        $(x86_arch_prctl_code_array) \
        $(rename_flags_array) \
@@ -989,6 +998,7 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea
                $(OUTPUT)$(perf_ioctl_array) \
                $(OUTPUT)$(prctl_option_array) \
                $(OUTPUT)$(usbdevfs_ioctl_array) \
+               $(OUTPUT)$(x86_arch_irq_vectors_array) \
                $(OUTPUT)$(x86_arch_MSRs_array) \
                $(OUTPUT)$(x86_arch_prctl_code_array) \
                $(OUTPUT)$(rename_flags_array) \
index 08e62ae..965ef01 100644 (file)
@@ -26,6 +26,7 @@ int cmd_list(int argc, const char **argv)
        int i;
        bool raw_dump = false;
        bool long_desc_flag = false;
+       bool deprecated = false;
        struct option list_options[] = {
                OPT_BOOLEAN(0, "raw-dump", &raw_dump, "Dump raw events"),
                OPT_BOOLEAN('d', "desc", &desc_flag,
@@ -34,6 +35,8 @@ int cmd_list(int argc, const char **argv)
                            "Print longer event descriptions."),
                OPT_BOOLEAN(0, "details", &details_flag,
                            "Print information on the perf event names and expressions used internally by events."),
+               OPT_BOOLEAN(0, "deprecated", &deprecated,
+                           "Print deprecated events."),
                OPT_INCR(0, "debug", &verbose,
                             "Enable debugging output"),
                OPT_END()
@@ -55,7 +58,7 @@ int cmd_list(int argc, const char **argv)
 
        if (argc == 0) {
                print_events(NULL, raw_dump, !desc_flag, long_desc_flag,
-                               details_flag);
+                               details_flag, deprecated);
                return 0;
        }
 
@@ -78,7 +81,8 @@ int cmd_list(int argc, const char **argv)
                        print_hwcache_events(NULL, raw_dump);
                else if (strcmp(argv[i], "pmu") == 0)
                        print_pmu_events(NULL, raw_dump, !desc_flag,
-                                               long_desc_flag, details_flag);
+                                               long_desc_flag, details_flag,
+                                               deprecated);
                else if (strcmp(argv[i], "sdt") == 0)
                        print_sdt_events(NULL, NULL, raw_dump);
                else if (strcmp(argv[i], "metric") == 0 || strcmp(argv[i], "metrics") == 0)
@@ -91,7 +95,8 @@ int cmd_list(int argc, const char **argv)
                        if (sep == NULL) {
                                print_events(argv[i], raw_dump, !desc_flag,
                                                        long_desc_flag,
-                                                       details_flag);
+                                                       details_flag,
+                                                       deprecated);
                                continue;
                        }
                        sep_idx = sep - argv[i];
@@ -117,7 +122,8 @@ int cmd_list(int argc, const char **argv)
                        print_hwcache_events(s, raw_dump);
                        print_pmu_events(s, raw_dump, !desc_flag,
                                                long_desc_flag,
-                                               details_flag);
+                                               details_flag,
+                                               deprecated);
                        print_tracepoint_events(NULL, s, raw_dump);
                        print_sdt_events(NULL, s, raw_dump);
                        metricgroup__print(true, true, s, raw_dump, details_flag);
index aae0e57..7accaf8 100644 (file)
@@ -399,6 +399,13 @@ static int report__setup_sample_type(struct report *rep)
                                PERF_SAMPLE_BRANCH_ANY))
                rep->nonany_branch_mode = true;
 
+#ifndef HAVE_LIBUNWIND_SUPPORT
+       if (dwarf_callchain_users) {
+               ui__warning("Please install libunwind development packages "
+                           "during the perf build.\n");
+       }
+#endif
+
        return 0;
 }
 
index 1c797a9..f86c5cc 100644 (file)
@@ -3864,10 +3864,11 @@ int cmd_script(int argc, const char **argv)
                goto out_delete;
 
        if (script.time_str) {
-               err = perf_time__parse_for_ranges(script.time_str, session,
+               err = perf_time__parse_for_ranges_reltime(script.time_str, session,
                                                  &script.ptime_range,
                                                  &script.range_size,
-                                                 &script.range_num);
+                                                 &script.range_num,
+                                                 reltime);
                if (err < 0)
                        goto out_delete;
 
index 468fc49..c88d4e1 100644 (file)
@@ -803,6 +803,12 @@ static struct option stat_options[] = {
        OPT_CALLBACK('M', "metrics", &evsel_list, "metric/metric group list",
                     "monitor specified metrics or metric groups (separated by ,)",
                     parse_metric_groups),
+       OPT_BOOLEAN_FLAG(0, "all-kernel", &stat_config.all_kernel,
+                        "Configure all used events to run in kernel space.",
+                        PARSE_OPT_EXCLUSIVE),
+       OPT_BOOLEAN_FLAG(0, "all-user", &stat_config.all_user,
+                        "Configure all used events to run in user space.",
+                        PARSE_OPT_EXCLUSIVE),
        OPT_END()
 };
 
index 144d417..43c05ea 100644 (file)
@@ -175,6 +175,7 @@ struct trace {
        bool                    multiple_threads;
        bool                    summary;
        bool                    summary_only;
+       bool                    errno_summary;
        bool                    failure_only;
        bool                    show_comm;
        bool                    print_sample;
@@ -284,6 +285,87 @@ struct syscall_tp {
        };
 };
 
+/*
+ * The evsel->priv as used by 'perf trace'
+ * sc: for raw_syscalls:sys_{enter,exit} and syscalls:sys_{enter,exit}_SYSCALLNAME
+ * fmt: for all the other tracepoints
+ */
+struct evsel_trace {
+       struct syscall_tp       sc;
+       struct syscall_arg_fmt  *fmt;
+};
+
+static struct evsel_trace *evsel_trace__new(void)
+{
+       return zalloc(sizeof(struct evsel_trace));
+}
+
+static void evsel_trace__delete(struct evsel_trace *et)
+{
+       if (et == NULL)
+               return;
+
+       zfree(&et->fmt);
+       free(et);
+}
+
+/*
+ * Used with raw_syscalls:sys_{enter,exit} and with the
+ * syscalls:sys_{enter,exit}_SYSCALL tracepoints
+ */
+static inline struct syscall_tp *__evsel__syscall_tp(struct evsel *evsel)
+{
+       struct evsel_trace *et = evsel->priv;
+
+       return &et->sc;
+}
+
+static struct syscall_tp *evsel__syscall_tp(struct evsel *evsel)
+{
+       if (evsel->priv == NULL) {
+               evsel->priv = evsel_trace__new();
+               if (evsel->priv == NULL)
+                       return NULL;
+       }
+
+       return __evsel__syscall_tp(evsel);
+}
+
+/*
+ * Used with all the other tracepoints.
+ */
+static inline struct syscall_arg_fmt *__evsel__syscall_arg_fmt(struct evsel *evsel)
+{
+       struct evsel_trace *et = evsel->priv;
+
+       return et->fmt;
+}
+
+static struct syscall_arg_fmt *evsel__syscall_arg_fmt(struct evsel *evsel)
+{
+       struct evsel_trace *et = evsel->priv;
+
+       if (evsel->priv == NULL) {
+               et = evsel->priv = evsel_trace__new();
+
+               if (et == NULL)
+                       return NULL;
+       }
+
+       if (et->fmt == NULL) {
+               et->fmt = calloc(evsel->tp_format->format.nr_fields, sizeof(struct syscall_arg_fmt));
+               if (et->fmt == NULL)
+                       goto out_delete;
+       }
+
+       return __evsel__syscall_arg_fmt(evsel);
+
+out_delete:
+       evsel_trace__delete(evsel->priv);
+       evsel->priv = NULL;
+       return NULL;
+}
+
 static int perf_evsel__init_tp_uint_field(struct evsel *evsel,
                                          struct tp_field *field,
                                          const char *name)
@@ -297,7 +379,7 @@ static int perf_evsel__init_tp_uint_field(struct evsel *evsel,
 }
 
 #define perf_evsel__init_sc_tp_uint_field(evsel, name) \
-       ({ struct syscall_tp *sc = evsel->priv;\
+       ({ struct syscall_tp *sc = __evsel__syscall_tp(evsel);\
           perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
 
 static int perf_evsel__init_tp_ptr_field(struct evsel *evsel,
@@ -313,7 +395,7 @@ static int perf_evsel__init_tp_ptr_field(struct evsel *evsel,
 }
 
 #define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
-       ({ struct syscall_tp *sc = evsel->priv;\
+       ({ struct syscall_tp *sc = __evsel__syscall_tp(evsel);\
           perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
 
 static void evsel__delete_priv(struct evsel *evsel)
@@ -324,73 +406,61 @@ static void evsel__delete_priv(struct evsel *evsel)
 
 static int perf_evsel__init_syscall_tp(struct evsel *evsel)
 {
-       struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp));
+       struct syscall_tp *sc = evsel__syscall_tp(evsel);
 
-       if (evsel->priv != NULL) {
+       if (sc != NULL) {
                if (perf_evsel__init_tp_uint_field(evsel, &sc->id, "__syscall_nr") &&
                    perf_evsel__init_tp_uint_field(evsel, &sc->id, "nr"))
-                       goto out_delete;
+                       return -ENOENT;
                return 0;
        }
 
        return -ENOMEM;
-out_delete:
-       zfree(&evsel->priv);
-       return -ENOENT;
 }
 
 static int perf_evsel__init_augmented_syscall_tp(struct evsel *evsel, struct evsel *tp)
 {
-       struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp));
+       struct syscall_tp *sc = evsel__syscall_tp(evsel);
 
-       if (evsel->priv != NULL) {
+       if (sc != NULL) {
                struct tep_format_field *syscall_id = perf_evsel__field(tp, "id");
                if (syscall_id == NULL)
                        syscall_id = perf_evsel__field(tp, "__syscall_nr");
-               if (syscall_id == NULL)
-                       goto out_delete;
-               if (__tp_field__init_uint(&sc->id, syscall_id->size, syscall_id->offset, evsel->needs_swap))
-                       goto out_delete;
+               if (syscall_id == NULL ||
+                   __tp_field__init_uint(&sc->id, syscall_id->size, syscall_id->offset, evsel->needs_swap))
+                       return -EINVAL;
 
                return 0;
        }
 
        return -ENOMEM;
-out_delete:
-       zfree(&evsel->priv);
-       return -EINVAL;
 }
 
 static int perf_evsel__init_augmented_syscall_tp_args(struct evsel *evsel)
 {
-       struct syscall_tp *sc = evsel->priv;
+       struct syscall_tp *sc = __evsel__syscall_tp(evsel);
 
        return __tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64));
 }
 
 static int perf_evsel__init_augmented_syscall_tp_ret(struct evsel *evsel)
 {
-       struct syscall_tp *sc = evsel->priv;
+       struct syscall_tp *sc = __evsel__syscall_tp(evsel);
 
        return __tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap);
 }
 
 static int perf_evsel__init_raw_syscall_tp(struct evsel *evsel, void *handler)
 {
-       evsel->priv = malloc(sizeof(struct syscall_tp));
-       if (evsel->priv != NULL) {
+       if (evsel__syscall_tp(evsel) != NULL) {
                if (perf_evsel__init_sc_tp_uint_field(evsel, id))
-                       goto out_delete;
+                       return -ENOENT;
 
                evsel->handler = handler;
                return 0;
        }
 
        return -ENOMEM;
-
-out_delete:
-       zfree(&evsel->priv);
-       return -ENOENT;
 }
 
 static struct evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *handler)
@@ -415,13 +485,27 @@ out_delete:
 }
 
 #define perf_evsel__sc_tp_uint(evsel, name, sample) \
-       ({ struct syscall_tp *fields = evsel->priv; \
+       ({ struct syscall_tp *fields = __evsel__syscall_tp(evsel); \
           fields->name.integer(&fields->name, sample); })
 
 #define perf_evsel__sc_tp_ptr(evsel, name, sample) \
-       ({ struct syscall_tp *fields = evsel->priv; \
+       ({ struct syscall_tp *fields = __evsel__syscall_tp(evsel); \
           fields->name.pointer(&fields->name, sample); })
 
+size_t strarray__scnprintf_suffix(struct strarray *sa, char *bf, size_t size, const char *intfmt, bool show_suffix, int val)
+{
+       int idx = val - sa->offset;
+
+       if (idx < 0 || idx >= sa->nr_entries || sa->entries[idx] == NULL) {
+               size_t printed = scnprintf(bf, size, intfmt, val);
+               if (show_suffix)
+                       printed += scnprintf(bf + printed, size - printed, " /* %s??? */", sa->prefix);
+               return printed;
+       }
+
+       return scnprintf(bf, size, "%s%s", sa->entries[idx], show_suffix ? sa->prefix : "");
+}
+
 size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, bool show_prefix, int val)
 {
        int idx = val - sa->offset;
@@ -451,6 +535,21 @@ static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
 
 #define SCA_STRARRAY syscall_arg__scnprintf_strarray
 
+bool syscall_arg__strtoul_strarray(char *bf, size_t size, struct syscall_arg *arg, u64 *ret)
+{
+       return strarray__strtoul(arg->parm, bf, size, ret);
+}
+
+bool syscall_arg__strtoul_strarray_flags(char *bf, size_t size, struct syscall_arg *arg, u64 *ret)
+{
+       return strarray__strtoul_flags(arg->parm, bf, size, ret);
+}
+
+bool syscall_arg__strtoul_strarrays(char *bf, size_t size, struct syscall_arg *arg, u64 *ret)
+{
+       return strarrays__strtoul(arg->parm, bf, size, ret);
+}
+
 size_t syscall_arg__scnprintf_strarray_flags(char *bf, size_t size, struct syscall_arg *arg)
 {
        return strarray__scnprintf_flags(arg->parm, bf, size, arg->show_string_prefix, arg->val);
@@ -492,6 +591,49 @@ bool strarray__strtoul(struct strarray *sa, char *bf, size_t size, u64 *ret)
        return false;
 }
 
+bool strarray__strtoul_flags(struct strarray *sa, char *bf, size_t size, u64 *ret)
+{
+       u64 val = 0;
+       char *tok = bf, *sep, *end;
+
+       *ret = 0;
+
+       while (size != 0) {
+               int toklen = size;
+
+               sep = memchr(tok, '|', size);
+               if (sep != NULL) {
+                       size -= sep - tok + 1;
+
+                       end = sep - 1;
+                       while (end > tok && isspace(*end))
+                               --end;
+
+                       toklen = end - tok + 1;
+               }
+
+               while (isspace(*tok))
+                       ++tok;
+
+               if (isalpha(*tok) || *tok == '_') {
+                       if (!strarray__strtoul(sa, tok, toklen, &val))
+                               return false;
+               } else {
+                       bool is_hexa = tok[0] == 0 && (tok[1] = 'x' || tok[1] == 'X');
+
+                       val = strtoul(tok, NULL, is_hexa ? 16 : 0);
+               }
+
+               *ret |= (1 << (val - 1));
+
+               if (sep == NULL)
+                       break;
+               tok = sep + 1;
+       }
+
+       return true;
+}
+
 bool strarrays__strtoul(struct strarrays *sas, char *bf, size_t size, u64 *ret)
 {
        int i;
@@ -562,7 +704,7 @@ static size_t syscall_arg__scnprintf_char_array(char *bf, size_t size, struct sy
        // XXX Hey, maybe for sched:sched_switch prev/next comm fields we can
        //     fill missing comms using thread__set_comm()...
        //     here or in a special syscall_arg__scnprintf_pid_sched_tp...
-       return scnprintf(bf, size, "\"%-.*s\"", arg->fmt->nr_entries, arg->val);
+       return scnprintf(bf, size, "\"%-.*s\"", arg->fmt->nr_entries ?: arg->len, arg->val);
 }
 
 #define SCA_CHAR_ARRAY syscall_arg__scnprintf_char_array
@@ -740,10 +882,12 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
 
 #define STRARRAY(name, array) \
          { .scnprintf  = SCA_STRARRAY, \
+           .strtoul    = STUL_STRARRAY, \
            .parm       = &strarray__##array, }
 
 #define STRARRAY_FLAGS(name, array) \
          { .scnprintf  = SCA_STRARRAY_FLAGS, \
+           .strtoul    = STUL_STRARRAY_FLAGS, \
            .parm       = &strarray__##array, }
 
 #include "trace/beauty/arch_errno_names.c"
@@ -799,7 +943,8 @@ static struct syscall_fmt syscall_fmts[] = {
        { .name     = "fchownat",
          .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
        { .name     = "fcntl",
-         .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */
+         .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD,  /* cmd */
+                          .strtoul   = STUL_STRARRAYS,
                           .parm      = &strarrays__fcntl_cmds_arrays,
                           .show_zero = true, },
                   [2] = { .scnprintf =  SCA_FCNTL_ARG, /* arg */ }, }, },
@@ -870,7 +1015,9 @@ static struct syscall_fmt syscall_fmts[] = {
        .alias = "old_mmap",
 #endif
          .arg = { [2] = { .scnprintf = SCA_MMAP_PROT,  /* prot */ },
-                  [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ },
+                  [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */
+                          .strtoul   = STUL_STRARRAY_FLAGS,
+                          .parm      = &strarray__mmap_flags, },
                   [5] = { .scnprintf = SCA_HEX,        /* offset */ }, }, },
        { .name     = "mount",
          .arg = { [0] = { .scnprintf = SCA_FILENAME, /* dev_name */ },
@@ -1513,7 +1660,8 @@ static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
 }
 
 static struct syscall_arg_fmt syscall_arg_fmts__by_name[] = {
-       { .name = "msr", .scnprintf = SCA_X86_MSR, .strtoul = STUL_X86_MSR, }
+       { .name = "msr",        .scnprintf = SCA_X86_MSR,         .strtoul = STUL_X86_MSR,         },
+       { .name = "vector",     .scnprintf = SCA_X86_IRQ_VECTORS, .strtoul = STUL_X86_IRQ_VECTORS, },
 };
 
 static int syscall_arg_fmt__cmp(const void *name, const void *fmtp)
@@ -1558,7 +1706,7 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
                        arg->scnprintf = SCA_PID;
                else if (strcmp(field->type, "umode_t") == 0)
                        arg->scnprintf = SCA_MODE_T;
-               else if ((field->flags & TEP_FIELD_IS_ARRAY) && strstarts(field->type, "char")) {
+               else if ((field->flags & TEP_FIELD_IS_ARRAY) && strstr(field->type, "char")) {
                        arg->scnprintf = SCA_CHAR_ARRAY;
                        arg->nr_entries = field->arraylen;
                } else if ((strcmp(field->type, "int") == 0 ||
@@ -1653,11 +1801,10 @@ static int trace__read_syscall_info(struct trace *trace, int id)
 
 static int perf_evsel__init_tp_arg_scnprintf(struct evsel *evsel)
 {
-       int nr_args = evsel->tp_format->format.nr_fields;
+       struct syscall_arg_fmt *fmt = evsel__syscall_arg_fmt(evsel);
 
-       evsel->priv = calloc(nr_args, sizeof(struct syscall_arg_fmt));
-       if (evsel->priv != NULL) {
-               syscall_arg_fmt__init_array(evsel->priv, evsel->tp_format->format.fields);
+       if (fmt != NULL) {
+               syscall_arg_fmt__init_array(fmt, evsel->tp_format->format.fields);
                return 0;
        }
 
@@ -1958,11 +2105,18 @@ out_cant_read:
        return NULL;
 }
 
-static void thread__update_stats(struct thread_trace *ttrace,
-                                int id, struct perf_sample *sample)
+struct syscall_stats {
+       struct stats stats;
+       u64          nr_failures;
+       int          max_errno;
+       u32          *errnos;
+};
+
+static void thread__update_stats(struct thread *thread, struct thread_trace *ttrace,
+                                int id, struct perf_sample *sample, long err, bool errno_summary)
 {
        struct int_node *inode;
-       struct stats *stats;
+       struct syscall_stats *stats;
        u64 duration = 0;
 
        inode = intlist__findnew(ttrace->syscall_stats, id);
@@ -1971,17 +2125,46 @@ static void thread__update_stats(struct thread_trace *ttrace,
 
        stats = inode->priv;
        if (stats == NULL) {
-               stats = malloc(sizeof(struct stats));
+               stats = malloc(sizeof(*stats));
                if (stats == NULL)
                        return;
-               init_stats(stats);
+
+               stats->nr_failures = 0;
+               stats->max_errno   = 0;
+               stats->errnos      = NULL;
+               init_stats(&stats->stats);
                inode->priv = stats;
        }
 
        if (ttrace->entry_time && sample->time > ttrace->entry_time)
                duration = sample->time - ttrace->entry_time;
 
-       update_stats(stats, duration);
+       update_stats(&stats->stats, duration);
+
+       if (err < 0) {
+               ++stats->nr_failures;
+
+               if (!errno_summary)
+                       return;
+
+               err = -err;
+               if (err > stats->max_errno) {
+                       u32 *new_errnos = realloc(stats->errnos, err * sizeof(u32));
+
+                       if (new_errnos) {
+                               memset(new_errnos + stats->max_errno, 0, (err - stats->max_errno) * sizeof(u32));
+                       } else {
+                               pr_debug("Not enough memory for errno stats for thread \"%s\"(%d/%d), results will be incomplete\n",
+                                        thread__comm_str(thread), thread->pid_, thread->tid);
+                               return;
+                       }
+
+                       stats->errnos = new_errnos;
+                       stats->max_errno = err;
+               }
+
+               ++stats->errnos[err - 1];
+       }
 }
 
 static int trace__printf_interrupted_entry(struct trace *trace)
@@ -2226,11 +2409,11 @@ static int trace__sys_exit(struct trace *trace, struct evsel *evsel,
 
        trace__fprintf_sample(trace, evsel, sample, thread);
 
-       if (trace->summary)
-               thread__update_stats(ttrace, id, sample);
-
        ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
 
+       if (trace->summary)
+               thread__update_stats(thread, ttrace, id, sample, ret, trace->errno_summary);
+
        if (!trace->fd_path_disabled && sc->is_open && ret >= 0 && ttrace->filename.pending_open) {
                trace__set_fd_pathname(thread, ret, ttrace->filename.name);
                ttrace->filename.pending_open = false;
@@ -2466,7 +2649,7 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct evsel *evsel,
        char bf[2048];
        size_t size = sizeof(bf);
        struct tep_format_field *field = evsel->tp_format->format.fields;
-       struct syscall_arg_fmt *arg = evsel->priv;
+       struct syscall_arg_fmt *arg = __evsel__syscall_arg_fmt(evsel);
        size_t printed = 0;
        unsigned long val;
        u8 bit = 1;
@@ -2486,10 +2669,19 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct evsel *evsel,
                if (syscall_arg.mask & bit)
                        continue;
 
+               syscall_arg.len = 0;
                syscall_arg.fmt = arg;
-               if (field->flags & TEP_FIELD_IS_ARRAY)
-                       val = (uintptr_t)(sample->raw_data + field->offset);
-               else
+               if (field->flags & TEP_FIELD_IS_ARRAY) {
+                       int offset = field->offset;
+
+                       if (field->flags & TEP_FIELD_IS_DYNAMIC) {
+                               offset = format_field__intval(field, sample, evsel->needs_swap);
+                               syscall_arg.len = offset >> 16;
+                               offset &= 0xffff;
+                       }
+
+                       val = (uintptr_t)(sample->raw_data + offset);
+               } else
                        val = format_field__intval(field, sample, evsel->needs_swap);
                /*
                 * Some syscall args need some mask, most don't and
@@ -2592,12 +2784,6 @@ static int trace__event_handler(struct trace *trace, struct evsel *evsel,
                        } else {
                                trace__fprintf_tp_fields(trace, evsel, sample, thread, NULL, 0);
                        }
-                       ++trace->nr_events_printed;
-
-                       if (evsel->max_events != ULONG_MAX && ++evsel->nr_events_printed == evsel->max_events) {
-                               evsel__disable(evsel);
-                               evsel__close(evsel);
-                       }
                }
        }
 
@@ -2608,6 +2794,13 @@ newline:
                trace__fprintf_callchain(trace, sample);
        else if (callchain_ret < 0)
                pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
+
+       ++trace->nr_events_printed;
+
+       if (evsel->max_events != ULONG_MAX && ++evsel->nr_events_printed == evsel->max_events) {
+               evsel__disable(evsel);
+               evsel__close(evsel);
+       }
 out:
        thread__put(thread);
        return 0;
@@ -2759,21 +2952,23 @@ static int trace__record(struct trace *trace, int argc, const char **argv)
                "-m", "1024",
                "-c", "1",
        };
-
+       pid_t pid = getpid();
+       char *filter = asprintf__tp_filter_pids(1, &pid);
        const char * const sc_args[] = { "-e", };
        unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
        const char * const majpf_args[] = { "-e", "major-faults" };
        unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
        const char * const minpf_args[] = { "-e", "minor-faults" };
        unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
+       int err = -1;
 
-       /* +1 is for the event string below */
-       rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
+       /* +3 is for the event string below and the pid filter */
+       rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 3 +
                majpf_args_nr + minpf_args_nr + argc;
        rec_argv = calloc(rec_argc + 1, sizeof(char *));
 
-       if (rec_argv == NULL)
-               return -ENOMEM;
+       if (rec_argv == NULL || filter == NULL)
+               goto out_free;
 
        j = 0;
        for (i = 0; i < ARRAY_SIZE(record_args); i++)
@@ -2790,11 +2985,13 @@ static int trace__record(struct trace *trace, int argc, const char **argv)
                        rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
                else {
                        pr_err("Neither raw_syscalls nor syscalls events exist.\n");
-                       free(rec_argv);
-                       return -1;
+                       goto out_free;
                }
        }
 
+       rec_argv[j++] = "--filter";
+       rec_argv[j++] = filter;
+
        if (trace->trace_pgfaults & TRACE_PFMAJ)
                for (i = 0; i < majpf_args_nr; i++)
                        rec_argv[j++] = majpf_args[i];
@@ -2806,7 +3003,11 @@ static int trace__record(struct trace *trace, int argc, const char **argv)
        for (i = 0; i < (unsigned int)argc; i++)
                rec_argv[j++] = argv[i];
 
-       return cmd_record(j, rec_argv);
+       err = cmd_record(j, rec_argv);
+out_free:
+       free(filter);
+       free(rec_argv);
+       return err;
 }
 
 static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
@@ -3488,7 +3689,7 @@ static int ordered_events__deliver_event(struct ordered_events *oe,
 static struct syscall_arg_fmt *perf_evsel__syscall_arg_fmt(struct evsel *evsel, char *arg)
 {
        struct tep_format_field *field;
-       struct syscall_arg_fmt *fmt = evsel->priv;
+       struct syscall_arg_fmt *fmt = __evsel__syscall_arg_fmt(evsel);
 
        if (evsel->tp_format == NULL || fmt == NULL)
                return NULL;
@@ -3526,7 +3727,7 @@ static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel
                        }
 
                right_end = right + 1;
-               while (isalnum(*right_end) || *right_end == '_')
+               while (isalnum(*right_end) || *right_end == '_' || *right_end == '|')
                        ++right_end;
 
                if (isalpha(*right)) {
@@ -3542,8 +3743,8 @@ static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel
 
                        fmt = perf_evsel__syscall_arg_fmt(evsel, arg);
                        if (fmt == NULL) {
-                               pr_debug("\"%s\" not found in \"%s\", can't set filter \"%s\"\n",
-                                        arg, evsel->name, evsel->filter);
+                               pr_err("\"%s\" not found in \"%s\", can't set filter \"%s\"\n",
+                                      arg, evsel->name, evsel->filter);
                                return -1;
                        }
 
@@ -3552,7 +3753,11 @@ static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel
 
                        if (fmt->strtoul) {
                                u64 val;
-                               if (fmt->strtoul(right, right_size, NULL, &val)) {
+                               struct syscall_arg syscall_arg = {
+                                       .parm = fmt->parm,
+                               };
+
+                               if (fmt->strtoul(right, right_size, &syscall_arg, &val)) {
                                        char *n, expansion[19];
                                        int expansion_lenght = scnprintf(expansion, sizeof(expansion), "%#" PRIx64, val);
                                        int expansion_offset = right - new_filter;
@@ -4016,17 +4221,17 @@ static size_t trace__fprintf_threads_header(FILE *fp)
 }
 
 DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
-       struct stats    *stats;
-       double          msecs;
-       int             syscall;
+       struct syscall_stats *stats;
+       double               msecs;
+       int                  syscall;
 )
 {
        struct int_node *source = rb_entry(nd, struct int_node, rb_node);
-       struct stats *stats = source->priv;
+       struct syscall_stats *stats = source->priv;
 
        entry->syscall = source->i;
        entry->stats   = stats;
-       entry->msecs   = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
+       entry->msecs   = stats ? (u64)stats->stats.n * (avg_stats(&stats->stats) / NSEC_PER_MSEC) : 0;
 }
 
 static size_t thread__dump_stats(struct thread_trace *ttrace,
@@ -4042,27 +4247,37 @@ static size_t thread__dump_stats(struct thread_trace *ttrace,
 
        printed += fprintf(fp, "\n");
 
-       printed += fprintf(fp, "   syscall            calls    total       min       avg       max      stddev\n");
-       printed += fprintf(fp, "                               (msec)    (msec)    (msec)    (msec)        (%%)\n");
-       printed += fprintf(fp, "   --------------- -------- --------- --------- --------- ---------     ------\n");
+       printed += fprintf(fp, "   syscall            calls  errors  total       min       avg       max       stddev\n");
+       printed += fprintf(fp, "                                     (msec)    (msec)    (msec)    (msec)        (%%)\n");
+       printed += fprintf(fp, "   --------------- --------  ------ -------- --------- --------- ---------     ------\n");
 
        resort_rb__for_each_entry(nd, syscall_stats) {
-               struct stats *stats = syscall_stats_entry->stats;
+               struct syscall_stats *stats = syscall_stats_entry->stats;
                if (stats) {
-                       double min = (double)(stats->min) / NSEC_PER_MSEC;
-                       double max = (double)(stats->max) / NSEC_PER_MSEC;
-                       double avg = avg_stats(stats);
+                       double min = (double)(stats->stats.min) / NSEC_PER_MSEC;
+                       double max = (double)(stats->stats.max) / NSEC_PER_MSEC;
+                       double avg = avg_stats(&stats->stats);
                        double pct;
-                       u64 n = (u64) stats->n;
+                       u64 n = (u64)stats->stats.n;
 
-                       pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
+                       pct = avg ? 100.0 * stddev_stats(&stats->stats) / avg : 0.0;
                        avg /= NSEC_PER_MSEC;
 
                        sc = &trace->syscalls.table[syscall_stats_entry->syscall];
                        printed += fprintf(fp, "   %-15s", sc->name);
-                       printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
-                                          n, syscall_stats_entry->msecs, min, avg);
+                       printed += fprintf(fp, " %8" PRIu64 " %6" PRIu64 " %9.3f %9.3f %9.3f",
+                                          n, stats->nr_failures, syscall_stats_entry->msecs, min, avg);
                        printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
+
+                       if (trace->errno_summary && stats->nr_failures) {
+                               const char *arch_name = perf_env__arch(trace->host->env);
+                               int e;
+
+                               for (e = 0; e < stats->max_errno; ++e) {
+                                       if (stats->errnos[e] != 0)
+                                               fprintf(fp, "\t\t\t\t%s: %d\n", arch_syscalls__strerrno(arch_name, e + 1), stats->errnos[e]);
+                               }
+                       }
                }
        }
 
@@ -4219,6 +4434,25 @@ static void evlist__set_default_evsel_handler(struct evlist *evlist, void *handl
        }
 }
 
+static void evsel__set_syscall_arg_fmt(struct evsel *evsel, const char *name)
+{
+       struct syscall_arg_fmt *fmt = evsel__syscall_arg_fmt(evsel);
+
+       if (fmt) {
+               struct syscall_fmt *scfmt = syscall_fmt__find(name);
+
+               if (scfmt) {
+                       int skip = 0;
+
+                       if (strcmp(evsel->tp_format->format.fields->name, "__syscall_nr") == 0 ||
+                           strcmp(evsel->tp_format->format.fields->name, "nr") == 0)
+                               ++skip;
+
+                       memcpy(fmt + skip, scfmt->arg, (evsel->tp_format->format.nr_fields - skip) * sizeof(*fmt));
+               }
+       }
+}
+
 static int evlist__set_syscall_tp_fields(struct evlist *evlist)
 {
        struct evsel *evsel;
@@ -4236,15 +4470,19 @@ static int evlist__set_syscall_tp_fields(struct evlist *evlist)
                        return -1;
 
                if (!strncmp(evsel->tp_format->name, "sys_enter_", 10)) {
-                       struct syscall_tp *sc = evsel->priv;
+                       struct syscall_tp *sc = __evsel__syscall_tp(evsel);
 
                        if (__tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64)))
                                return -1;
+
+                       evsel__set_syscall_arg_fmt(evsel, evsel->tp_format->name + sizeof("sys_enter_") - 1);
                } else if (!strncmp(evsel->tp_format->name, "sys_exit_", 9)) {
-                       struct syscall_tp *sc = evsel->priv;
+                       struct syscall_tp *sc = __evsel__syscall_tp(evsel);
 
                        if (__tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap))
                                return -1;
+
+                       evsel__set_syscall_arg_fmt(evsel, evsel->tp_format->name + sizeof("sys_exit_") - 1);
                }
        }
 
@@ -4501,6 +4739,8 @@ int cmd_trace(int argc, const char **argv)
                    "Show only syscall summary with statistics"),
        OPT_BOOLEAN('S', "with-summary", &trace.summary,
                    "Show all syscalls and summary with statistics"),
+       OPT_BOOLEAN(0, "errno-summary", &trace.errno_summary,
+                   "Show errno stats per syscall, use with -s or -S"),
        OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
                     "Trace pagefaults", parse_pagefaults, "maj"),
        OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
@@ -4775,7 +5015,7 @@ int cmd_trace(int argc, const char **argv)
 init_augmented_syscall_tp:
                                if (perf_evsel__init_augmented_syscall_tp(evsel, evsel))
                                        goto out;
-                               sc = evsel->priv;
+                               sc = __evsel__syscall_tp(evsel);
                                /*
                                 * For now with BPF raw_augmented we hook into
                                 * raw_syscalls:sys_enter and there we get all
@@ -4806,6 +5046,10 @@ init_augmented_syscall_tp:
        if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
                return trace__record(&trace, argc-1, &argv[1]);
 
+       /* Using just --errno-summary will trigger --summary */
+       if (trace.errno_summary && !trace.summary && !trace.summary_only)
+               trace.summary_only = true;
+
        /* summary_only implies summary option, but don't overwrite summary if set */
        if (trace.summary_only)
                trace.summary = trace.summary_only;
index 93c46d3..48290a0 100755 (executable)
@@ -28,6 +28,7 @@ arch/x86/include/asm/disabled-features.h
 arch/x86/include/asm/required-features.h
 arch/x86/include/asm/cpufeatures.h
 arch/x86/include/asm/inat_types.h
+arch/x86/include/asm/irq_vectors.h
 arch/x86/include/asm/msr-index.h
 arch/x86/include/uapi/asm/prctl.h
 arch/x86/lib/x86-opcode-map.txt
index 0889c9c..0f23363 100644 (file)
@@ -107,6 +107,7 @@ else
 endif
 
 LIBAPI = $(API_PATH)libapi.a
+export LIBAPI
 
 $(LIBAPI): FORCE
        $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) $(OUTPUT)libapi.a
index 6504561..205ddbb 100644 (file)
@@ -338,15 +338,13 @@ static struct perf_mmap* perf_evlist__alloc_mmap(struct perf_evlist *evlist, boo
        int i;
        struct perf_mmap *map;
 
-       evlist->nr_mmaps = perf_cpu_map__nr(evlist->cpus);
-       if (perf_cpu_map__empty(evlist->cpus))
-               evlist->nr_mmaps = perf_thread_map__nr(evlist->threads);
-
        map = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
        if (!map)
                return NULL;
 
        for (i = 0; i < evlist->nr_mmaps; i++) {
+               struct perf_mmap *prev = i ? &map[i - 1] : NULL;
+
                /*
                 * When the perf_mmap() call is made we grab one refcount, plus
                 * one extra to let perf_mmap__consume() get the last
@@ -356,7 +354,7 @@ static struct perf_mmap* perf_evlist__alloc_mmap(struct perf_evlist *evlist, boo
                 * Each PERF_EVENT_IOC_SET_OUTPUT points to this mmap and
                 * thus does perf_mmap__get() on it.
                 */
-               perf_mmap__init(&map[i], overwrite, NULL);
+               perf_mmap__init(&map[i], prev, overwrite, NULL);
        }
 
        return map;
@@ -382,18 +380,22 @@ static void perf_evlist__set_sid_idx(struct perf_evlist *evlist,
 static struct perf_mmap*
 perf_evlist__mmap_cb_get(struct perf_evlist *evlist, bool overwrite, int idx)
 {
-       struct perf_mmap *map = &evlist->mmap[idx];
+       struct perf_mmap *maps;
 
-       if (overwrite) {
-               if (!evlist->mmap_ovw) {
-                       evlist->mmap_ovw = perf_evlist__alloc_mmap(evlist, true);
-                       if (!evlist->mmap_ovw)
-                               return NULL;
-               }
-               map = &evlist->mmap_ovw[idx];
+       maps = overwrite ? evlist->mmap_ovw : evlist->mmap;
+
+       if (!maps) {
+               maps = perf_evlist__alloc_mmap(evlist, overwrite);
+               if (!maps)
+                       return NULL;
+
+               if (overwrite)
+                       evlist->mmap_ovw = maps;
+               else
+                       evlist->mmap = maps;
        }
 
-       return map;
+       return &maps[idx];
 }
 
 #define FD(e, x, y) (*(int *) xyarray__entry(e->fd, x, y))
@@ -405,6 +407,15 @@ perf_evlist__mmap_cb_mmap(struct perf_mmap *map, struct perf_mmap_param *mp,
        return perf_mmap__mmap(map, mp, output, cpu);
 }
 
+static void perf_evlist__set_mmap_first(struct perf_evlist *evlist, struct perf_mmap *map,
+                                       bool overwrite)
+{
+       if (overwrite)
+               evlist->mmap_ovw_first = map;
+       else
+               evlist->mmap_first = map;
+}
+
 static int
 mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
               int idx, struct perf_mmap_param *mp, int cpu_idx,
@@ -460,6 +471,9 @@ mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
 
                        if (ops->mmap(map, mp, *output, evlist_cpu) < 0)
                                return -1;
+
+                       if (!idx)
+                               perf_evlist__set_mmap_first(evlist, map, overwrite);
                } else {
                        if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
                                return -1;
@@ -542,6 +556,17 @@ out_unmap:
        return -1;
 }
 
+static int perf_evlist__nr_mmaps(struct perf_evlist *evlist)
+{
+       int nr_mmaps;
+
+       nr_mmaps = perf_cpu_map__nr(evlist->cpus);
+       if (perf_cpu_map__empty(evlist->cpus))
+               nr_mmaps = perf_thread_map__nr(evlist->threads);
+
+       return nr_mmaps;
+}
+
 int perf_evlist__mmap_ops(struct perf_evlist *evlist,
                          struct perf_evlist_mmap_ops *ops,
                          struct perf_mmap_param *mp)
@@ -553,10 +578,9 @@ int perf_evlist__mmap_ops(struct perf_evlist *evlist,
        if (!ops || !ops->get || !ops->mmap)
                return -EINVAL;
 
-       if (!evlist->mmap)
-               evlist->mmap = perf_evlist__alloc_mmap(evlist, false);
-       if (!evlist->mmap)
-               return -ENOMEM;
+       mp->mask = evlist->mmap_len - page_size - 1;
+
+       evlist->nr_mmaps = perf_evlist__nr_mmaps(evlist);
 
        perf_evlist__for_each_entry(evlist, evsel) {
                if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
@@ -583,7 +607,6 @@ int perf_evlist__mmap(struct perf_evlist *evlist, int pages)
        };
 
        evlist->mmap_len = (pages + 1) * page_size;
-       mp.mask = evlist->mmap_len - page_size - 1;
 
        return perf_evlist__mmap_ops(evlist, &ops, &mp);
 }
@@ -605,3 +628,13 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
        zfree(&evlist->mmap);
        zfree(&evlist->mmap_ovw);
 }
+
+struct perf_mmap*
+perf_evlist__next_mmap(struct perf_evlist *evlist, struct perf_mmap *map,
+                      bool overwrite)
+{
+       if (map)
+               return map->next;
+
+       return overwrite ? evlist->mmap_ovw_first : evlist->mmap_first;
+}
index be0b25a..a2fbccf 100644 (file)
@@ -25,6 +25,8 @@ struct perf_evlist {
        struct hlist_head        heads[PERF_EVLIST__HLIST_SIZE];
        struct perf_mmap        *mmap;
        struct perf_mmap        *mmap_ovw;
+       struct perf_mmap        *mmap_first;
+       struct perf_mmap        *mmap_ovw_first;
 };
 
 typedef void
@@ -48,6 +50,7 @@ int perf_evlist__mmap_ops(struct perf_evlist *evlist,
                          struct perf_evlist_mmap_ops *ops,
                          struct perf_mmap_param *mp);
 
+void perf_evlist__init(struct perf_evlist *evlist);
 void perf_evlist__exit(struct perf_evlist *evlist);
 
 /**
index a69b829..1ffd083 100644 (file)
@@ -50,6 +50,7 @@ struct perf_evsel {
        bool                     system_wide;
 };
 
+void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr);
 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
 void perf_evsel__close_fd(struct perf_evsel *evsel);
 void perf_evsel__free_fd(struct perf_evsel *evsel);
index ee536c4..be7556e 100644 (file)
@@ -32,6 +32,7 @@ struct perf_mmap {
        u64                      flush;
        libperf_unmap_cb_t       unmap_cb;
        char                     event_copy[PERF_SAMPLE_MAX_SIZE] __aligned(8);
+       struct perf_mmap        *next;
 };
 
 struct perf_mmap_param {
@@ -41,8 +42,8 @@ struct perf_mmap_param {
 
 size_t perf_mmap__mmap_len(struct perf_mmap *map);
 
-void perf_mmap__init(struct perf_mmap *map, bool overwrite,
-                    libperf_unmap_cb_t unmap_cb);
+void perf_mmap__init(struct perf_mmap *map, struct perf_mmap *prev,
+                    bool overwrite, libperf_unmap_cb_t unmap_cb);
 int perf_mmap__mmap(struct perf_mmap *map, struct perf_mmap_param *mp,
                    int fd, int cpu);
 void perf_mmap__munmap(struct perf_mmap *map);
index b7a20cd..2093e88 100644 (file)
@@ -4,14 +4,28 @@
 
 #include <stdio.h>
 
-#define __T_START fprintf(stdout, "- running %s...", __FILE__)
-#define __T_OK    fprintf(stdout, "OK\n")
-#define __T_FAIL  fprintf(stdout, "FAIL\n")
+int tests_failed;
+
+#define __T_START                                      \
+do {                                                   \
+       fprintf(stdout, "- running %s...", __FILE__);   \
+       fflush(NULL);                                   \
+       tests_failed = 0;                               \
+} while (0)
+
+#define __T_END                                                                \
+do {                                                                   \
+       if (tests_failed)                                               \
+               fprintf(stdout, "  FAILED (%d)\n", tests_failed);       \
+       else                                                            \
+               fprintf(stdout, "OK\n");                                \
+} while (0)
 
 #define __T(text, cond)                                                          \
 do {                                                                             \
        if (!(cond)) {                                                           \
                fprintf(stderr, "FAILED %s:%d %s\n", __FILE__, __LINE__, text);  \
+               tests_failed++;                                                  \
                return -1;                                                       \
        }                                                                        \
 } while (0)
index 2a80e4b..a3f6d68 100644 (file)
@@ -9,6 +9,7 @@
 #endif
 
 enum libperf_print_level {
+       LIBPERF_ERR,
        LIBPERF_WARN,
        LIBPERF_INFO,
        LIBPERF_DEBUG,
index 16f526e..0a7479d 100644 (file)
@@ -3,13 +3,13 @@
 #define __LIBPERF_EVLIST_H
 
 #include <perf/core.h>
+#include <stdbool.h>
 
 struct perf_evlist;
 struct perf_evsel;
 struct perf_cpu_map;
 struct perf_thread_map;
 
-LIBPERF_API void perf_evlist__init(struct perf_evlist *evlist);
 LIBPERF_API void perf_evlist__add(struct perf_evlist *evlist,
                                  struct perf_evsel *evsel);
 LIBPERF_API void perf_evlist__remove(struct perf_evlist *evlist,
@@ -38,4 +38,12 @@ LIBPERF_API int perf_evlist__filter_pollfd(struct perf_evlist *evlist,
 LIBPERF_API int perf_evlist__mmap(struct perf_evlist *evlist, int pages);
 LIBPERF_API void perf_evlist__munmap(struct perf_evlist *evlist);
 
+LIBPERF_API struct perf_mmap *perf_evlist__next_mmap(struct perf_evlist *evlist,
+                                                    struct perf_mmap *map,
+                                                    bool overwrite);
+#define perf_evlist__for_each_mmap(evlist, pos, overwrite)             \
+       for ((pos) = perf_evlist__next_mmap((evlist), NULL, overwrite); \
+            (pos) != NULL;                                             \
+            (pos) = perf_evlist__next_mmap((evlist), (pos), overwrite))
+
 #endif /* __LIBPERF_EVLIST_H */
index 4388667..557f581 100644 (file)
@@ -21,8 +21,6 @@ struct perf_counts_values {
        };
 };
 
-LIBPERF_API void perf_evsel__init(struct perf_evsel *evsel,
-                                 struct perf_event_attr *attr);
 LIBPERF_API struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr);
 LIBPERF_API void perf_evsel__delete(struct perf_evsel *evsel);
 LIBPERF_API int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus,
index 37db745..2c27e15 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef __LIBPERF_INTERNAL_H
 #define __LIBPERF_INTERNAL_H
 
+#include <perf/core.h>
+
 void libperf_print(enum libperf_print_level level,
                   const char *format, ...)
        __attribute__((format(printf, 2, 3)));
@@ -11,6 +13,7 @@ do {                            \
        libperf_print(level, "libperf: " fmt, ##__VA_ARGS__);     \
 } while (0)
 
+#define pr_err(fmt, ...)        __pr(LIBPERF_ERR, fmt, ##__VA_ARGS__)
 #define pr_warning(fmt, ...)    __pr(LIBPERF_WARN, fmt, ##__VA_ARGS__)
 #define pr_info(fmt, ...)       __pr(LIBPERF_INFO, fmt, ##__VA_ARGS__)
 #define pr_debug(fmt, ...)      __pr(LIBPERF_DEBUG, fmt, ##__VA_ARGS__)
index 2184aba..7be1af8 100644 (file)
@@ -21,7 +21,6 @@ LIBPERF_0.0.1 {
                perf_evsel__delete;
                perf_evsel__enable;
                perf_evsel__disable;
-               perf_evsel__init;
                perf_evsel__open;
                perf_evsel__close;
                perf_evsel__read;
@@ -34,7 +33,6 @@ LIBPERF_0.0.1 {
                perf_evlist__close;
                perf_evlist__enable;
                perf_evlist__disable;
-               perf_evlist__init;
                perf_evlist__add;
                perf_evlist__remove;
                perf_evlist__next;
@@ -43,6 +41,7 @@ LIBPERF_0.0.1 {
                perf_evlist__mmap;
                perf_evlist__munmap;
                perf_evlist__filter_pollfd;
+               perf_evlist__next_mmap;
                perf_mmap__consume;
                perf_mmap__read_init;
                perf_mmap__read_done;
index 0752c19..79d5ed6 100644 (file)
 #include <linux/kernel.h>
 #include "internal.h"
 
-void perf_mmap__init(struct perf_mmap *map, bool overwrite,
-                    libperf_unmap_cb_t unmap_cb)
+void perf_mmap__init(struct perf_mmap *map, struct perf_mmap *prev,
+                    bool overwrite, libperf_unmap_cb_t unmap_cb)
 {
        map->fd = -1;
        map->overwrite = overwrite;
        map->unmap_cb  = unmap_cb;
        refcount_set(&map->refcnt, 0);
+       if (prev)
+               prev->next = map;
 }
 
 size_t perf_mmap__mmap_len(struct perf_mmap *map)
index 1ee4e9b..a43cd08 100644 (file)
@@ -16,13 +16,13 @@ all:
 
 include $(srctree)/tools/scripts/Makefile.include
 
-INCLUDE = -I$(srctree)/tools/perf/lib/include -I$(srctree)/tools/include
+INCLUDE = -I$(srctree)/tools/perf/lib/include -I$(srctree)/tools/include -I$(srctree)/tools/lib
 
 $(TESTS_A): FORCE
-       $(QUIET_LINK)$(CC) $(INCLUDE) $(CFLAGS) -o $@ $(subst -a,.c,$@) ../libperf.a
+       $(QUIET_LINK)$(CC) $(INCLUDE) $(CFLAGS) -o $@ $(subst -a,.c,$@) ../libperf.a $(LIBAPI)
 
 $(TESTS_SO): FORCE
-       $(QUIET_LINK)$(CC) $(INCLUDE) $(CFLAGS) -L.. -o $@ $(subst -so,.c,$@) -lperf
+       $(QUIET_LINK)$(CC) $(INCLUDE) $(CFLAGS) -L.. -o $@ $(subst -so,.c,$@) $(LIBAPI) -lperf
 
 all: $(TESTS_A) $(TESTS_SO)
 
index aa34c20..c8d4509 100644 (file)
@@ -26,6 +26,6 @@ int main(int argc, char **argv)
        perf_cpu_map__put(cpus);
        perf_cpu_map__put(cpus);
 
-       __T_OK;
+       __T_END;
        return 0;
 }
index e6b2ab2..6d8ebe0 100644 (file)
@@ -1,12 +1,23 @@
 // SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE // needed for sched.h to get sched_[gs]etaffinity and CPU_(ZERO,SET)
+#include <sched.h>
 #include <stdio.h>
 #include <stdarg.h>
+#include <unistd.h>
+#include <stdlib.h>
 #include <linux/perf_event.h>
+#include <linux/limits.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/prctl.h>
 #include <perf/cpumap.h>
 #include <perf/threadmap.h>
 #include <perf/evlist.h>
 #include <perf/evsel.h>
+#include <perf/mmap.h>
+#include <perf/event.h>
 #include <internal/tests.h>
+#include <api/fs/fs.h>
 
 static int libperf_print(enum libperf_print_level level,
                         const char *fmt, va_list ap)
@@ -181,6 +192,210 @@ static int test_stat_thread_enable(void)
        return 0;
 }
 
+static int test_mmap_thread(void)
+{
+       struct perf_evlist *evlist;
+       struct perf_evsel *evsel;
+       struct perf_mmap *map;
+       struct perf_cpu_map *cpus;
+       struct perf_thread_map *threads;
+       struct perf_event_attr attr = {
+               .type             = PERF_TYPE_TRACEPOINT,
+               .sample_period    = 1,
+               .wakeup_watermark = 1,
+               .disabled         = 1,
+       };
+       char path[PATH_MAX];
+       int id, err, pid, go_pipe[2];
+       union perf_event *event;
+       char bf;
+       int count = 0;
+
+       snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id",
+                sysfs__mountpoint());
+
+       if (filename__read_int(path, &id)) {
+               fprintf(stderr, "error: failed to get tracepoint id: %s\n", path);
+               return -1;
+       }
+
+       attr.config = id;
+
+       err = pipe(go_pipe);
+       __T("failed to create pipe", err == 0);
+
+       fflush(NULL);
+
+       pid = fork();
+       if (!pid) {
+               int i;
+
+               read(go_pipe[0], &bf, 1);
+
+               /* Generate 100 prctl calls. */
+               for (i = 0; i < 100; i++)
+                       prctl(0, 0, 0, 0, 0);
+
+               exit(0);
+       }
+
+       threads = perf_thread_map__new_dummy();
+       __T("failed to create threads", threads);
+
+       cpus = perf_cpu_map__dummy_new();
+       __T("failed to create cpus", cpus);
+
+       perf_thread_map__set_pid(threads, 0, pid);
+
+       evlist = perf_evlist__new();
+       __T("failed to create evlist", evlist);
+
+       evsel = perf_evsel__new(&attr);
+       __T("failed to create evsel1", evsel);
+
+       perf_evlist__add(evlist, evsel);
+
+       perf_evlist__set_maps(evlist, cpus, threads);
+
+       err = perf_evlist__open(evlist);
+       __T("failed to open evlist", err == 0);
+
+       err = perf_evlist__mmap(evlist, 4);
+       __T("failed to mmap evlist", err == 0);
+
+       perf_evlist__enable(evlist);
+
+       /* kick the child and wait for it to finish */
+       write(go_pipe[1], &bf, 1);
+       waitpid(pid, NULL, 0);
+
+       /*
+        * There's no need to call perf_evlist__disable,
+        * monitored process is dead now.
+        */
+
+       perf_evlist__for_each_mmap(evlist, map, false) {
+               if (perf_mmap__read_init(map) < 0)
+                       continue;
+
+               while ((event = perf_mmap__read_event(map)) != NULL) {
+                       count++;
+                       perf_mmap__consume(map);
+               }
+
+               perf_mmap__read_done(map);
+       }
+
+       /* calls perf_evlist__munmap/perf_evlist__close */
+       perf_evlist__delete(evlist);
+
+       perf_thread_map__put(threads);
+       perf_cpu_map__put(cpus);
+
+       /*
+        * The generated prctl calls should match the
+        * number of events in the buffer.
+        */
+       __T("failed count", count == 100);
+
+       return 0;
+}
+
+static int test_mmap_cpus(void)
+{
+       struct perf_evlist *evlist;
+       struct perf_evsel *evsel;
+       struct perf_mmap *map;
+       struct perf_cpu_map *cpus;
+       struct perf_event_attr attr = {
+               .type             = PERF_TYPE_TRACEPOINT,
+               .sample_period    = 1,
+               .wakeup_watermark = 1,
+               .disabled         = 1,
+       };
+       cpu_set_t saved_mask;
+       char path[PATH_MAX];
+       int id, err, cpu, tmp;
+       union perf_event *event;
+       int count = 0;
+
+       snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id",
+                sysfs__mountpoint());
+
+       if (filename__read_int(path, &id)) {
+               fprintf(stderr, "error: failed to get tracepoint id: %s\n", path);
+               return -1;
+       }
+
+       attr.config = id;
+
+       cpus = perf_cpu_map__new(NULL);
+       __T("failed to create cpus", cpus);
+
+       evlist = perf_evlist__new();
+       __T("failed to create evlist", evlist);
+
+       evsel = perf_evsel__new(&attr);
+       __T("failed to create evsel1", evsel);
+
+       perf_evlist__add(evlist, evsel);
+
+       perf_evlist__set_maps(evlist, cpus, NULL);
+
+       err = perf_evlist__open(evlist);
+       __T("failed to open evlist", err == 0);
+
+       err = perf_evlist__mmap(evlist, 4);
+       __T("failed to mmap evlist", err == 0);
+
+       perf_evlist__enable(evlist);
+
+       err = sched_getaffinity(0, sizeof(saved_mask), &saved_mask);
+       __T("sched_getaffinity failed", err == 0);
+
+       perf_cpu_map__for_each_cpu(cpu, tmp, cpus) {
+               cpu_set_t mask;
+
+               CPU_ZERO(&mask);
+               CPU_SET(cpu, &mask);
+
+               err = sched_setaffinity(0, sizeof(mask), &mask);
+               __T("sched_setaffinity failed", err == 0);
+
+               prctl(0, 0, 0, 0, 0);
+       }
+
+       err = sched_setaffinity(0, sizeof(saved_mask), &saved_mask);
+       __T("sched_setaffinity failed", err == 0);
+
+       perf_evlist__disable(evlist);
+
+       perf_evlist__for_each_mmap(evlist, map, false) {
+               if (perf_mmap__read_init(map) < 0)
+                       continue;
+
+               while ((event = perf_mmap__read_event(map)) != NULL) {
+                       count++;
+                       perf_mmap__consume(map);
+               }
+
+               perf_mmap__read_done(map);
+       }
+
+       /* calls perf_evlist__munmap/perf_evlist__close */
+       perf_evlist__delete(evlist);
+
+       /*
+        * The generated prctl events should match the
+        * number of cpus or be bigger (we are system-wide).
+        */
+       __T("failed count", count >= perf_cpu_map__nr(cpus));
+
+       perf_cpu_map__put(cpus);
+
+       return 0;
+}
+
 int main(int argc, char **argv)
 {
        __T_START;
@@ -190,7 +405,9 @@ int main(int argc, char **argv)
        test_stat_cpu();
        test_stat_thread();
        test_stat_thread_enable();
+       test_mmap_thread();
+       test_mmap_cpus();
 
-       __T_OK;
+       __T_END;
        return 0;
 }
index 1b6c428..135722a 100644 (file)
@@ -130,6 +130,6 @@ int main(int argc, char **argv)
        test_stat_thread();
        test_stat_thread_enable();
 
-       __T_OK;
+       __T_END;
        return 0;
 }
index 8c5f472..7dc4d6f 100644 (file)
@@ -26,6 +26,6 @@ int main(int argc, char **argv)
        perf_thread_map__put(threads);
        perf_thread_map__put(threads);
 
-       __T_OK;
+       __T_END;
        return 0;
 }
index 0d1556f..7da8694 100644 (file)
@@ -1,4 +1,18 @@
 [
+   {
+           "EventCode": "0x00",
+           "EventName": "uncore_hisi_ddrc.flux_wr",
+           "BriefDescription": "DDRC total write operations",
+           "PublicDescription": "DDRC total write operations",
+           "Unit": "hisi_sccl,ddrc",
+   },
+   {
+           "EventCode": "0x01",
+           "EventName": "uncore_hisi_ddrc.flux_rd",
+           "BriefDescription": "DDRC total read operations",
+           "PublicDescription": "DDRC total read operations",
+           "Unit": "hisi_sccl,ddrc",
+   },
    {
            "EventCode": "0x02",
            "EventName": "uncore_hisi_ddrc.flux_wcmd",
@@ -15,7 +29,7 @@
    },
    {
            "EventCode": "0x04",
-           "EventName": "uncore_hisi_ddrc.flux_wr",
+           "EventName": "uncore_hisi_ddrc.pre_cmd",
            "BriefDescription": "DDRC precharge commands",
            "PublicDescription": "DDRC precharge commands",
            "Unit": "hisi_sccl,ddrc",
index 447d306..3be418a 100644 (file)
            "PublicDescription": "The number of all operations received by the HHA from another SCCL in this socket",
            "Unit": "hisi_sccl,hha",
    },
+   {
+           "EventCode": "0x03",
+           "EventName": "uncore_hisi_hha.rx_ccix",
+           "BriefDescription": "Count of the number of operations that HHA has received from CCIX",
+           "PublicDescription": "Count of the number of operations that HHA has received from CCIX",
+           "Unit": "hisi_sccl,hha",
+   },
    {
            "EventCode": "0x1c",
            "EventName": "uncore_hisi_hha.rd_ddr_64b",
@@ -29,7 +36,7 @@
    },
    {
            "EventCode": "0x1d",
-           "EventName": "uncore_hisi_hha.wr_dr_64b",
+           "EventName": "uncore_hisi_hha.wr_ddr_64b",
            "BriefDescription": "The number of write operations sent by HHA to DDRC which size is 64 bytes",
            "PublicDescription": "The number of write operations sent by HHA to DDRC which size is 64 bytes",
            "Unit": "hisi_sccl,hha",
            "PublicDescription": "The number of write operations sent by HHA to DDRC which size is 128 bytes",
            "Unit": "hisi_sccl,hha",
    },
+   {
+           "EventCode": "0x20",
+           "EventName": "uncore_hisi_hha.spill_num",
+           "BriefDescription": "Count of the number of spill operations that the HHA has sent",
+           "PublicDescription": "Count of the number of spill operations that the HHA has sent",
+           "Unit": "hisi_sccl,hha",
+   },
+   {
+           "EventCode": "0x21",
+           "EventName": "uncore_hisi_hha.spill_success",
+           "BriefDescription": "Count of the number of successful spill operations that the HHA has sent",
+           "PublicDescription": "Count of the number of successful spill operations that the HHA has sent",
+           "Unit": "hisi_sccl,hha",
+   },
 ]
index ca48747..f463d0a 100644 (file)
            "PublicDescription": "l3c precharge commands",
            "Unit": "hisi_sccl,l3c",
    },
+   {
+           "EventCode": "0x20",
+           "EventName": "uncore_hisi_l3c.rd_spipe",
+           "BriefDescription": "Count of the number of read lines that come from this cluster of CPU core in spipe",
+           "PublicDescription": "Count of the number of read lines that come from this cluster of CPU core in spipe",
+           "Unit": "hisi_sccl,l3c",
+   },
+   {
+           "EventCode": "0x21",
+           "EventName": "uncore_hisi_l3c.wr_spipe",
+           "BriefDescription": "Count of the number of write lines that come from this cluster of CPU core in spipe",
+           "PublicDescription": "Count of the number of write lines that come from this cluster of CPU core in spipe",
+           "Unit": "hisi_sccl,l3c",
+   },
+   {
+           "EventCode": "0x22",
+           "EventName": "uncore_hisi_l3c.rd_hit_spipe",
+           "BriefDescription": "Count of the number of read lines that hits in spipe of this L3C",
+           "PublicDescription": "Count of the number of read lines that hits in spipe of this L3C",
+           "Unit": "hisi_sccl,l3c",
+   },
+   {
+           "EventCode": "0x23",
+           "EventName": "uncore_hisi_l3c.wr_hit_spipe",
+           "BriefDescription": "Count of the number of write lines that hits in spipe of this L3C",
+           "PublicDescription": "Count of the number of write lines that hits in spipe of this L3C",
+           "Unit": "hisi_sccl,l3c",
+   },
+   {
+           "EventCode": "0x29",
+           "EventName": "uncore_hisi_l3c.back_invalid",
+           "BriefDescription": "Count of the number of L3C back invalid operations",
+           "PublicDescription": "Count of the number of L3C back invalid operations",
+           "Unit": "hisi_sccl,l3c",
+   },
+   {
+           "EventCode": "0x40",
+           "EventName": "uncore_hisi_l3c.retry_cpu",
+           "BriefDescription": "Count of the number of retry that L3C suppresses the CPU operations",
+           "PublicDescription": "Count of the number of retry that L3C suppresses the CPU operations",
+           "Unit": "hisi_sccl,l3c",
+   },
+   {
+           "EventCode": "0x41",
+           "EventName": "uncore_hisi_l3c.retry_ring",
+           "BriefDescription": "Count of the number of retry that L3C suppresses the ring operations",
+           "PublicDescription": "Count of the number of retry that L3C suppresses the ring operations",
+           "Unit": "hisi_sccl,l3c",
+   },
+   {
+           "EventCode": "0x42",
+           "EventName": "uncore_hisi_l3c.prefetch_drop",
+           "BriefDescription": "Count of the number of prefetch drops from this L3C",
+           "PublicDescription": "Count of the number of prefetch drops from this L3C",
+           "Unit": "hisi_sccl,l3c",
+   },
 ]
index e283726..7d69727 100644 (file)
@@ -322,7 +322,8 @@ static int print_events_table_entry(void *data, char *name, char *event,
                                    char *desc, char *long_desc,
                                    char *pmu, char *unit, char *perpkg,
                                    char *metric_expr,
-                                   char *metric_name, char *metric_group)
+                                   char *metric_name, char *metric_group,
+                                   char *deprecated)
 {
        struct perf_entry_data *pd = data;
        FILE *outfp = pd->outfp;
@@ -354,6 +355,8 @@ static int print_events_table_entry(void *data, char *name, char *event,
                fprintf(outfp, "\t.metric_name = \"%s\",\n", metric_name);
        if (metric_group)
                fprintf(outfp, "\t.metric_group = \"%s\",\n", metric_group);
+       if (deprecated)
+               fprintf(outfp, "\t.deprecated = \"%s\",\n", deprecated);
        fprintf(outfp, "},\n");
 
        return 0;
@@ -371,6 +374,7 @@ struct event_struct {
        char *metric_expr;
        char *metric_name;
        char *metric_group;
+       char *deprecated;
 };
 
 #define ADD_EVENT_FIELD(field) do { if (field) {               \
@@ -398,6 +402,7 @@ struct event_struct {
        op(metric_expr);                                        \
        op(metric_name);                                        \
        op(metric_group);                                       \
+       op(deprecated);                                         \
 } while (0)
 
 static LIST_HEAD(arch_std_events);
@@ -416,7 +421,8 @@ static void free_arch_std_events(void)
 static int save_arch_std_events(void *data, char *name, char *event,
                                char *desc, char *long_desc, char *pmu,
                                char *unit, char *perpkg, char *metric_expr,
-                               char *metric_name, char *metric_group)
+                               char *metric_name, char *metric_group,
+                               char *deprecated)
 {
        struct event_struct *es;
 
@@ -479,7 +485,8 @@ static int
 try_fixup(const char *fn, char *arch_std, char **event, char **desc,
          char **name, char **long_desc, char **pmu, char **filter,
          char **perpkg, char **unit, char **metric_expr, char **metric_name,
-         char **metric_group, unsigned long long eventcode)
+         char **metric_group, unsigned long long eventcode,
+         char **deprecated)
 {
        /* try to find matching event from arch standard values */
        struct event_struct *es;
@@ -507,7 +514,8 @@ int json_events(const char *fn,
                      char *long_desc,
                      char *pmu, char *unit, char *perpkg,
                      char *metric_expr,
-                     char *metric_name, char *metric_group),
+                     char *metric_name, char *metric_group,
+                     char *deprecated),
          void *data)
 {
        int err;
@@ -536,6 +544,7 @@ int json_events(const char *fn,
                char *metric_expr = NULL;
                char *metric_name = NULL;
                char *metric_group = NULL;
+               char *deprecated = NULL;
                char *arch_std = NULL;
                unsigned long long eventcode = 0;
                struct msrmap *msr = NULL;
@@ -614,6 +623,8 @@ int json_events(const char *fn,
                                addfield(map, &unit, "", "", val);
                        } else if (json_streq(map, field, "PerPkg")) {
                                addfield(map, &perpkg, "", "", val);
+                       } else if (json_streq(map, field, "Deprecated")) {
+                               addfield(map, &deprecated, "", "", val);
                        } else if (json_streq(map, field, "MetricName")) {
                                addfield(map, &metric_name, "", "", val);
                        } else if (json_streq(map, field, "MetricGroup")) {
@@ -658,12 +669,14 @@ int json_events(const char *fn,
                        err = try_fixup(fn, arch_std, &event, &desc, &name,
                                        &long_desc, &pmu, &filter, &perpkg,
                                        &unit, &metric_expr, &metric_name,
-                                       &metric_group, eventcode);
+                                       &metric_group, eventcode,
+                                       &deprecated);
                        if (err)
                                goto free_strings;
                }
                err = func(data, name, real_event(name, event), desc, long_desc,
-                          pmu, unit, perpkg, metric_expr, metric_name, metric_group);
+                          pmu, unit, perpkg, metric_expr, metric_name,
+                          metric_group, deprecated);
 free_strings:
                free(event);
                free(desc);
@@ -673,6 +686,7 @@ free_strings:
                free(pmu);
                free(filter);
                free(perpkg);
+               free(deprecated);
                free(unit);
                free(metric_expr);
                free(metric_name);
index 4684c67..5cda49a 100644 (file)
@@ -7,7 +7,8 @@ int json_events(const char *fn,
                                char *long_desc,
                                char *pmu,
                                char *unit, char *perpkg, char *metric_expr,
-                               char *metric_name, char *metric_group),
+                               char *metric_name, char *metric_group,
+                               char *deprecated),
                void *data);
 char *get_cpu_str(void);
 
index 92a4d15..caeb577 100644 (file)
@@ -17,6 +17,7 @@ struct pmu_event {
        const char *metric_expr;
        const char *metric_name;
        const char *metric_group;
+       const char *deprecated;
 };
 
 /*
index 016bba2..d0b9353 100644 (file)
 #include <unistd.h>
 #include <string.h>
 #include <sys/ioctl.h>
-#include <time.h>
 #include <fcntl.h>
-#include <signal.h>
-#include <sys/mman.h>
-#include <linux/compiler.h>
 #include <linux/hw_breakpoint.h>
 
 #include "tests.h"
@@ -192,3 +188,19 @@ int test__bp_accounting(struct test *test __maybe_unused, int subtest __maybe_un
 
        return bp_accounting(wp_cnt, share);
 }
+
+bool test__bp_account_is_supported(void)
+{
+       /*
+        * PowerPC and S390 do not support creation of instruction
+        * breakpoints using the perf_event interface.
+        *
+        * Just disable the test for these architectures until these
+        * issues are resolved.
+        */
+#if defined(__powerpc__) || defined(__s390x__)
+       return false;
+#else
+       return true;
+#endif
+}
index c1c2c13..166f411 100644 (file)
@@ -49,14 +49,6 @@ asm (
        "__test_function:\n"
        "incq (%rdi)\n"
        "ret\n");
-#elif defined (__aarch64__)
-extern void __test_function(volatile long *ptr);
-asm (
-       ".globl __test_function\n"
-       "__test_function:\n"
-       "str x30, [x0]\n"
-       "ret\n");
-
 #else
 static void __test_function(volatile long *ptr)
 {
@@ -302,10 +294,15 @@ bool test__bp_signal_is_supported(void)
         * stepping into the SIGIO handler and getting stuck on the
         * breakpointed instruction.
         *
+        * Since arm64 has the same issue with arm for the single-step
+        * handling, this case also gets suck on the breakpointed
+        * instruction.
+        *
         * Just disable the test for these architectures until these
         * issues are resolved.
         */
-#if defined(__powerpc__) || defined(__s390x__) || defined(__arm__)
+#if defined(__powerpc__) || defined(__s390x__) || defined(__arm__) || \
+    defined(__aarch64__)
        return false;
 #else
        return true;
index 55774ba..8b286e9 100644 (file)
@@ -121,7 +121,7 @@ static struct test generic_tests[] = {
        {
                .desc = "Breakpoint accounting",
                .func = test__bp_accounting,
-               .is_supported = test__bp_signal_is_supported,
+               .is_supported = test__bp_account_is_supported,
        },
        {
                .desc = "Watchpoint",
index 4965f8b..adaff90 100644 (file)
@@ -54,6 +54,7 @@ int test__task_exit(struct test *test __maybe_unused, int subtest __maybe_unused
        struct perf_cpu_map *cpus;
        struct perf_thread_map *threads;
        struct mmap *md;
+       int retry_count = 0;
 
        signal(SIGCHLD, sig_handler);
 
@@ -111,6 +112,7 @@ int test__task_exit(struct test *test __maybe_unused, int subtest __maybe_unused
        if (evlist__mmap(evlist, 128) < 0) {
                pr_debug("failed to mmap events: %d (%s)\n", errno,
                         str_error_r(errno, sbuf, sizeof(sbuf)));
+               err = -1;
                goto out_delete_evlist;
        }
 
@@ -132,6 +134,13 @@ retry:
 out_init:
        if (!exited || !nr_exit) {
                evlist__poll(evlist, -1);
+
+               if (retry_count++ > 1000) {
+                       pr_debug("Failed after retrying 1000 times\n");
+                       err = -1;
+                       goto out_free_maps;
+               }
+
                goto retry;
        }
 
index 72912eb..9837b6e 100644 (file)
@@ -111,6 +111,7 @@ int test__map_groups__merge_in(struct test *t, int subtest);
 int test__time_utils(struct test *t, int subtest);
 
 bool test__bp_signal_is_supported(void);
+bool test__bp_account_is_supported(void);
 bool test__wp_is_supported(void);
 
 #if defined(__arm__) || defined(__aarch64__)
index 77ad80a..5a61043 100644 (file)
@@ -28,9 +28,11 @@ struct strarray {
 }
 
 size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, bool show_prefix, int val);
+size_t strarray__scnprintf_suffix(struct strarray *sa, char *bf, size_t size, const char *intfmt, bool show_suffix, int val);
 size_t strarray__scnprintf_flags(struct strarray *sa, char *bf, size_t size, bool show_prefix, unsigned long flags);
 
 bool strarray__strtoul(struct strarray *sa, char *bf, size_t size, u64 *ret);
+bool strarray__strtoul_flags(struct strarray *sa, char *bf, size_t size, u64 *ret);
 
 struct trace;
 struct thread;
@@ -87,6 +89,7 @@ struct syscall_arg_fmt;
 
 /**
  * @val: value of syscall argument being formatted
+ * @len: for tracepoint dynamic arrays, if fmt->nr_entries == 0, then its not a fixed array, look at arg->len
  * @args: All the args, use syscall_args__val(arg, nth) to access one
  * @augmented_args: Extra data that can be collected, for instance, with eBPF for expanding the pathname for open, etc
  * @augmented_args_size: augmented_args total payload size
@@ -109,6 +112,7 @@ struct syscall_arg {
        struct thread *thread;
        struct trace  *trace;
        void          *parm;
+       u16           len;
        u8            idx;
        u8            mask;
        bool          show_string_prefix;
@@ -119,6 +123,21 @@ unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx);
 size_t syscall_arg__scnprintf_strarray_flags(char *bf, size_t size, struct syscall_arg *arg);
 #define SCA_STRARRAY_FLAGS syscall_arg__scnprintf_strarray_flags
 
+bool syscall_arg__strtoul_strarray(char *bf, size_t size, struct syscall_arg *arg, u64 *ret);
+#define STUL_STRARRAY syscall_arg__strtoul_strarray
+
+bool syscall_arg__strtoul_strarray_flags(char *bf, size_t size, struct syscall_arg *arg, u64 *ret);
+#define STUL_STRARRAY_FLAGS syscall_arg__strtoul_strarray_flags
+
+bool syscall_arg__strtoul_strarrays(char *bf, size_t size, struct syscall_arg *arg, u64 *ret);
+#define STUL_STRARRAYS syscall_arg__strtoul_strarrays
+
+size_t syscall_arg__scnprintf_x86_irq_vectors(char *bf, size_t size, struct syscall_arg *arg);
+#define SCA_X86_IRQ_VECTORS syscall_arg__scnprintf_x86_irq_vectors
+
+bool syscall_arg__strtoul_x86_irq_vectors(char *bf, size_t size, struct syscall_arg *arg, u64 *ret);
+#define STUL_X86_IRQ_VECTORS syscall_arg__strtoul_x86_irq_vectors
+
 size_t syscall_arg__scnprintf_x86_MSR(char *bf, size_t size, struct syscall_arg *arg);
 #define SCA_X86_MSR syscall_arg__scnprintf_x86_MSR
 
index 859a8a9..9fa771a 100644 (file)
@@ -33,11 +33,11 @@ static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
 
 #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
 
-static size_t mmap__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix)
-{
 #include "trace/beauty/generated/mmap_flags_array.c"
        static DEFINE_STRARRAY(mmap_flags, "MAP_");
 
+static size_t mmap__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix)
+{
        return strarray__scnprintf_flags(&strarray__mmap_flags, bf, size, show_prefix, flags);
 }
 
diff --git a/tools/perf/trace/beauty/tracepoints/x86_irq_vectors.c b/tools/perf/trace/beauty/tracepoints/x86_irq_vectors.c
new file mode 100644 (file)
index 0000000..8eb9bc8
--- /dev/null
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: LGPL-2.1
+/*
+ * trace/beauty/x86_irq_vectors.c
+ *
+ *  Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
+ */
+
+#include "trace/beauty/beauty.h"
+
+#include "trace/beauty/generated/x86_arch_irq_vectors_array.c"
+
+static DEFINE_STRARRAY(x86_irq_vectors, "_VECTOR");
+
+static size_t x86_irq_vectors__scnprintf(unsigned long vector, char *bf, size_t size, bool show_prefix)
+{
+       return strarray__scnprintf_suffix(&strarray__x86_irq_vectors, bf, size, "%#x", show_prefix, vector);
+}
+
+size_t syscall_arg__scnprintf_x86_irq_vectors(char *bf, size_t size, struct syscall_arg *arg)
+{
+       unsigned long vector = arg->val;
+
+       return x86_irq_vectors__scnprintf(vector, bf, size, arg->show_string_prefix);
+}
+
+bool syscall_arg__strtoul_x86_irq_vectors(char *bf, size_t size, struct syscall_arg *arg __maybe_unused, u64 *ret)
+{
+       return strarray__strtoul(&strarray__x86_irq_vectors, bf, size, ret);
+}
diff --git a/tools/perf/trace/beauty/tracepoints/x86_irq_vectors.sh b/tools/perf/trace/beauty/tracepoints/x86_irq_vectors.sh
new file mode 100755 (executable)
index 0000000..f920003
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+# SPDX-License-Identifier: LGPL-2.1
+# (C) 2019, Arnaldo Carvalho de Melo <acme@redhat.com>
+
+if [ $# -ne 1 ] ; then
+       arch_x86_header_dir=tools/arch/x86/include/asm/
+else
+       arch_x86_header_dir=$1
+fi
+
+x86_irq_vectors=${arch_x86_header_dir}/irq_vectors.h
+
+# FIRST_EXTERNAL_VECTOR is not that useful, find what is its number
+# and then replace whatever is using it and that is useful, which at
+# the time of writing of this script was: IRQ_MOVE_CLEANUP_VECTOR.
+
+first_external_regex='^#define[[:space:]]+FIRST_EXTERNAL_VECTOR[[:space:]]+(0x[[:xdigit:]]+)$'
+first_external_vector=$(egrep ${first_external_regex} ${x86_irq_vectors} | sed -r "s/${first_external_regex}/\1/g")
+
+printf "static const char *x86_irq_vectors[] = {\n"
+regex='^#define[[:space:]]+([[:alnum:]_]+)_VECTOR[[:space:]]+(0x[[:xdigit:]]+)$'
+sed -r "s/FIRST_EXTERNAL_VECTOR/${first_external_vector}/g" ${x86_irq_vectors} | \
+egrep ${regex} | \
+       sed -r "s/${regex}/\2 \1/g" | sort -n | \
+       xargs printf "\t[%s] = \"%s\",\n"
+printf "};\n\n"
+
index bc69ca6..ef1866a 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/string.h>
 #include <bpf/libbpf.h>
 #include <subcmd/parse-options.h>
+#include <subcmd/run-command.h>
 
 /* FIXME: For the HE_COLORSET */
 #include "ui/browser.h"
@@ -1489,44 +1490,26 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start
  * means that it's not a disassembly line so should be treated differently.
  * The ops.raw part will be parsed further according to type of the instruction.
  */
-static int symbol__parse_objdump_line(struct symbol *sym, FILE *file,
+static int symbol__parse_objdump_line(struct symbol *sym,
                                      struct annotate_args *args,
-                                     int *line_nr)
+                                     char *parsed_line, int *line_nr)
 {
        struct map *map = args->ms.map;
        struct annotation *notes = symbol__annotation(sym);
        struct disasm_line *dl;
-       char *line = NULL, *parsed_line, *tmp, *tmp2;
-       size_t line_len;
+       char *tmp;
        s64 line_ip, offset = -1;
        regmatch_t match[2];
 
-       if (getline(&line, &line_len, file) < 0)
-               return -1;
-
-       if (!line)
-               return -1;
-
-       line_ip = -1;
-       parsed_line = strim(line);
-
        /* /filename:linenr ? Save line number and ignore. */
        if (regexec(&file_lineno, parsed_line, 2, match, 0) == 0) {
                *line_nr = atoi(parsed_line + match[1].rm_so);
                return 0;
        }
 
-       tmp = skip_spaces(parsed_line);
-       if (*tmp) {
-               /*
-                * Parse hexa addresses followed by ':'
-                */
-               line_ip = strtoull(tmp, &tmp2, 16);
-               if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
-                       line_ip = -1;
-       }
-
-       if (line_ip != -1) {
+       /* Process hex address followed by ':'. */
+       line_ip = strtoull(parsed_line, &tmp, 16);
+       if (parsed_line != tmp && tmp[0] == ':' && tmp[1] != '\0') {
                u64 start = map__rip_2objdump(map, sym->start),
                    end = map__rip_2objdump(map, sym->end);
 
@@ -1534,7 +1517,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, FILE *file,
                if ((u64)line_ip < start || (u64)line_ip >= end)
                        offset = -1;
                else
-                       parsed_line = tmp2 + 1;
+                       parsed_line = tmp + 1;
        }
 
        args->offset  = offset;
@@ -1543,7 +1526,6 @@ static int symbol__parse_objdump_line(struct symbol *sym, FILE *file,
        args->ms.sym  = sym;
 
        dl = disasm_line__new(args);
-       free(line);
        (*line_nr)++;
 
        if (dl == NULL)
@@ -1861,6 +1843,67 @@ static int symbol__disassemble_bpf(struct symbol *sym __maybe_unused,
 }
 #endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
 
+/*
+ * Possibly create a new version of line with tabs expanded. Returns the
+ * existing or new line, storage is updated if a new line is allocated. If
+ * allocation fails then NULL is returned.
+ */
+static char *expand_tabs(char *line, char **storage, size_t *storage_len)
+{
+       size_t i, src, dst, len, new_storage_len, num_tabs;
+       char *new_line;
+       size_t line_len = strlen(line);
+
+       for (num_tabs = 0, i = 0; i < line_len; i++)
+               if (line[i] == '\t')
+                       num_tabs++;
+
+       if (num_tabs == 0)
+               return line;
+
+       /*
+        * Space for the line and '\0', less the leading and trailing
+        * spaces. Each tab may introduce 7 additional spaces.
+        */
+       new_storage_len = line_len + 1 + (num_tabs * 7);
+
+       new_line = malloc(new_storage_len);
+       if (new_line == NULL) {
+               pr_err("Failure allocating memory for tab expansion\n");
+               return NULL;
+       }
+
+       /*
+        * Copy regions starting at src and expand tabs. If there are two
+        * adjacent tabs then 'src == i', the memcpy is of size 0 and the spaces
+        * are inserted.
+        */
+       for (i = 0, src = 0, dst = 0; i < line_len && num_tabs; i++) {
+               if (line[i] == '\t') {
+                       len = i - src;
+                       memcpy(&new_line[dst], &line[src], len);
+                       dst += len;
+                       new_line[dst++] = ' ';
+                       while (dst % 8 != 0)
+                               new_line[dst++] = ' ';
+                       src = i + 1;
+                       num_tabs--;
+               }
+       }
+
+       /* Expand the last region. */
+       len = line_len + 1 - src;
+       memcpy(&new_line[dst], &line[src], len);
+       dst += len;
+       new_line[dst] = '\0';
+
+       free(*storage);
+       *storage = new_line;
+       *storage_len = new_storage_len;
+       return new_line;
+
+}
+
 static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
 {
        struct annotation_options *opts = args->options;
@@ -1872,10 +1915,19 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
        struct kcore_extract kce;
        bool delete_extract = false;
        bool decomp = false;
-       int stdout_fd[2];
        int lineno = 0;
        int nline;
-       pid_t pid;
+       char *line;
+       size_t line_len;
+       const char *objdump_argv[] = {
+               "/bin/sh",
+               "-c",
+               NULL, /* Will be the objdump command to run. */
+               "--",
+               NULL, /* Will be the symfs path. */
+               NULL,
+       };
+       struct child_process objdump_process;
        int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename));
 
        if (err)
@@ -1905,7 +1957,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
 
                if (dso__decompress_kmodule_path(dso, symfs_filename,
                                                 tmp, sizeof(tmp)) < 0)
-                       goto out;
+                       return -1;
 
                decomp = true;
                strcpy(symfs_filename, tmp);
@@ -1914,13 +1966,13 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
        err = asprintf(&command,
                 "%s %s%s --start-address=0x%016" PRIx64
                 " --stop-address=0x%016" PRIx64
-                " -l -d %s %s -C \"$1\" 2>/dev/null|grep -v \"$1:\"|expand",
+                " -l -d %s %s -C \"$1\"",
                 opts->objdump_path ?: "objdump",
                 opts->disassembler_style ? "-M " : "",
                 opts->disassembler_style ?: "",
                 map__rip_2objdump(map, sym->start),
                 map__rip_2objdump(map, sym->end),
-                opts->show_asm_raw ? "" : "--no-show-raw",
+                opts->show_asm_raw ? "" : "--no-show-raw-insn",
                 opts->annotate_src ? "-S" : "");
 
        if (err < 0) {
@@ -1930,55 +1982,73 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
 
        pr_debug("Executing: %s\n", command);
 
-       err = -1;
-       if (pipe(stdout_fd) < 0) {
-               pr_err("Failure creating the pipe to run %s\n", command);
-               goto out_free_command;
-       }
+       objdump_argv[2] = command;
+       objdump_argv[4] = symfs_filename;
 
-       pid = fork();
-       if (pid < 0) {
-               pr_err("Failure forking to run %s\n", command);
-               goto out_close_stdout;
-       }
-
-       if (pid == 0) {
-               close(stdout_fd[0]);
-               dup2(stdout_fd[1], 1);
-               close(stdout_fd[1]);
-               execl("/bin/sh", "sh", "-c", command, "--", symfs_filename,
-                     NULL);
-               perror(command);
-               exit(-1);
+       /* Create a pipe to read from for stdout */
+       memset(&objdump_process, 0, sizeof(objdump_process));
+       objdump_process.argv = objdump_argv;
+       objdump_process.out = -1;
+       if (start_command(&objdump_process)) {
+               pr_err("Failure starting to run %s\n", command);
+               err = -1;
+               goto out_free_command;
        }
 
-       close(stdout_fd[1]);
-
-       file = fdopen(stdout_fd[0], "r");
+       file = fdopen(objdump_process.out, "r");
        if (!file) {
                pr_err("Failure creating FILE stream for %s\n", command);
                /*
                 * If we were using debug info should retry with
                 * original binary.
                 */
-               goto out_free_command;
+               err = -1;
+               goto out_close_stdout;
        }
 
+       /* Storage for getline. */
+       line = NULL;
+       line_len = 0;
+
        nline = 0;
        while (!feof(file)) {
+               const char *match;
+               char *expanded_line;
+
+               if (getline(&line, &line_len, file) < 0 || !line)
+                       break;
+
+               /* Skip lines containing "filename:" */
+               match = strstr(line, symfs_filename);
+               if (match && match[strlen(symfs_filename)] == ':')
+                       continue;
+
+               expanded_line = strim(line);
+               expanded_line = expand_tabs(expanded_line, &line, &line_len);
+               if (!expanded_line)
+                       break;
+
                /*
                 * The source code line number (lineno) needs to be kept in
                 * across calls to symbol__parse_objdump_line(), so that it
                 * can associate it with the instructions till the next one.
                 * See disasm_line__new() and struct disasm_line::line_nr.
                 */
-               if (symbol__parse_objdump_line(sym, file, args, &lineno) < 0)
+               if (symbol__parse_objdump_line(sym, args, expanded_line,
+                                              &lineno) < 0)
                        break;
                nline++;
        }
+       free(line);
+
+       err = finish_command(&objdump_process);
+       if (err)
+               pr_err("Error running %s\n", command);
 
-       if (nline == 0)
+       if (nline == 0) {
+               err = -1;
                pr_err("No output from %s\n", command);
+       }
 
        /*
         * kallsyms does not have symbol sizes so there may a nop at the end.
@@ -1988,23 +2058,21 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
                delete_last_nop(sym);
 
        fclose(file);
-       err = 0;
+
+out_close_stdout:
+       close(objdump_process.out);
+
 out_free_command:
        free(command);
-out_remove_tmp:
-       close(stdout_fd[0]);
 
+out_remove_tmp:
        if (decomp)
                unlink(symfs_filename);
 
        if (delete_extract)
                kcore_extract__delete(&kce);
-out:
-       return err;
 
-out_close_stdout:
-       close(stdout_fd[1]);
-       goto out_free_command;
+       return err;
 }
 
 static void calc_percent(struct sym_hist *sym_hist,
index 8793b4e..fdce590 100644 (file)
@@ -21,6 +21,7 @@
 #include "../perf.h"
 #include "asm/bug.h"
 #include "bpf-event.h"
+#include "util/string2.h"
 #include <signal.h>
 #include <unistd.h>
 #include <sched.h>
@@ -598,14 +599,13 @@ static struct mmap *evlist__alloc_mmap(struct evlist *evlist,
        int i;
        struct mmap *map;
 
-       evlist->core.nr_mmaps = perf_cpu_map__nr(evlist->core.cpus);
-       if (perf_cpu_map__empty(evlist->core.cpus))
-               evlist->core.nr_mmaps = perf_thread_map__nr(evlist->core.threads);
        map = zalloc(evlist->core.nr_mmaps * sizeof(struct mmap));
        if (!map)
                return NULL;
 
        for (i = 0; i < evlist->core.nr_mmaps; i++) {
+               struct perf_mmap *prev = i ? &map[i - 1].core : NULL;
+
                /*
                 * When the perf_mmap() call is made we grab one refcount, plus
                 * one extra to let perf_mmap__consume() get the last
@@ -615,7 +615,7 @@ static struct mmap *evlist__alloc_mmap(struct evlist *evlist,
                 * Each PERF_EVENT_IOC_SET_OUTPUT points to this mmap and
                 * thus does perf_mmap__get() on it.
                 */
-               perf_mmap__init(&map[i].core, overwrite, perf_mmap__unmap_cb);
+               perf_mmap__init(&map[i].core, prev, overwrite, perf_mmap__unmap_cb);
        }
 
        return map;
@@ -636,19 +636,21 @@ static struct perf_mmap*
 perf_evlist__mmap_cb_get(struct perf_evlist *_evlist, bool overwrite, int idx)
 {
        struct evlist *evlist = container_of(_evlist, struct evlist, core);
-       struct mmap *maps = evlist->mmap;
+       struct mmap *maps;
 
-       if (overwrite) {
-               maps = evlist->overwrite_mmap;
+       maps = overwrite ? evlist->overwrite_mmap : evlist->mmap;
 
-               if (!maps) {
-                       maps = evlist__alloc_mmap(evlist, true);
-                       if (!maps)
-                               return NULL;
+       if (!maps) {
+               maps = evlist__alloc_mmap(evlist, overwrite);
+               if (!maps)
+                       return NULL;
 
+               if (overwrite) {
                        evlist->overwrite_mmap = maps;
                        if (evlist->bkw_mmap_state == BKW_MMAP_NOTREADY)
                                perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_RUNNING);
+               } else {
+                       evlist->mmap = maps;
                }
        }
 
@@ -809,14 +811,8 @@ int evlist__mmap_ex(struct evlist *evlist, unsigned int pages,
                .mmap = perf_evlist__mmap_cb_mmap,
        };
 
-       if (!evlist->mmap)
-               evlist->mmap = evlist__alloc_mmap(evlist, false);
-       if (!evlist->mmap)
-               return -ENOMEM;
-
        evlist->core.mmap_len = evlist__mmap_size(pages);
        pr_debug("mmap size %zuB\n", evlist->core.mmap_len);
-       mp.core.mask = evlist->core.mmap_len - page_size - 1;
 
        auxtrace_mmap_params__init(&mp.auxtrace_mp, evlist->core.mmap_len,
                                   auxtrace_pages, auxtrace_overwrite);
@@ -959,7 +955,7 @@ int perf_evlist__append_tp_filter(struct evlist *evlist, const char *filter)
        return err;
 }
 
-static char *asprintf__tp_filter_pids(size_t npids, pid_t *pids)
+char *asprintf__tp_filter_pids(size_t npids, pid_t *pids)
 {
        char *filter;
        size_t i;
index b5e2ade..db882f6 100644 (file)
@@ -2600,7 +2600,7 @@ out_enomem:
  * Print the help text for the event symbols:
  */
 void print_events(const char *event_glob, bool name_only, bool quiet_flag,
-                       bool long_desc, bool details_flag)
+                       bool long_desc, bool details_flag, bool deprecated)
 {
        print_symbol_events(event_glob, PERF_TYPE_HARDWARE,
                            event_symbols_hw, PERF_COUNT_HW_MAX, name_only);
@@ -2612,7 +2612,7 @@ void print_events(const char *event_glob, bool name_only, bool quiet_flag,
        print_hwcache_events(event_glob, name_only);
 
        print_pmu_events(event_glob, name_only, quiet_flag, long_desc,
-                       details_flag);
+                       details_flag, deprecated);
 
        if (event_glob != NULL)
                return;
index 616ca1e..769e07c 100644 (file)
@@ -195,7 +195,7 @@ void parse_events_evlist_error(struct parse_events_state *parse_state,
                               int idx, const char *str);
 
 void print_events(const char *event_glob, bool name_only, bool quiet,
-                 bool long_desc, bool details_flag);
+                 bool long_desc, bool details_flag, bool deprecated);
 
 struct event_symbol {
        const char      *symbol;
index 5608da8..adbe97e 100644 (file)
@@ -308,7 +308,8 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
                                 char *long_desc, char *topic,
                                 char *unit, char *perpkg,
                                 char *metric_expr,
-                                char *metric_name)
+                                char *metric_name,
+                                char *deprecated)
 {
        struct parse_events_term *term;
        struct perf_pmu_alias *alias;
@@ -325,6 +326,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
        alias->unit[0] = '\0';
        alias->per_pkg = false;
        alias->snapshot = false;
+       alias->deprecated = false;
 
        ret = parse_events_terms(&alias->terms, val);
        if (ret) {
@@ -379,6 +381,9 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
        alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1;
        alias->str = strdup(newval);
 
+       if (deprecated)
+               alias->deprecated = true;
+
        if (!perf_pmu_merge_alias(alias, list))
                list_add_tail(&alias->list, list);
 
@@ -400,7 +405,7 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
        strim(buf);
 
        return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL,
-                                    NULL, NULL, NULL);
+                                    NULL, NULL, NULL, NULL);
 }
 
 static inline bool pmu_alias_info_file(char *name)
@@ -787,7 +792,8 @@ new_alias:
                                (char *)pe->long_desc, (char *)pe->topic,
                                (char *)pe->unit, (char *)pe->perpkg,
                                (char *)pe->metric_expr,
-                               (char *)pe->metric_name);
+                               (char *)pe->metric_name,
+                               (char *)pe->deprecated);
        }
 }
 
@@ -1383,7 +1389,7 @@ static void wordwrap(char *s, int start, int max, int corr)
 }
 
 void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
-                       bool long_desc, bool details_flag)
+                       bool long_desc, bool details_flag, bool deprecated)
 {
        struct perf_pmu *pmu;
        struct perf_pmu_alias *alias;
@@ -1414,6 +1420,9 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
                                format_alias(buf, sizeof(buf), pmu, alias);
                        bool is_cpu = !strcmp(pmu->name, "cpu");
 
+                       if (alias->deprecated && !deprecated)
+                               continue;
+
                        if (event_glob != NULL &&
                            !(strglobmatch_nocase(name, event_glob) ||
                              (!is_cpu && strglobmatch_nocase(alias->name,
index f36ade6..3e8cd31 100644 (file)
@@ -57,6 +57,7 @@ struct perf_pmu_alias {
        double scale;
        bool per_pkg;
        bool snapshot;
+       bool deprecated;
        char *metric_expr;
        char *metric_name;
 };
@@ -85,7 +86,8 @@ int perf_pmu__format_parse(char *dir, struct list_head *head);
 struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
 
 void print_pmu_events(const char *event_glob, bool name_only, bool quiet,
-                     bool long_desc, bool details_flag);
+                     bool long_desc, bool details_flag,
+                     bool deprecated);
 bool pmu_have_event(const char *pname, const char *name);
 
 int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, ...) __scanf(3, 4);
index 1596185..741f040 100644 (file)
@@ -539,10 +539,11 @@ static int perl_stop_script(void)
 
 static int perl_generate_script(struct tep_handle *pevent, const char *outfile)
 {
+       int i, not_first, count, nr_events;
+       struct tep_event **all_events;
        struct tep_event *event = NULL;
        struct tep_format_field *f;
        char fname[PATH_MAX];
-       int not_first, count;
        FILE *ofp;
 
        sprintf(fname, "%s.pl", outfile);
@@ -603,8 +604,11 @@ sub print_backtrace\n\
 }\n\n\
 ");
 
+       nr_events = tep_get_events_count(pevent);
+       all_events = tep_list_events(pevent, TEP_EVENT_SORT_ID);
 
-       while ((event = trace_find_next_event(pevent, event))) {
+       for (i = 0; all_events && i < nr_events; i++) {
+               event = all_events[i];
                fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name);
                fprintf(ofp, "\tmy (");
 
index 5d341ef..93c03b3 100644 (file)
@@ -1687,10 +1687,11 @@ static int python_stop_script(void)
 
 static int python_generate_script(struct tep_handle *pevent, const char *outfile)
 {
+       int i, not_first, count, nr_events;
+       struct tep_event **all_events;
        struct tep_event *event = NULL;
        struct tep_format_field *f;
        char fname[PATH_MAX];
-       int not_first, count;
        FILE *ofp;
 
        sprintf(fname, "%s.py", outfile);
@@ -1735,7 +1736,11 @@ static int python_generate_script(struct tep_handle *pevent, const char *outfile
        fprintf(ofp, "def trace_end():\n");
        fprintf(ofp, "\tprint(\"in trace_end\")\n\n");
 
-       while ((event = trace_find_next_event(pevent, event))) {
+       nr_events = tep_get_events_count(pevent);
+       all_events = tep_list_events(pevent, TEP_EVENT_SORT_ID);
+
+       for (i = 0; all_events && i < nr_events; i++) {
+               event = all_events[i];
                fprintf(ofp, "def %s__%s(", event->system, event->name);
                fprintf(ofp, "event_name, ");
                fprintf(ofp, "context, ");
index ebdd130..6822e4f 100644 (file)
@@ -490,6 +490,16 @@ int create_perf_stat_counter(struct evsel *evsel,
        if (config->identifier)
                attr->sample_type = PERF_SAMPLE_IDENTIFIER;
 
+       if (config->all_user) {
+               attr->exclude_kernel = 1;
+               attr->exclude_user   = 0;
+       }
+
+       if (config->all_kernel) {
+               attr->exclude_kernel = 0;
+               attr->exclude_user   = 1;
+       }
+
        /*
         * Disabling all counters initially, they will be enabled
         * either manually by us or by kernel via enable_on_exec
index edbeb2f..081c4a5 100644 (file)
@@ -106,6 +106,8 @@ struct perf_stat_config {
        bool                     big_num;
        bool                     no_merge;
        bool                     walltime_run_table;
+       bool                     all_kernel;
+       bool                     all_user;
        FILE                    *output;
        unsigned int             interval;
        unsigned int             timeout;
index 708805f..73df616 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/string.h>
 #include <linux/types.h>
+#include <sys/types.h> // pid_t
 #include <stddef.h>
 #include <string.h>
 
@@ -32,6 +33,8 @@ static inline char *asprintf_expr_not_in_ints(const char *var, size_t nints, int
        return asprintf_expr_inout_ints(var, false, nints, ints);
 }
 
+char *asprintf__tp_filter_pids(size_t npids, pid_t *pids);
+
 char *strpbrk_esc(char *str, const char *stopset);
 char *strdup_esc(const char *str);
 
index 9796a2e..3024439 100644 (file)
@@ -458,10 +458,11 @@ bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf,
        return true;
 }
 
-int perf_time__parse_for_ranges(const char *time_str,
+int perf_time__parse_for_ranges_reltime(const char *time_str,
                                struct perf_session *session,
                                struct perf_time_interval **ranges,
-                               int *range_size, int *range_num)
+                               int *range_size, int *range_num,
+                               bool reltime)
 {
        bool has_percent = strchr(time_str, '%');
        struct perf_time_interval *ptime_range;
@@ -471,7 +472,7 @@ int perf_time__parse_for_ranges(const char *time_str,
        if (!ptime_range)
                return -ENOMEM;
 
-       if (has_percent) {
+       if (has_percent || reltime) {
                if (session->evlist->first_sample_time == 0 &&
                    session->evlist->last_sample_time == 0) {
                        pr_err("HINT: no first/last sample time found in perf data.\n"
@@ -479,7 +480,9 @@ int perf_time__parse_for_ranges(const char *time_str,
                               "(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n");
                        goto error;
                }
+       }
 
+       if (has_percent) {
                num = perf_time__percent_parse_str(
                                ptime_range, size,
                                time_str,
@@ -492,6 +495,15 @@ int perf_time__parse_for_ranges(const char *time_str,
        if (num < 0)
                goto error_invalid;
 
+       if (reltime) {
+               int i;
+
+               for (i = 0; i < num; i++) {
+                       ptime_range[i].start += session->evlist->first_sample_time;
+                       ptime_range[i].end += session->evlist->first_sample_time;
+               }
+       }
+
        *range_size = size;
        *range_num = num;
        *ranges = ptime_range;
@@ -504,6 +516,15 @@ error:
        return ret;
 }
 
+int perf_time__parse_for_ranges(const char *time_str,
+                               struct perf_session *session,
+                               struct perf_time_interval **ranges,
+                               int *range_size, int *range_num)
+{
+       return perf_time__parse_for_ranges_reltime(time_str, session, ranges,
+                                       range_size, range_num, false);
+}
+
 int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz)
 {
        u64  sec = timestamp / NSEC_PER_SEC;
index 4f42988..1142b0b 100644 (file)
@@ -26,6 +26,11 @@ bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf,
 
 struct perf_session;
 
+int perf_time__parse_for_ranges_reltime(const char *str, struct perf_session *session,
+                               struct perf_time_interval **ranges,
+                               int *range_size, int *range_num,
+                               bool reltime);
+
 int perf_time__parse_for_ranges(const char *str, struct perf_session *session,
                                struct perf_time_interval **ranges,
                                int *range_size, int *range_num);
index 5d6bfc7..9634f0a 100644 (file)
@@ -173,37 +173,6 @@ int parse_event_file(struct tep_handle *pevent,
        return tep_parse_event(pevent, buf, size, sys);
 }
 
-struct tep_event *trace_find_next_event(struct tep_handle *pevent,
-                                       struct tep_event *event)
-{
-       static int idx;
-       int events_count;
-       struct tep_event *all_events;
-
-       all_events = tep_get_first_event(pevent);
-       events_count = tep_get_events_count(pevent);
-       if (!pevent || !all_events || events_count < 1)
-               return NULL;
-
-       if (!event) {
-               idx = 0;
-               return all_events;
-       }
-
-       if (idx < events_count && event == (all_events + idx)) {
-               idx++;
-               if (idx == events_count)
-                       return NULL;
-               return (all_events + idx);
-       }
-
-       for (idx = 1; idx < events_count; idx++) {
-               if (event == (all_events + (idx - 1)))
-                       return (all_events + idx);
-       }
-       return NULL;
-}
-
 struct flag {
        const char *name;
        unsigned long long value;
index 2e15838..72fdf2a 100644 (file)
@@ -47,8 +47,6 @@ void parse_saved_cmdline(struct tep_handle *pevent, char *file, unsigned int siz
 
 ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe);
 
-struct tep_event *trace_find_next_event(struct tep_handle *pevent,
-                                       struct tep_event *event);
 unsigned long long read_size(struct tep_event *event, void *ptr, int size);
 unsigned long long eval_flag(const char *flag);