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

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

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>
This commit is contained in:
Ingo Molnar
2019-10-22 01:15:45 +02:00
60 changed files with 1301 additions and 287 deletions

View File

@@ -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 */

View File

@@ -36,6 +36,9 @@ Enable debugging output.
Print how named events are resolved internally into perf events, and also Print how named events are resolved internally into perf events, and also
any extra expressions computed by perf stat. any extra expressions computed by perf stat.
--deprecated::
Print deprecated events. By default the deprecated events are hidden.
[[EVENT_MODIFIERS]] [[EVENT_MODIFIERS]]
EVENT MODIFIERS EVENT MODIFIERS
--------------- ---------------

View 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. 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 EXAMPLES
-------- --------

View 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 Show all syscalls followed by a summary by thread with min, max, and
average times (in msec) and relative stddev. 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:: --tool_stats::
Show tool stats such as number of times fd->pathname was discovered thru 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. hooking the open syscall return + vfs_getname or via reading /proc/pid/fd, etc.

View File

@@ -265,6 +265,11 @@ LDFLAGS += -Wl,-z,noexecstack
EXTLIBS = -lpthread -lrt -lm -ldl 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),) ifeq ($(FEATURES_DUMP),)
include $(srctree)/tools/build/Makefile.feature include $(srctree)/tools/build/Makefile.feature
else else

View File

@@ -114,6 +114,8 @@ include ../scripts/utilities.mak
# Define NO_LIBZSTD if you do not want support of Zstandard based runtime # Define NO_LIBZSTD if you do not want support of Zstandard based runtime
# trace compression in record mode. # trace compression in record mode.
# #
# Define TCMALLOC to enable tcmalloc heap profiling.
#
# As per kernel Makefile, avoid funny character set dependencies # As per kernel Makefile, avoid funny character set dependencies
unexport LC_ALL 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) $(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) > $@ $(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_array := $(beauty_outdir)/x86_arch_MSRs_array.c
x86_arch_MSRs_tbl := $(srctree)/tools/perf/trace/beauty/tracepoints/x86_msr.sh 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) \ $(perf_ioctl_array) \
$(prctl_option_array) \ $(prctl_option_array) \
$(usbdevfs_ioctl_array) \ $(usbdevfs_ioctl_array) \
$(x86_arch_irq_vectors_array) \
$(x86_arch_MSRs_array) \ $(x86_arch_MSRs_array) \
$(x86_arch_prctl_code_array) \ $(x86_arch_prctl_code_array) \
$(rename_flags_array) \ $(rename_flags_array) \
@@ -989,6 +998,7 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea
$(OUTPUT)$(perf_ioctl_array) \ $(OUTPUT)$(perf_ioctl_array) \
$(OUTPUT)$(prctl_option_array) \ $(OUTPUT)$(prctl_option_array) \
$(OUTPUT)$(usbdevfs_ioctl_array) \ $(OUTPUT)$(usbdevfs_ioctl_array) \
$(OUTPUT)$(x86_arch_irq_vectors_array) \
$(OUTPUT)$(x86_arch_MSRs_array) \ $(OUTPUT)$(x86_arch_MSRs_array) \
$(OUTPUT)$(x86_arch_prctl_code_array) \ $(OUTPUT)$(x86_arch_prctl_code_array) \
$(OUTPUT)$(rename_flags_array) \ $(OUTPUT)$(rename_flags_array) \

View File

@@ -26,6 +26,7 @@ int cmd_list(int argc, const char **argv)
int i; int i;
bool raw_dump = false; bool raw_dump = false;
bool long_desc_flag = false; bool long_desc_flag = false;
bool deprecated = false;
struct option list_options[] = { struct option list_options[] = {
OPT_BOOLEAN(0, "raw-dump", &raw_dump, "Dump raw events"), OPT_BOOLEAN(0, "raw-dump", &raw_dump, "Dump raw events"),
OPT_BOOLEAN('d', "desc", &desc_flag, OPT_BOOLEAN('d', "desc", &desc_flag,
@@ -34,6 +35,8 @@ int cmd_list(int argc, const char **argv)
"Print longer event descriptions."), "Print longer event descriptions."),
OPT_BOOLEAN(0, "details", &details_flag, OPT_BOOLEAN(0, "details", &details_flag,
"Print information on the perf event names and expressions used internally by events."), "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, OPT_INCR(0, "debug", &verbose,
"Enable debugging output"), "Enable debugging output"),
OPT_END() OPT_END()
@@ -55,7 +58,7 @@ int cmd_list(int argc, const char **argv)
if (argc == 0) { if (argc == 0) {
print_events(NULL, raw_dump, !desc_flag, long_desc_flag, print_events(NULL, raw_dump, !desc_flag, long_desc_flag,
details_flag); details_flag, deprecated);
return 0; return 0;
} }
@@ -78,7 +81,8 @@ int cmd_list(int argc, const char **argv)
print_hwcache_events(NULL, raw_dump); print_hwcache_events(NULL, raw_dump);
else if (strcmp(argv[i], "pmu") == 0) else if (strcmp(argv[i], "pmu") == 0)
print_pmu_events(NULL, raw_dump, !desc_flag, 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) else if (strcmp(argv[i], "sdt") == 0)
print_sdt_events(NULL, NULL, raw_dump); print_sdt_events(NULL, NULL, raw_dump);
else if (strcmp(argv[i], "metric") == 0 || strcmp(argv[i], "metrics") == 0) 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) { if (sep == NULL) {
print_events(argv[i], raw_dump, !desc_flag, print_events(argv[i], raw_dump, !desc_flag,
long_desc_flag, long_desc_flag,
details_flag); details_flag,
deprecated);
continue; continue;
} }
sep_idx = sep - argv[i]; sep_idx = sep - argv[i];
@@ -117,7 +122,8 @@ int cmd_list(int argc, const char **argv)
print_hwcache_events(s, raw_dump); print_hwcache_events(s, raw_dump);
print_pmu_events(s, raw_dump, !desc_flag, print_pmu_events(s, raw_dump, !desc_flag,
long_desc_flag, long_desc_flag,
details_flag); details_flag,
deprecated);
print_tracepoint_events(NULL, s, raw_dump); print_tracepoint_events(NULL, s, raw_dump);
print_sdt_events(NULL, s, raw_dump); print_sdt_events(NULL, s, raw_dump);
metricgroup__print(true, true, s, raw_dump, details_flag); metricgroup__print(true, true, s, raw_dump, details_flag);

View File

@@ -399,6 +399,13 @@ static int report__setup_sample_type(struct report *rep)
PERF_SAMPLE_BRANCH_ANY)) PERF_SAMPLE_BRANCH_ANY))
rep->nonany_branch_mode = true; 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; return 0;
} }

View File

@@ -3864,10 +3864,11 @@ int cmd_script(int argc, const char **argv)
goto out_delete; goto out_delete;
if (script.time_str) { 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.ptime_range,
&script.range_size, &script.range_size,
&script.range_num); &script.range_num,
reltime);
if (err < 0) if (err < 0)
goto out_delete; goto out_delete;

View File

@@ -803,6 +803,12 @@ static struct option stat_options[] = {
OPT_CALLBACK('M', "metrics", &evsel_list, "metric/metric group list", OPT_CALLBACK('M', "metrics", &evsel_list, "metric/metric group list",
"monitor specified metrics or metric groups (separated by ,)", "monitor specified metrics or metric groups (separated by ,)",
parse_metric_groups), 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() OPT_END()
}; };

View File

