]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge tag 'perf-core-for-mingo-20161024' of git://git.kernel.org/pub/scm/linux/kernel...
authorIngo Molnar <mingo@kernel.org>
Mon, 24 Oct 2016 18:42:42 +0000 (20:42 +0200)
committerIngo Molnar <mingo@kernel.org>
Mon, 24 Oct 2016 18:42:42 +0000 (20:42 +0200)
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

New features:

- Dynamicly change verbosity level by pressing 'V' in the 'perf top/report'
  hists TUI browser (Alexis Berlemont)

- Implement 'perf trace --delay' in the same fashion as in 'perf record --delay',
  to skip sampling workload initialization events (Alexis Berlemont)

- Make vendor named events case insensitive in 'perf list', i.e.
  'perf list LONGEST_LAT' works just the same as  'perf list longest_lat' (Andi Kleen)

- Show instruction bytes and lenght in 'perf script' for Intel PT and BTS (Andi Kleen, Adrian Hunter)

   E.g:

    % perf record -e intel_pt// foo
    % perf script --itrace=i0ns -F ip,insn,insnlen
     ffffffff8101232f ilen: 5 insn: 0f 1f 44 00 00
     ffffffff81012334 ilen: 1 insn: 5b
     ffffffff81012335 ilen: 1 insn: 5d
     ffffffff81012336 ilen: 1 insn: c3
     ffffffff810123e3 ilen: 1 insn: 5b
     ffffffff810123e4 ilen: 2 insn: 41 5c
     ffffffff810123e6 ilen: 1 insn: 5d
     ffffffff810123e7 ilen: 1 insn: c3
     ffffffff810124a6 ilen: 2 insn: 31 c0
     ffffffff810124a8 ilen: 9 insn: 41 83 bc 24 a8 01 00 00 01
     ffffffff810124b1 ilen: 2 insn: 75 87

- Allow enabling the perf_event_attr.branch_type attribute member: (Andi Kleen)

  perf record -e sched:sched_switch,cpu/cpu-cycles,branch_type=any/ ...

- Add unwinding support for jitdump (Stefano Sanfilippo)

Fixes:

- Use raw_syscall:sys_enter timestamp in 'perf trace' (Arnaldo Carvalho de Melo)

Infrastructure:

- Allow jitdump to be built without libdwarf (Maciej Debski)

- Sync x86's syscall table tools/ copy (Arnaldo Carvalho de Melo)

- Fixes to avoid calling die() in library fuctions already propagating other
  errors (Arnaldo Carvalho de Melo)

- Improvements to allow libtraceevent to be properly installed in distro
  packages (Jiri Olsa)

- Removing coresight miscellaneous debug output (Mathieu Poirier)

- Cache align the 'perf bench futex' worker struct (Sebastian Andrzej Siewior)

Documentation:

- Minor improvements on the documentation of event parameters (Andi Kleen)

- Add jitdump format specification document (Stephane Eranian)

Spelling fixes:

- Fix typo "No enough" to "Not enough" (Alexander Alemayhu)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
54 files changed:
tools/include/asm-generic/bitops.h
tools/include/asm-generic/bitops/__ffz.h [new file with mode: 0644]
tools/include/asm-generic/bitops/find.h
tools/include/linux/bitops.h
tools/lib/find_bit.c
tools/lib/traceevent/Makefile
tools/perf/Documentation/jitdump-specification.txt [new file with mode: 0644]
tools/perf/Documentation/perf-record.txt
tools/perf/Documentation/perf-script.txt
tools/perf/Documentation/perf-trace.txt
tools/perf/MANIFEST
tools/perf/Makefile.config
tools/perf/arch/arm/util/cs-etm.c
tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
tools/perf/bench/futex-hash.c
tools/perf/bench/mem-functions.c
tools/perf/builtin-report.c
tools/perf/builtin-script.c
tools/perf/builtin-trace.c
tools/perf/jvmti/jvmti_agent.c
tools/perf/jvmti/libjvmti.c
tools/perf/tests/backward-ring-buffer.c
tools/perf/tests/bpf.c
tools/perf/ui/browsers/hists.c
tools/perf/util/Build
tools/perf/util/bpf-loader.c
tools/perf/util/event.h
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/genelf.c
tools/perf/util/genelf.h
tools/perf/util/header.c
tools/perf/util/intel-bts.c
tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c
tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.h
tools/perf/util/intel-pt-decoder/intel-pt-log.c
tools/perf/util/intel-pt.c
tools/perf/util/jitdump.c
tools/perf/util/jitdump.h
tools/perf/util/llvm-utils.c
tools/perf/util/map.c
tools/perf/util/parse-branch-options.c
tools/perf/util/parse-branch-options.h
tools/perf/util/parse-events.c
tools/perf/util/pmu.c
tools/perf/util/quote.c
tools/perf/util/session.c
tools/perf/util/string.c
tools/perf/util/unwind-libunwind-local.c
tools/perf/util/util.h
tools/perf/util/values.c
tools/perf/util/values.h

index 653d1bad77de2331ba18771f99a01dddcee0175c..0304600121daa90b3b4ac3621dec03ba94f252d0 100644 (file)
@@ -13,6 +13,7 @@
  */
 
 #include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/__ffz.h>
 #include <asm-generic/bitops/fls.h>
 #include <asm-generic/bitops/__fls.h>
 #include <asm-generic/bitops/fls64.h>
diff --git a/tools/include/asm-generic/bitops/__ffz.h b/tools/include/asm-generic/bitops/__ffz.h
new file mode 100644 (file)
index 0000000..6744bd4
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _ASM_GENERIC_BITOPS_FFZ_H_
+#define _ASM_GENERIC_BITOPS_FFZ_H_
+
+/*
+ * ffz - find first zero in word.
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
+ */
+#define ffz(x)  __ffs(~(x))
+
+#endif /* _ASM_GENERIC_BITOPS_FFZ_H_ */
index 31f51547fcd4164f54a575c93b54b43e6a2f5ce9..5538ecdc964a2f9e131b88e2e1a3709606963fba 100644 (file)
@@ -15,6 +15,21 @@ extern unsigned long find_next_bit(const unsigned long *addr, unsigned long
                size, unsigned long offset);
 #endif
 
+#ifndef find_next_zero_bit
+
+/**
+ * find_next_zero_bit - find the next cleared bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The bitmap size in bits
+ *
+ * Returns the bit number of the next zero bit
+ * If no bits are zero, returns @size.
+ */
+unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
+                                unsigned long offset);
+#endif
+
 #ifndef find_first_bit
 
 /**
@@ -30,4 +45,17 @@ extern unsigned long find_first_bit(const unsigned long *addr,
 
 #endif /* find_first_bit */
 
+#ifndef find_first_zero_bit
+
+/**
+ * find_first_zero_bit - find the first cleared bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum number of bits to search
+ *
+ * Returns the bit number of the first cleared bit.
+ * If no bits are zero, returns @size.
+ */
+unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size);
+#endif
+
 #endif /*_TOOLS_LINUX_ASM_GENERIC_BITOPS_FIND_H_ */
index 49c929a104eee364fe796f64d895d3ab9cced797..fc446343ff417760dc8e3d98ebd0e33e5deb3dad 100644 (file)
@@ -39,6 +39,11 @@ extern unsigned long __sw_hweight64(__u64 w);
             (bit) < (size);                                    \
             (bit) = find_next_bit((addr), (size), (bit) + 1))
 
+#define for_each_clear_bit(bit, addr, size) \
+       for ((bit) = find_first_zero_bit((addr), (size));       \
+            (bit) < (size);                                    \
+            (bit) = find_next_zero_bit((addr), (size), (bit) + 1))
+
 /* same as for_each_set_bit() but use bit as value to start with */
 #define for_each_set_bit_from(bit, addr, size) \
        for ((bit) = find_next_bit((addr), (size), (bit));      \
index 9122a9e800460bad45b7756800538d4a5f8f8316..6d8b8f22cf55d8a825d6dd4d56f992dd5e1d63b8 100644 (file)
@@ -82,3 +82,28 @@ unsigned long find_first_bit(const unsigned long *addr, unsigned long size)
        return size;
 }
 #endif
+
+#ifndef find_first_zero_bit
+/*
+ * Find the first cleared bit in a memory region.
+ */
+unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size)
+{
+       unsigned long idx;
+
+       for (idx = 0; idx * BITS_PER_LONG < size; idx++) {
+               if (addr[idx] != ~0UL)
+                       return min(idx * BITS_PER_LONG + ffz(addr[idx]), size);
+       }
+
+       return size;
+}
+#endif
+
+#ifndef find_next_zero_bit
+unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
+                                unsigned long offset)
+{
+       return _find_next_bit(addr, size, offset, ~0UL);
+}
+#endif
index 7851df1490e0a81f6a17776bbdb464f564a99894..c76012ebdb9ccaa144fae77f6f56c1ea3acd1884 100644 (file)
@@ -99,8 +99,6 @@ libdir_SQ = $(subst ','\'',$(libdir))
 libdir_relative_SQ = $(subst ','\'',$(libdir_relative))
 plugin_dir_SQ = $(subst ','\'',$(plugin_dir))
 
-LIB_FILE = libtraceevent.a libtraceevent.so
-
 CONFIG_INCLUDES = 
 CONFIG_LIBS    =
 CONFIG_FLAGS   =
@@ -114,6 +112,9 @@ N           =
 
 EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION)
 
+LIB_TARGET  = libtraceevent.a libtraceevent.so.$(EVENT_PARSE_VERSION)
+LIB_INSTALL = libtraceevent.a libtraceevent.so*
+
 INCLUDES = -I. -I $(srctree)/tools/include $(CONFIG_INCLUDES)
 
 # Set compile option CFLAGS
@@ -156,11 +157,11 @@ PLUGINS += plugin_cfg80211.so
 PLUGINS    := $(addprefix $(OUTPUT),$(PLUGINS))
 PLUGINS_IN := $(PLUGINS:.so=-in.o)
 
-TE_IN    := $(OUTPUT)libtraceevent-in.o
-LIB_FILE := $(addprefix $(OUTPUT),$(LIB_FILE))
+TE_IN      := $(OUTPUT)libtraceevent-in.o
+LIB_TARGET := $(addprefix $(OUTPUT),$(LIB_TARGET))
 DYNAMIC_LIST_FILE := $(OUTPUT)libtraceevent-dynamic-list
 
-CMD_TARGETS = $(LIB_FILE) $(PLUGINS) $(DYNAMIC_LIST_FILE)
+CMD_TARGETS = $(LIB_TARGET) $(PLUGINS) $(DYNAMIC_LIST_FILE)
 
 TARGETS = $(CMD_TARGETS)
 
@@ -171,8 +172,10 @@ all_cmd: $(CMD_TARGETS)
 $(TE_IN): force
        $(Q)$(MAKE) $(build)=libtraceevent
 