@@ -175,6 +175,7 @@ struct trace {
bool multiple_threads; bool multiple_threads;
bool summary; bool summary;
bool summary_only; bool summary_only;
bool errno_summary;
bool failure_only; bool failure_only;
bool show_comm; bool show_comm;
bool print_sample; 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, static int perf_evsel__init_tp_uint_field(struct evsel *evsel,
struct tp_field *field, struct tp_field *field,
const char *name) 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) \ #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); }) perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
static int perf_evsel__init_tp_ptr_field(struct evsel *evsel, 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) \ #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); }) perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
static void evsel__delete_priv(struct evsel *evsel) 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) 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") && if (perf_evsel__init_tp_uint_field(evsel, &sc->id, "__syscall_nr") &&
perf_evsel__init_tp_uint_field(evsel, &sc->id, "nr")) perf_evsel__init_tp_uint_field(evsel, &sc->id, "nr"))
goto out_delete; return -ENOENT;
return 0; return 0;
} }
return -ENOMEM; return -ENOMEM;
out_delete:
zfree(&evsel->priv);
return -ENOENT;
} }
static int perf_evsel__init_augmented_syscall_tp(struct evsel *evsel, struct evsel *tp) 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"); struct tep_format_field *syscall_id = perf_evsel__field(tp, "id");
if (syscall_id == NULL) if (syscall_id == NULL)
syscall_id = perf_evsel__field(tp, "__syscall_nr"); syscall_id = perf_evsel__field(tp, "__syscall_nr");
if (syscall_id == NULL) if (syscall_id == NULL ||
goto out_delete; __tp_field__init_uint(&sc->id, syscall_id->size, syscall_id->offset, evsel->needs_swap))
if (__tp_field__init_uint(&sc->id, syscall_id->size, syscall_id->offset, evsel->needs_swap)) return -EINVAL;
goto out_delete;
return 0; return 0;
} }
return -ENOMEM; return -ENOMEM;
out_delete:
zfree(&evsel->priv);
return -EINVAL;
} }
static int perf_evsel__init_augmented_syscall_tp_args(struct evsel *evsel) 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)); return __tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64));
} }
static int perf_evsel__init_augmented_syscall_tp_ret(struct evsel *evsel) 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); 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) static int perf_evsel__init_raw_syscall_tp(struct evsel *evsel, void *handler)
{ {
evsel->priv = malloc(sizeof(struct syscall_tp)); if (evsel__syscall_tp(evsel) != NULL) {
if (evsel->priv != NULL) {
if (perf_evsel__init_sc_tp_uint_field(evsel, id)) if (perf_evsel__init_sc_tp_uint_field(evsel, id))
goto out_delete; return -ENOENT;
evsel->handler = handler; evsel->handler = handler;
return 0; return 0;
} }
return -ENOMEM; return -ENOMEM;
out_delete:
zfree(&evsel->priv);
return -ENOENT;
} }
static struct evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *handler) 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) \ #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); }) fields->name.integer(&fields->name, sample); })
#define perf_evsel__sc_tp_ptr(evsel, 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); }) 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) 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; 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 #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) 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); 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; 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) bool strarrays__strtoul(struct strarrays *sas, char *bf, size_t size, u64 *ret)
{ {
int i; 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 // XXX Hey, maybe for sched:sched_switch prev/next comm fields we can
// fill missing comms using thread__set_comm()... // fill missing comms using thread__set_comm()...
// here or in a special syscall_arg__scnprintf_pid_sched_tp... // 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 #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) \ #define STRARRAY(name, array) \
{ .scnprintf = SCA_STRARRAY, \ { .scnprintf = SCA_STRARRAY, \
.strtoul = STUL_STRARRAY, \
.parm = &strarray__##array, } .parm = &strarray__##array, }
#define STRARRAY_FLAGS(name, array) \ #define STRARRAY_FLAGS(name, array) \
{ .scnprintf = SCA_STRARRAY_FLAGS, \ { .scnprintf = SCA_STRARRAY_FLAGS, \
.strtoul = STUL_STRARRAY_FLAGS, \
.parm = &strarray__##array, } .parm = &strarray__##array, }
#include "trace/beauty/arch_errno_names.c" #include "trace/beauty/arch_errno_names.c"
@@ -799,7 +943,8 @@ static struct syscall_fmt syscall_fmts[] = {
{ .name = "fchownat", { .name = "fchownat",
.arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, }, .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
{ .name = "fcntl", { .name = "fcntl",
.arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */ .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */
.strtoul = STUL_STRARRAYS,
.parm = &strarrays__fcntl_cmds_arrays, .parm = &strarrays__fcntl_cmds_arrays,
.show_zero = true, }, .show_zero = true, },
[2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, }, [2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, },
@@ -870,7 +1015,9 @@ static struct syscall_fmt syscall_fmts[] = {
.alias = "old_mmap", .alias = "old_mmap",
#endif #endif
.arg = { [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, .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 */ }, }, }, [5] = { .scnprintf = SCA_HEX, /* offset */ }, }, },
{ .name = "mount", { .name = "mount",
.arg = { [0] = { .scnprintf = SCA_FILENAME, /* dev_name */ }, .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[] = { 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) 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; arg->scnprintf = SCA_PID;
else if (strcmp(field->type, "umode_t") == 0) else if (strcmp(field->type, "umode_t") == 0)
arg->scnprintf = SCA_MODE_T; 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->scnprintf = SCA_CHAR_ARRAY;
arg->nr_entries = field->arraylen; arg->nr_entries = field->arraylen;
} else if ((strcmp(field->type, "int") == 0 || } 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) 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 (fmt != NULL) {
if (evsel->priv != NULL) { syscall_arg_fmt__init_array(fmt, evsel->tp_format->format.fields);
syscall_arg_fmt__init_array(evsel->priv, evsel->tp_format->format.fields);
return 0; return 0;
} }
@@ -1958,11 +2105,18 @@ out_cant_read:
return NULL; return NULL;
} }
static void thread__update_stats(struct thread_trace *ttrace, struct syscall_stats {
int id, struct perf_sample *sample) 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 int_node *inode;
struct stats *stats; struct syscall_stats *stats;
u64 duration = 0; u64 duration = 0;
inode = intlist__findnew(ttrace->syscall_stats, id); inode = intlist__findnew(ttrace->syscall_stats, id);
@@ -1971,17 +2125,46 @@ static void thread__update_stats(struct thread_trace *ttrace,
stats = inode->priv; stats = inode->priv;
if (stats == NULL) { if (stats == NULL) {
stats = malloc(sizeof(struct stats)); stats = malloc(sizeof(*stats));
if (stats == NULL) if (stats == NULL)
return; return;
init_stats(stats);
stats->nr_failures = 0;
stats->max_errno = 0;
stats->errnos = NULL;
init_stats(&stats->stats);
inode->priv = stats; inode->priv = stats;
} }
if (ttrace->entry_time && sample->time > ttrace->entry_time) if (ttrace->entry_time && sample->time > ttrace->entry_time)
duration = 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) 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); 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); 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) { if (!trace->fd_path_disabled && sc->is_open && ret >= 0 && ttrace->filename.pending_open) {
trace__set_fd_pathname(thread, ret, ttrace->filename.name); trace__set_fd_pathname(thread, ret, ttrace->filename.name);
ttrace->filename.pending_open = false; 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]; char bf[2048];
size_t size = sizeof(bf); size_t size = sizeof(bf);
struct tep_format_field *field = evsel->tp_format->format.fields; 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; size_t printed = 0;
unsigned long val; unsigned long val;
u8 bit = 1; 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) if (syscall_arg.mask & bit)
continue; continue;
syscall_arg.len = 0;
syscall_arg.fmt = arg; syscall_arg.fmt = arg;
if (field->flags & TEP_FIELD_IS_ARRAY) if (field->flags & TEP_FIELD_IS_ARRAY) {
val = (uintptr_t)(sample->raw_data + field->offset); int offset = field->offset;
else
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); val = format_field__intval(field, sample, evsel->needs_swap);
/* /*
* Some syscall args need some mask, most don't and * 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 { } else {
trace__fprintf_tp_fields(trace, evsel, sample, thread, NULL, 0); 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); trace__fprintf_callchain(trace, sample);
else if (callchain_ret < 0) else if (callchain_ret < 0)
pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel)); 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: out:
thread__put(thread); thread__put(thread);
return 0; return 0;
@@ -2759,21 +2952,23 @@ static int trace__record(struct trace *trace, int argc, const char **argv)
"-m", "1024", "-m", "1024",
"-c", "1", "-c", "1",
}; };
pid_t pid = getpid();
char *filter = asprintf__tp_filter_pids(1, &pid);
const char * const sc_args[] = { "-e", }; const char * const sc_args[] = { "-e", };
unsigned int sc_args_nr = ARRAY_SIZE(sc_args); unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
const char * const majpf_args[] = { "-e", "major-faults" }; const char * const majpf_args[] = { "-e", "major-faults" };
unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args); unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
const char * const minpf_args[] = { "-e", "minor-faults" }; const char * const minpf_args[] = { "-e", "minor-faults" };
unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args); unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
int err = -1;
/* +1 is for the event string below */ /* +3 is for the event string below and the pid filter */
rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 + rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 3 +
majpf_args_nr + minpf_args_nr + argc; majpf_args_nr + minpf_args_nr + argc;
rec_argv = calloc(rec_argc + 1, sizeof(char *)); rec_argv = calloc(rec_argc + 1, sizeof(char *));
if (rec_argv == NULL) if (rec_argv == NULL || filter == NULL)
return -ENOMEM; goto out_free;
j = 0; j = 0;
for (i = 0; i < ARRAY_SIZE(record_args); i++) 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"; rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
else { else {
pr_err("Neither raw_syscalls nor syscalls events exist.\n"); pr_err("Neither raw_syscalls nor syscalls events exist.\n");
free(rec_argv); goto out_free;
return -1;
} }
} }
rec_argv[j++] = "--filter";
rec_argv[j++] = filter;
if (trace->trace_pgfaults & TRACE_PFMAJ) if (trace->trace_pgfaults & TRACE_PFMAJ)
for (i = 0; i < majpf_args_nr; i++) for (i = 0; i < majpf_args_nr; i++)
rec_argv[j++] = majpf_args[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++) for (i = 0; i < (unsigned int)argc; i++)
rec_argv[j++] = argv[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); 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) static struct syscall_arg_fmt *perf_evsel__syscall_arg_fmt(struct evsel *evsel, char *arg)
{ {
struct tep_format_field *field; 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) if (evsel->tp_format == NULL || fmt == NULL)
return NULL; return NULL;
@@ -3526,7 +3727,7 @@ static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel
} }
right_end = right + 1; right_end = right + 1;
while (isalnum(*right_end) || *right_end == '_') while (isalnum(*right_end) || *right_end == '_' || *right_end == '|')
++right_end; ++right_end;
if (isalpha(*right)) { 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); fmt = perf_evsel__syscall_arg_fmt(evsel, arg);
if (fmt == NULL) { if (fmt == NULL) {
pr_debug("\"%s\" not found in \"%s\", can't set filter \"%s\"\n", pr_err("\"%s\" not found in \"%s\", can't set filter \"%s\"\n",
arg, evsel->name, evsel->filter); arg, evsel->name, evsel->filter);
return -1; return -1;
} }
@@ -3552,7 +3753,11 @@ static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel
if (fmt->strtoul) { if (fmt->strtoul) {
u64 val; 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]; char *n, expansion[19];
int expansion_lenght = scnprintf(expansion, sizeof(expansion), "%#" PRIx64, val); int expansion_lenght = scnprintf(expansion, sizeof(expansion), "%#" PRIx64, val);
int expansion_offset = right - new_filter; 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, DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
struct stats *stats; struct syscall_stats *stats;
double msecs; double msecs;
int syscall; int syscall;
) )
{ {
struct int_node *source = rb_entry(nd, struct int_node, rb_node); 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->syscall = source->i;
entry->stats = stats; 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, 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, "\n");
printed += fprintf(fp, " syscall calls total min avg max stddev\n"); printed += fprintf(fp, " syscall calls errors total min avg max stddev\n");
printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n"); printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n"); printed += fprintf(fp, " --------------- -------- ------ -------- --------- --------- --------- ------\n");
resort_rb__for_each_entry(nd, syscall_stats) { 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) { if (stats) {
double min = (double)(stats->min) / NSEC_PER_MSEC; double min = (double)(stats->stats.min) / NSEC_PER_MSEC;
double max = (double)(stats->max) / NSEC_PER_MSEC; double max = (double)(stats->stats.max) / NSEC_PER_MSEC;
double avg = avg_stats(stats); double avg = avg_stats(&stats->stats);
double pct; 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; avg /= NSEC_PER_MSEC;
sc = &trace->syscalls.table[syscall_stats_entry->syscall]; sc = &trace->syscalls.table[syscall_stats_entry->syscall];
printed += fprintf(fp, " %-15s", sc->name); printed += fprintf(fp, " %-15s", sc->name);
printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f", printed += fprintf(fp, " %8" PRIu64 " %6" PRIu64 " %9.3f %9.3f %9.3f",
n, syscall_stats_entry->msecs, min, avg); n, stats->nr_failures, syscall_stats_entry->msecs, min, avg);
printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct); 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) static int evlist__set_syscall_tp_fields(struct evlist *evlist)
{ {
struct evsel *evsel; struct evsel *evsel;
@@ -4236,15 +4470,19 @@ static int evlist__set_syscall_tp_fields(struct evlist *evlist)
return -1; return -1;
if (!strncmp(evsel->tp_format->name, "sys_enter_", 10)) { 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))) if (__tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64)))
return -1; 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)) { } 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)) if (__tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap))
return -1; 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"), "Show only syscall summary with statistics"),
OPT_BOOLEAN('S', "with-summary", &trace.summary, OPT_BOOLEAN('S', "with-summary", &trace.summary,
"Show all syscalls and summary with statistics"), "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", OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
"Trace pagefaults", parse_pagefaults, "maj"), "Trace pagefaults", parse_pagefaults, "maj"),
OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"), 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: init_augmented_syscall_tp:
if (perf_evsel__init_augmented_syscall_tp(evsel, evsel)) if (perf_evsel__init_augmented_syscall_tp(evsel, evsel))
goto out; goto out;
sc = evsel->priv; sc = __evsel__syscall_tp(evsel);
/* /*
* For now with BPF raw_augmented we hook into * For now with BPF raw_augmented we hook into
* raw_syscalls:sys_enter and there we get all * 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)) if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
return trace__record(&trace, argc-1, &argv[1]); 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 */ /* summary_only implies summary option, but don't overwrite summary if set */
if (trace.summary_only) if (trace.summary_only)
trace.summary = trace.summary_only; trace.summary = trace.summary_only;

View File

@@ -28,6 +28,7 @@ arch/x86/include/asm/disabled-features.h
arch/x86/include/asm/required-features.h arch/x86/include/asm/required-features.h
arch/x86/include/asm/cpufeatures.h arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/inat_types.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/asm/msr-index.h
arch/x86/include/uapi/asm/prctl.h arch/x86/include/uapi/asm/prctl.h
arch/x86/lib/x86-opcode-map.txt arch/x86/lib/x86-opcode-map.txt

View File

@@ -107,6 +107,7 @@ else
endif endif
LIBAPI = $(API_PATH)libapi.a LIBAPI = $(API_PATH)libapi.a
export LIBAPI
$(LIBAPI): FORCE $(LIBAPI): FORCE
$(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) $(OUTPUT)libapi.a $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) $(OUTPUT)libapi.a

View File

@@ -338,15 +338,13 @@ static struct perf_mmap* perf_evlist__alloc_mmap(struct perf_evlist *evlist, boo
int i; int i;
struct perf_mmap *map; 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)); map = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
if (!map) if (!map)
return NULL; return NULL;
for (i = 0; i < evlist->nr_mmaps; i++) { 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 * When the perf_mmap() call is made we grab one refcount, plus
* one extra to let perf_mmap__consume() get the last * 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 * Each PERF_EVENT_IOC_SET_OUTPUT points to this mmap and
* thus does perf_mmap__get() on it. * thus does perf_mmap__get() on it.
*/ */
perf_mmap__init(&map[i], overwrite, NULL); perf_mmap__init(&map[i], prev, overwrite, NULL);
} }
return map; return map;
@@ -382,18 +380,22 @@ static void perf_evlist__set_sid_idx(struct perf_evlist *evlist,
static struct perf_mmap* static struct perf_mmap*
perf_evlist__mmap_cb_get(struct perf_evlist *evlist, bool overwrite, int idx) 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) { maps = overwrite ? evlist->mmap_ovw : evlist->mmap;
if (!evlist->mmap_ovw) {
evlist->mmap_ovw = perf_evlist__alloc_mmap(evlist, true); if (!maps) {
if (!evlist->mmap_ovw) maps = perf_evlist__alloc_mmap(evlist, overwrite);
return NULL; if (!maps)
} return NULL;
map = &evlist->mmap_ovw[idx];
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)) #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); 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 static int
mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops, mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
int idx, struct perf_mmap_param *mp, int cpu_idx, 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) if (ops->mmap(map, mp, *output, evlist_cpu) < 0)
return -1; return -1;
if (!idx)
perf_evlist__set_mmap_first(evlist, map, overwrite);
} else { } else {
if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0) if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
return -1; return -1;
@@ -542,6 +556,17 @@ out_unmap:
return -1; 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, int perf_evlist__mmap_ops(struct perf_evlist *evlist,
struct perf_evlist_mmap_ops *ops, struct perf_evlist_mmap_ops *ops,
struct perf_mmap_param *mp) struct perf_mmap_param *mp)
@@ -553,10 +578,9 @@ int perf_evlist__mmap_ops(struct perf_evlist *evlist,
if (!ops || !ops->get || !ops->mmap) if (!ops || !ops->get || !ops->mmap)
return -EINVAL; return -EINVAL;
if (!evlist->mmap) mp->mask = evlist->mmap_len - page_size - 1;
evlist->mmap = perf_evlist__alloc_mmap(evlist, false);
if (!evlist->mmap) evlist->nr_mmaps = perf_evlist__nr_mmaps(evlist);
return -ENOMEM;
perf_evlist__for_each_entry(evlist, evsel) { perf_evlist__for_each_entry(evlist, evsel) {
if ((evsel->attr.read_format & PERF_FORMAT_ID) && 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; evlist->mmap_len = (pages + 1) * page_size;
mp.mask = evlist->mmap_len - page_size - 1;
return perf_evlist__mmap_ops(evlist, &ops, &mp); 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);
zfree(&evlist->mmap_ovw); 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;
}

View File

@@ -25,6 +25,8 @@ struct perf_evlist {
struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
struct perf_mmap *mmap; struct perf_mmap *mmap;
struct perf_mmap *mmap_ovw; struct perf_mmap *mmap_ovw;
struct perf_mmap *mmap_first;
struct perf_mmap *mmap_ovw_first;
}; };
typedef void typedef void
@@ -48,6 +50,7 @@ int perf_evlist__mmap_ops(struct perf_evlist *evlist,
struct perf_evlist_mmap_ops *ops, struct perf_evlist_mmap_ops *ops,
struct perf_mmap_param *mp); struct perf_mmap_param *mp);
void perf_evlist__init(struct perf_evlist *evlist);
void perf_evlist__exit(struct perf_evlist *evlist); void perf_evlist__exit(struct perf_evlist *evlist);
/** /**

View File

@@ -50,6 +50,7 @@ struct perf_evsel {
bool system_wide; 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); 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__close_fd(struct perf_evsel *evsel);
void perf_evsel__free_fd(struct perf_evsel *evsel); void perf_evsel__free_fd(struct perf_evsel *evsel);

View File

@@ -32,6 +32,7 @@ struct perf_mmap {
u64 flush; u64 flush;
libperf_unmap_cb_t unmap_cb; libperf_unmap_cb_t unmap_cb;
char event_copy[PERF_SAMPLE_MAX_SIZE] __aligned(8); char event_copy[PERF_SAMPLE_MAX_SIZE] __aligned(8);
struct perf_mmap *next;
}; };
struct perf_mmap_param { struct perf_mmap_param {
@@ -41,8 +42,8 @@ struct perf_mmap_param {
size_t perf_mmap__mmap_len(struct perf_mmap *map); size_t perf_mmap__mmap_len(struct perf_mmap *map);
void perf_mmap__init(struct perf_mmap *map, bool overwrite, void perf_mmap__init(struct perf_mmap *map, struct perf_mmap *prev,
libperf_unmap_cb_t unmap_cb); bool overwrite, libperf_unmap_cb_t unmap_cb);
int perf_mmap__mmap(struct perf_mmap *map, struct perf_mmap_param *mp, int perf_mmap__mmap(struct perf_mmap *map, struct perf_mmap_param *mp,
int fd, int cpu); int fd, int cpu);
void perf_mmap__munmap(struct perf_mmap *map); void perf_mmap__munmap(struct perf_mmap *map);

View File

@@ -4,14 +4,28 @@
#include <stdio.h> #include <stdio.h>
#define __T_START fprintf(stdout, "- running %s...", __FILE__) int tests_failed;
#define __T_OK fprintf(stdout, "OK\n")
#define __T_FAIL fprintf(stdout, "FAIL\n") #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) \ #define __T(text, cond) \
do { \ do { \
if (!(cond)) { \ if (!(cond)) { \
fprintf(stderr, "FAILED %s:%d %s\n", __FILE__, __LINE__, text); \ fprintf(stderr, "FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
tests_failed++; \
return -1; \ return -1; \
} \ } \
} while (0) } while (0)

View File

@@ -9,6 +9,7 @@
#endif #endif
enum libperf_print_level { enum libperf_print_level {
LIBPERF_ERR,
LIBPERF_WARN, LIBPERF_WARN,
LIBPERF_INFO, LIBPERF_INFO,
LIBPERF_DEBUG, LIBPERF_DEBUG,

View File

@@ -3,13 +3,13 @@
#define __LIBPERF_EVLIST_H #define __LIBPERF_EVLIST_H
#include <perf/core.h> #include <perf/core.h>
#include <stdbool.h>
struct perf_evlist; struct perf_evlist;
struct perf_evsel; struct perf_evsel;
struct perf_cpu_map; struct perf_cpu_map;
struct perf_thread_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, LIBPERF_API void perf_evlist__add(struct perf_evlist *evlist,
struct perf_evsel *evsel); struct perf_evsel *evsel);
LIBPERF_API void perf_evlist__remove(struct perf_evlist *evlist, 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 int perf_evlist__mmap(struct perf_evlist *evlist, int pages);
LIBPERF_API void perf_evlist__munmap(struct perf_evlist *evlist); 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 */ #endif /* __LIBPERF_EVLIST_H */