-$(OUTPUT)libtraceevent.so: $(TE_IN)
-       $(QUIET_LINK)$(CC) --shared $^ -o $@
+$(OUTPUT)libtraceevent.so.$(EVENT_PARSE_VERSION): $(TE_IN)
+       $(QUIET_LINK)$(CC) --shared $^ -Wl,-soname,libtraceevent.so.$(EP_VERSION) -o $@
+       @ln -sf $(@F) $(OUTPUT)libtraceevent.so
+       @ln -sf $(@F) $(OUTPUT)libtraceevent.so.$(EP_VERSION)
 
 $(OUTPUT)libtraceevent.a: $(TE_IN)
        $(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^
@@ -236,11 +239,15 @@ TAGS:     force
        find . -name '*.[ch]' | xargs etags \
        --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/'
 
+define do_install_mkdir
+       if [ ! -d '$(DESTDIR_SQ)$1' ]; then             \
+               $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$1'; \
+       fi
+endef
+
 define do_install
-       if [ ! -d '$(DESTDIR_SQ)$2' ]; then             \
-               $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \
-       fi;                                             \
-       $(INSTALL) $1 '$(DESTDIR_SQ)$2'
+       $(call do_install_mkdir,$2);                    \
+       $(INSTALL) $(if $3,-m $3,) $1 '$(DESTDIR_SQ)$2'
 endef
 
 define do_install_plugins
@@ -257,13 +264,20 @@ define do_generate_dynamic_list_file
 endef
 
 install_lib: all_cmd install_plugins
-       $(call QUIET_INSTALL, $(LIB_FILE)) \
-               $(call do_install,$(LIB_FILE),$(libdir_SQ))
+       $(call QUIET_INSTALL, $(LIB_TARGET)) \
+               $(call do_install_mkdir,$(libdir_SQ)); \
+               cp -fpR $(LIB_INSTALL) $(DESTDIR)$(libdir_SQ)
 
 install_plugins: $(PLUGINS)
        $(call QUIET_INSTALL, trace_plugins) \
                $(call do_install_plugins, $(PLUGINS))
 
+install_headers:
+       $(call QUIET_INSTALL, headers) \
+               $(call do_install,event-parse.h,$(prefix)/include/traceevent,644); \
+               $(call do_install,event-utils.h,$(prefix)/include/traceevent,644); \
+               $(call do_install,kbuffer.h,$(prefix)/include/traceevent,644)
+
 install: install_lib
 
 clean:
diff --git a/tools/perf/Documentation/jitdump-specification.txt b/tools/perf/Documentation/jitdump-specification.txt
new file mode 100644 (file)
index 0000000..4c62b07
--- /dev/null
@@ -0,0 +1,170 @@
+JITDUMP specification version 2
+Last Revised: 09/15/2016
+Author: Stephane Eranian <eranian@gmail.com>
+
+--------------------------------------------------------
+| Revision  |    Date    | Description                 |
+--------------------------------------------------------
+|   1       | 09/07/2016 | Initial revision            |
+--------------------------------------------------------
+|   2       | 09/15/2016 | Add JIT_CODE_UNWINDING_INFO |
+--------------------------------------------------------
+
+
+I/ Introduction
+
+
+This document describes the jitdump file format. The file is generated by Just-In-time compiler runtimes to save meta-data information about the generated code, such as address, size, and name of generated functions, the native code generated, the source line information. The data may then be used by performance tools, such as Linux perf to generate function and assembly level profiles.
+
+The format is not specific to any particular programming language. It can be extended as need be.
+
+The format of the file is binary. It is self-describing in terms of endianness and is portable across multiple processor architectures.
+
+
+II/ Overview of the format
+
+
+The format requires only sequential accesses, i.e., append only mode. The file starts with a fixed size file header describing the version of the specification, the endianness.
+
+The header is followed by a series of records, each starting with a fixed size header describing the type of record and its size. It is, itself, followed by the payload for the record. Records can have a variable size even for a given type.
+
+Each entry in the file is timestamped. All timestamps must use the same clock source. The CLOCK_MONOTONIC clock source is recommended.
+
+
+III/ Jitdump file header format
+
+Each jitdump file starts with a fixed size header containing the following fields in order:
+
+
+* uint32_t magic     : a magic number tagging the file type. The value is 4-byte long and represents the string "JiTD" in ASCII form. It is 0x4A695444 or 0x4454694a depending on the endianness. The field can be used to detect the endianness of the file
+* uint32_t version   : a 4-byte value representing the format version. It is currently set to 2
+* uint32_t total_size: size in bytes of file header
+* uint32_t elf_mach  : ELF architecture encoding (ELF e_machine value as specified in /usr/include/elf.h)
+* uint32_t pad1      : padding. Reserved for future use
+* uint32_t pid       : JIT runtime process identification (OS specific)
+* uint64_t timestamp : timestamp of when the file was created
+* uint64_t flags     : a bitmask of flags
+
+The flags currently defined are as follows:
+ * bit 0: JITDUMP_FLAGS_ARCH_TIMESTAMP : set if the jitdump file is using an architecture-specific timestamp clock source. For instance, on x86, one could use TSC directly
+
+IV/ Record header
+
+The file header is immediately followed by records. Each record starts with a fixed size header describing the record that follows.
+
+The record header is specified in order as follows:
+* uint32_t id        : a value identifying the record type (see below)
+* uint32_t total_size: the size in bytes of the record including the header.
+* uint64_t timestamp : a timestamp of when the record was created.
+
+The following record types are defined:
+ * Value 0 : JIT_CODE_LOAD      : record describing a jitted function
+ * Value 1 : JIT_CODE_MOVE      : record describing an already jitted function which is moved
+ * Value 2 : JIT_CODE_DEBUG_INFO: record describing the debug information for a jitted function
+ * Value 3 : JIT_CODE_CLOSE     : record marking the end of the jit runtime (optional)
+ * Value 4 : JIT_CODE_UNWINDING_INFO: record describing a function unwinding information
+
+ The payload of the record must immediately follow the record header without padding.
+
+V/ JIT_CODE_LOAD record
+
+
+  The record has the following fields following the fixed-size record header in order:
+  * uint32_t pid: OS process id of the runtime generating the jitted code
+  * uint32_t tid: OS thread identification of the runtime thread generating the jitted code
+  * uint64_t vma: virtual address of jitted code start
+  * uint64_t code_addr: code start address for the jitted code. By default vma = code_addr
+  * uint64_t code_size: size in bytes of the generated jitted code
+  * uint64_t code_index: unique identifier for the jitted code (see below)
+  * char[n]: function name in ASCII including the null termination
+  * native code: raw byte encoding of the jitted code
+
+  The record header total_size field is inclusive of all components:
+  * record header
+  * fixed-sized fields
+  * function name string, including termination
+  * native code length
+  * record specific variable data (e.g., array of data entries)
+
+The code_index is used to uniquely identify each jitted function. The index can be a monotonically increasing 64-bit value. Each time a function is jitted it gets a new number. This value is used in case the code for a function is moved and avoids having to issue another JIT_CODE_LOAD record.
+
+The format supports empty functions with no native code.
+
+
+VI/ JIT_CODE_MOVE record
+
+  The record type is optional.
+
+  The record has the following fields following the fixed-size record header in order:
+  * uint32_t pid          : OS process id of the runtime generating the jitted code
+  * uint32_t tid          : OS thread identification of the runtime thread generating the jitted code
+  * uint64_t vma          : new virtual address of jitted code start
+  * uint64_t old_code_addr: previous code address for the same function
+  * uint64_t new_code_addr: alternate new code started address for the jitted code. By default it should be equal to the vma address.
+  * uint64_t code_size    : size in bytes of the jitted code
+  * uint64_t code_index   : index referring to the JIT_CODE_LOAD code_index record of when the function was initially jitted
+
+
+The MOVE record can be used in case an already jitted function is simply moved by the runtime inside the code cache.
+
+The JIT_CODE_MOVE record cannot come before the JIT_CODE_LOAD record for the same function name. The function cannot have changed name, otherwise a new JIT_CODE_LOAD record must be emitted.
+
+The code size of the function cannot change.
+
+
+VII/ JIT_DEBUG_INFO record
+
+The record type is optional.
+
+The record contains source lines debug information, i.e., a way to map a code address back to a source line. This information may be used by the performance tool.
+
+The record has the following fields following the fixed-size record header in order:
+  * uint64_t code_addr: address of function for which the debug information is generated
+  * uint64_t nr_entry : number of debug entries for the function
+  * debug_entry[n]: array of nr_entry debug entries for the function
+
+The debug_entry describes the source line information. It is defined as follows in order:
+* uint64_t code_addr: address of function for which the debug information is generated
+* uint32_t line     : source file line number (starting at 1)
+* uint32_t discrim  : column discriminator, 0 is default
+* char name[n]      : source file name in ASCII, including null termination
+
+The debug_entry entries are saved in sequence but given that they have variable sizes due to the file name string, they cannot be indexed directly.
+They need to be walked sequentially. The next debug_entry is found at sizeof(debug_entry) + strlen(name) + 1.
+
+IMPORTANT:
+  The JIT_CODE_DEBUG for a given function must always be generated BEFORE the JIT_CODE_LOAD for the function. This facilitates greatly the parser for the jitdump file.
+
+
+VIII/ JIT_CODE_CLOSE record
+
+
+The record type is optional.
+
+The record is used as a marker for the end of the jitted runtime. It can be replaced by the end of the file.
+
+The JIT_CODE_CLOSE record does not have any specific fields, the record header contains all the information needed.
+
+
+IX/ JIT_CODE_UNWINDING_INFO
+
+
+The record type is optional.
+
+The record is used to describe the unwinding information for a jitted function.
+
+The record has the following fields following the fixed-size record header in order:
+
+uint64_t unwind_data_size   : the size in bytes of the unwinding data table at the end of the record
+uint64_t eh_frame_hdr_size  : the size in bytes of the DWARF EH Frame Header at the start of the unwinding data table at the end of the record
+uint64_t mapped_size        : the size of the unwinding data mapped in memory
+const char unwinding_data[n]: an array of unwinding data, consisting of the EH Frame Header, followed by the actual EH Frame
+
+
+The EH Frame header follows the Linux Standard Base (LSB) specification as described in the document at https://refspecs.linuxfoundation.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
+
+
+The EH Frame follows the LSB specicfication as described in the document at https://refspecs.linuxbase.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
+
+
+NOTE: The mapped_size is generally either the same as unwind_data_size (if the unwinding data was mapped in memory by the running process) or zero (if the unwinding data is not mapped by the process). If the unwinding data was not mapped, then only the EH Frame Header will be read, which can be used to specify FP based unwinding for a function which does not have unwinding information.
index 92335193dc3382690a7f490437469d48c451e130..27fc3617c6a42066bf7a64bb2ace9961a350183b 100644 (file)
@@ -45,9 +45,9 @@ OPTIONS
           param1 and param2 are defined as formats for the PMU in:
           /sys/bus/event_source/devices/<pmu>/format/*
 
-         There are also some params which are not defined in .../<pmu>/format/*.
+         There are also some parameters which are not defined in .../<pmu>/format/*.
          These params can be used to overload default config values per event.
-         Here is a list of the params.
+         Here are some common parameters:
          - 'period': Set event sampling period
          - 'freq': Set event sampling frequency
          - 'time': Disable/enable time stamping. Acceptable values are 1 for
@@ -57,8 +57,11 @@ OPTIONS
                         FP mode, "dwarf" for DWARF mode, "lbr" for LBR mode and
                         "no" for disable callgraph.
          - 'stack-size': user stack size for dwarf mode
+
+          See the linkperf:perf-list[1] man page for more parameters.
+
          Note: If user explicitly sets options which conflict with the params,
-         the value set by the params will be overridden.
+         the value set by the parameters will be overridden.
 
          Also not defined in .../<pmu>/format/* are PMU driver specific
          configuration parameters.  Any configuration parameter preceded by
index 053bbbd84ece30c673afe7e176328f8390a6bda9..c01904f388ce807cb4acefc607df9314a56fcbb4 100644 (file)
@@ -117,7 +117,7 @@ OPTIONS
         Comma separated list of fields to print. Options are:
         comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff,
         srcline, period, iregs, brstack, brstacksym, flags, bpf-output,
-        callindent. Field list can be prepended with the type, trace, sw or hw,
+        callindent, insn, insnlen. Field list can be prepended with the type, trace, sw or hw,
         to indicate to which event type the field list applies.
         e.g., -F sw:comm,tid,time,ip,sym  and -F trace:time,cpu,trace
 
@@ -181,6 +181,10 @@ OPTIONS
        Instruction Trace decoding. For calls and returns, it will display the
        name of the symbol indented with spaces to reflect the stack depth.
 
+       When doing instruction trace decoding insn and insnlen give the
+       instruction bytes and the instruction length of the current
+       instruction.
+
        Finally, a user may not set fields to none for all event types.
        i.e., -F "" is not allowed.
 
index 1ab0782369b1faa9bbe6758ed0e3439c414eb7e1..781b019751a4cb8bafeb70afc467aca54c410177 100644 (file)
@@ -39,6 +39,11 @@ OPTIONS
        Prefixing with ! shows all syscalls but the ones specified.  You may
        need to escape it.
 
+-D msecs::
+--delay msecs::
+After starting the program, wait msecs before measuring. This is useful to
+filter out the startup phase of the program, which is often very different.
+
 -o::
 --output=::
        Output file name.
index 0bda2cca2b3a641fa0a13531c02114b548cddcb6..a511e5f31e36185a7e9fd8cb83eed23371cc9002 100644 (file)
@@ -51,6 +51,7 @@ tools/include/asm-generic/bitops/arch_hweight.h
 tools/include/asm-generic/bitops/atomic.h
 tools/include/asm-generic/bitops/const_hweight.h
 tools/include/asm-generic/bitops/__ffs.h
+tools/include/asm-generic/bitops/__ffz.h
 tools/include/asm-generic/bitops/__fls.h
 tools/include/asm-generic/bitops/find.h
 tools/include/asm-generic/bitops/fls64.h
index 72edf83d76b72188b193fc5f28934fa26dab2b1d..cffdd9cf3ebf764a1d4fbed2421045e4ee148c7b 100644 (file)
@@ -366,7 +366,7 @@ ifndef NO_SDT
 endif
 
 ifdef PERF_HAVE_JITDUMP
-  ifndef NO_DWARF
+  ifndef NO_LIBELF
     $(call detected,CONFIG_JITDUMP)
     CFLAGS += -DHAVE_JITDUMP
   endif
index 47d584da581999f8dc546bfebd7072ca1fe56954..dfea6b6355254e0eac677dfc05dcce0463089f6e 100644 (file)
@@ -575,8 +575,6 @@ static FILE *cs_device__open_file(const char *name)
        snprintf(path, PATH_MAX,
                 "%s" CS_BUS_DEVICE_PATH "%s", sysfs, name);
 
-       printf("path: %s\n", path);
-
        if (stat(path, &st) < 0)
                return NULL;
 
index 555263e385c9210af5f70e08dd27871005c5a865..e9ce9c7c39b48ca5e439735c87d6fe5b138d7fbc 100644 (file)
 543    x32     io_setup                compat_sys_io_setup
 544    x32     io_submit               compat_sys_io_submit
 545    x32     execveat                compat_sys_execveat/ptregs
-534    x32     preadv2                 compat_sys_preadv2
-535    x32     pwritev2                compat_sys_pwritev2
+546    x32     preadv2                 compat_sys_preadv64v2
+547    x32     pwritev2                compat_sys_pwritev64v2
index 8024cd5febd226da1e3bfe99003f8eb217bdfc69..d9e5e80bb4d0b7b2b49972057c28a377a40aec89 100644 (file)
@@ -39,12 +39,15 @@ static unsigned int threads_starting;
 static struct stats throughput_stats;
 static pthread_cond_t thread_parent, thread_worker;
 
+#define SMP_CACHE_BYTES 256
+#define __cacheline_aligned __attribute__ ((aligned (SMP_CACHE_BYTES)))
+
 struct worker {
        int tid;
        u_int32_t *futex;
        pthread_t thread;
        unsigned long ops;
-};
+} __cacheline_aligned;
 
 static const struct option options[] = {
        OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"),
index c684910e5a482af6bee4ebd15c86708813ff6777..52504a83b5a15a0649f45f936d72d97a0fe4159f 100644 (file)
@@ -106,9 +106,10 @@ static double timeval2double(struct timeval *ts)
 
 struct bench_mem_info {
        const struct function *functions;
-       u64 (*do_cycles)(const struct function *r, size_t size);
-       double (*do_gettimeofday)(const struct function *r, size_t size);
+       u64 (*do_cycles)(const struct function *r, size_t size, void *src, void *dst);
+       double (*do_gettimeofday)(const struct function *r, size_t size, void *src, void *dst);
        const char *const *usage;
+       bool alloc_src;
 };
 
 static void __bench_mem_function(struct bench_mem_info *info, int r_idx, size_t size, double size_total)
@@ -116,16 +117,26 @@ static void __bench_mem_function(struct bench_mem_info *info, int r_idx, size_t
        const struct function *r = &info->functions[r_idx];
        double result_bps = 0.0;
        u64 result_cycles = 0;
+       void *src = NULL, *dst = zalloc(size);
 
        printf("# function '%s' (%s)\n", r->name, r->desc);
 
+       if (dst == NULL)
+               goto out_alloc_failed;
+
+       if (info->alloc_src) {
+               src = zalloc(size);
+               if (src == NULL)
+                       goto out_alloc_failed;
+       }
+
        if (bench_format == BENCH_FORMAT_DEFAULT)
                printf("# Copying %s bytes ...\n\n", size_str);
 
        if (use_cycles) {
-               result_cycles = info->do_cycles(r, size);
+               result_cycles = info->do_cycles(r, size, src, dst);
        } else {
-               result_bps = info->do_gettimeofday(r, size);
+               result_bps = info->do_gettimeofday(r, size, src, dst);
        }
 
        switch (bench_format) {
@@ -149,6 +160,14 @@ static void __bench_mem_function(struct bench_mem_info *info, int r_idx, size_t
                BUG_ON(1);
                break;
        }
+
+out_free:
+       free(src);
+       free(dst);
+       return;
+out_alloc_failed:
+       printf("# Memory allocation failed - maybe size (%s) is too large?\n", size_str);
+       goto out_free;
 }
 
 static int bench_mem_common(int argc, const char **argv, struct bench_mem_info *info)
@@ -201,28 +220,14 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info *
        return 0;
 }
 
-static void memcpy_alloc_mem(void **dst, void **src, size_t size)
-{
-       *dst = zalloc(size);
-       if (!*dst)
-               die("memory allocation failed - maybe size is too large?\n");
-
-       *src = zalloc(size);
-       if (!*src)
-               die("memory allocation failed - maybe size is too large?\n");
-
-       /* Make sure to always prefault zero pages even if MMAP_THRESH is crossed: */
-       memset(*src, 0, size);
-}
-
-static u64 do_memcpy_cycles(const struct function *r, size_t size)
+static u64 do_memcpy_cycles(const struct function *r, size_t size, void *src, void *dst)
 {
        u64 cycle_start = 0ULL, cycle_end = 0ULL;
-       void *src = NULL, *dst = NULL;
        memcpy_t fn = r->fn.memcpy;
        int i;
 
-       memcpy_alloc_mem(&dst, &src, size);
+       /* Make sure to always prefault zero pages even if MMAP_THRESH is crossed: */
+       memset(src, 0, size);
 
        /*
         * We prefault the freshly allocated memory range here,
@@ -235,20 +240,15 @@ static u64 do_memcpy_cycles(const struct function *r, size_t size)
                fn(dst, src, size);
        cycle_end = get_cycles();
 
-       free(src);
-       free(dst);
        return cycle_end - cycle_start;
 }
 
-static double do_memcpy_gettimeofday(const struct function *r, size_t size)
+static double do_memcpy_gettimeofday(const struct function *r, size_t size, void *src, void *dst)
 {
        struct timeval tv_start, tv_end, tv_diff;
        memcpy_t fn = r->fn.memcpy;
-       void *src = NULL, *dst = NULL;
        int i;
 
-       memcpy_alloc_mem(&dst, &src, size);
-
        /*
         * We prefault the freshly allocated memory range here,
         * to not measure page fault overhead:
@@ -262,9 +262,6 @@ static double do_memcpy_gettimeofday(const struct function *r, size_t size)
 
        timersub(&tv_end, &tv_start, &tv_diff);
 
-       free(src);
-       free(dst);
-
        return (double)(((double)size * nr_loops) / timeval2double(&tv_diff));
 }
 
@@ -294,27 +291,18 @@ int bench_mem_memcpy(int argc, const char **argv, const char *prefix __maybe_unu
                .do_cycles              = do_memcpy_cycles,
                .do_gettimeofday        = do_memcpy_gettimeofday,
                .usage                  = bench_mem_memcpy_usage,
+               .alloc_src              = true,
        };
 
        return bench_mem_common(argc, argv, &info);
 }
 
-static void memset_alloc_mem(void **dst, size_t size)
-{
-       *dst = zalloc(size);
-       if (!*dst)
-               die("memory allocation failed - maybe size is too large?\n");
-}
-
-static u64 do_memset_cycles(const struct function *r, size_t size)
+static u64 do_memset_cycles(const struct function *r, size_t size, void *src __maybe_unused, void *dst)
 {
        u64 cycle_start = 0ULL, cycle_end = 0ULL;
        memset_t fn = r->fn.memset;
-       void *dst = NULL;
        int i;
 
-       memset_alloc_mem(&dst, size);
-
        /*
         * We prefault the freshly allocated memory range here,
         * to not measure page fault overhead:
@@ -326,19 +314,15 @@ static u64 do_memset_cycles(const struct function *r, size_t size)
                fn(dst, i, size);
        cycle_end = get_cycles();
 
-       free(dst);
        return cycle_end - cycle_start;
 }
 
-static double do_memset_gettimeofday(const struct function *r, size_t size)
+static double do_memset_gettimeofday(const struct function *r, size_t size, void *src __maybe_unused, void *dst)
 {
        struct timeval tv_start, tv_end, tv_diff;
        memset_t fn = r->fn.memset;
-       void *dst = NULL;
        int i;
 
-       memset_alloc_mem(&dst, size);
-
        /*
         * We prefault the freshly allocated memory range here,
         * to not measure page fault overhead:
@@ -352,7 +336,6 @@ static double do_memset_gettimeofday(const struct function *r, size_t size)
 
        timersub(&tv_end, &tv_start, &tv_diff);
 
-       free(dst);
        return (double)(((double)size * nr_loops) / timeval2double(&tv_diff));
 }
 
index 6e88460cd13d3d65ad54f18470a1e8d7e445b06d..8064de8ceedc44a05321ae22f762f32002e0aab9 100644 (file)
@@ -207,11 +207,14 @@ static int process_read_event(struct perf_tool *tool,
 
        if (rep->show_threads) {
                const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
-               perf_read_values_add_value(&rep->show_threads_values,
+               int err = perf_read_values_add_value(&rep->show_threads_values,
                                           event->read.pid, event->read.tid,
                                           event->read.id,
                                           name,
                                           event->read.value);
+
+               if (err)
+                       return err;
        }
 
        dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
@@ -539,8 +542,11 @@ static int __cmd_report(struct report *rep)
                }
        }
 
-       if (rep->show_threads)
-               perf_read_values_init(&rep->show_threads_values);
+       if (rep->show_threads) {
+               ret = perf_read_values_init(&rep->show_threads_values);
+               if (ret)
+                       return ret;
+       }
 
        ret = report__setup_sample_type(rep);
        if (ret) {
index 7228d141a789d8d50dd4386df0e38e9bba7e9183..412fb6e65ac06dcdb7e00e667c9f12d0a8edbeda 100644 (file)
@@ -66,6 +66,8 @@ enum perf_output_field {
        PERF_OUTPUT_WEIGHT          = 1U << 18,
        PERF_OUTPUT_BPF_OUTPUT      = 1U << 19,
        PERF_OUTPUT_CALLINDENT      = 1U << 20,
+       PERF_OUTPUT_INSN            = 1U << 21,
+       PERF_OUTPUT_INSNLEN         = 1U << 22,
 };
 
 struct output_option {
@@ -93,6 +95,8 @@ struct output_option {
        {.str = "weight",   .field = PERF_OUTPUT_WEIGHT},
        {.str = "bpf-output",   .field = PERF_OUTPUT_BPF_OUTPUT},
        {.str = "callindent", .field = PERF_OUTPUT_CALLINDENT},
+       {.str = "insn", .field = PERF_OUTPUT_INSN},
+       {.str = "insnlen", .field = PERF_OUTPUT_INSNLEN},
 };
 
 /* default set to maintain compatibility with current format */
@@ -624,6 +628,20 @@ static void print_sample_callindent(struct perf_sample *sample,
                printf("%*s", spacing - len, "");
 }
 
+static void print_insn(struct perf_sample *sample,
+                      struct perf_event_attr *attr)
+{
+       if (PRINT_FIELD(INSNLEN))
+               printf(" ilen: %d", sample->insn_len);
+       if (PRINT_FIELD(INSN)) {
+               int i;
+
+               printf(" insn:");
+               for (i = 0; i < sample->insn_len; i++)
+                       printf(" %02x", (unsigned char)sample->insn[i]);
+       }
+}
+
 static void print_sample_bts(struct perf_sample *sample,
                             struct perf_evsel *evsel,
                             struct thread *thread,
@@ -668,6 +686,8 @@ static void print_sample_bts(struct perf_sample *sample,
        if (print_srcline_last)
                map__fprintf_srcline(al->map, al->addr, "\n  ", stdout);
 
+       print_insn(sample, attr);
+
        printf("\n");
 }
 
@@ -911,7 +931,7 @@ static void process_event(struct perf_script *script,
 
        if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT))
                print_sample_bpf_output(sample);
-
+       print_insn(sample, attr);
        printf("\n");
 }
 