View 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 struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr);
LIBPERF_API void perf_evsel__delete(struct perf_evsel *evsel); 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, LIBPERF_API int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus,

View File

@@ -2,6 +2,8 @@
#ifndef __LIBPERF_INTERNAL_H #ifndef __LIBPERF_INTERNAL_H
#define __LIBPERF_INTERNAL_H #define __LIBPERF_INTERNAL_H
#include <perf/core.h>
void libperf_print(enum libperf_print_level level, void libperf_print(enum libperf_print_level level,
const char *format, ...) const char *format, ...)
__attribute__((format(printf, 2, 3))); __attribute__((format(printf, 2, 3)));
@@ -11,6 +13,7 @@ do { \
libperf_print(level, "libperf: " fmt, ##__VA_ARGS__); \ libperf_print(level, "libperf: " fmt, ##__VA_ARGS__); \
} while (0) } while (0)
#define pr_err(fmt, ...) __pr(LIBPERF_ERR, fmt, ##__VA_ARGS__)
#define pr_warning(fmt, ...) __pr(LIBPERF_WARN, 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_info(fmt, ...) __pr(LIBPERF_INFO, fmt, ##__VA_ARGS__)
#define pr_debug(fmt, ...) __pr(LIBPERF_DEBUG, fmt, ##__VA_ARGS__) #define pr_debug(fmt, ...) __pr(LIBPERF_DEBUG, fmt, ##__VA_ARGS__)

View File

@@ -21,7 +21,6 @@ LIBPERF_0.0.1 {
perf_evsel__delete; perf_evsel__delete;
perf_evsel__enable; perf_evsel__enable;
perf_evsel__disable; perf_evsel__disable;
perf_evsel__init;
perf_evsel__open; perf_evsel__open;
perf_evsel__close; perf_evsel__close;
perf_evsel__read; perf_evsel__read;
@@ -34,7 +33,6 @@ LIBPERF_0.0.1 {
perf_evlist__close; perf_evlist__close;
perf_evlist__enable; perf_evlist__enable;
perf_evlist__disable; perf_evlist__disable;
perf_evlist__init;
perf_evlist__add; perf_evlist__add;
perf_evlist__remove; perf_evlist__remove;
perf_evlist__next; perf_evlist__next;
@@ -43,6 +41,7 @@ LIBPERF_0.0.1 {
perf_evlist__mmap; perf_evlist__mmap;
perf_evlist__munmap; perf_evlist__munmap;
perf_evlist__filter_pollfd; perf_evlist__filter_pollfd;
perf_evlist__next_mmap;
perf_mmap__consume; perf_mmap__consume;
perf_mmap__read_init; perf_mmap__read_init;
perf_mmap__read_done; perf_mmap__read_done;

View File

@@ -13,13 +13,15 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include "internal.h" #include "internal.h"
void perf_mmap__init(struct perf_mmap *map, bool overwrite, void perf_mmap__init(struct perf_mmap *map, struct perf_mmap *prev,
libperf_unmap_cb_t unmap_cb) bool overwrite, libperf_unmap_cb_t unmap_cb)
{ {
map->fd = -1; map->fd = -1;
map->overwrite = overwrite; map->overwrite = overwrite;
map->unmap_cb = unmap_cb; map->unmap_cb = unmap_cb;
refcount_set(&map->refcnt, 0); refcount_set(&map->refcnt, 0);
if (prev)
prev->next = map;
} }
size_t perf_mmap__mmap_len(struct perf_mmap *map) size_t perf_mmap__mmap_len(struct perf_mmap *map)

View File

@@ -16,13 +16,13 @@ all:
include $(srctree)/tools/scripts/Makefile.include 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 $(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 $(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) all: $(TESTS_A) $(TESTS_SO)

View File

@@ -26,6 +26,6 @@ int main(int argc, char **argv)
perf_cpu_map__put(cpus); perf_cpu_map__put(cpus);
perf_cpu_map__put(cpus); perf_cpu_map__put(cpus);
__T_OK; __T_END;
return 0; return 0;
} }

View File

@@ -1,12 +1,23 @@
// SPDX-License-Identifier: GPL-2.0 // 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 <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <unistd.h>
#include <stdlib.h>
#include <linux/perf_event.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/cpumap.h>
#include <perf/threadmap.h> #include <perf/threadmap.h>
#include <perf/evlist.h> #include <perf/evlist.h>
#include <perf/evsel.h> #include <perf/evsel.h>
#include <perf/mmap.h>
#include <perf/event.h>
#include <internal/tests.h> #include <internal/tests.h>
#include <api/fs/fs.h>
static int libperf_print(enum libperf_print_level level, static int libperf_print(enum libperf_print_level level,
const char *fmt, va_list ap) const char *fmt, va_list ap)
@@ -181,6 +192,210 @@ static int test_stat_thread_enable(void)
return 0; 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) int main(int argc, char **argv)
{ {
__T_START; __T_START;
@@ -190,7 +405,9 @@ int main(int argc, char **argv)
test_stat_cpu(); test_stat_cpu();
test_stat_thread(); test_stat_thread();
test_stat_thread_enable(); test_stat_thread_enable();
test_mmap_thread();
test_mmap_cpus();
__T_OK; __T_END;
return 0; return 0;
} }

View File

@@ -130,6 +130,6 @@ int main(int argc, char **argv)
test_stat_thread(); test_stat_thread();
test_stat_thread_enable(); test_stat_thread_enable();
__T_OK; __T_END;
return 0; return 0;
} }

View File

@@ -26,6 +26,6 @@ int main(int argc, char **argv)
perf_thread_map__put(threads); perf_thread_map__put(threads);
perf_thread_map__put(threads); perf_thread_map__put(threads);
__T_OK; __T_END;
return 0; return 0;
} }

View 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", "EventCode": "0x02",
"EventName": "uncore_hisi_ddrc.flux_wcmd", "EventName": "uncore_hisi_ddrc.flux_wcmd",
@@ -15,7 +29,7 @@
}, },
{ {
"EventCode": "0x04", "EventCode": "0x04",
"EventName": "uncore_hisi_ddrc.flux_wr", "EventName": "uncore_hisi_ddrc.pre_cmd",
"BriefDescription": "DDRC precharge commands", "BriefDescription": "DDRC precharge commands",
"PublicDescription": "DDRC precharge commands", "PublicDescription": "DDRC precharge commands",
"Unit": "hisi_sccl,ddrc", "Unit": "hisi_sccl,ddrc",

View File

@@ -20,6 +20,13 @@
"PublicDescription": "The number of all operations received by the HHA from another SCCL in this socket", "PublicDescription": "The number of all operations received by the HHA from another SCCL in this socket",
"Unit": "hisi_sccl,hha", "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", "EventCode": "0x1c",
"EventName": "uncore_hisi_hha.rd_ddr_64b", "EventName": "uncore_hisi_hha.rd_ddr_64b",
@@ -29,7 +36,7 @@
}, },
{ {
"EventCode": "0x1d", "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", "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", "PublicDescription": "The number of write operations sent by HHA to DDRC which size is 64 bytes",
"Unit": "hisi_sccl,hha", "Unit": "hisi_sccl,hha",
@@ -48,4 +55,18 @@
"PublicDescription": "The number of write operations sent by HHA to DDRC which size is 128 bytes", "PublicDescription": "The number of write operations sent by HHA to DDRC which size is 128 bytes",
"Unit": "hisi_sccl,hha", "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",
},
] ]

View File

@@ -34,4 +34,60 @@
"PublicDescription": "l3c precharge commands", "PublicDescription": "l3c precharge commands",
"Unit": "hisi_sccl,l3c", "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",
},
] ]

View File