@@ -2124,7 +2144,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
                     "Valid types: hw,sw,trace,raw. "
                     "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
                     "addr,symoff,period,iregs,brstack,brstacksym,flags,"
-                    "bpf-output,callindent", parse_output_fields),
+                    "bpf-output,callindent,insn,insnlen", parse_output_fields),
        OPT_BOOLEAN('a', "all-cpus", &system_wide,
                    "system-wide collection from all CPUs"),
        OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
index c298bd3e1d909cfd808f911af1df053e608f55fe..5f45166c892d6bb4f6b4e3ae261bf0d3794378b5 100644 (file)
@@ -843,7 +843,6 @@ static size_t fprintf_duration(unsigned long t, FILE *fp)
  */
 struct thread_trace {
        u64               entry_time;
-       u64               exit_time;
        bool              entry_pending;
        unsigned long     nr_events;
        unsigned long     pfmaj, pfmin;
@@ -1452,7 +1451,7 @@ static int trace__printf_interrupted_entry(struct trace *trace, struct perf_samp
 
        duration = sample->time - ttrace->entry_time;
 
-       printed  = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
+       printed  = trace__fprintf_entry_head(trace, trace->current, duration, ttrace->entry_time, trace->output);
        printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
        ttrace->entry_pending = false;
 
@@ -1499,7 +1498,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
 
        if (sc->is_exit) {
                if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
-                       trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
+                       trace__fprintf_entry_head(trace, thread, 1, ttrace->entry_time, trace->output);
                        fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
                }
        } else {
@@ -1571,8 +1570,6 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
                ++trace->stats.vfs_getname;
        }
 
-       ttrace->exit_time = sample->time;
-
        if (ttrace->entry_time) {
                duration = sample->time - ttrace->entry_time;
                if (trace__filter_duration(trace, duration))
@@ -1592,7 +1589,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
        if (trace->summary_only)
                goto out;
 
-       trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
+       trace__fprintf_entry_head(trace, thread, duration, ttrace->entry_time, trace->output);
 
        if (ttrace->entry_pending) {
                fprintf(trace->output, "%-70s", ttrace->entry_str);
@@ -2310,12 +2307,17 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
        if (err < 0)
                goto out_error_mmap;
 
-       if (!target__none(&trace->opts.target))
+       if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
                perf_evlist__enable(evlist);
 
        if (forks)
                perf_evlist__start_workload(evlist);
 
+       if (trace->opts.initial_delay) {
+               usleep(trace->opts.initial_delay * 1000);
+               perf_evlist__enable(evlist);
+       }
+
        trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
                                  evlist->threads->nr > 1 ||
                                  perf_evlist__first(evlist)->attr.inherit;
@@ -2816,6 +2818,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
                     "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
        OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
                        "per thread proc mmap processing timeout in ms"),
+       OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
+                    "ms to wait before starting measurement after program "
+                    "start"),
        OPT_END()
        };
        bool __maybe_unused max_stack_user_set = true;