@@ -322,7 +322,8 @@ static int print_events_table_entry(void *data, char *name, char *event,
char *desc, char *long_desc, char *desc, char *long_desc,
char *pmu, char *unit, char *perpkg, char *pmu, char *unit, char *perpkg,
char *metric_expr, char *metric_expr,
char *metric_name, char *metric_group) char *metric_name, char *metric_group,
char *deprecated)
{ {
struct perf_entry_data *pd = data; struct perf_entry_data *pd = data;
FILE *outfp = pd->outfp; 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); fprintf(outfp, "\t.metric_name = \"%s\",\n", metric_name);
if (metric_group) if (metric_group)
fprintf(outfp, "\t.metric_group = \"%s\",\n", metric_group); fprintf(outfp, "\t.metric_group = \"%s\",\n", metric_group);
if (deprecated)
fprintf(outfp, "\t.deprecated = \"%s\",\n", deprecated);
fprintf(outfp, "},\n"); fprintf(outfp, "},\n");
return 0; return 0;
@@ -371,6 +374,7 @@ struct event_struct {
char *metric_expr; char *metric_expr;
char *metric_name; char *metric_name;
char *metric_group; char *metric_group;
char *deprecated;
}; };
#define ADD_EVENT_FIELD(field) do { if (field) { \ #define ADD_EVENT_FIELD(field) do { if (field) { \
@@ -398,6 +402,7 @@ struct event_struct {
op(metric_expr); \ op(metric_expr); \
op(metric_name); \ op(metric_name); \
op(metric_group); \ op(metric_group); \
op(deprecated); \
} while (0) } while (0)
static LIST_HEAD(arch_std_events); 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, static int save_arch_std_events(void *data, char *name, char *event,
char *desc, char *long_desc, char *pmu, char *desc, char *long_desc, char *pmu,
char *unit, char *perpkg, char *metric_expr, 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; struct event_struct *es;
@@ -479,7 +485,8 @@ static int
try_fixup(const char *fn, char *arch_std, char **event, char **desc, try_fixup(const char *fn, char *arch_std, char **event, char **desc,
char **name, char **long_desc, char **pmu, char **filter, char **name, char **long_desc, char **pmu, char **filter,
char **perpkg, char **unit, char **metric_expr, char **metric_name, 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 */ /* try to find matching event from arch standard values */
struct event_struct *es; struct event_struct *es;
@@ -507,7 +514,8 @@ int json_events(const char *fn,
char *long_desc, char *long_desc,
char *pmu, char *unit, char *perpkg, char *pmu, char *unit, char *perpkg,
char *metric_expr, char *metric_expr,
char *metric_name, char *metric_group), char *metric_name, char *metric_group,
char *deprecated),
void *data) void *data)
{ {
int err; int err;
@@ -536,6 +544,7 @@ int json_events(const char *fn,
char *metric_expr = NULL; char *metric_expr = NULL;
char *metric_name = NULL; char *metric_name = NULL;
char *metric_group = NULL; char *metric_group = NULL;
char *deprecated = NULL;
char *arch_std = NULL; char *arch_std = NULL;
unsigned long long eventcode = 0; unsigned long long eventcode = 0;
struct msrmap *msr = NULL; struct msrmap *msr = NULL;
@@ -614,6 +623,8 @@ int json_events(const char *fn,
addfield(map, &unit, "", "", val); addfield(map, &unit, "", "", val);
} else if (json_streq(map, field, "PerPkg")) { } else if (json_streq(map, field, "PerPkg")) {
addfield(map, &perpkg, "", "", val); addfield(map, &perpkg, "", "", val);
} else if (json_streq(map, field, "Deprecated")) {
addfield(map, &deprecated, "", "", val);
} else if (json_streq(map, field, "MetricName")) { } else if (json_streq(map, field, "MetricName")) {
addfield(map, &metric_name, "", "", val); addfield(map, &metric_name, "", "", val);
} else if (json_streq(map, field, "MetricGroup")) { } 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, err = try_fixup(fn, arch_std, &event, &desc, &name,
&long_desc, &pmu, &filter, &perpkg, &long_desc, &pmu, &filter, &perpkg,
&unit, &metric_expr, &metric_name, &unit, &metric_expr, &metric_name,
&metric_group, eventcode); &metric_group, eventcode,
&deprecated);
if (err) if (err)
goto free_strings; goto free_strings;
} }
err = func(data, name, real_event(name, event), desc, long_desc, 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_strings:
free(event); free(event);
free(desc); free(desc);
@@ -673,6 +686,7 @@ free_strings:
free(pmu); free(pmu);
free(filter); free(filter);
free(perpkg); free(perpkg);
free(deprecated);
free(unit); free(unit);
free(metric_expr); free(metric_expr);
free(metric_name); free(metric_name);

View File

@@ -7,7 +7,8 @@ int json_events(const char *fn,
char *long_desc, char *long_desc,
char *pmu, char *pmu,
char *unit, char *perpkg, char *metric_expr, char *unit, char *perpkg, char *metric_expr,
char *metric_name, char *metric_group), char *metric_name, char *metric_group,
char *deprecated),
void *data); void *data);
char *get_cpu_str(void); char *get_cpu_str(void);

View File

@@ -17,6 +17,7 @@ struct pmu_event {
const char *metric_expr; const char *metric_expr;
const char *metric_name; const char *metric_name;
const char *metric_group; const char *metric_group;
const char *deprecated;
}; };
/* /*

View File

@@ -10,11 +10,7 @@
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <time.h>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h>
#include <sys/mman.h>
#include <linux/compiler.h>
#include <linux/hw_breakpoint.h> #include <linux/hw_breakpoint.h>
#include "tests.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); 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
}

View File

@@ -49,14 +49,6 @@ asm (
"__test_function:\n" "__test_function:\n"
"incq (%rdi)\n" "incq (%rdi)\n"
"ret\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 #else
static void __test_function(volatile long *ptr) 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 * stepping into the SIGIO handler and getting stuck on the
* breakpointed instruction. * 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 * Just disable the test for these architectures until these
* issues are resolved. * issues are resolved.
*/ */
#if defined(__powerpc__) || defined(__s390x__) || defined(__arm__) #if defined(__powerpc__) || defined(__s390x__) || defined(__arm__) || \
defined(__aarch64__)
return false; return false;
#else #else
return true; return true;

View File