index 55daefff0d54daae31f6b1134a6a499792a310d7..e9651a9d670e90a2b46f5083aaa02e981494baff 100644 (file)
 static char jit_path[PATH_MAX];
 static void *marker_addr;
 
-/*
- * padding buffer
- */
-static const char pad_bytes[7];
-
 static inline pid_t gettid(void)
 {
        return (pid_t)syscall(__NR_gettid);
@@ -230,7 +225,6 @@ init_arch_timestamp(void)
 
 void *jvmti_open(void)
 {
-       int pad_cnt;
        char dump_path[PATH_MAX];
        struct jitheader header;
        int fd;
@@ -288,10 +282,6 @@ void *jvmti_open(void)
        header.total_size = sizeof(header);
        header.pid        = getpid();
 
-       /* calculate amount of padding '\0' */
-       pad_cnt = PADDING_8ALIGNED(header.total_size);
-       header.total_size += pad_cnt;
-
        header.timestamp = perf_get_timestamp();
 
        if (use_arch_timestamp)
@@ -301,13 +291,6 @@ void *jvmti_open(void)
                warn("jvmti: cannot write dumpfile header");
                goto error;
        }
-
-       /* write padding '\0' if necessary */
-       if (pad_cnt && !fwrite(pad_bytes, pad_cnt, 1, fp)) {
-               warn("jvmti: cannot write dumpfile header padding");
-               goto error;
-       }
-
        return fp;
 error:
        fclose(fp);
@@ -349,7 +332,6 @@ jvmti_write_code(void *agent, char const *sym,
        static int code_generation = 1;
        struct jr_code_load rec;
        size_t sym_len;
-       size_t padding_count;
        FILE *fp = agent;
        int ret = -1;
 
@@ -366,8 +348,6 @@ jvmti_write_code(void *agent, char const *sym,
 
        rec.p.id           = JIT_CODE_LOAD;
        rec.p.total_size   = sizeof(rec) + sym_len;
-       padding_count      = PADDING_8ALIGNED(rec.p.total_size);
-       rec.p. total_size += padding_count;
        rec.p.timestamp    = perf_get_timestamp();
 
        rec.code_size  = size;
@@ -393,9 +373,6 @@ jvmti_write_code(void *agent, char const *sym,
        ret = fwrite_unlocked(&rec, sizeof(rec), 1, fp);
        fwrite_unlocked(sym, sym_len, 1, fp);
 
-       if (padding_count)
-               fwrite_unlocked(pad_bytes, padding_count, 1, fp);
-
        if (code)
                fwrite_unlocked(code, size, 1, fp);
 
@@ -412,7 +389,6 @@ jvmti_write_debug_info(void *agent, uint64_t code, const char *file,
 {
        struct jr_code_debug_info rec;
        size_t sret, len, size, flen;
-       size_t padding_count;
        uint64_t addr;
        const char *fn = file;
        FILE *fp = agent;
@@ -443,16 +419,10 @@ jvmti_write_debug_info(void *agent, uint64_t code, const char *file,
         * int      : line number
         * int      : column discriminator
         * file[]   : source file name
-        * padding  : pad to multiple of 8 bytes
         */
        size += nr_lines * sizeof(struct debug_entry);
        size += flen * nr_lines;
-       /*
-        * pad to 8 bytes
-        */
-       padding_count = PADDING_8ALIGNED(size);
-
-       rec.p.total_size = size + padding_count;
+       rec.p.total_size = size;
 
        /*
         * If JVM is multi-threaded, nultiple concurrent calls to agent
@@ -486,12 +456,6 @@ jvmti_write_debug_info(void *agent, uint64_t code, const char *file,
                if (sret != 1)
                        goto error;
        }
-       if (padding_count) {
-               sret = fwrite_unlocked(pad_bytes, padding_count, 1, fp);
-               if (sret != 1)
-                       goto error;
-       }
-
        funlockfile(fp);
        return 0;
 error:
index ac12e4b91a9265fda46192f28a8854e755515c7f..5612641c69b403d00dbcb5f344600361301faf27 100644 (file)
 static int has_line_numbers;
 void *jvmti_agent;
 
+static void print_error(jvmtiEnv *jvmti, const char *msg, jvmtiError ret)
+{
+       char *err_msg = NULL;
+       jvmtiError err;
+       err = (*jvmti)->GetErrorName(jvmti, ret, &err_msg);
+       if (err == JVMTI_ERROR_NONE) {
+               warnx("%s failed with %s", msg, err_msg);
+               (*jvmti)->Deallocate(jvmti, (unsigned char *)err_msg);
+       } else {
+               warnx("%s failed with an unknown error %d", msg, ret);
+       }
+}
+
 static jvmtiError
 do_get_line_numbers(jvmtiEnv *jvmti, void *pc, jmethodID m, jint bci,
                    jvmti_line_info_t *tab, jint *nr)
@@ -22,8 +35,10 @@ do_get_line_numbers(jvmtiEnv *jvmti, void *pc, jmethodID m, jint bci,
        jvmtiError ret;
 
        ret = (*jvmti)->GetLineNumberTable(jvmti, m, &nr_lines, &loc_tab);
-       if (ret != JVMTI_ERROR_NONE)
+       if (ret != JVMTI_ERROR_NONE) {
+               print_error(jvmti, "GetLineNumberTable", ret);
                return ret;
+       }
 
        for (i = 0; i < nr_lines; i++) {
                if (loc_tab[i].start_location < bci) {
@@ -71,6 +86,8 @@ get_line_numbers(jvmtiEnv *jvmti, const void *compile_info, jvmti_line_info_t **
                                        /* free what was allocated for nothing */
                                        (*jvmti)->Deallocate(jvmti, (unsigned char *)lne);
                                        nr_total += (int)nr;
+                               } else {
+                                       print_error(jvmti, "GetLineNumberTable", ret);
                                }
                        }
                }
@@ -130,7 +147,7 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
        ret = (*jvmti)->GetMethodDeclaringClass(jvmti, method,
                                                &decl_class);
        if (ret != JVMTI_ERROR_NONE) {
-               warnx("jvmti: cannot get declaring class");
+               print_error(jvmti, "GetMethodDeclaringClass", ret);
                return;
        }
 
@@ -144,21 +161,21 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
 
        ret = (*jvmti)->GetSourceFileName(jvmti, decl_class, &file_name);
        if (ret != JVMTI_ERROR_NONE) {
-               warnx("jvmti: cannot get source filename ret=%d", ret);
+               print_error(jvmti, "GetSourceFileName", ret);
                goto error;
        }
 
        ret = (*jvmti)->GetClassSignature(jvmti, decl_class,
                                          &class_sign, NULL);
        if (ret != JVMTI_ERROR_NONE) {
-               warnx("jvmti: getclassignature failed");
+               print_error(jvmti, "GetClassSignature", ret);
                goto error;
        }
 
        ret = (*jvmti)->GetMethodName(jvmti, method, &func_name,
                                      &func_sign, NULL);
        if (ret != JVMTI_ERROR_NONE) {
-               warnx("jvmti: failed getmethodname");
+               print_error(jvmti, "GetMethodName", ret);
                goto error;
        }
 
@@ -253,7 +270,7 @@ Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __unused)
 
        ret = (*jvmti)->AddCapabilities(jvmti, &caps1);
        if (ret != JVMTI_ERROR_NONE) {
-               warnx("jvmti: acquire compiled_method capability failed");
+               print_error(jvmti, "AddCapabilities", ret);
                return -1;
        }
        ret = (*jvmti)->GetJLocationFormat(jvmti, &format);
@@ -264,7 +281,9 @@ Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __unused)
                ret = (*jvmti)->AddCapabilities(jvmti, &caps1);
                 if (ret == JVMTI_ERROR_NONE)
                         has_line_numbers = 1;
-        }
+        } else if (ret != JVMTI_ERROR_NONE)
+               print_error(jvmti, "GetJLocationFormat", ret);
+
 
        memset(&cb, 0, sizeof(cb));
 
@@ -273,21 +292,21 @@ Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __unused)
 
        ret = (*jvmti)->SetEventCallbacks(jvmti, &cb, sizeof(cb));
        if (ret != JVMTI_ERROR_NONE) {
-               warnx("jvmti: cannot set event callbacks");
+               print_error(jvmti, "SetEventCallbacks", ret);
                return -1;
        }
 
        ret = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
                        JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
        if (ret != JVMTI_ERROR_NONE) {
-               warnx("jvmti: setnotification failed for method_load");
+               print_error(jvmti, "SetEventNotificationMode(METHOD_LOAD)", ret);
                return -1;
        }
 
        ret = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
                        JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
        if (ret != JVMTI_ERROR_NONE) {
-               warnx("jvmti: setnotification failed on code_generated");
+               print_error(jvmti, "SetEventNotificationMode(CODE_GENERATED)", ret);
                return -1;
        }
        return 0;
index e6d1816e431a9c3bd0839db29dd8b231c40b8455..42e892b1e97981a19511d026f977c45feff0497b 100644 (file)
@@ -97,7 +97,7 @@ int test__backward_ring_buffer(int subtest __maybe_unused)
 
        evlist = perf_evlist__new();
        if (!evlist) {
-               pr_debug("No enough memory to create evlist\n");
+               pr_debug("Not enough memory to create evlist\n");
                return TEST_FAIL;
        }
 
index 2673e86ed50fad3496e1b50c7770142e21d6d32c..8f0298aff222b5d28cd2e60762875e3a2036a1e6 100644 (file)
@@ -125,7 +125,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void),
        /* Instead of perf_evlist__new_default, don't add default events */
        evlist = perf_evlist__new();
        if (!evlist) {
-               pr_debug("No enough memory to create evlist\n");
+               pr_debug("Not enough memory to create evlist\n");
                return TEST_FAIL;
        }
 
index 31d6d5a7c2dc5ee5e19c6ad2ada9fc4c5dac6521..ddc4c3e59cc1f88bb40e0737d54aabbc4458df86 100644 (file)
@@ -2807,7 +2807,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
                        do_zoom_dso(browser, actions);
                        continue;
                case 'V':
-                       browser->show_dso = !browser->show_dso;
+                       verbose = (verbose + 1) % 4;
+                       browser->show_dso = verbose > 0;
+                       ui_helpline__fpush("Verbosity level set to %d\n",
+                                          verbose);
                        continue;
                case 't':
                        actions->thread = thread;
index eb60e613d7954319e8d2ee16f9a94eb1481160e1..1dc67efad6340f7aef55f1727f00f7f20d8baa2c 100644 (file)
@@ -120,7 +120,7 @@ libperf-y += demangle-rust.o
 ifdef CONFIG_JITDUMP
 libperf-$(CONFIG_LIBELF) += jitdump.o
 libperf-$(CONFIG_LIBELF) += genelf.o
-libperf-$(CONFIG_LIBELF) += genelf_debug.o
+libperf-$(CONFIG_DWARF) += genelf_debug.o
 endif
 
 CFLAGS_config.o   += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
index 2b2c9b82f5abc55d22ff451ec32161c558091895..a5fd275238f770bf020ef4faa954f5365d13c405 100644 (file)
@@ -241,7 +241,7 @@ parse_prog_config_kvpair(const char *config_str, struct perf_probe_event *pev)
        int err = 0;
 
        if (!text) {
-               pr_debug("No enough memory: dup config_str failed\n");
+               pr_debug("Not enough memory: dup config_str failed\n");
                return ERR_PTR(-ENOMEM);
        }
 