@@ -121,7 +121,7 @@ static struct test generic_tests[] = {
{ {
.desc = "Breakpoint accounting", .desc = "Breakpoint accounting",
.func = test__bp_accounting, .func = test__bp_accounting,
.is_supported = test__bp_signal_is_supported, .is_supported = test__bp_account_is_supported,
}, },
{ {
.desc = "Watchpoint", .desc = "Watchpoint",

View 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_cpu_map *cpus;
struct perf_thread_map *threads; struct perf_thread_map *threads;
struct mmap *md; struct mmap *md;
int retry_count = 0;
signal(SIGCHLD, sig_handler); 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) { if (evlist__mmap(evlist, 128) < 0) {
pr_debug("failed to mmap events: %d (%s)\n", errno, pr_debug("failed to mmap events: %d (%s)\n", errno,
str_error_r(errno, sbuf, sizeof(sbuf))); str_error_r(errno, sbuf, sizeof(sbuf)));
err = -1;
goto out_delete_evlist; goto out_delete_evlist;
} }
@@ -132,6 +134,13 @@ retry:
out_init: out_init:
if (!exited || !nr_exit) { if (!exited || !nr_exit) {
evlist__poll(evlist, -1); evlist__poll(evlist, -1);
if (retry_count++ > 1000) {
pr_debug("Failed after retrying 1000 times\n");
err = -1;
goto out_free_maps;
}
goto retry; goto retry;
} }

View 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); int test__time_utils(struct test *t, int subtest);
bool test__bp_signal_is_supported(void); bool test__bp_signal_is_supported(void);
bool test__bp_account_is_supported(void);
bool test__wp_is_supported(void); bool test__wp_is_supported(void);
#if defined(__arm__) || defined(__aarch64__) #if defined(__arm__) || defined(__aarch64__)

View 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(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); 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(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 trace;
struct thread; struct thread;
@@ -87,6 +89,7 @@ struct syscall_arg_fmt;
/** /**
* @val: value of syscall argument being formatted * @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 * @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: 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 * @augmented_args_size: augmented_args total payload size
@@ -109,6 +112,7 @@ struct syscall_arg {
struct thread *thread; struct thread *thread;
struct trace *trace; struct trace *trace;
void *parm; void *parm;
u16 len;
u8 idx; u8 idx;
u8 mask; u8 mask;
bool show_string_prefix; 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); 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 #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); 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 #define SCA_X86_MSR syscall_arg__scnprintf_x86_MSR

View 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 #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" #include "trace/beauty/generated/mmap_flags_array.c"
static DEFINE_STRARRAY(mmap_flags, "MAP_"); 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); return strarray__scnprintf_flags(&strarray__mmap_flags, bf, size, show_prefix, flags);
} }

View File

@@ -1 +1,2 @@
perf-y += x86_irq_vectors.o
perf-y += x86_msr.o perf-y += x86_msr.o

View File

@@ -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);
}

View File

@@ -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"

View File

@@ -43,6 +43,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <bpf/libbpf.h> #include <bpf/libbpf.h>
#include <subcmd/parse-options.h> #include <subcmd/parse-options.h>
#include <subcmd/run-command.h>
/* FIXME: For the HE_COLORSET */ /* FIXME: For the HE_COLORSET */
#include "ui/browser.h" #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. * 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. * 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, struct annotate_args *args,
int *line_nr) char *parsed_line, int *line_nr)
{ {
struct map *map = args->ms.map; struct map *map = args->ms.map;
struct annotation *notes = symbol__annotation(sym); struct annotation *notes = symbol__annotation(sym);
struct disasm_line *dl; struct disasm_line *dl;
char *line = NULL, *parsed_line, *tmp, *tmp2; char *tmp;
size_t line_len;
s64 line_ip, offset = -1; s64 line_ip, offset = -1;
regmatch_t match[2]; 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. */ /* /filename:linenr ? Save line number and ignore. */
if (regexec(&file_lineno, parsed_line, 2, match, 0) == 0) { if (regexec(&file_lineno, parsed_line, 2, match, 0) == 0) {
*line_nr = atoi(parsed_line + match[1].rm_so); *line_nr = atoi(parsed_line + match[1].rm_so);
return 0; return 0;
} }
tmp = skip_spaces(parsed_line); /* Process hex address followed by ':'. */
if (*tmp) { line_ip = strtoull(parsed_line, &tmp, 16);
/* if (parsed_line != tmp && tmp[0] == ':' && tmp[1] != '\0') {
* 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) {
u64 start = map__rip_2objdump(map, sym->start), u64 start = map__rip_2objdump(map, sym->start),
end = map__rip_2objdump(map, sym->end); 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) if ((u64)line_ip < start || (u64)line_ip >= end)
offset = -1; offset = -1;
else else
parsed_line = tmp2 + 1; parsed_line = tmp + 1;
} }
args->offset = offset; args->offset = offset;
@@ -1543,7 +1526,6 @@ static int symbol__parse_objdump_line(struct symbol *sym, FILE *file,
args->ms.sym = sym; args->ms.sym = sym;
dl = disasm_line__new(args); dl = disasm_line__new(args);
free(line);
(*line_nr)++; (*line_nr)++;
if (dl == NULL) 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) #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) static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
{ {
struct annotation_options *opts = args->options; 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; struct kcore_extract kce;
bool delete_extract = false; bool delete_extract = false;
bool decomp = false; bool decomp = false;
int stdout_fd[2];
int lineno = 0; int lineno = 0;
int nline; 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)); int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename));
if (err) 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, if (dso__decompress_kmodule_path(dso, symfs_filename,
tmp, sizeof(tmp)) < 0) tmp, sizeof(tmp)) < 0)
goto out; return -1;
decomp = true; decomp = true;
strcpy(symfs_filename, tmp); strcpy(symfs_filename, tmp);
@@ -1914,13 +1966,13 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
err = asprintf(&command, err = asprintf(&command,
"%s %s%s --start-address=0x%016" PRIx64 "%s %s%s --start-address=0x%016" PRIx64
" --stop-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->objdump_path ?: "objdump",
opts->disassembler_style ? "-M " : "", opts->disassembler_style ? "-M " : "",
opts->disassembler_style ?: "", opts->disassembler_style ?: "",
map__rip_2objdump(map, sym->start), map__rip_2objdump(map, sym->start),
map__rip_2objdump(map, sym->end), 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" : ""); opts->annotate_src ? "-S" : "");
if (err < 0) { if (err < 0) {
@@ -1930,55 +1982,73 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
pr_debug("Executing: %s\n", command); pr_debug("Executing: %s\n", command);
err = -1; objdump_argv[2] = command;
if (pipe(stdout_fd) < 0) { objdump_argv[4] = symfs_filename;
pr_err("Failure creating the pipe to run %s\n", command);
/* 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; goto out_free_command;
} }
pid = fork(); file = fdopen(objdump_process.out, "r");
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);
}
close(stdout_fd[1]);
file = fdopen(stdout_fd[0], "r");
if (!file) { if (!file) {
pr_err("Failure creating FILE stream for %s\n", command); pr_err("Failure creating FILE stream for %s\n", command);
/* /*
* If we were using debug info should retry with * If we were using debug info should retry with
* original binary. * original binary.
*/ */
goto out_free_command; err = -1;
goto out_close_stdout;
} }
/* Storage for getline. */
line = NULL;
line_len = 0;
nline = 0; nline = 0;
while (!feof(file)) { 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 * The source code line number (lineno) needs to be kept in
* across calls to symbol__parse_objdump_line(), so that it * across calls to symbol__parse_objdump_line(), so that it
* can associate it with the instructions till the next one. * can associate it with the instructions till the next one.
* See disasm_line__new() and struct disasm_line::line_nr. * 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; break;
nline++; nline++;
} }
free(line);
if (nline == 0) err = finish_command(&objdump_process);
if (err)
pr_err("Error running %s\n", command);
if (nline == 0) {
err = -1;
pr_err("No output from %s\n", command); pr_err("No output from %s\n", command);
}
/* /*
* kallsyms does not have symbol sizes so there may a nop at the end. * 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); delete_last_nop(sym);
fclose(file); fclose(file);
err = 0;
out_close_stdout:
close(objdump_process.out);
out_free_command: out_free_command:
free(command); free(command);
out_remove_tmp:
close(stdout_fd[0]);
out_remove_tmp:
if (decomp) if (decomp)
unlink(symfs_filename); unlink(symfs_filename);
if (delete_extract) if (delete_extract)
kcore_extract__delete(&kce); kcore_extract__delete(&kce);
out:
return err;
out_close_stdout: return err;
close(stdout_fd[1]);
goto out_free_command;
} }
static void calc_percent(struct sym_hist *sym_hist, static void calc_percent(struct sym_hist *sym_hist,

View File

@@ -21,6 +21,7 @@
#include "../perf.h" #include "../perf.h"
#include "asm/bug.h" #include "asm/bug.h"
#include "bpf-event.h" #include "bpf-event.h"
#include "util/string2.h"
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
#include <sched.h> #include <sched.h>
@@ -598,14 +599,13 @@ static struct mmap *evlist__alloc_mmap(struct evlist *evlist,
int i; int i;
struct mmap *map; 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)); map = zalloc(evlist->core.nr_mmaps * sizeof(struct mmap));
if (!map) if (!map)
return NULL; return NULL;
for (i = 0; i < evlist->core.nr_mmaps; i++) { 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 * When the perf_mmap() call is made we grab one refcount, plus
* one extra to let perf_mmap__consume() get the last * 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 * Each PERF_EVENT_IOC_SET_OUTPUT points to this mmap and
* thus does perf_mmap__get() on it. * 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; return map;
@@ -636,19 +636,21 @@ static struct perf_mmap*
perf_evlist__mmap_cb_get(struct perf_evlist *_evlist, bool overwrite, int idx) perf_evlist__mmap_cb_get(struct perf_evlist *_evlist, bool overwrite, int idx)
{ {
struct evlist *evlist = container_of(_evlist, struct evlist, core); struct evlist *evlist = container_of(_evlist, struct evlist, core);
struct mmap *maps = evlist->mmap; struct mmap *maps;
if (overwrite) { maps = overwrite ? evlist->overwrite_mmap : evlist->mmap;
maps = evlist->overwrite_mmap;
if (!maps) { if (!maps) {
maps = evlist__alloc_mmap(evlist, true); maps = evlist__alloc_mmap(evlist, overwrite);
if (!maps) if (!maps)
return NULL; return NULL;
if (overwrite) {
evlist->overwrite_mmap = maps; evlist->overwrite_mmap = maps;
if (evlist->bkw_mmap_state == BKW_MMAP_NOTREADY) if (evlist->bkw_mmap_state == BKW_MMAP_NOTREADY)
perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_RUNNING); 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, .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); evlist->core.mmap_len = evlist__mmap_size(pages);
pr_debug("mmap size %zuB\n", evlist->core.mmap_len); 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_mmap_params__init(&mp.auxtrace_mp, evlist->core.mmap_len,
auxtrace_pages, auxtrace_overwrite); auxtrace_pages, auxtrace_overwrite);
@@ -959,7 +955,7 @@ int perf_evlist__append_tp_filter(struct evlist *evlist, const char *filter)
return err; 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; char *filter;
size_t i; size_t i;

View File

@@ -2600,7 +2600,7 @@ out_enomem:
* Print the help text for the event symbols: * Print the help text for the event symbols:
*/ */
void print_events(const char *event_glob, bool name_only, bool quiet_flag, 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, print_symbol_events(event_glob, PERF_TYPE_HARDWARE,
event_symbols_hw, PERF_COUNT_HW_MAX, name_only); 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_hwcache_events(event_glob, name_only);
print_pmu_events(event_glob, name_only, quiet_flag, long_desc, print_pmu_events(event_glob, name_only, quiet_flag, long_desc,
details_flag); details_flag, deprecated);
if (event_glob != NULL) if (event_glob != NULL)
return; return;

View File

@@ -195,7 +195,7 @@ void parse_events_evlist_error(struct parse_events_state *parse_state,
int idx, const char *str); int idx, const char *str);
void print_events(const char *event_glob, bool name_only, bool quiet, 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 { struct event_symbol {
const char *symbol; const char *symbol;

View 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 *long_desc, char *topic,
char *unit, char *perpkg, char *unit, char *perpkg,
char *metric_expr, char *metric_expr,
char *metric_name) char *metric_name,
char *deprecated)
{ {
struct parse_events_term *term; struct parse_events_term *term;
struct perf_pmu_alias *alias; 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->unit[0] = '\0';
alias->per_pkg = false; alias->per_pkg = false;
alias->snapshot = false; alias->snapshot = false;
alias->deprecated = false;
ret = parse_events_terms(&alias->terms, val); ret = parse_events_terms(&alias->terms, val);
if (ret) { 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->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1;
alias->str = strdup(newval); alias->str = strdup(newval);
if (deprecated)
alias->deprecated = true;
if (!perf_pmu_merge_alias(alias, list)) if (!perf_pmu_merge_alias(alias, list))
list_add_tail(&alias->list, 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); strim(buf);
return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL, 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) static inline bool pmu_alias_info_file(char *name)
@@ -787,7 +792,8 @@ new_alias:
(char *)pe->long_desc, (char *)pe->topic, (char *)pe->long_desc, (char *)pe->topic,
(char *)pe->unit, (char *)pe->perpkg, (char *)pe->unit, (char *)pe->perpkg,
(char *)pe->metric_expr, (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, 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 *pmu;
struct perf_pmu_alias *alias; 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); format_alias(buf, sizeof(buf), pmu, alias);
bool is_cpu = !strcmp(pmu->name, "cpu"); bool is_cpu = !strcmp(pmu->name, "cpu");
if (alias->deprecated && !deprecated)
continue;
if (event_glob != NULL && if (event_glob != NULL &&
!(strglobmatch_nocase(name, event_glob) || !(strglobmatch_nocase(name, event_glob) ||
(!is_cpu && strglobmatch_nocase(alias->name, (!is_cpu && strglobmatch_nocase(alias->name,

View File

@@ -57,6 +57,7 @@ struct perf_pmu_alias {
double scale; double scale;
bool per_pkg; bool per_pkg;
bool snapshot; bool snapshot;
bool deprecated;
char *metric_expr; char *metric_expr;
char *metric_name; 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); struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
void print_pmu_events(const char *event_glob, bool name_only, bool quiet, 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); 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); int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, ...) __scanf(3, 4);

View File

@@ -539,10 +539,11 @@ static int perl_stop_script(void)
static int perl_generate_script(struct tep_handle *pevent, const char *outfile) 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_event *event = NULL;
struct tep_format_field *f; struct tep_format_field *f;
char fname[PATH_MAX]; char fname[PATH_MAX];
int not_first, count;
FILE *ofp; FILE *ofp;
sprintf(fname, "%s.pl", outfile); sprintf(fname, "%s.pl", outfile);
@@ -603,8 +604,11 @@ sub print_backtrace\n\
}\n\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, "sub %s::%s\n{\n", event->system, event->name);
fprintf(ofp, "\tmy ("); fprintf(ofp, "\tmy (");

View File

@@ -1687,10 +1687,11 @@ static int python_stop_script(void)
static int python_generate_script(struct tep_handle *pevent, const char *outfile) 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_event *event = NULL;
struct tep_format_field *f; struct tep_format_field *f;
char fname[PATH_MAX]; char fname[PATH_MAX];
int not_first, count;
FILE *ofp; FILE *ofp;
sprintf(fname, "%s.py", outfile); 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, "def trace_end():\n");
fprintf(ofp, "\tprint(\"in trace_end\")\n\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, "def %s__%s(", event->system, event->name);
fprintf(ofp, "event_name, "); fprintf(ofp, "event_name, ");
fprintf(ofp, "context, "); fprintf(ofp, "context, ");

View File

@@ -490,6 +490,16 @@ int create_perf_stat_counter(struct evsel *evsel,
if (config->identifier) if (config->identifier)
attr->sample_type = PERF_SAMPLE_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 * Disabling all counters initially, they will be enabled
* either manually by us or by kernel via enable_on_exec * either manually by us or by kernel via enable_on_exec

View File

@@ -106,6 +106,8 @@ struct perf_stat_config {
bool big_num; bool big_num;
bool no_merge; bool no_merge;
bool walltime_run_table; bool walltime_run_table;
bool all_kernel;
bool all_user;
FILE *output; FILE *output;
unsigned int interval; unsigned int interval;
unsigned int timeout; unsigned int timeout;

View File

@@ -4,6 +4,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/types.h> #include <linux/types.h>
#include <sys/types.h> // pid_t
#include <stddef.h> #include <stddef.h>
#include <string.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); 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 *strpbrk_esc(char *str, const char *stopset);
char *strdup_esc(const char *str); char *strdup_esc(const char *str);

View File

@@ -458,10 +458,11 @@ bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf,
return true; 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_session *session,
struct perf_time_interval **ranges, 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, '%'); bool has_percent = strchr(time_str, '%');
struct perf_time_interval *ptime_range; struct perf_time_interval *ptime_range;
@@ -471,7 +472,7 @@ int perf_time__parse_for_ranges(const char *time_str,
if (!ptime_range) if (!ptime_range)
return -ENOMEM; return -ENOMEM;
if (has_percent) { if (has_percent || reltime) {
if (session->evlist->first_sample_time == 0 && if (session->evlist->first_sample_time == 0 &&
session->evlist->last_sample_time == 0) { session->evlist->last_sample_time == 0) {
pr_err("HINT: no first/last sample time found in perf data.\n" 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"); "(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n");
goto error; goto error;
} }
}
if (has_percent) {
num = perf_time__percent_parse_str( num = perf_time__percent_parse_str(
ptime_range, size, ptime_range, size,
time_str, time_str,
@@ -492,6 +495,15 @@ int perf_time__parse_for_ranges(const char *time_str,
if (num < 0) if (num < 0)
goto error_invalid; 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_size = size;
*range_num = num; *range_num = num;
*ranges = ptime_range; *ranges = ptime_range;
@@ -504,6 +516,15 @@ error:
return ret; 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) int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz)
{ {
u64 sec = timestamp / NSEC_PER_SEC; u64 sec = timestamp / NSEC_PER_SEC;

View File

@@ -26,6 +26,11 @@ bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf,
struct perf_session; 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, int perf_time__parse_for_ranges(const char *str, struct perf_session *session,
struct perf_time_interval **ranges, struct perf_time_interval **ranges,
int *range_size, int *range_num); int *range_size, int *range_num);

View File

@@ -173,37 +173,6 @@ int parse_event_file(struct tep_handle *pevent,
return tep_parse_event(pevent, buf, size, sys); 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 { struct flag {
const char *name; const char *name;
unsigned long long value; unsigned long long value;

View 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); 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 read_size(struct tep_event *event, void *ptr, int size);
unsigned long long eval_flag(const char *flag); unsigned long long eval_flag(const char *flag);