@@ -531,7 +531,7 @@ static int map_prologue(struct perf_probe_event *pev, int *mapping,
 
        ptevs = malloc(array_sz);
        if (!ptevs) {
-               pr_debug("No enough memory: alloc ptevs failed\n");
+               pr_debug("Not enough memory: alloc ptevs failed\n");
                return -ENOMEM;
        }
 
@@ -604,13 +604,13 @@ static int hook_load_preprocessor(struct bpf_program *prog)
        priv->need_prologue = true;
        priv->insns_buf = malloc(sizeof(struct bpf_insn) * BPF_MAXINSNS);
        if (!priv->insns_buf) {
-               pr_debug("No enough memory: alloc insns_buf failed\n");
+               pr_debug("Not enough memory: alloc insns_buf failed\n");
                return -ENOMEM;
        }
 
        priv->type_mapping = malloc(sizeof(int) * pev->ntevs);
        if (!priv->type_mapping) {
-               pr_debug("No enough memory: alloc type_mapping failed\n");
+               pr_debug("Not enough memory: alloc type_mapping failed\n");
                return -ENOMEM;
        }
        memset(priv->type_mapping, -1,
@@ -864,7 +864,7 @@ bpf_map_op_setkey(struct bpf_map_op *op, struct parse_events_term *term)
 
                op->k.array.ranges = memdup(term->array.ranges, memsz);
                if (!op->k.array.ranges) {
-                       pr_debug("No enough memory to alloc indices for map\n");
+                       pr_debug("Not enough memory to alloc indices for map\n");
                        return -ENOMEM;
                }
                op->key_type = BPF_MAP_KEY_RANGES;
@@ -929,7 +929,7 @@ bpf_map_priv__clone(struct bpf_map_priv *priv)
 
        newpriv = zalloc(sizeof(*newpriv));
        if (!newpriv) {
-               pr_debug("No enough memory to alloc map private\n");
+               pr_debug("Not enough memory to alloc map private\n");
                return NULL;
        }
        INIT_LIST_HEAD(&newpriv->ops_list);
@@ -960,7 +960,7 @@ bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op)
        if (!priv) {
                priv = zalloc(sizeof(*priv));
                if (!priv) {
-                       pr_debug("No enough memory to alloc map private\n");
+                       pr_debug("Not enough memory to alloc map private\n");
                        return -ENOMEM;
                }
                INIT_LIST_HEAD(&priv->ops_list);
index 8d363d5e65a2e14c019fd18a6129ceef7b1538c3..c735c53a26f8f6dcb37727299e0560d07a5f6ddb 100644 (file)
@@ -177,6 +177,8 @@ enum {
        PERF_IP_FLAG_TRACE_BEGIN        |\
        PERF_IP_FLAG_TRACE_END)
 
+#define MAX_INSN 16
+
 struct perf_sample {
        u64 ip;
        u32 pid, tid;
@@ -193,6 +195,7 @@ struct perf_sample {
        u32 flags;
        u16 insn_len;
        u8  cpumode;
+       char insn[MAX_INSN];
        void *raw_data;
        struct ip_callchain *callchain;
        struct branch_stack *branch_stack;
index 8bc271141d9df9051aa93bdf4677ba79ff5473e0..e58a2fbf3b160c2acd827d0c6b9aeca5a0c8f1ce 100644 (file)
@@ -28,6 +28,7 @@
 #include "debug.h"
 #include "trace-event.h"
 #include "stat.h"
+#include "util/parse-branch-options.h"
 
 static struct {
        bool sample_id_all;
@@ -708,6 +709,14 @@ static void apply_config_terms(struct perf_evsel *evsel,
                case PERF_EVSEL__CONFIG_TERM_CALLGRAPH:
                        callgraph_buf = term->val.callgraph;
                        break;
+               case PERF_EVSEL__CONFIG_TERM_BRANCH:
+                       if (term->val.branch && strcmp(term->val.branch, "no")) {
+                               perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
+                               parse_branch_str(term->val.branch,
+                                                &attr->branch_sample_type);
+                       } else
+                               perf_evsel__reset_sample_bit(evsel, BRANCH_STACK);
+                       break;
                case PERF_EVSEL__CONFIG_TERM_STACK_USER:
                        dump_size = term->val.stack_user;
                        break;
index b1503b0ecdff511c14493552f063bba0a88dabaf..8cd7cd2274836f9b2725d1b54e80feb78d12f863 100644 (file)
@@ -47,6 +47,7 @@ enum {
        PERF_EVSEL__CONFIG_TERM_MAX_STACK,
        PERF_EVSEL__CONFIG_TERM_OVERWRITE,
        PERF_EVSEL__CONFIG_TERM_DRV_CFG,
+       PERF_EVSEL__CONFIG_TERM_BRANCH,
        PERF_EVSEL__CONFIG_TERM_MAX,
 };
 
@@ -63,6 +64,7 @@ struct perf_evsel_config_term {
                int     max_stack;
                bool    inherit;
                bool    overwrite;
+               char    *branch;
        } val;
 };
 
index c1ef805c6a8f4decc9f5c5c613b6b590e8c31581..c540d47583e763292f3392744c51a00319d56586 100644 (file)
 #include <limits.h>
 #include <fcntl.h>
 #include <err.h>
+#ifdef HAVE_DWARF_SUPPORT
 #include <dwarf.h>
+#endif
 
 #include "perf.h"
 #include "genelf.h"
 #include "../util/jitdump.h"
 
+#ifndef NT_GNU_BUILD_ID
+#define NT_GNU_BUILD_ID 3
+#endif
+
 #define JVMTI
 
 #define BUILD_ID_URANDOM /* different uuid for each run */
@@ -67,6 +73,8 @@ static char shd_string_table[] = {
        '.', 'd', 'e', 'b', 'u', 'g', '_', 'l', 'i', 'n', 'e', 0, /* 52 */
        '.', 'd', 'e', 'b', 'u', 'g', '_', 'i', 'n', 'f', 'o', 0, /* 64 */
        '.', 'd', 'e', 'b', 'u', 'g', '_', 'a', 'b', 'b', 'r', 'e', 'v', 0, /* 76 */
+       '.', 'e', 'h', '_', 'f', 'r', 'a', 'm', 'e', '_', 'h', 'd', 'r', 0, /* 90 */
+       '.', 'e', 'h', '_', 'f', 'r', 'a', 'm', 'e', 0, /* 104 */
 };
 
 static struct buildid_note {
@@ -147,6 +155,86 @@ gen_build_id(struct buildid_note *note, unsigned long load_addr, const void *cod
 }
 #endif
 
+static int
+jit_add_eh_frame_info(Elf *e, void* unwinding, uint64_t unwinding_header_size,
+                     uint64_t unwinding_size, uint64_t base_offset)
+{
+       Elf_Data *d;
+       Elf_Scn *scn;
+       Elf_Shdr *shdr;
+       uint64_t unwinding_table_size = unwinding_size - unwinding_header_size;
+
+       /*
+        * setup eh_frame section
+        */
+       scn = elf_newscn(e);
+       if (!scn) {
+               warnx("cannot create section");
+               return -1;
+       }
+
+       d = elf_newdata(scn);
+       if (!d) {
+               warnx("cannot get new data");
+               return -1;
+       }
+
+       d->d_align = 8;
+       d->d_off = 0LL;
+       d->d_buf = unwinding;
+       d->d_type = ELF_T_BYTE;
+       d->d_size = unwinding_table_size;
+       d->d_version = EV_CURRENT;
+
+       shdr = elf_getshdr(scn);
+       if (!shdr) {
+               warnx("cannot get section header");
+               return -1;
+       }
+
+       shdr->sh_name = 104;
+       shdr->sh_type = SHT_PROGBITS;
+       shdr->sh_addr = base_offset;
+       shdr->sh_flags = SHF_ALLOC;
+       shdr->sh_entsize = 0;
+
+       /*
+        * setup eh_frame_hdr section
+        */
+       scn = elf_newscn(e);
+       if (!scn) {
+               warnx("cannot create section");
+               return -1;
+       }
+
+       d = elf_newdata(scn);
+       if (!d) {
+               warnx("cannot get new data");
+               return -1;
+       }
+
+       d->d_align = 4;
+       d->d_off = 0LL;
+       d->d_buf = unwinding + unwinding_table_size;
+       d->d_type = ELF_T_BYTE;
+       d->d_size = unwinding_header_size;
+       d->d_version = EV_CURRENT;
+
+       shdr = elf_getshdr(scn);
+       if (!shdr) {
+               warnx("cannot get section header");
+               return -1;
+       }
+
+       shdr->sh_name = 90;
+       shdr->sh_type = SHT_PROGBITS;
+       shdr->sh_addr = base_offset + unwinding_table_size;
+       shdr->sh_flags = SHF_ALLOC;
+       shdr->sh_entsize = 0;
+
+       return 0;
+}
+
 /*
  * fd: file descriptor open for writing for the output file
  * load_addr: code load address (could be zero, just used for buildid)
@@ -157,13 +245,15 @@ gen_build_id(struct buildid_note *note, unsigned long load_addr, const void *cod
 int
 jit_write_elf(int fd, uint64_t load_addr, const char *sym,
              const void *code, int csize,
-             void *debug, int nr_debug_entries)
+             void *debug __maybe_unused, int nr_debug_entries __maybe_unused,
+             void *unwinding, uint64_t unwinding_header_size, uint64_t unwinding_size)
 {
        Elf *e;
        Elf_Data *d;
        Elf_Scn *scn;
        Elf_Ehdr *ehdr;
        Elf_Shdr *shdr;
+       uint64_t eh_frame_base_offset;
        char *strsym = NULL;
        int symlen;
        int retval = -1;
@@ -194,7 +284,7 @@ jit_write_elf(int fd, uint64_t load_addr, const char *sym,
        ehdr->e_type = ET_DYN;
        ehdr->e_entry = GEN_ELF_TEXT_OFFSET;
        ehdr->e_version = EV_CURRENT;
-       ehdr->e_shstrndx= 2; /* shdr index for section name */
+       ehdr->e_shstrndx= unwinding ? 4 : 2; /* shdr index for section name */
 
        /*
         * setup text section
@@ -230,6 +320,18 @@ jit_write_elf(int fd, uint64_t load_addr, const char *sym,
        shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
        shdr->sh_entsize = 0;
 
+       /*
+        * Setup .eh_frame_hdr and .eh_frame
+        */
+       if (unwinding) {
+               eh_frame_base_offset = ALIGN_8(GEN_ELF_TEXT_OFFSET + csize);
+               retval = jit_add_eh_frame_info(e, unwinding,
+                                              unwinding_header_size, unwinding_size,
+                                              eh_frame_base_offset);
+               if (retval)
+                       goto error;
+       }
+
        /*
         * setup section headers string table
         */
@@ -298,7 +400,7 @@ jit_write_elf(int fd, uint64_t load_addr, const char *sym,
        shdr->sh_type = SHT_SYMTAB;
        shdr->sh_flags = 0;
        shdr->sh_entsize = sizeof(Elf_Sym);
-       shdr->sh_link = 4; /* index of .strtab section */
+       shdr->sh_link = unwinding ? 6 : 4; /* index of .strtab section */
 
        /*
         * setup symbols string table
@@ -386,11 +488,14 @@ jit_write_elf(int fd, uint64_t load_addr, const char *sym,
        shdr->sh_size = sizeof(bnote);
        shdr->sh_entsize = 0;
 
+#ifdef HAVE_DWARF_SUPPORT
        if (debug && nr_debug_entries) {
                retval = jit_add_debug_info(e, load_addr, debug, nr_debug_entries);
                if (retval)
                        goto error;
-       } else {
+       } else
+#endif
+       {
                if (elf_update(e, ELF_C_WRITE) < 0) {
                        warnx("elf_update 4 failed");
                        goto error;
index 2fbeb59c4bdd91b2b9de943d153c3674c46ca125..2424bd9862a309381ad4748f674114f4a31b2678 100644 (file)
@@ -3,9 +3,12 @@
 
 /* genelf.c */
 int jit_write_elf(int fd, uint64_t code_addr, const char *sym,
-                 const void *code, int csize, void *debug, int nr_debug_entries);
+                 const void *code, int csize, void *debug, int nr_debug_entries,
+                 void *unwinding, uint64_t unwinding_header_size, uint64_t unwinding_size);
+#ifdef HAVE_DWARF_SUPPORT
 /* genelf_debug.c */
 int jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_entries);
+#endif
 
 #if   defined(__arm__)
 #define GEN_ELF_ARCH   EM_ARM
index 2f3eded54b0cc65a6d2ac59456a2acf2d7921059..d89c9c7ef4e54ba6381c7b63d8db29c87328b3ea 100644 (file)
@@ -2250,11 +2250,28 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
        struct header_print_data hd;
        struct perf_header *header = &session->header;
        int fd = perf_data_file__fd(session->file);
+       struct stat st;
+       int ret, bit;
+
        hd.fp = fp;
        hd.full = full;
 
+       ret = fstat(fd, &st);
+       if (ret == -1)
+               return -1;
+
+       fprintf(fp, "# captured on: %s", ctime(&st.st_ctime));
+
        perf_header__process_sections(header, fd, &hd,
                                      perf_file_section__fprintf_info);
+
+       fprintf(fp, "# missing features: ");
+       for_each_clear_bit(bit, header->adds_features, HEADER_LAST_FEATURE) {
+               if (bit)
+                       fprintf(fp, "%s ", feat_ops[bit].name);
+       }
+
+       fprintf(fp, "\n");
        return 0;
 }
 
@@ -2273,7 +2290,7 @@ static int do_write_feat(int fd, struct perf_header *h, int type,
 
                err = feat_ops[type].write(fd, h, evlist);
                if (err < 0) {
-                       pr_debug("failed to write feature %d\n", type);
+                       pr_debug("failed to write feature %s\n", feat_ops[type].name);
 
                        /* undo anything written */
                        lseek(fd, (*p)->offset, SEEK_SET);
index f545ec1e758a722d1d462e9defd6ff1ba186145f..6c2eb5da4afc0d290786881ebd9a7d9c5f83775f 100644 (file)
@@ -295,6 +295,7 @@ static int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq,
        sample.cpu = btsq->cpu;
        sample.flags = btsq->sample_flags;
        sample.insn_len = btsq->intel_pt_insn.length;
+       memcpy(sample.insn, btsq->intel_pt_insn.buf, INTEL_PT_INSN_BUF_SZ);
 
        if (bts->synth_opts.inject) {
                event.sample.header.size = bts->branches_event_size;
@@ -319,15 +320,12 @@ static int intel_bts_get_next_insn(struct intel_bts_queue *btsq, u64 ip)
        struct machine *machine = btsq->bts->machine;
        struct thread *thread;
        struct addr_location al;
-       unsigned char buf[1024];
-       size_t bufsz;
+       unsigned char buf[INTEL_PT_INSN_BUF_SZ];
        ssize_t len;
        int x86_64;
        uint8_t cpumode;
        int err = -1;
 
-       bufsz = intel_pt_insn_max_size();
-
        if (machine__kernel_ip(machine, ip))
                cpumode = PERF_RECORD_MISC_KERNEL;
        else
@@ -341,7 +339,8 @@ static int intel_bts_get_next_insn(struct intel_bts_queue *btsq, u64 ip)
        if (!al.map || !al.map->dso)
                goto out_put;
 
-       len = dso__data_read_addr(al.map->dso, al.map, machine, ip, buf, bufsz);
+       len = dso__data_read_addr(al.map->dso, al.map, machine, ip, buf,
+                                 INTEL_PT_INSN_BUF_SZ);
        if (len <= 0)
                goto out_put;
 
index 16c06d3ae577297ff4e312e911428e0b5c985b61..e4e7dc781d21d17b309513c54ff7c0cf0ab9d383 100644 (file)
@@ -980,6 +980,8 @@ out:
 out_no_progress:
        decoder->state.insn_op = intel_pt_insn->op;
        decoder->state.insn_len = intel_pt_insn->length;
+       memcpy(decoder->state.insn, intel_pt_insn->buf,
+              INTEL_PT_INSN_BUF_SZ);
 
        if (decoder->tx_flags & INTEL_PT_IN_TX)
                decoder->state.flags |= INTEL_PT_IN_TX;
index 89399985fa4d4bfec664a1630ebc13c37da3b6d0..e90619a43c0cefdd6edebb0369e77dbf46017c21 100644 (file)
@@ -66,6 +66,7 @@ struct intel_pt_state {
        uint32_t flags;
        enum intel_pt_insn_op insn_op;
        int insn_len;
+       char insn[INTEL_PT_INSN_BUF_SZ];
 };
 
 struct intel_pt_insn;
index d23138c06665a85d080c4ac668b828b3eb777724..7913363bde5c0407fded864f62a839c8b28056ea 100644 (file)
 
 #include "intel-pt-insn-decoder.h"
 
+#if INTEL_PT_INSN_BUF_SZ < MAX_INSN_SIZE || INTEL_PT_INSN_BUF_SZ > MAX_INSN
+#error Instruction buffer size too small
+#endif
+
 /* Based on branch_type() from perf_event_intel_lbr.c */
 static void intel_pt_insn_decoder(struct insn *insn,
                                  struct intel_pt_insn *intel_pt_insn)
@@ -166,10 +170,10 @@ int intel_pt_get_insn(const unsigned char *buf, size_t len, int x86_64,
        if (!insn_complete(&insn) || insn.length > len)
                return -1;
        intel_pt_insn_decoder(&insn, intel_pt_insn);
-       if (insn.length < INTEL_PT_INSN_DBG_BUF_SZ)
+       if (insn.length < INTEL_PT_INSN_BUF_SZ)
                memcpy(intel_pt_insn->buf, buf, insn.length);
        else
-               memcpy(intel_pt_insn->buf, buf, INTEL_PT_INSN_DBG_BUF_SZ);
+               memcpy(intel_pt_insn->buf, buf, INTEL_PT_INSN_BUF_SZ);
        return 0;
 }
 
@@ -211,11 +215,6 @@ int intel_pt_insn_desc(const struct intel_pt_insn *intel_pt_insn, char *buf,
        return 0;
 }
 
-size_t intel_pt_insn_max_size(void)
-{
-       return MAX_INSN_SIZE;
-}
-
 int intel_pt_insn_type(enum intel_pt_insn_op op)
 {
        switch (op) {
index b0adbf37323e422bf8cb5c5ae6886f521d0ee662..37ec5627ae9b04e4720dc394d02958ff16253f9a 100644 (file)
@@ -20,7 +20,7 @@
 #include <stdint.h>
 
 #define INTEL_PT_INSN_DESC_MAX         32
-#define INTEL_PT_INSN_DBG_BUF_SZ       16
+#define INTEL_PT_INSN_BUF_SZ           16
 
 enum intel_pt_insn_op {
        INTEL_PT_OP_OTHER,
@@ -47,7 +47,7 @@ struct intel_pt_insn {
        enum intel_pt_insn_branch       branch;
        int                             length;
        int32_t                         rel;
-       unsigned char                   buf[INTEL_PT_INSN_DBG_BUF_SZ];
+       unsigned char                   buf[INTEL_PT_INSN_BUF_SZ];
 };
 
 int intel_pt_get_insn(const unsigned char *buf, size_t len, int x86_64,
@@ -58,8 +58,6 @@ const char *intel_pt_insn_name(enum intel_pt_insn_op op);
 int intel_pt_insn_desc(const struct intel_pt_insn *intel_pt_insn, char *buf,
                       size_t buf_len);
 
-size_t intel_pt_insn_max_size(void);
-
 int intel_pt_insn_type(enum intel_pt_insn_op op);
 
 #endif
index 319bef33a64b2104ab7b17436e6c222f4d656d01..e02bc7b166a0e48f1cf537606a71ab43875c6de8 100644 (file)
@@ -119,8 +119,8 @@ void __intel_pt_log_insn(struct intel_pt_insn *intel_pt_insn, uint64_t ip)
        if (intel_pt_log_open())
                return;
 
-       if (len > INTEL_PT_INSN_DBG_BUF_SZ)
-               len = INTEL_PT_INSN_DBG_BUF_SZ;
+       if (len > INTEL_PT_INSN_BUF_SZ)
+               len = INTEL_PT_INSN_BUF_SZ;
        intel_pt_print_data(intel_pt_insn->buf, len, ip, 8);
        if (intel_pt_insn_desc(intel_pt_insn, desc, INTEL_PT_INSN_DESC_MAX) > 0)
                fprintf(f, "%s\n", desc);
index dc041d4368c812d6e932e31e4f56d3a24620ee6c..85d5eeb66c75339fc7c230bfcd7bcabd975ee402 100644 (file)
@@ -143,6 +143,7 @@ struct intel_pt_queue {
        u32 flags;
        u16 insn_len;
        u64 last_insn_cnt;
+       char insn[INTEL_PT_INSN_BUF_SZ];
 };
 
 static void intel_pt_dump(struct intel_pt *pt __maybe_unused,
@@ -315,6 +316,7 @@ struct intel_pt_cache_entry {
        enum intel_pt_insn_branch       branch;
        int                             length;
        int32_t                         rel;
+       char                            insn[INTEL_PT_INSN_BUF_SZ];
 };
 
 static int intel_pt_config_div(const char *var, const char *value, void *data)
@@ -400,6 +402,7 @@ static int intel_pt_cache_add(struct dso *dso, struct machine *machine,
        e->branch = intel_pt_insn->branch;
        e->length = intel_pt_insn->length;
        e->rel = intel_pt_insn->rel;
+       memcpy(e->insn, intel_pt_insn->buf, INTEL_PT_INSN_BUF_SZ);
 
        err = auxtrace_cache__add(c, offset, &e->entry);
        if (err)
@@ -428,8 +431,7 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
        struct machine *machine = ptq->pt->machine;
        struct thread *thread;
        struct addr_location al;
-       unsigned char buf[1024];
-       size_t bufsz;
+       unsigned char buf[INTEL_PT_INSN_BUF_SZ];
        ssize_t len;
        int x86_64;
        u8 cpumode;
@@ -437,11 +439,11 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
        u64 insn_cnt = 0;
        bool one_map = true;
 
+       intel_pt_insn->length = 0;
+
        if (to_ip && *ip == to_ip)
                goto out_no_cache;
 
-       bufsz = intel_pt_insn_max_size();
-
        if (*ip >= ptq->pt->kernel_start)
                cpumode = PERF_RECORD_MISC_KERNEL;
        else
@@ -478,6 +480,8 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
                                intel_pt_insn->branch = e->branch;
                                intel_pt_insn->length = e->length;
                                intel_pt_insn->rel = e->rel;
+                               memcpy(intel_pt_insn->buf, e->insn,
+                                      INTEL_PT_INSN_BUF_SZ);
                                intel_pt_log_insn_no_data(intel_pt_insn, *ip);
                                return 0;
                        }
@@ -493,7 +497,8 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
 
                while (1) {
                        len = dso__data_read_offset(al.map->dso, machine,
-                                                   offset, buf, bufsz);
+                                                   offset, buf,
+                                                   INTEL_PT_INSN_BUF_SZ);
                        if (len <= 0)
                                return -EINVAL;
 
@@ -900,6 +905,7 @@ static void intel_pt_sample_flags(struct intel_pt_queue *ptq)
                if (ptq->state->flags & INTEL_PT_IN_TX)
                        ptq->flags |= PERF_IP_FLAG_IN_TX;
                ptq->insn_len = ptq->state->insn_len;
+               memcpy(ptq->insn, ptq->state->insn, INTEL_PT_INSN_BUF_SZ);
        }
 }
 
@@ -1080,6 +1086,7 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq)
        sample.cpu = ptq->cpu;
        sample.flags = ptq->flags;
        sample.insn_len = ptq->insn_len;
+       memcpy(sample.insn, ptq->insn, INTEL_PT_INSN_BUF_SZ);
 
        /*
         * perf report cannot handle events without a branch stack when using
@@ -1141,6 +1148,7 @@ static int intel_pt_synth_instruction_sample(struct intel_pt_queue *ptq)
        sample.cpu = ptq->cpu;
        sample.flags = ptq->flags;
        sample.insn_len = ptq->insn_len;
+       memcpy(sample.insn, ptq->insn, INTEL_PT_INSN_BUF_SZ);
 
        ptq->last_insn_cnt = ptq->state->tot_insn_cnt;
 
@@ -1203,6 +1211,7 @@ static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq)
        sample.cpu = ptq->cpu;
        sample.flags = ptq->flags;
        sample.insn_len = ptq->insn_len;
+       memcpy(sample.insn, ptq->insn, INTEL_PT_INSN_BUF_SZ);
 
        if (pt->synth_opts.callchain) {
                thread_stack__sample(ptq->thread, ptq->chain,
index 95f0884aae0286078681ecf19546546f9d6fb2a9..c9a941ef0f6dde0c88da23a6d233d120646c3257 100644 (file)
@@ -37,6 +37,10 @@ struct jit_buf_desc {
        bool             needs_bswap; /* handles cross-endianess */
        bool             use_arch_timestamp;
        void             *debug_data;
+       void             *unwinding_data;
+       uint64_t         unwinding_size;
+       uint64_t         unwinding_mapped_size;
+       uint64_t         eh_frame_hdr_size;
        size_t           nr_debug_entries;
        uint32_t         code_load_count;
        u64              bytes_written;
@@ -68,7 +72,10 @@ jit_emit_elf(char *filename,
             const void *code,
             int csize,
             void *debug,
-            int nr_debug_entries)
+            int nr_debug_entries,
+            void *unwinding,
+            uint32_t unwinding_header_size,
+            uint32_t unwinding_size)
 {
        int ret, fd;
 
@@ -81,7 +88,8 @@ jit_emit_elf(char *filename,
                return -1;
        }
 
-        ret = jit_write_elf(fd, code_addr, sym, (const void *)code, csize, debug, nr_debug_entries);
+       ret = jit_write_elf(fd, code_addr, sym, (const void *)code, csize, debug, nr_debug_entries,
+                           unwinding, unwinding_header_size, unwinding_size);
 
         close(fd);
 
@@ -172,6 +180,12 @@ jit_open(struct jit_buf_desc *jd, const char *name)
                        header.elf_mach,
                        jd->use_arch_timestamp);
 
+       if (header.version > JITHEADER_VERSION) {
+               pr_err("wrong jitdump version %u, expected " STR(JITHEADER_VERSION),
+                       header.version);
+               goto error;
+       }
+
        if (header.flags & JITDUMP_FLAGS_RESERVED) {
                pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n",
                       (unsigned long long)header.flags & JITDUMP_FLAGS_RESERVED);
@@ -263,8 +277,7 @@ jit_get_next_entry(struct jit_buf_desc *jd)
                return NULL;
 
        if (id >= JIT_CODE_MAX) {
-               pr_warning("next_entry: unknown prefix %d, skipping\n", id);
-               return NULL;
+               pr_warning("next_entry: unknown record type %d, skipping\n", id);
        }
        if (bs > jd->bufsize) {
                void *n;
@@ -296,6 +309,13 @@ jit_get_next_entry(struct jit_buf_desc *jd)
                        }
                }
                break;
+       case JIT_CODE_UNWINDING_INFO:
+               if (jd->needs_bswap) {
+                       jr->unwinding.unwinding_size = bswap_64(jr->unwinding.unwinding_size);
+                       jr->unwinding.eh_frame_hdr_size = bswap_64(jr->unwinding.eh_frame_hdr_size);
+                       jr->unwinding.mapped_size = bswap_64(jr->unwinding.mapped_size);
+               }
+               break;
        case JIT_CODE_CLOSE:
                break;
        case JIT_CODE_LOAD:
@@ -322,7 +342,8 @@ jit_get_next_entry(struct jit_buf_desc *jd)
                break;
        case JIT_CODE_MAX:
        default:
-               return NULL;
+               /* skip unknown record (we have read them) */
+               break;
        }
        return jr;
 }
@@ -370,7 +391,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
        u16 idr_size;
        const char *sym;
        uint32_t count;
-       int ret, csize;
+       int ret, csize, usize;
        pid_t pid, tid;
        struct {
                u32 pid, tid;
@@ -380,6 +401,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
        pid   = jr->load.pid;
        tid   = jr->load.tid;
        csize = jr->load.code_size;
+       usize = jd->unwinding_mapped_size;
        addr  = jr->load.code_addr;
        sym   = (void *)((unsigned long)jr + sizeof(jr->load));
        code  = (unsigned long)jr + jr->load.p.total_size - csize;
@@ -400,7 +422,8 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
 
        size = PERF_ALIGN(size, sizeof(u64));
        uaddr = (uintptr_t)code;
-       ret = jit_emit_elf(filename, sym, addr, (const void *)uaddr, csize, jd->debug_data, jd->nr_debug_entries);
+       ret = jit_emit_elf(filename, sym, addr, (const void *)uaddr, csize, jd->debug_data, jd->nr_debug_entries,
+                          jd->unwinding_data, jd->eh_frame_hdr_size, jd->unwinding_size);
 
        if (jd->debug_data && jd->nr_debug_entries) {
                free(jd->debug_data);
@@ -408,6 +431,14 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
                jd->nr_debug_entries = 0;
        }
 
+       if (jd->unwinding_data && jd->eh_frame_hdr_size) {
+               free(jd->unwinding_data);
+               jd->unwinding_data = NULL;
+               jd->eh_frame_hdr_size = 0;
+               jd->unwinding_mapped_size = 0;
+               jd->unwinding_size = 0;
+       }
+
        if (ret) {
                free(event);
                return -1;
@@ -422,7 +453,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
 
        event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET;
        event->mmap2.start = addr;
-       event->mmap2.len   = csize;
+       event->mmap2.len   = usize ? ALIGN_8(csize) + usize : csize;
        event->mmap2.pid   = pid;
        event->mmap2.tid   = tid;
        event->mmap2.ino   = st.st_ino;
@@ -473,6 +504,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
        char *filename;
        size_t size;
        struct stat st;
+       int usize;
        u16 idr_size;
        int ret;
        pid_t pid, tid;
@@ -483,6 +515,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
 
        pid = jr->move.pid;
        tid =  jr->move.tid;
+       usize = jd->unwinding_mapped_size;
        idr_size = jd->machine->id_hdr_size;
 
        /*
@@ -511,7 +544,8 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
                        (sizeof(event->mmap2.filename) - size) + idr_size);
        event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET;
        event->mmap2.start = jr->move.new_code_addr;
-       event->mmap2.len   = jr->move.code_size;
+       event->mmap2.len   = usize ? ALIGN_8(jr->move.code_size) + usize
+                                  : jr->move.code_size;
        event->mmap2.pid   = pid;
        event->mmap2.tid   = tid;
        event->mmap2.ino   = st.st_ino;
@@ -577,11 +611,36 @@ static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr)
        return 0;
 }
 
+static int
+jit_repipe_unwinding_info(struct jit_buf_desc *jd, union jr_entry *jr)
+{
+       void *unwinding_data;
+       uint32_t unwinding_data_size;
+
+       if (!(jd && jr))
+               return -1;
+
+       unwinding_data_size  = jr->prefix.total_size - sizeof(jr->unwinding);
+       unwinding_data = malloc(unwinding_data_size);
+       if (!unwinding_data)
+               return -1;
+
+       memcpy(unwinding_data, &jr->unwinding.unwinding_data,
+              unwinding_data_size);
+
+       jd->eh_frame_hdr_size = jr->unwinding.eh_frame_hdr_size;
+       jd->unwinding_size = jr->unwinding.unwinding_size;
+       jd->unwinding_mapped_size = jr->unwinding.mapped_size;
+       jd->unwinding_data = unwinding_data;
+
+       return 0;
+}
+
 static int
 jit_process_dump(struct jit_buf_desc *jd)
 {
        union jr_entry *jr;
-       int ret;
+       int ret = 0;
 
        while ((jr = jit_get_next_entry(jd))) {
                switch(jr->prefix.id) {
@@ -594,6 +653,9 @@ jit_process_dump(struct jit_buf_desc *jd)
                case JIT_CODE_DEBUG_INFO:
                        ret = jit_repipe_debug_info(jd, jr);
                        break;
+               case JIT_CODE_UNWINDING_INFO:
+                       ret = jit_repipe_unwinding_info(jd, jr);
+                       break;
                default:
                        ret = 0;
                        continue;
index bcacd20d0c1c709ed3f983c4792393d851fa47d0..c6b9b67f43bfbbbcec0d1ae06f11aab17aa9d4ce 100644 (file)
@@ -19,6 +19,7 @@
 #define JITHEADER_MAGIC_SW     0x4454694A
 
 #define PADDING_8ALIGNED(x) ((((x) + 7) & 7) ^ 7)
+#define ALIGN_8(x) (((x) + 7) & (~7))
 
 #define JITHEADER_VERSION 1
 
@@ -48,6 +49,7 @@ enum jit_record_type {
         JIT_CODE_MOVE           = 1,
        JIT_CODE_DEBUG_INFO     = 2,
        JIT_CODE_CLOSE          = 3,
+       JIT_CODE_UNWINDING_INFO = 4,
 
        JIT_CODE_MAX,
 };
@@ -101,12 +103,22 @@ struct jr_code_debug_info {
        struct debug_entry entries[0];
 };
 
+struct jr_code_unwinding_info {
+       struct jr_prefix p;
+
+       uint64_t unwinding_size;
+       uint64_t eh_frame_hdr_size;
+       uint64_t mapped_size;
+       const char unwinding_data[0];
+};
+
 union jr_entry {
         struct jr_code_debug_info info;
         struct jr_code_close close;
         struct jr_code_load load;
         struct jr_code_move move;
         struct jr_prefix prefix;
+        struct jr_code_unwinding_info unwinding;
 };
 
 static inline struct debug_entry *
index bf7216b8731ddbbeb9326181857962d54c6c3d03..27b6f303720a4e61c62873d6116a2a351e880471 100644 (file)
@@ -339,7 +339,7 @@ dump_obj(const char *path, void *obj_buf, size_t size)
        char *p;
 
        if (!obj_path) {
-               pr_warning("WARNING: No enough memory, skip object dumping\n");
+               pr_warning("WARNING: Not enough memory, skip object dumping\n");
                return;
        }
 
index c662fef95d1444f243195e90370a7d5e97d06856..4f9a71c63026d185e48807895f0bee39570e8598 100644 (file)
@@ -682,9 +682,16 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp
                        continue;
 
                if (verbose >= 2) {
-                       fputs("overlapping maps:\n", fp);
-                       map__fprintf(map, fp);
-                       map__fprintf(pos, fp);
+
+                       if (use_browser) {
+                               pr_warning("overlapping maps in %s "
+                                          "(disable tui for more info)\n",
+                                          map->dso->name);
+                       } else {
+                               fputs("overlapping maps:\n", fp);
+                               map__fprintf(map, fp);
+                               map__fprintf(pos, fp);
+                       }
                }
 
                rb_erase_init(&pos->rb_node, root);
@@ -702,7 +709,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp
 
                        before->end = map->start;
                        __map_groups__insert(pos->groups, before);
-                       if (verbose >= 2)
+                       if (verbose >= 2 && !use_browser)
                                map__fprintf(before, fp);
                        map__put(before);
                }
@@ -717,7 +724,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp
 
                        after->start = map->end;
                        __map_groups__insert(pos->groups, after);
-                       if (verbose >= 2)
+                       if (verbose >= 2 && !use_browser)
                                map__fprintf(after, fp);
                        map__put(after);
                }
index afc088dd7d20948929aa087661f13f913b850b97..3634d6974300c07a5f9cb208ef36a3bfb3296913 100644 (file)
@@ -31,59 +31,51 @@ static const struct branch_mode branch_modes[] = {
        BRANCH_END
 };
 
-int
-parse_branch_stack(const struct option *opt, const char *str, int unset)
+int parse_branch_str(const char *str, __u64 *mode)
 {
 #define ONLY_PLM \
        (PERF_SAMPLE_BRANCH_USER        |\
         PERF_SAMPLE_BRANCH_KERNEL      |\
         PERF_SAMPLE_BRANCH_HV)
 
-       uint64_t *mode = (uint64_t *)opt->value;
+       int ret = 0;
+       char *p, *s;
+       char *os = NULL;
        const struct branch_mode *br;
-       char *s, *os = NULL, *p;
-       int ret = -1;
 
-       if (unset)
+       if (str == NULL) {
+               *mode = PERF_SAMPLE_BRANCH_ANY;
                return 0;
+       }
 
-       /*
-        * cannot set it twice, -b + --branch-filter for instance
-        */
-       if (*mode)
+       /* because str is read-only */
+       s = os = strdup(str);
+       if (!s)
                return -1;
 
-       /* str may be NULL in case no arg is passed to -b */
-       if (str) {
-               /* because str is read-only */
-               s = os = strdup(str);
-               if (!s)
-                       return -1;
-
-               for (;;) {
-                       p = strchr(s, ',');
-                       if (p)
-                               *p = '\0';
-
-                       for (br = branch_modes; br->name; br++) {
-                               if (!strcasecmp(s, br->name))
-                                       break;
-                       }
-                       if (!br->name) {
-                               ui__warning("unknown branch filter %s,"
-                                           " check man page\n", s);
-                               goto error;
-                       }
-
-                       *mode |= br->mode;
-
-                       if (!p)
-                               break;
+       for (;;) {
+               p = strchr(s, ',');
+               if (p)
+                       *p = '\0';
 
-                       s = p + 1;
+               for (br = branch_modes; br->name; br++) {
+                       if (!strcasecmp(s, br->name))
+                               break;
+               }
+               if (!br->name) {
+                       ret = -1;
+                       ui__warning("unknown branch filter %s,"
+                                   " check man page\n", s);
+                       goto error;
                }
+
+               *mode |= br->mode;
+
+               if (!p)
+                       break;
+
+               s = p + 1;
        }
-       ret = 0;
 
        /* default to any branch */
        if ((*mode & ~ONLY_PLM) == 0) {
@@ -93,3 +85,20 @@ error:
        free(os);
        return ret;
 }
+
+int
+parse_branch_stack(const struct option *opt, const char *str, int unset)
+{
+       __u64 *mode = (__u64 *)opt->value;
+
+       if (unset)
+               return 0;
+
+       /*
+        * cannot set it twice, -b + --branch-filter for instance
+        */
+       if (*mode)
+               return -1;
+
+       return parse_branch_str(str, mode);
+}
index b9d9470c2e82d30ee6ae87e2a65bf051a1b48876..6086fd90eb23a3c2454f0d7db8c7cd0509b0de64 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _PERF_PARSE_BRANCH_OPTIONS_H
 #define _PERF_PARSE_BRANCH_OPTIONS_H 1
-struct option;
+#include <stdint.h>
 int parse_branch_stack(const struct option *opt, const char *str, int unset);
+int parse_branch_str(const char *str, __u64 *mode);
 #endif /* _PERF_PARSE_BRANCH_OPTIONS_H */
index 4e778eae151046c358da9e0ea0b03ef92170bec0..3c876b8ba4de68afaf312e4bc6df07a4b58f0211 100644 (file)
@@ -22,6 +22,7 @@
 #include "cpumap.h"
 #include "probe-file.h"
 #include "asm/bug.h"
+#include "util/parse-branch-options.h"
 
 #define MAX_NAME_LEN 100
 
@@ -973,10 +974,13 @@ do {                                                                         \
                CHECK_TYPE_VAL(NUM);
                break;
        case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
-               /*
-                * TODO uncomment when the field is available
-                * attr->branch_sample_type = term->val.num;
-                */
+               CHECK_TYPE_VAL(STR);
+               if (strcmp(term->val.str, "no") &&
+                   parse_branch_str(term->val.str, &attr->branch_sample_type)) {
+                       err->str = strdup("invalid branch sample type");
+                       err->idx = term->err_val;
+                       return -EINVAL;
+               }
                break;
        case PARSE_EVENTS__TERM_TYPE_TIME:
                CHECK_TYPE_VAL(NUM);
@@ -1119,6 +1123,9 @@ do {                                                              \
                case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
                        ADD_CONFIG_TERM(CALLGRAPH, callgraph, term->val.str);
                        break;
+               case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
+                       ADD_CONFIG_TERM(BRANCH, branch, term->val.str);
+                       break;
                case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
                        ADD_CONFIG_TERM(STACK_USER, stack_user, term->val.num);
                        break;
index b1474dcadfa2b6f3f067c3cc40d0e6700756fa01..31b845ec32e24eb5667d075d83c84cbbe442786f 100644 (file)
@@ -504,6 +504,7 @@ static void pmu_add_cpu_aliases(struct list_head *head)
        struct pmu_events_map *map;
        struct pmu_event *pe;
        char *cpuid;
+       static bool printed;
 
        cpuid = getenv("PERF_CPUID");
        if (cpuid)
@@ -513,7 +514,10 @@ static void pmu_add_cpu_aliases(struct list_head *head)
        if (!cpuid)
                return;
 
-       pr_debug("Using CPUID %s\n", cpuid);
+       if (!printed) {
+               pr_debug("Using CPUID %s\n", cpuid);
+               printed = true;
+       }
 
        i = 0;
        while (1) {
@@ -1135,8 +1139,8 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
                        bool is_cpu = !strcmp(pmu->name, "cpu");
 
                        if (event_glob != NULL &&
-                           !(strglobmatch(name, event_glob) ||
-                             (!is_cpu && strglobmatch(alias->name,
+                           !(strglobmatch_nocase(name, event_glob) ||
+                             (!is_cpu && strglobmatch_nocase(alias->name,
                                                       event_glob))))
                                continue;
 
index 639d1da2f9786dee3b9e535724b5f1beaed3edda..293534c1a474352486df78087a4d452bcb96fe20 100644 (file)
@@ -54,7 +54,7 @@ int sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen)
                        break;
                ret = sq_quote_buf(dst, argv[i]);
                if (maxlen && dst->len > maxlen)
-                       die("Too many or long arguments");
+                       return -ENOSPC;
        }
        return ret;
 }
index 5d61242a6e648a1b65c8b9d16c93e02f8ed655cd..f268201048a0b69774cef2e6a8f4cb4a1634de01 100644 (file)
@@ -2025,20 +2025,10 @@ out_delete_map:
 void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
                                bool full)
 {
-       struct stat st;
-       int fd, ret;
-
        if (session == NULL || fp == NULL)
                return;
 
-       fd = perf_data_file__fd(session->file);
-
-       ret = fstat(fd, &st);
-       if (ret == -1)
-               return;
-
        fprintf(fp, "# ========\n");
-       fprintf(fp, "# captured on: %s", ctime(&st.st_ctime));
        perf_header__fprintf_info(session, fp, full);
        fprintf(fp, "# ========\n#\n");
 }
index 7f7e072be746f5985eb3c9ae5e84ad3ce9115b61..d8dfaf64b32e19af441b121803e4b4418d31c69e 100644 (file)
@@ -193,7 +193,8 @@ error:
 }
 
 /* Glob/lazy pattern matching */
-static bool __match_glob(const char *str, const char *pat, bool ignore_space)
+static bool __match_glob(const char *str, const char *pat, bool ignore_space,
+                       bool case_ins)
 {
        while (*str && *pat && *pat != '*') {
                if (ignore_space) {
@@ -219,8 +220,13 @@ static bool __match_glob(const char *str, const char *pat, bool ignore_space)
                                return false;
                else if (*pat == '\\') /* Escaped char match as normal char */
                        pat++;
-               if (*str++ != *pat++)
+               if (case_ins) {
+                       if (tolower(*str) != tolower(*pat))
+                               return false;
+               } else if (*str != *pat)
                        return false;
+               str++;
+               pat++;
        }
        /* Check wild card */
        if (*pat == '*') {
@@ -229,7 +235,7 @@ static bool __match_glob(const char *str, const char *pat, bool ignore_space)
                if (!*pat)      /* Tail wild card matches all */
                        return true;
                while (*str)
-                       if (__match_glob(str++, pat, ignore_space))
+                       if (__match_glob(str++, pat, ignore_space, case_ins))
                                return true;
        }
        return !*str && !*pat;
@@ -249,7 +255,12 @@ static bool __match_glob(const char *str, const char *pat, bool ignore_space)
  */
 bool strglobmatch(const char *str, const char *pat)
 {
-       return __match_glob(str, pat, false);
+       return __match_glob(str, pat, false, false);
+}
+
+bool strglobmatch_nocase(const char *str, const char *pat)
+{
+       return __match_glob(str, pat, false, true);
 }
 
 /**
@@ -262,7 +273,7 @@ bool strglobmatch(const char *str, const char *pat)
  */
 bool strlazymatch(const char *str, const char *pat)
 {
-       return __match_glob(str, pat, true);
+       return __match_glob(str, pat, true, false);
 }
 
 /**
index 20c2e5743903872771ae975b340b63aec521c3d3..6fec84dff3f777ac51f4f7201e2fb97d849d2aaf 100644 (file)
@@ -357,8 +357,8 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
                di.format   = UNW_INFO_FORMAT_REMOTE_TABLE;
                di.start_ip = map->start;
                di.end_ip   = map->end;
-               di.u.rti.segbase    = map->start + segbase;
-               di.u.rti.table_data = map->start + table_data;
+               di.u.rti.segbase    = map->start + segbase - map->pgoff;
+               di.u.rti.table_data = map->start + table_data - map->pgoff;
                di.u.rti.table_len  = fde_count * sizeof(struct table_entry)
                                      / sizeof(unw_word_t);
                ret = dwarf_search_unwind_table(as, ip, &di, pi,
index 43899e0d6fa148d80ebc08643d1fa9cf73ef93e9..71b6992f1d985d7db11bd6b97f0656faed7ddf7c 100644 (file)
@@ -222,6 +222,7 @@ s64 perf_atoll(const char *str);
 char **argv_split(const char *str, int *argcp);
 void argv_free(char **argv);
 bool strglobmatch(const char *str, const char *pat);
+bool strglobmatch_nocase(const char *str, const char *pat);
 bool strlazymatch(const char *str, const char *pat);
 static inline bool strisglob(const char *str)
 {
index 0fb3c1fcd3e62d0a1b26c032c0128ded5ef84035..5074be4ed467bcad894ccb2ed9936d593f12907f 100644 (file)
@@ -2,15 +2,18 @@
 
 #include "util.h"
 #include "values.h"
+#include "debug.h"
 
-void perf_read_values_init(struct perf_read_values *values)
+int perf_read_values_init(struct perf_read_values *values)
 {
        values->threads_max = 16;
        values->pid = malloc(values->threads_max * sizeof(*values->pid));
        values->tid = malloc(values->threads_max * sizeof(*values->tid));
        values->value = malloc(values->threads_max * sizeof(*values->value));
-       if (!values->pid || !values->tid || !values->value)
-               die("failed to allocate read_values threads arrays");
+       if (!values->pid || !values->tid || !values->value) {
+               pr_debug("failed to allocate read_values threads arrays");
+               goto out_free_pid;
+       }
        values->threads = 0;
 
        values->counters_max = 16;
@@ -18,9 +21,22 @@ void perf_read_values_init(struct perf_read_values *values)
                                      * sizeof(*values->counterrawid));
        values->countername = malloc(values->counters_max
                                     * sizeof(*values->countername));
-       if (!values->counterrawid || !values->countername)
-               die("failed to allocate read_values counters arrays");
+       if (!values->counterrawid || !values->countername) {
+               pr_debug("failed to allocate read_values counters arrays");
+               goto out_free_counter;
+       }
        values->counters = 0;
+
+       return 0;
+
+out_free_counter:
+       zfree(&values->counterrawid);
+       zfree(&values->countername);
+out_free_pid:
+       zfree(&values->pid);
+       zfree(&values->tid);
+       zfree(&values->value);
+       return -ENOMEM;
 }
 
 void perf_read_values_destroy(struct perf_read_values *values)
@@ -41,17 +57,27 @@ void perf_read_values_destroy(struct perf_read_values *values)
        zfree(&values->countername);
 }
 
-static void perf_read_values__enlarge_threads(struct perf_read_values *values)
+static int perf_read_values__enlarge_threads(struct perf_read_values *values)
 {
-       values->threads_max *= 2;
-       values->pid = realloc(values->pid,
-                             values->threads_max * sizeof(*values->pid));
-       values->tid = realloc(values->tid,
-                             values->threads_max * sizeof(*values->tid));
-       values->value = realloc(values->value,
-                               values->threads_max * sizeof(*values->value));
-       if (!values->pid || !values->tid || !values->value)
-               die("failed to enlarge read_values threads arrays");
+       int nthreads_max = values->threads_max * 2;
+       void *npid = realloc(values->pid, nthreads_max * sizeof(*values->pid)),
+            *ntid = realloc(values->tid, nthreads_max * sizeof(*values->tid)),
+            *nvalue = realloc(values->value, nthreads_max * sizeof(*values->value));
+
+       if (!npid || !ntid || !nvalue)
+               goto out_err;
+
+       values->threads_max = nthreads_max;
+       values->pid = npid;
+       values->tid = ntid;
+       values->value = nvalue;
+       return 0;
+out_err:
+       free(npid);
+       free(ntid);
+       free(nvalue);
+       pr_debug("failed to enlarge read_values threads arrays");
+       return -ENOMEM;
 }
 
 static int perf_read_values__findnew_thread(struct perf_read_values *values,
@@ -63,15 +89,21 @@ static int perf_read_values__findnew_thread(struct perf_read_values *values,
                if (values->pid[i] == pid && values->tid[i] == tid)
                        return i;
 
-       if (values->threads == values->threads_max)
-               perf_read_values__enlarge_threads(values);
+       if (values->threads == values->threads_max) {
+               i = perf_read_values__enlarge_threads(values);
+               if (i < 0)
+                       return i;
+       }
 
-       i = values->threads++;
+       i = values->threads + 1;
+       values->value[i] = malloc(values->counters_max * sizeof(**values->value));
+       if (!values->value[i]) {
+               pr_debug("failed to allocate read_values counters array");
+               return -ENOMEM;
+       }
        values->pid[i] = pid;
        values->tid[i] = tid;
-       values->value[i] = malloc(values->counters_max * sizeof(**values->value));
-       if (!values->value[i])
-               die("failed to allocate read_values counters array");
+       values->threads = i;
 
        return i;
 }
@@ -115,16 +147,21 @@ static int perf_read_values__findnew_counter(struct perf_read_values *values,
        return i;
 }
 
-void perf_read_values_add_value(struct perf_read_values *values,
+int perf_read_values_add_value(struct perf_read_values *values,
                                u32 pid, u32 tid,
                                u64 rawid, const char *name, u64 value)
 {
        int tindex, cindex;
 
        tindex = perf_read_values__findnew_thread(values, pid, tid);
+       if (tindex < 0)
+               return tindex;
        cindex = perf_read_values__findnew_counter(values, rawid, name);
+       if (cindex < 0)
+               return cindex;
 
        values->value[tindex][cindex] = value;
+       return 0;
 }
 
 static void perf_read_values__display_pretty(FILE *fp,
index b21a80c6cf8def4fe265a301f0bbf69078f7409a..808ff9c73bf5d4dfb4b3e50f9ee8297904b11019 100644 (file)
@@ -14,10 +14,10 @@ struct perf_read_values {
        u64 **value;
 };
 
-void perf_read_values_init(struct perf_read_values *values);
+int perf_read_values_init(struct perf_read_values *values);
 void perf_read_values_destroy(struct perf_read_values *values);
 
-void perf_read_values_add_value(struct perf_read_values *values,
+int perf_read_values_add_value(struct perf_read_values *values,
                                u32 pid, u32 tid,
                                u64 rawid, const char *name, u64 value);