Commit 891e8abe authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'perf-tools-for-v6.12-1-2024-09-19' of...

Merge tag 'perf-tools-for-v6.12-1-2024-09-19' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools

Pull perf tools updates from Arnaldo Carvalho de Melo:

 - Use BPF + BTF to collect and pretty print syscall and tracepoint
   arguments in 'perf trace', done as an GSoC activity

 - Data-type profiling improvements:

     - Cache debuginfo to speed up data type resolution

     - Add the 'typecln' sort order, to show which cacheline in a target
       is hot or cold. The following shows members in the cfs_rq's first
       cache line:

         $ perf report -s type,typecln,typeoff -H
         ...
         -    2.67%        struct cfs_rq
            +    1.23%        struct cfs_rq: cache-line 2
            +    0.57%        struct cfs_rq: cache-line 4
            +    0.46%        struct cfs_rq: cache-line 6
            -    0.41%        struct cfs_rq: cache-line 0
                    0.39%        struct cfs_rq +0x14 (h_nr_running)
                    0.02%        struct cfs_rq +0x38 (tasks_timeline.rb_leftmost)

     - When a typedef resolves to a unnamed struct, use the typedef name

     - When a struct has just one basic type field (int, etc), resolve
       the type sort order to the name of the struct, not the type of
       the field

     - Support type folding/unfolding in the data-type annotation TUI

     - Fix bitfields offsets and sizes

     - Initial support for PowerPC, using libcapstone and the usual
       objdump disassembly parsing routines

 - Add support for disassembling and addr2line using the LLVM libraries,
   speeding up those operations

 - Support --addr2line option in 'perf script' as with other tools

 - Intel branch counters (LBR event logging) support, only available in
   recent Intel processors, for instance, the new "brcntr" field can be
   asked from 'perf script' to print the information collected from this
   feature:

     $ perf script -F +brstackinsn,+brcntr

     # Branch counter abbr list:
     # branch-instructions:ppp = A
     # branch-misses = B
     # '-' No event occurs
     # '+' Event occurrences may be lost due to branch counter saturated
         tchain_edit  332203 3366329.405674:  53030 branch-instructions:ppp:    401781 f3+0x2c (home/sdp/test/tchain_edit)
            f3+31:
         0000000000401774   insn: eb 04                  br_cntr: AA  # PRED 5 cycles [5]
         000000000040177a   insn: 81 7d fc 0f 27 00 00
         0000000000401781   insn: 7e e3                  br_cntr: A   # PRED 1 cycles [6] 2.00 IPC
         0000000000401766   insn: 8b 45 fc
         0000000000401769   insn: 83 e0 01
         000000000040176c   insn: 85 c0
         000000000040176e   insn: 74 06                  br_cntr: A   # PRED 1 cycles [7] 4.00 IPC
         0000000000401776   insn: 83 45 fc 01
         000000000040177a   insn: 81 7d fc 0f 27 00 00
         0000000000401781   insn: 7e e3                  br_cntr: A   # PRED 7 cycles [14] 0.43 IPC

 - Support Timed PEBS (Precise Event-Based Sampling), a recent hardware
   feature in Intel processors

 - Add 'perf ftrace profile' subcommand, using ftrace's function-graph
   tracer so that users can see the total, average, max execution time
   as well as the number of invocations easily, for instance:

     $ sudo perf ftrace profile -G __x64_sys_perf_event_open -- \
       perf stat -e cycles -C1 true 2> /dev/null | head
     # Total (us)  Avg (us)  Max (us)  Count  Function
           65.611    65.611    65.611      1  __x64_sys_perf_event_open
           30.527    30.527    30.527      1  anon_inode_getfile
           30.260    30.260    30.260      1  __anon_inode_getfile
           29.700    29.700    29.700      1  alloc_file_pseudo
           17.578    17.578    17.578      1  d_alloc_pseudo
           17.382    17.382    17.382      1  __d_alloc
           16.738    16.738    16.738      1  kmem_cache_alloc_lru
           15.686    15.686    15.686      1  perf_event_alloc
           14.012     7.006    11.264      2  obj_cgroup_charge

 - 'perf sched timehist' improvements, including the addition of
   priority showing/filtering command line options

 - Varios improvements to the 'perf probe', including 'perf test'
   regression testings

 - Introduce the 'perf check', initially to check if some feature is
   in place, using it in 'perf test'

 - Various fixes for 32-bit systems

 - Address more leak sanitizer failures

 - Fix memory leaks (LBR, disasm lock ops, etc)

 - More reference counting fixes (branch_info, etc)

 - Constify 'struct perf_tool' parameters to improve code generation
   and reduce the chances of having its internals changed, which isn't
   expected

 - More constifications in various other places

 - Add more build tests, including for JEVENTS

 - Add more 'perf test' entries ('perf record LBR', pipe/inject,
   --setup-filter, 'perf ftrace', 'cgroup sampling', etc)

 - Inject build ids for all entries in a call chain in 'perf inject',
   not just for the main sample

 - Improve the BPF based sample filter, allowing root to setup filters
   in bpffs that then can be used by non-root users

 - Allow filtering by cgroups with the BPF based sample filter

 - Allow a more compact way for 'perf mem report' using the
   -T/--type-profile and also provide a --sort option similar to the one
   in 'perf report', 'perf top', to setup the sort order manually

 - Fix --group behavior in 'perf annotate' when leader has no samples,
   where it was not showing anything even when other events in the group
   had samples

 - Fix spinlock and rwlock accounting in 'perf lock contention'

 - Fix libsubcmd fixdep Makefile dependencies

 - Improve 'perf ftrace' error message when ftrace isn't available

 - Update various Intel JSON vendor event files

 - ARM64 CoreSight hardware tracing infrastructure improvements, mostly
   not visible to users

 - Update power10 JSON events

* tag 'perf-tools-for-v6.12-1-2024-09-19' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools: (310 commits)
  perf trace: Mark the 'head' arg in the set_robust_list syscall as coming from user space
  perf trace: Mark the 'rseq' arg in the rseq syscall as coming from user space
  perf env: Find correct branch counter info on hybrid
  perf evlist: Print hint for group
  tools: Drop nonsensical -O6
  perf pmu: To info add event_type_desc
  perf evsel: Add accessor for tool_event
  perf pmus: Fake PMU clean up
  perf list: Avoid potential out of bounds memory read
  perf help: Fix a typo ("bellow")
  perf ftrace: Detect whether ftrace is enabled on system
  perf test shell probe_vfs_getname: Remove extraneous '=' from probe line number regex
  perf build: Require at least clang 16.0.6 to build BPF skeletons
  perf trace: If a syscall arg is marked as 'const', assume it is coming _from_ userspace
  perf parse-events: Remove duplicated include in parse-events.c
  perf callchain: Allow symbols to be optional when resolving a callchain
  perf inject: Lazy build-id mmap2 event insertion
  perf inject: Add new mmap2-buildid-all option
  perf inject: Fix build ID injection
  perf annotate-data: Add pr_debug_scope()
  ...
parents 673a5009 1de5b5dc
hostprogs := fixdep
fixdep-y := fixdep.o
......@@ -43,12 +43,5 @@ ifneq ($(wildcard $(TMP_O)),)
$(Q)$(MAKE) -C feature OUTPUT=$(TMP_O) clean >/dev/null
endif
$(OUTPUT)fixdep-in.o: FORCE
$(Q)$(MAKE) $(build)=fixdep
$(OUTPUT)fixdep: $(OUTPUT)fixdep-in.o
$(QUIET_LINK)$(HOSTCC) $(KBUILD_HOSTLDFLAGS) -o $@ $<
FORCE:
.PHONY: FORCE
$(OUTPUT)fixdep: $(srctree)/tools/build/fixdep.c
$(QUIET_CC)$(HOSTCC) $(KBUILD_HOSTCFLAGS) $(KBUILD_HOSTLDFLAGS) -o $@ $<
......@@ -100,7 +100,6 @@ FEATURE_TESTS_EXTRA := \
libunwind-debug-frame-aarch64 \
cxx \
llvm \
llvm-version \
clang \
libbpf \
libbpf-btf__load_from_kernel_by_id \
......@@ -136,6 +135,7 @@ FEATURE_DISPLAY ?= \
libunwind \
libdw-dwarf-unwind \
libcapstone \
llvm-perf \
zlib \
lzma \
get_cpuid \
......
# SPDX-License-Identifier: GPL-2.0-only
build := -f $(srctree)/tools/build/Makefile.build dir=. obj
# More than just $(Q), we sometimes want to suppress all command output from a
# recursive make -- even the 'up to date' printout.
ifeq ($(V),1)
Q ?=
SILENT_MAKE = +$(Q)$(MAKE)
else
Q ?= @
SILENT_MAKE = +$(Q)$(MAKE) --silent
endif
fixdep:
$(Q)$(MAKE) -C $(srctree)/tools/build CFLAGS= LDFLAGS= $(OUTPUT)fixdep
$(SILENT_MAKE) -C $(srctree)/tools/build CFLAGS= LDFLAGS= $(OUTPUT)fixdep
fixdep-clean:
$(Q)$(MAKE) -C $(srctree)/tools/build clean
......
......@@ -73,7 +73,7 @@ FILES= \
test-libopencsd.bin \
test-clang.bin \
test-llvm.bin \
test-llvm-version.bin \
test-llvm-perf.bin \
test-libaio.bin \
test-libzstd.bin \
test-clang-bpf-co-re.bin \
......@@ -388,9 +388,12 @@ $(OUTPUT)test-llvm.bin:
$(shell $(LLVM_CONFIG) --system-libs) \
> $(@:.bin=.make.output) 2>&1
$(OUTPUT)test-llvm-version.bin:
$(BUILDXX) -std=gnu++17 \
-I$(shell $(LLVM_CONFIG) --includedir) \
$(OUTPUT)test-llvm-perf.bin:
$(BUILDXX) -std=gnu++17 \
-I$(shell $(LLVM_CONFIG) --includedir) \
-L$(shell $(LLVM_CONFIG) --libdir) \
$(shell $(LLVM_CONFIG) --libs Core BPF) \
$(shell $(LLVM_CONFIG) --system-libs) \
> $(@:.bin=.make.output) 2>&1
$(OUTPUT)test-clang.bin:
......
......@@ -134,10 +134,6 @@
#undef main
#endif
#define main main_test_libcapstone
# include "test-libcapstone.c"
#undef main
#define main main_test_lzma
# include "test-lzma.c"
#undef main
......
// SPDX-License-Identifier: GPL-2.0
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/raw_ostream.h"
#if LLVM_VERSION_MAJOR < 13
# error "Perf requires llvm-devel/llvm-dev version 13 or greater"
#endif
int main()
{
llvm::errs() << "Hello World!\n";
llvm::llvm_shutdown();
return 0;
}
......@@ -49,12 +49,21 @@
* Interpretation of the PERF_RECORD_AUX_OUTPUT_HW_ID payload.
* Used to associate a CPU with the CoreSight Trace ID.
* [07:00] - Trace ID - uses 8 bits to make value easy to read in file.
* [59:08] - Unused (SBZ)
* [63:60] - Version
* [39:08] - Sink ID - as reported in /sys/bus/event_source/devices/cs_etm/sinks/
* Added in minor version 1.
* [55:40] - Unused (SBZ)
* [59:56] - Minor Version - previously existing fields are compatible with
* all minor versions.
* [63:60] - Major Version - previously existing fields mean different things
* in new major versions.
*/
#define CS_AUX_HW_ID_TRACE_ID_MASK GENMASK_ULL(7, 0)
#define CS_AUX_HW_ID_VERSION_MASK GENMASK_ULL(63, 60)
#define CS_AUX_HW_ID_SINK_ID_MASK GENMASK_ULL(39, 8)
#define CS_AUX_HW_ID_CURR_VERSION 0
#define CS_AUX_HW_ID_MINOR_VERSION_MASK GENMASK_ULL(59, 56)
#define CS_AUX_HW_ID_MAJOR_VERSION_MASK GENMASK_ULL(63, 60)
#define CS_AUX_HW_ID_MAJOR_VERSION 0
#define CS_AUX_HW_ID_MINOR_VERSION 1
#endif
......@@ -46,5 +46,7 @@ extern char * __must_check skip_spaces(const char *);
extern char *strim(char *);
extern void remove_spaces(char *s);
extern void *memchr_inv(const void *start, int c, size_t bytes);
#endif /* _TOOLS_LINUX_STRING_H_ */
......@@ -31,11 +31,7 @@ CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -U_FORTIFY_SOURCE -fPIC
ifeq ($(DEBUG),0)
ifeq ($(CC_NO_CLANG), 0)
CFLAGS += -O3
else
CFLAGS += -O6
endif
endif
ifeq ($(DEBUG),0)
......
......@@ -69,7 +69,7 @@ char *get_tracing_file(const char *name)
{
char *file;
if (asprintf(&file, "%s/%s", tracing_path_mount(), name) < 0)
if (asprintf(&file, "%s%s", tracing_path_mount(), name) < 0)
return NULL;
return file;
......
......@@ -5,3 +5,4 @@ TAGS
tags
cscope.*
/bpf_helper_defs.h
fixdep
......@@ -108,6 +108,8 @@ MAKEOVERRIDES=
all:
OUTPUT ?= ./
OUTPUT := $(abspath $(OUTPUT))/
export srctree OUTPUT CC LD CFLAGS V
include $(srctree)/tools/build/Makefile.include
......@@ -141,7 +143,10 @@ all: fixdep
all_cmd: $(CMD_TARGETS) check
$(BPF_IN_SHARED): force $(BPF_GENERATED)
$(SHARED_OBJDIR) $(STATIC_OBJDIR):
$(Q)mkdir -p $@
$(BPF_IN_SHARED): force $(BPF_GENERATED) | $(SHARED_OBJDIR)
@(test -f ../../include/uapi/linux/bpf.h -a -f ../../../include/uapi/linux/bpf.h && ( \
(diff -B ../../include/uapi/linux/bpf.h ../../../include/uapi/linux/bpf.h >/dev/null) || \
echo "Warning: Kernel ABI header at 'tools/include/uapi/linux/bpf.h' differs from latest version at 'include/uapi/linux/bpf.h'" >&2 )) || true
......@@ -151,9 +156,11 @@ $(BPF_IN_SHARED): force $(BPF_GENERATED)
@(test -f ../../include/uapi/linux/if_xdp.h -a -f ../../../include/uapi/linux/if_xdp.h && ( \
(diff -B ../../include/uapi/linux/if_xdp.h ../../../include/uapi/linux/if_xdp.h >/dev/null) || \
echo "Warning: Kernel ABI header at 'tools/include/uapi/linux/if_xdp.h' differs from latest version at 'include/uapi/linux/if_xdp.h'" >&2 )) || true
$(SILENT_MAKE) -C $(srctree)/tools/build CFLAGS= LDFLAGS= OUTPUT=$(SHARED_OBJDIR) $(SHARED_OBJDIR)fixdep
$(Q)$(MAKE) $(build)=libbpf OUTPUT=$(SHARED_OBJDIR) CFLAGS="$(CFLAGS) $(SHLIB_FLAGS)"
$(BPF_IN_STATIC): force $(BPF_GENERATED)
$(BPF_IN_STATIC): force $(BPF_GENERATED) | $(STATIC_OBJDIR)
$(SILENT_MAKE) -C $(srctree)/tools/build CFLAGS= LDFLAGS= OUTPUT=$(STATIC_OBJDIR) $(STATIC_OBJDIR)fixdep
$(Q)$(MAKE) $(build)=libbpf OUTPUT=$(STATIC_OBJDIR)
$(BPF_HELPER_DEFS): $(srctree)/tools/include/uapi/linux/bpf.h
......@@ -263,7 +270,7 @@ install_pkgconfig: $(PC_FILE)
install: install_lib install_pkgconfig install_headers
clean:
clean: fixdep-clean
$(call QUIET_CLEAN, libbpf) $(RM) -rf $(CMD_TARGETS) \
*~ .*.d .*.cmd LIBBPF-CFLAGS $(BPF_GENERATED) \
$(SHARED_OBJDIR) $(STATIC_OBJDIR) \
......
# SPDX-License-Identifier: GPL-2.0-only
libperf.pc
libperf.so.*
tests-shared
tests-static
......@@ -153,6 +153,19 @@ char *strim(char *s)
return skip_spaces(s);
}
/*
* remove_spaces - Removes whitespaces from @s
*/
void remove_spaces(char *s)
{
char *d = s;
do {
while (*d == ' ')
++d;
} while ((*s++ = *d++));
}
/**
* strreplace - Replace all occurrences of character in string.
* @s: The string to operate on.
......
......@@ -38,10 +38,8 @@ endif
ifeq ($(DEBUG),1)
CFLAGS += -O0
else ifeq ($(CC_NO_CLANG), 0)
CFLAGS += -O3
else
CFLAGS += -O6
CFLAGS += -O3
endif
# Treat warnings as errors unless directed not to
......@@ -76,7 +74,7 @@ include $(srctree)/tools/build/Makefile.include
all: fixdep $(LIBFILE)
$(SUBCMD_IN): FORCE
$(SUBCMD_IN): fixdep FORCE
@$(MAKE) $(build)=libsubcmd
$(LIBFILE): $(SUBCMD_IN)
......
......@@ -633,10 +633,11 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o
const char *const subcommands[], const char *usagestr[], int flags)
{
struct parse_opt_ctx_t ctx;
char *buf = NULL;
/* build usage string if it's not provided */
if (subcommands && !usagestr[0]) {
char *buf = NULL;
astrcatf(&buf, "%s %s [<options>] {", subcmd_config.exec_name, argv[0]);
for (int i = 0; subcommands[i]; i++) {
......@@ -678,10 +679,7 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o
astrcatf(&error_buf, "unknown switch `%c'", *ctx.opt);
usage_with_options(usagestr, options);
}
if (buf) {
usagestr[0] = NULL;
free(buf);
}
return parse_options_end(&ctx);
}
......
......@@ -31,11 +31,7 @@ CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
CFLAGS += -ggdb3 -Wall -Wextra -std=gnu11 -U_FORTIFY_SOURCE -fPIC
ifeq ($(DEBUG),0)
ifeq ($(CC_NO_CLANG), 0)
CFLAGS += -O3
else
CFLAGS += -O6
endif
endif
ifeq ($(DEBUG),0)
......
perf-bench-y += builtin-bench.o
perf-y += builtin-annotate.o
perf-y += builtin-check.o
perf-y += builtin-config.o
perf-y += builtin-diff.o
perf-y += builtin-evlist.o
......
......@@ -165,6 +165,9 @@ include::itrace.txt[]
--type-stat::
Show stats for the data type annotation.
--skip-empty::
Do not display empty (or dummy) events.
SEE ALSO
--------
......
perf-check(1)
===============
NAME
----
perf-check - check if features are present in perf
SYNOPSIS
--------
[verse]
'perf check' [<options>]
'perf check' {feature <feature_list>} [<options>]
DESCRIPTION
-----------
With no subcommands given, 'perf check' command just prints the command
usage on the standard output.
If the subcommand 'feature' is used, then status of feature is printed
on the standard output (unless '-q' is also passed), ie. whether it is
compiled-in/built-in or not.
Also, 'perf check feature' returns with exit status 0 if the feature
is built-in, otherwise returns with exit status 1.
SUBCOMMANDS
-----------
feature::
Print whether feature(s) is compiled-in or not, and also returns with an
exit status of 0, if passed feature(s) are compiled-in, else 1.
It expects a feature list as an argument. There can be a single feature
name/macro, or multiple features can also be passed as a comma-separated
list, in which case the exit status will be 0 only if all of the passed
features are compiled-in.
The feature names/macros are case-insensitive.
Example Usage:
perf check feature libtraceevent
perf check feature HAVE_LIBTRACEEVENT
perf check feature libtraceevent,bpf
Supported feature names/macro:
aio / HAVE_AIO_SUPPORT
bpf / HAVE_LIBBPF_SUPPORT
bpf_skeletons / HAVE_BPF_SKEL
debuginfod / HAVE_DEBUGINFOD_SUPPORT
dwarf / HAVE_DWARF_SUPPORT
dwarf_getlocations / HAVE_DWARF_GETLOCATIONS_SUPPORT
dwarf-unwind / HAVE_DWARF_UNWIND_SUPPORT
auxtrace / HAVE_AUXTRACE_SUPPORT
libaudit / HAVE_LIBAUDIT_SUPPORT
libbfd / HAVE_LIBBFD_SUPPORT
libcapstone / HAVE_LIBCAPSTONE_SUPPORT
libcrypto / HAVE_LIBCRYPTO_SUPPORT
libdw-dwarf-unwind / HAVE_DWARF_SUPPORT
libelf / HAVE_LIBELF_SUPPORT
libnuma / HAVE_LIBNUMA_SUPPORT
libopencsd / HAVE_CSTRACE_SUPPORT
libperl / HAVE_LIBPERL_SUPPORT
libpfm4 / HAVE_LIBPFM
libpython / HAVE_LIBPYTHON_SUPPORT
libslang / HAVE_SLANG_SUPPORT
libtraceevent / HAVE_LIBTRACEEVENT
libunwind / HAVE_LIBUNWIND_SUPPORT
lzma / HAVE_LZMA_SUPPORT
numa_num_possible_cpus / HAVE_LIBNUMA_SUPPORT
syscall_table / HAVE_SYSCALL_TABLE_SUPPORT
zlib / HAVE_ZLIB_SUPPORT
zstd / HAVE_ZSTD_SUPPORT
OPTIONS
-------
-q::
--quiet::
Do not print any messages or warnings
This can be used along with subcommands such as 'perf check feature'
to hide unnecessary output in test scripts, eg.
'perf check feature --quiet libtraceevent'
......@@ -9,7 +9,7 @@ perf-ftrace - simple wrapper for kernel's ftrace functionality
SYNOPSIS
--------
[verse]
'perf ftrace' {trace|latency} <command>
'perf ftrace' {trace|latency|profile} <command>
DESCRIPTION
-----------
......@@ -23,6 +23,9 @@ kernel's ftrace infrastructure.
'perf ftrace latency' calculates execution latency of a given function
(optionally with BPF) and display it as a histogram.
'perf ftrace profile' show a execution profile for each function including
total, average, max time and the number of calls.
The following options apply to perf ftrace.
COMMON OPTIONS
......@@ -125,6 +128,7 @@ OPTIONS for 'perf ftrace trace'
- verbose - Show process names, PIDs, timestamps, etc.
- thresh=<n> - Setup trace duration threshold in microseconds.
- depth=<n> - Set max depth for function graph tracer to follow.
- tail - Print function name at the end.
OPTIONS for 'perf ftrace latency'
......@@ -145,6 +149,48 @@ OPTIONS for 'perf ftrace latency'
Use nano-second instead of micro-second as a base unit of the histogram.
OPTIONS for 'perf ftrace profile'
---------------------------------
-T::
--trace-funcs=::
Set function filter on the given function (or a glob pattern).
Multiple functions can be given by using this option more than once.
The function argument also can be a glob pattern. It will be passed
to 'set_ftrace_filter' in tracefs.
-N::
--notrace-funcs=::
Do not trace functions given by the argument. Like -T option, this
can be used more than once to specify multiple functions (or glob
patterns). It will be passed to 'set_ftrace_notrace' in tracefs.
-G::
--graph-funcs=::
Set graph filter on the given function (or a glob pattern). This is
useful to trace for functions executed from the given function. This
can be used more than once to specify multiple functions. It will be
passed to 'set_graph_function' in tracefs.
-g::
--nograph-funcs=::
Set graph notrace filter on the given function (or a glob pattern).
Like -G option, this is useful for the function_graph tracer only and
disables tracing for function executed from the given function. This
can be used more than once to specify multiple functions. It will be
passed to 'set_graph_notrace' in tracefs.
-m::
--buffer-size::
Set the size of per-cpu tracing buffer, <size> is expected to
be a number with appended unit character - B/K/M/G.
-s::
--sort=::
Sort the result by the given field. Available values are:
total, avg, max, count, name. Default is 'total'.
SEE ALSO
--------
linkperf:perf-record[1], linkperf:perf-trace[1]
......@@ -115,9 +115,9 @@ STAT LIVE OPTIONS
-m::
--mmap-pages=::
Number of mmap data pages (must be a power of two) or size
specification with appended unit character - B/K/M/G. The
size is rounded up to have nearest pages power of two value.
Number of mmap data pages (must be a power of two) or size
specification in bytes with appended unit character - B/K/M/G.
The size is rounded up to the nearest power-of-two page value.
-a::
--all-cpus::
......
......@@ -72,6 +72,7 @@ counted. The following modifiers exist:
W - group is weak and will fallback to non-group if not schedulable,
e - group or event are exclusive and do not share the PMU
b - use BPF aggregration (see perf stat --bpf-counters)
R - retire latency value of the event
The 'p' modifier can be used for specifying how precise the instruction
address should be. The 'p' modifier can be specified multiple times:
......
......@@ -28,15 +28,8 @@ and kernel support is required. See linkperf:perf-arm-spe[1] for a setup guide.
Due to the statistical nature of SPE sampling, not every memory operation will
be sampled.
OPTIONS
-------
<command>...::
Any command you can specify in a shell.
-i::
--input=<file>::
Input file name.
COMMON OPTIONS
--------------
-f::
--force::
Don't do ownership validation
......@@ -45,24 +38,9 @@ OPTIONS
--type=<type>::
Select the memory operation type: load or store (default: load,store)
-D::
--dump-raw-samples::
Dump the raw decoded samples on the screen in a format that is easy to parse with
one sample per line.
-x::
--field-separator=<separator>::
Specify the field separator used when dump raw samples (-D option). By default,
The separator is the space character.
-C::
--cpu=<cpu>::
Monitor only on the list of CPUs provided. Multiple CPUs can be provided as a
comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. Default
is to monitor all CPUS.
-U::
--hide-unresolved::
Only display entries resolved to a symbol.
-v::
--verbose::
Be more verbose (show counter open errors, etc)
-p::
--phys-data::
......@@ -73,6 +51,9 @@ OPTIONS
RECORD OPTIONS
--------------
<command>...::
Any command you can specify in a shell.
-e::
--event <event>::
Event selector. Use 'perf mem record -e list' to list available events.
......@@ -85,14 +66,65 @@ RECORD OPTIONS
--all-user::
Configure all used events to run in user space.
-v::
--verbose::
Be more verbose (show counter open errors, etc)
--ldlat <n>::
Specify desired latency for loads event. Supported on Intel and Arm64
processors only. Ignored on other archs.
REPORT OPTIONS
--------------
-i::
--input=<file>::
Input file name.
-C::
--cpu=<cpu>::
Monitor only on the list of CPUs provided. Multiple CPUs can be provided as a
comma-separated list with no space: 0,1. Ranges of CPUs are specified with -
like 0-2. Default is to monitor all CPUS.
-D::
--dump-raw-samples::
Dump the raw decoded samples on the screen in a format that is easy to parse with
one sample per line.
-s::
--sort=<key>::
Group result by given key(s) - multiple keys can be specified
in CSV format. The keys are specific to memory samples are:
symbol_daddr, symbol_iaddr, dso_daddr, locked, tlb, mem, snoop,
dcacheline, phys_daddr, data_page_size, blocked.
- symbol_daddr: name of data symbol being executed on at the time of sample
- symbol_iaddr: name of code symbol being executed on at the time of sample
- dso_daddr: name of library or module containing the data being executed
on at the time of the sample
- locked: whether the bus was locked at the time of the sample
- tlb: type of tlb access for the data at the time of the sample
- mem: type of memory access for the data at the time of the sample
- snoop: type of snoop (if any) for the data at the time of the sample
- dcacheline: the cacheline the data address is on at the time of the sample
- phys_daddr: physical address of data being executed on at the time of sample
- data_page_size: the data page size of data being executed on at the time of sample
- blocked: reason of blocked load access for the data at the time of the sample
And the default sort keys are changed to local_weight, mem, sym, dso,
symbol_daddr, dso_daddr, snoop, tlb, locked, blocked, local_ins_lat.
-T::
--type-profile::
Show data-type profile result instead of code symbols. This requires
the debug information and it will change the default sort keys to:
mem, snoop, tlb, type.
-U::
--hide-unresolved::
Only display entries resolved to a symbol.
-x::
--field-separator=<separator>::
Specify the field separator used when dump raw samples (-D option). By default,
The separator is the space character.
In addition, for report all perf report options are valid, and for record
all perf record options.
......
......@@ -273,10 +273,11 @@ OPTIONS
-m::
--mmap-pages=::
Number of mmap data pages (must be a power of two) or size
specification with appended unit character - B/K/M/G. The
size is rounded up to have nearest pages power of two value.
Also, by adding a comma, the number of mmap pages for AUX
area tracing can be specified.
specification in bytes with appended unit character - B/K/M/G.
The size is rounded up to the nearest power-of-two page value.
By adding a comma, an additional parameter with the same
semantics used for the normal mmap areas can be specified for
AUX tracing area.
-g::
Enables call-graph (stack chain/backtrace) recording for both
......@@ -828,6 +829,11 @@ filtered through the mask provided by -C option.
only, as of now. So the applications built without the frame
pointer might see bogus addresses.
--setup-filter=<action>::
Prepare BPF filter to be used by regular users. The action should be
either "pin" or "unpin". The filter can be used after it's pinned.
include::intel-hybrid.txt[]
SEE ALSO
......
......@@ -614,6 +614,7 @@ include::itrace.txt[]
'Avg Cycles%' - block average sampled cycles / sum of total block average
sampled cycles
'Avg Cycles' - block average sampled cycles
'Branch Counter' - block branch counter histogram (with -v showing the number)
--skip-empty::
Do not print 0 results in the --stat output.
......
......@@ -212,6 +212,15 @@ OPTIONS for 'perf sched timehist'
--state::
Show task state when it switched out.
--show-prio::
Show task priority.
--prio::
Only show events for given task priority(ies). Multiple priorities can be
provided as a comma-separated list with no spaces: 0,120. Ranges of
priorities are specified with -: 120-129. A combination of both can also be
provided: 0,120-129.
OPTIONS for 'perf sched replay'
------------------------------
......
......@@ -134,7 +134,7 @@ OPTIONS
srcline, period, iregs, uregs, brstack, brstacksym, flags, bpf-output,
brstackinsn, brstackinsnlen, brstackdisasm, brstackoff, callindent, insn, disasm,
insnlen, synth, phys_addr, metric, misc, srccode, ipc, data_page_size,
code_page_size, ins_lat, machine_pid, vcpu, cgroup, retire_lat,
code_page_size, ins_lat, machine_pid, vcpu, cgroup, retire_lat, brcntr,
Field list can be prepended with the type, trace, sw or hw,
to indicate to which event type the field list applies.
......@@ -369,6 +369,9 @@ OPTIONS
--demangle-kernel::
Demangle kernel symbol names to human readable form (for C++ kernels).
--addr2line=<path>::
Path to addr2line binary.
--header
Show perf.data header.
......
......@@ -498,6 +498,14 @@ To interpret the results it is usually needed to know on which
CPUs the workload runs on. If needed the CPUs can be forced using
taskset.
--record-tpebs::
Enable automatic sampling on Intel TPEBS retire_latency events (event with :R
modifier). Without this option, perf would not capture dynamic retire_latency
at runtime. Currently, a zero value is assigned to the retire_latency event when
this option is not set. The TPEBS hardware feature starts from Intel Granite
Rapids microarchitecture. This option only exists in X86_64 and is meaningful on
Intel platforms with TPEBS feature.
--td-level::
Print the top-down statistics that equal the input level. It allows
users to print the interested top-down metrics level instead of the
......
......@@ -83,8 +83,8 @@ Default is to monitor all CPUS.
-m <pages>::
--mmap-pages=<pages>::
Number of mmap data pages (must be a power of two) or size
specification with appended unit character - B/K/M/G. The
size is rounded up to have nearest pages power of two value.
specification in bytes with appended unit character - B/K/M/G.
The size is rounded up to the nearest power-of-two page value.
-p <pid>::
--pid=<pid>::
......
......@@ -106,8 +106,8 @@ filter out the startup phase of the program, which is often very different.
-m::
--mmap-pages=::
Number of mmap data pages (must be a power of two) or size
specification with appended unit character - B/K/M/G. The
size is rounded up to have nearest pages power of two value.
specification in bytes with appended unit character - B/K/M/G.
The size is rounded up to the nearest power-of-two page value.
-C::
--cpu::
......
......@@ -325,6 +325,36 @@ other four level 2 metrics by subtracting corresponding metrics as below.
Fetch_Bandwidth = Frontend_Bound - Fetch_Latency
Core_Bound = Backend_Bound - Memory_Bound
TPEBS in TopDown
================
TPEBS (Timed PEBS) is one of the new Intel PMU features provided since Granite
Rapids microarchitecture. The TPEBS feature adds a 16 bit retire_latency field
in the Basic Info group of the PEBS record. It records the Core cycles since the
retirement of the previous instruction to the retirement of current instruction.
Please refer to Section 8.4.1 of "Intel® Architecture Instruction Set Extensions
Programming Reference" for more details about this feature. Because this feature
extends PEBS record, sampling with weight option is required to get the
retire_latency value.
perf record -e event_name -W ...
In the most recent release of TMA, the metrics begin to use event retire_latency
values in some of the metrics’ formulas on processors that support TPEBS feature.
For previous generations that do not support TPEBS, the values are static and
predefined per processor family by the hardware architects. Due to the diversity
of workloads in execution environments, retire_latency values measured at real
time are more accurate. Therefore, new TMA metrics that use TPEBS will provide
more accurate performance analysis results.
To support TPEBS in TMA metrics, a new modifier :R on event is added. Perf would
capture retire_latency value of required events(event with :R in metric formula)
with perf record. The retire_latency value would be used in metric calculation.
Currently, this feature is supported through perf stat
perf stat -M metric_name --record-tpebs ...
[1] https://software.intel.com/en-us/top-down-microarchitecture-analysis-method-win
[2] https://sites.google.com/site/analysismethods/yasin-pubs
......
......@@ -51,8 +51,14 @@ else
override DEBUG = 0
endif
ifeq ($(JOBS),1)
BUILD_TYPE := sequential
else
BUILD_TYPE := parallel
endif
define print_msg
@printf ' BUILD: Doing '\''make \033[33m-j'$(JOBS)'\033[m'\'' parallel build\n'
@printf ' BUILD: Doing '\''make \033[33m-j'$(JOBS)'\033[m'\'' $(BUILD_TYPE) build\n'
endef
define make
......
......@@ -31,14 +31,8 @@ $(call detected_var,SRCARCH)
ifneq ($(NO_SYSCALL_TABLE),1)
NO_SYSCALL_TABLE := 1
ifeq ($(SRCARCH),x86)
ifeq (${IS_64_BIT}, 1)
NO_SYSCALL_TABLE := 0
endif
else
ifeq ($(SRCARCH),$(filter $(SRCARCH),powerpc arm64 s390 mips loongarch))
NO_SYSCALL_TABLE := 0
endif
ifeq ($(SRCARCH),$(filter $(SRCARCH),x86 powerpc arm64 s390 mips loongarch))
NO_SYSCALL_TABLE := 0
endif
ifneq ($(NO_SYSCALL_TABLE),1)
......@@ -55,8 +49,9 @@ endif
# Additional ARCH settings for x86
ifeq ($(SRCARCH),x86)
$(call detected,CONFIG_X86)
CFLAGS += -I$(OUTPUT)arch/x86/include/generated
ifeq (${IS_64_BIT}, 1)
CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT -I$(OUTPUT)arch/x86/include/generated
CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT
ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
LIBUNWIND_LIBS = -lunwind-x86_64 -lunwind -llzma
$(call detected,CONFIG_X86_64)
......@@ -238,11 +233,7 @@ endif
ifeq ($(DEBUG),0)
CORE_CFLAGS += -DNDEBUG=1
ifeq ($(CC_NO_CLANG), 0)
CORE_CFLAGS += -O3
else
CORE_CFLAGS += -O6
endif
CORE_CFLAGS += -O3
else
CORE_CFLAGS += -g
CXXFLAGS += -g
......@@ -710,8 +701,8 @@ ifeq ($(BUILD_BPF_SKEL),1)
BUILD_BPF_SKEL := 0
else
CLANG_VERSION := $(shell $(CLANG) --version | head -1 | sed 's/.*clang version \([[:digit:]]\+.[[:digit:]]\+.[[:digit:]]\+\).*/\1/g')
ifeq ($(call version-lt3,$(CLANG_VERSION),12.0.1),1)
$(warning Warning: Disabled BPF skeletons as reliable BTF generation needs at least $(CLANG) version 12.0.1)
ifeq ($(call version-lt3,$(CLANG_VERSION),16.0.6),1)
$(warning Warning: Disabled BPF skeletons as at least $(CLANG) version 16.0.6 is reported to be a working setup with the current of BPF based perf features)
BUILD_BPF_SKEL := 0
endif
endif
......@@ -985,6 +976,23 @@ ifdef BUILD_NONDISTRO
endif
endif
ifndef NO_LIBLLVM
$(call feature_check,llvm-perf)
ifeq ($(feature-llvm-perf), 1)
CFLAGS += -DHAVE_LIBLLVM_SUPPORT
CFLAGS += $(shell $(LLVM_CONFIG) --cflags)
CXXFLAGS += -DHAVE_LIBLLVM_SUPPORT
CXXFLAGS += $(shell $(LLVM_CONFIG) --cxxflags)
LIBLLVM = $(shell $(LLVM_CONFIG) --libs all) $(shell $(LLVM_CONFIG) --system-libs)
EXTLIBS += -L$(shell $(LLVM_CONFIG) --libdir) $(LIBLLVM)
EXTLIBS += -lstdc++
$(call detected,CONFIG_LIBLLVM)
else
$(warning No libllvm 13+ found, slower source file resolution, please install llvm-devel/llvm-dev)
NO_LIBLLVM := 1
endif
endif
ifndef NO_DEMANGLE
$(call feature_check,cxa-demangle)
ifeq ($(feature-cxa-demangle), 1)
......@@ -1031,17 +1039,6 @@ ifndef NO_LIBZSTD
endif
endif
ifndef NO_LIBCAP
ifeq ($(feature-libcap), 1)
CFLAGS += -DHAVE_LIBCAP_SUPPORT
EXTLIBS += -lcap
$(call detected,CONFIG_LIBCAP)
else
$(warning No libcap found, disables capability support, please install libcap-devel/libcap-dev)
NO_LIBCAP := 1
endif
endif
ifndef NO_BACKTRACE
ifeq ($(feature-backtrace), 1)
CFLAGS += -DHAVE_BACKTRACE_SUPPORT
......
......@@ -163,6 +163,8 @@ ifneq ($(OUTPUT),)
# for flex/bison parsers.
VPATH += $(OUTPUT)
export VPATH
# create symlink to the original source
SOURCE := $(shell ln -sf $(srctree)/tools/perf $(OUTPUT)/source)
endif
ifeq ($(V),1)
......@@ -1140,6 +1142,8 @@ install-tests: all install-gtk
$(INSTALL) tests/shell/common/*.pl '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/common'; \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/base_probe'; \
$(INSTALL) tests/shell/base_probe/*.sh '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/base_probe'; \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/base_report'; \
$(INSTALL) tests/shell/base_probe/*.sh '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/base_report'; \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/coresight' ; \
$(INSTALL) tests/shell/coresight/*.sh '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/coresight'
$(Q)$(MAKE) -C tests/shell/coresight install-tests
......@@ -1277,6 +1281,8 @@ clean:: $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean $(LIBSYMBOL)-clean $(
$(OUTPUT)util/intel-pt-decoder/inat-tables.c \
$(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c \
$(OUTPUT)pmu-events/pmu-events.c \
$(OUTPUT)pmu-events/test-empty-pmu-events.c \
$(OUTPUT)pmu-events/empty-pmu-events.log \
$(OUTPUT)pmu-events/metric_test.log \
$(OUTPUT)$(fadvise_advice_array) \
$(OUTPUT)$(fsconfig_arrays) \
......
......@@ -643,7 +643,8 @@ static bool cs_etm_is_ete(struct perf_pmu *cs_etm_pmu, struct perf_cpu cpu)
static __u64 cs_etm_get_legacy_trace_id(struct perf_cpu cpu)
{
return CORESIGHT_LEGACY_CPU_TRACE_ID(cpu.cpu);
/* Wrap at 48 so that invalid trace IDs aren't saved into files. */
return CORESIGHT_LEGACY_CPU_TRACE_ID(cpu.cpu % 48);
}
static void cs_etm_save_etmv4_header(__u64 data[], struct auxtrace_record *itr, struct perf_cpu cpu)
......@@ -654,8 +655,7 @@ static void cs_etm_save_etmv4_header(__u64 data[], struct auxtrace_record *itr,
/* Get trace configuration register */
data[CS_ETMV4_TRCCONFIGR] = cs_etmv4_get_config(itr);
/* traceID set to legacy version, in case new perf running on older system */
data[CS_ETMV4_TRCTRACEIDR] = cs_etm_get_legacy_trace_id(cpu) |
CORESIGHT_TRACE_ID_UNUSED_FLAG;
data[CS_ETMV4_TRCTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);
/* Get read-only information from sysFS */
cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0],
......@@ -687,7 +687,7 @@ static void cs_etm_save_ete_header(__u64 data[], struct auxtrace_record *itr, st
/* Get trace configuration register */
data[CS_ETE_TRCCONFIGR] = cs_etmv4_get_config(itr);
/* traceID set to legacy version, in case new perf running on older system */
data[CS_ETE_TRCTRACEIDR] = cs_etm_get_legacy_trace_id(cpu) | CORESIGHT_TRACE_ID_UNUSED_FLAG;
data[CS_ETE_TRCTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);
/* Get read-only information from sysFS */
cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCIDR0], &data[CS_ETE_TRCIDR0]);
......@@ -743,8 +743,7 @@ static void cs_etm_get_metadata(struct perf_cpu cpu, u32 *offset,
/* Get configuration register */
info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr);
/* traceID set to legacy value in case new perf running on old system */
info->priv[*offset + CS_ETM_ETMTRACEIDR] = cs_etm_get_legacy_trace_id(cpu) |
CORESIGHT_TRACE_ID_UNUSED_FLAG;
info->priv[*offset + CS_ETM_ETMTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);
/* Get read-only information from sysFS */
cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv3_ro[CS_ETM_ETMCCER],
&info->priv[*offset + CS_ETM_ETMCCER]);
......@@ -888,7 +887,6 @@ struct auxtrace_record *cs_etm_record_init(int *err)
}
ptr->cs_etm_pmu = cs_etm_pmu;
ptr->itr.pmu = cs_etm_pmu;
ptr->itr.parse_snapshot_options = cs_etm_parse_snapshot_options;
ptr->itr.recording_options = cs_etm_recording_options;
ptr->itr.info_priv_size = cs_etm_info_priv_size;
......
......@@ -23,16 +23,19 @@ void perf_pmu__arch_init(struct perf_pmu *pmu)
#ifdef HAVE_AUXTRACE_SUPPORT
if (!strcmp(pmu->name, CORESIGHT_ETM_PMU_NAME)) {
/* add ETM default config here */
pmu->auxtrace = true;
pmu->selectable = true;
pmu->perf_event_attr_init_default = cs_etm_get_default_config;
#if defined(__aarch64__)
} else if (strstarts(pmu->name, ARM_SPE_PMU_NAME)) {
pmu->auxtrace = true;
pmu->selectable = true;
pmu->is_uncore = false;
pmu->perf_event_attr_init_default = arm_spe_pmu_default_config;
if (strstarts(pmu->name, "arm_spe_"))
pmu->mem_events = perf_mem_events_arm;
} else if (strstarts(pmu->name, HISI_PTT_PMU_NAME)) {
pmu->auxtrace = true;
pmu->selectable = true;
#endif
}
......
......@@ -11,7 +11,8 @@ struct arm64_annotate {
static int arm64_mov__parse(struct arch *arch __maybe_unused,
struct ins_operands *ops,
struct map_symbol *ms __maybe_unused)
struct map_symbol *ms __maybe_unused,
struct disasm_line *dl __maybe_unused)
{
char *s = strchr(ops->raw, ','), *target, *endptr;
......
......@@ -8,6 +8,7 @@
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/log2.h>
#include <linux/string.h>
#include <linux/zalloc.h>
#include <time.h>
......@@ -132,32 +133,66 @@ static __u64 arm_spe_pmu__sample_period(const struct perf_pmu *arm_spe_pmu)
return sample_period;
}
static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
{
u64 bit;
evsel->core.attr.freq = 0;
evsel->core.attr.sample_period = arm_spe_pmu__sample_period(evsel->pmu);
evsel->needs_auxtrace_mmap = true;
/*
* To obtain the auxtrace buffer file descriptor, the auxtrace event
* must come first.
*/
evlist__to_front(evsel->evlist, evsel);
/*
* In the case of per-cpu mmaps, sample CPU for AUX event;
* also enable the timestamp tracing for samples correlation.
*/
if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) {
evsel__set_sample_bit(evsel, CPU);
evsel__set_config_if_unset(evsel->pmu, evsel, "ts_enable", 1);
}
/*
* Set this only so that perf report knows that SPE generates memory info. It has no effect
* on the opening of the event or the SPE data produced.
*/
evsel__set_sample_bit(evsel, DATA_SRC);
/*
* The PHYS_ADDR flag does not affect the driver behaviour, it is used to
* inform that the resulting output's SPE samples contain physical addresses
* where applicable.
*/
bit = perf_pmu__format_bits(evsel->pmu, "pa_enable");
if (evsel->core.attr.config & bit)
evsel__set_sample_bit(evsel, PHYS_ADDR);
}
static int arm_spe_recording_options(struct auxtrace_record *itr,
struct evlist *evlist,
struct record_opts *opts)
{
struct arm_spe_recording *sper =
container_of(itr, struct arm_spe_recording, itr);
struct perf_pmu *arm_spe_pmu = sper->arm_spe_pmu;
struct evsel *evsel, *arm_spe_evsel = NULL;
struct evsel *evsel, *tmp;
struct perf_cpu_map *cpus = evlist->core.user_requested_cpus;
bool privileged = perf_event_paranoid_check(-1);
struct evsel *tracking_evsel;
int err;
u64 bit;
sper->evlist = evlist;
evlist__for_each_entry(evlist, evsel) {
if (evsel->core.attr.type == arm_spe_pmu->type) {
if (arm_spe_evsel) {
pr_err("There may be only one " ARM_SPE_PMU_NAME "x event\n");
if (evsel__is_aux_event(evsel)) {
if (!strstarts(evsel->pmu_name, ARM_SPE_PMU_NAME)) {
pr_err("Found unexpected auxtrace event: %s\n",
evsel->pmu_name);
return -EINVAL;
}
evsel->core.attr.freq = 0;
evsel->core.attr.sample_period = arm_spe_pmu__sample_period(arm_spe_pmu);
evsel->needs_auxtrace_mmap = true;
arm_spe_evsel = evsel;
opts->full_auxtrace = true;
}
}
......@@ -222,37 +257,11 @@ static int arm_spe_recording_options(struct auxtrace_record *itr,
pr_debug2("%sx snapshot size: %zu\n", ARM_SPE_PMU_NAME,
opts->auxtrace_snapshot_size);
/*
* To obtain the auxtrace buffer file descriptor, the auxtrace event
* must come first.
*/
evlist__to_front(evlist, arm_spe_evsel);
/*
* In the case of per-cpu mmaps, sample CPU for AUX event;
* also enable the timestamp tracing for samples correlation.
*/
if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) {
evsel__set_sample_bit(arm_spe_evsel, CPU);
evsel__set_config_if_unset(arm_spe_pmu, arm_spe_evsel,
"ts_enable", 1);
evlist__for_each_entry_safe(evlist, tmp, evsel) {
if (evsel__is_aux_event(evsel))
arm_spe_setup_evsel(evsel, cpus);
}
/*
* Set this only so that perf report knows that SPE generates memory info. It has no effect
* on the opening of the event or the SPE data produced.
*/
evsel__set_sample_bit(arm_spe_evsel, DATA_SRC);
/*
* The PHYS_ADDR flag does not affect the driver behaviour, it is used to
* inform that the resulting output's SPE samples contain physical addresses
* where applicable.
*/
bit = perf_pmu__format_bits(arm_spe_pmu, "pa_enable");
if (arm_spe_evsel->core.attr.config & bit)
evsel__set_sample_bit(arm_spe_evsel, PHYS_ADDR);
/* Add dummy event to keep tracking */
err = parse_event(evlist, "dummy:u");
if (err)
......@@ -301,12 +310,16 @@ static int arm_spe_snapshot_start(struct auxtrace_record *itr)
struct arm_spe_recording *ptr =
container_of(itr, struct arm_spe_recording, itr);
struct evsel *evsel;
int ret = -EINVAL;
evlist__for_each_entry(ptr->evlist, evsel) {
if (evsel->core.attr.type == ptr->arm_spe_pmu->type)
return evsel__disable(evsel);
if (evsel__is_aux_event(evsel)) {
ret = evsel__disable(evsel);
if (ret < 0)
return ret;
}
}
return -EINVAL;
return ret;
}
static int arm_spe_snapshot_finish(struct auxtrace_record *itr)
......@@ -314,12 +327,16 @@ static int arm_spe_snapshot_finish(struct auxtrace_record *itr)
struct arm_spe_recording *ptr =
container_of(itr, struct arm_spe_recording, itr);
struct evsel *evsel;
int ret = -EINVAL;
evlist__for_each_entry(ptr->evlist, evsel) {
if (evsel->core.attr.type == ptr->arm_spe_pmu->type)
return evsel__enable(evsel);
if (evsel__is_aux_event(evsel)) {
ret = evsel__enable(evsel);
if (ret < 0)
return ret;
}
}
return -EINVAL;
return ret;
}
static int arm_spe_alloc_wrapped_array(struct arm_spe_recording *ptr, int idx)
......@@ -497,7 +514,6 @@ struct auxtrace_record *arm_spe_recording_init(int *err,
}
sper->arm_spe_pmu = arm_spe_pmu;
sper->itr.pmu = arm_spe_pmu;
sper->itr.snapshot_start = arm_spe_snapshot_start;
sper->itr.snapshot_finish = arm_spe_snapshot_finish;
sper->itr.find_snapshot = arm_spe_find_snapshot;
......
......@@ -174,7 +174,6 @@ struct auxtrace_record *hisi_ptt_recording_init(int *err,
}
pttr->hisi_ptt_pmu = hisi_ptt_pmu;
pttr->itr.pmu = hisi_ptt_pmu;
pttr->itr.recording_options = hisi_ptt_recording_options;
pttr->itr.info_priv_size = hisi_ptt_info_priv_size;
pttr->itr.info_fill = hisi_ptt_info_fill;
......
......@@ -5,7 +5,8 @@
* Copyright (C) 2020-2023 Loongson Technology Corporation Limited
*/
static int loongarch_call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
static int loongarch_call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms,
struct disasm_line *dl __maybe_unused)
{
char *c, *endptr, *tok, *name;
struct map *map = ms->map;
......@@ -51,7 +52,8 @@ static struct ins_ops loongarch_call_ops = {
.scnprintf = call__scnprintf,
};
static int loongarch_jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
static int loongarch_jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms,
struct disasm_line *dl __maybe_unused)
{
struct map *map = ms->map;
struct symbol *sym = ms->sym;
......
......@@ -49,12 +49,266 @@ static struct ins_ops *powerpc__associate_instruction_ops(struct arch *arch, con
return ops;
}
#define PPC_OP(op) (((op) >> 26) & 0x3F)
#define PPC_21_30(R) (((R) >> 1) & 0x3ff)
#define PPC_22_30(R) (((R) >> 1) & 0x1ff)
struct insn_offset {
const char *name;
int value;
};
/*
* There are memory instructions with opcode 31 which are
* of X Form, Example:
* ldx RT,RA,RB
* ______________________________________
* | 31 | RT | RA | RB | 21 |/|
* --------------------------------------
* 0 6 11 16 21 30 31
*
* But all instructions with opcode 31 are not memory.
* Example: add RT,RA,RB
*
* Use bits 21 to 30 to check memory insns with 31 as opcode.
* In ins_array below, for ldx instruction:
* name => OP_31_XOP_LDX
* value => 21
*/
static struct insn_offset ins_array[] = {
{ .name = "OP_31_XOP_LXSIWZX", .value = 12, },
{ .name = "OP_31_XOP_LWARX", .value = 20, },
{ .name = "OP_31_XOP_LDX", .value = 21, },
{ .name = "OP_31_XOP_LWZX", .value = 23, },
{ .name = "OP_31_XOP_LDUX", .value = 53, },
{ .name = "OP_31_XOP_LWZUX", .value = 55, },
{ .name = "OP_31_XOP_LXSIWAX", .value = 76, },
{ .name = "OP_31_XOP_LDARX", .value = 84, },
{ .name = "OP_31_XOP_LBZX", .value = 87, },
{ .name = "OP_31_XOP_LVX", .value = 103, },
{ .name = "OP_31_XOP_LBZUX", .value = 119, },
{ .name = "OP_31_XOP_STXSIWX", .value = 140, },
{ .name = "OP_31_XOP_STDX", .value = 149, },
{ .name = "OP_31_XOP_STWX", .value = 151, },
{ .name = "OP_31_XOP_STDUX", .value = 181, },
{ .name = "OP_31_XOP_STWUX", .value = 183, },
{ .name = "OP_31_XOP_STBX", .value = 215, },
{ .name = "OP_31_XOP_STVX", .value = 231, },
{ .name = "OP_31_XOP_STBUX", .value = 247, },
{ .name = "OP_31_XOP_LHZX", .value = 279, },
{ .name = "OP_31_XOP_LHZUX", .value = 311, },
{ .name = "OP_31_XOP_LXVDSX", .value = 332, },
{ .name = "OP_31_XOP_LWAX", .value = 341, },
{ .name = "OP_31_XOP_LHAX", .value = 343, },
{ .name = "OP_31_XOP_LWAUX", .value = 373, },
{ .name = "OP_31_XOP_LHAUX", .value = 375, },
{ .name = "OP_31_XOP_STHX", .value = 407, },
{ .name = "OP_31_XOP_STHUX", .value = 439, },
{ .name = "OP_31_XOP_LXSSPX", .value = 524, },
{ .name = "OP_31_XOP_LDBRX", .value = 532, },
{ .name = "OP_31_XOP_LSWX", .value = 533, },
{ .name = "OP_31_XOP_LWBRX", .value = 534, },
{ .name = "OP_31_XOP_LFSUX", .value = 567, },
{ .name = "OP_31_XOP_LXSDX", .value = 588, },
{ .name = "OP_31_XOP_LSWI", .value = 597, },
{ .name = "OP_31_XOP_LFDX", .value = 599, },
{ .name = "OP_31_XOP_LFDUX", .value = 631, },
{ .name = "OP_31_XOP_STXSSPX", .value = 652, },
{ .name = "OP_31_XOP_STDBRX", .value = 660, },
{ .name = "OP_31_XOP_STXWX", .value = 661, },
{ .name = "OP_31_XOP_STWBRX", .value = 662, },
{ .name = "OP_31_XOP_STFSX", .value = 663, },
{ .name = "OP_31_XOP_STFSUX", .value = 695, },
{ .name = "OP_31_XOP_STXSDX", .value = 716, },
{ .name = "OP_31_XOP_STSWI", .value = 725, },
{ .name = "OP_31_XOP_STFDX", .value = 727, },
{ .name = "OP_31_XOP_STFDUX", .value = 759, },
{ .name = "OP_31_XOP_LXVW4X", .value = 780, },
{ .name = "OP_31_XOP_LHBRX", .value = 790, },
{ .name = "OP_31_XOP_LXVD2X", .value = 844, },
{ .name = "OP_31_XOP_LFIWAX", .value = 855, },
{ .name = "OP_31_XOP_LFIWZX", .value = 887, },
{ .name = "OP_31_XOP_STXVW4X", .value = 908, },
{ .name = "OP_31_XOP_STHBRX", .value = 918, },
{ .name = "OP_31_XOP_STXVD2X", .value = 972, },
{ .name = "OP_31_XOP_STFIWX", .value = 983, },
};
/*
* Arithmetic instructions which are having opcode as 31.
* These instructions are tracked to save the register state
* changes. Example:
*
* lwz r10,264(r3)
* add r31, r3, r3
* lwz r9, 0(r31)
*
* Here instruction tracking needs to identify the "add"
* instruction and save data type of r3 to r31. If a sample
* is hit at next "lwz r9, 0(r31)", by this instruction tracking,
* data type of r31 can be resolved.
*/
static struct insn_offset arithmetic_ins_op_31[] = {
{ .name = "SUB_CARRY_XO_FORM", .value = 8, },
{ .name = "MUL_HDW_XO_FORM1", .value = 9, },
{ .name = "ADD_CARRY_XO_FORM", .value = 10, },
{ .name = "MUL_HW_XO_FORM1", .value = 11, },
{ .name = "SUB_XO_FORM", .value = 40, },
{ .name = "MUL_HDW_XO_FORM", .value = 73, },
{ .name = "MUL_HW_XO_FORM", .value = 75, },
{ .name = "SUB_EXT_XO_FORM", .value = 136, },
{ .name = "ADD_EXT_XO_FORM", .value = 138, },
{ .name = "SUB_ZERO_EXT_XO_FORM", .value = 200, },
{ .name = "ADD_ZERO_EXT_XO_FORM", .value = 202, },
{ .name = "SUB_EXT_XO_FORM2", .value = 232, },
{ .name = "MUL_DW_XO_FORM", .value = 233, },
{ .name = "ADD_EXT_XO_FORM2", .value = 234, },
{ .name = "MUL_W_XO_FORM", .value = 235, },
{ .name = "ADD_XO_FORM", .value = 266, },
{ .name = "DIV_DW_XO_FORM1", .value = 457, },
{ .name = "DIV_W_XO_FORM1", .value = 459, },
{ .name = "DIV_DW_XO_FORM", .value = 489, },
{ .name = "DIV_W_XO_FORM", .value = 491, },
};
static struct insn_offset arithmetic_two_ops[] = {
{ .name = "mulli", .value = 7, },
{ .name = "subfic", .value = 8, },
{ .name = "addic", .value = 12, },
{ .name = "addic.", .value = 13, },
{ .name = "addi", .value = 14, },
{ .name = "addis", .value = 15, },
};
static int cmp_offset(const void *a, const void *b)
{
const struct insn_offset *val1 = a;
const struct insn_offset *val2 = b;
return (val1->value - val2->value);
}
static struct ins_ops *check_ppc_insn(struct disasm_line *dl)
{
int raw_insn = dl->raw.raw_insn;
int opcode = PPC_OP(raw_insn);
int mem_insn_31 = PPC_21_30(raw_insn);
struct insn_offset *ret;
struct insn_offset mem_insns_31_opcode = {
"OP_31_INSN",
mem_insn_31
};
char name_insn[32];
/*
* Instructions with opcode 32 to 63 are memory
* instructions in powerpc
*/
if ((opcode & 0x20)) {
/*
* Set name in case of raw instruction to
* opcode to be used in insn-stat
*/
if (!strlen(dl->ins.name)) {
sprintf(name_insn, "%d", opcode);
dl->ins.name = strdup(name_insn);
}
return &load_store_ops;
} else if (opcode == 31) {
/* Check for memory instructions with opcode 31 */
ret = bsearch(&mem_insns_31_opcode, ins_array, ARRAY_SIZE(ins_array), sizeof(ins_array[0]), cmp_offset);
if (ret) {
if (!strlen(dl->ins.name))
dl->ins.name = strdup(ret->name);
return &load_store_ops;
} else {
mem_insns_31_opcode.value = PPC_22_30(raw_insn);
ret = bsearch(&mem_insns_31_opcode, arithmetic_ins_op_31, ARRAY_SIZE(arithmetic_ins_op_31),
sizeof(arithmetic_ins_op_31[0]), cmp_offset);
if (ret != NULL)
return &arithmetic_ops;
/* Bits 21 to 30 has value 444 for "mr" insn ie, OR X form */
if (PPC_21_30(raw_insn) == 444)
return &arithmetic_ops;
}
} else {
mem_insns_31_opcode.value = opcode;
ret = bsearch(&mem_insns_31_opcode, arithmetic_two_ops, ARRAY_SIZE(arithmetic_two_ops),
sizeof(arithmetic_two_ops[0]), cmp_offset);
if (ret != NULL)
return &arithmetic_ops;
}
return NULL;
}
/*
* Instruction tracking function to track register state moves.
* Example sequence:
* ld r10,264(r3)
* mr r31,r3
* <<after some sequence>
* ld r9,312(r31)
*
* Previous instruction sequence shows that register state of r3
* is moved to r31. update_insn_state_powerpc tracks these state
* changes
*/
#ifdef HAVE_DWARF_SUPPORT
static void update_insn_state_powerpc(struct type_state *state,
struct data_loc_info *dloc, Dwarf_Die * cu_die __maybe_unused,
struct disasm_line *dl)
{
struct annotated_insn_loc loc;
struct annotated_op_loc *src = &loc.ops[INSN_OP_SOURCE];
struct annotated_op_loc *dst = &loc.ops[INSN_OP_TARGET];
struct type_state_reg *tsr;
u32 insn_offset = dl->al.offset;
if (annotate_get_insn_location(dloc->arch, dl, &loc) < 0)
return;
/*
* Value 444 for bits 21:30 is for "mr"
* instruction. "mr" is extended OR. So set the
* source and destination reg correctly
*/
if (PPC_21_30(dl->raw.raw_insn) == 444) {
int src_reg = src->reg1;
src->reg1 = dst->reg1;
dst->reg1 = src_reg;
}
if (!has_reg_type(state, dst->reg1))
return;
tsr = &state->regs[dst->reg1];
if (!has_reg_type(state, src->reg1) ||
!state->regs[src->reg1].ok) {
tsr->ok = false;
return;
}
tsr->type = state->regs[src->reg1].type;
tsr->kind = state->regs[src->reg1].kind;
tsr->ok = true;
pr_debug_dtp("mov [%x] reg%d -> reg%d",
insn_offset, src->reg1, dst->reg1);
pr_debug_type_name(&tsr->type, tsr->kind);
}
#endif /* HAVE_DWARF_SUPPORT */
static int powerpc__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
{
if (!arch->initialized) {
arch->initialized = true;
arch->associate_instruction_ops = powerpc__associate_instruction_ops;
arch->objdump.comment_char = '#';
annotate_opts.show_asm_raw = true;
}
return 0;
......
......@@ -98,3 +98,56 @@ int regs_query_register_offset(const char *name)
return roff->ptregs_offset;
return -EINVAL;
}
#define PPC_OP(op) (((op) >> 26) & 0x3F)
#define PPC_RA(a) (((a) >> 16) & 0x1f)
#define PPC_RT(t) (((t) >> 21) & 0x1f)
#define PPC_RB(b) (((b) >> 11) & 0x1f)
#define PPC_D(D) ((D) & 0xfffe)
#define PPC_DS(DS) ((DS) & 0xfffc)
#define OP_LD 58
#define OP_STD 62
static int get_source_reg(u32 raw_insn)
{
return PPC_RA(raw_insn);
}
static int get_target_reg(u32 raw_insn)
{
return PPC_RT(raw_insn);
}
static int get_offset_opcode(u32 raw_insn)
{
int opcode = PPC_OP(raw_insn);
/* DS- form */
if ((opcode == OP_LD) || (opcode == OP_STD))
return PPC_DS(raw_insn);
else
return PPC_D(raw_insn);
}
/*
* Fills the required fields for op_loc depending on if it
* is a source or target.
* D form: ins RT,D(RA) -> src_reg1 = RA, offset = D, dst_reg1 = RT
* DS form: ins RT,DS(RA) -> src_reg1 = RA, offset = DS, dst_reg1 = RT
* X form: ins RT,RA,RB -> src_reg1 = RA, src_reg2 = RB, dst_reg1 = RT
*/
void get_powerpc_regs(u32 raw_insn, int is_source,
struct annotated_op_loc *op_loc)
{
if (is_source)
op_loc->reg1 = get_source_reg(raw_insn);
else
op_loc->reg1 = get_target_reg(raw_insn);
if (op_loc->multi_regs)
op_loc->reg2 = PPC_RB(raw_insn);
/* TODO: Implement offset handling for X Form */
if ((op_loc->mem_ref) && (PPC_OP(raw_insn) != 31))
op_loc->offset = get_offset_opcode(raw_insn);
}
......@@ -2,7 +2,7 @@
#include <linux/compiler.h>
static int s390_call__parse(struct arch *arch, struct ins_operands *ops,
struct map_symbol *ms)
struct map_symbol *ms, struct disasm_line *dl __maybe_unused)
{
char *endptr, *tok, *name;
struct map *map = ms->map;
......@@ -52,7 +52,8 @@ static struct ins_ops s390_call_ops = {
static int s390_mov__parse(struct arch *arch __maybe_unused,
struct ins_operands *ops,
struct map_symbol *ms __maybe_unused)
struct map_symbol *ms __maybe_unused,
struct disasm_line *dl __maybe_unused)
{
char *s = strchr(ops->raw, ','), *target, *endptr;
......
......@@ -13,6 +13,7 @@ PERF_HAVE_JITDUMP := 1
generated := $(OUTPUT)arch/x86/include/generated
out := $(generated)/asm
header := $(out)/syscalls_64.c
header_32 := $(out)/syscalls_32.c
sys := $(srctree)/tools/perf/arch/x86/entry/syscalls
systbl := $(sys)/syscalltbl.sh
......@@ -22,7 +23,10 @@ $(shell [ -d '$(out)' ] || mkdir -p '$(out)')
$(header): $(sys)/syscall_64.tbl $(systbl)
$(Q)$(SHELL) '$(systbl)' $(sys)/syscall_64.tbl 'x86_64' > $@
$(header_32): $(sys)/syscall_32.tbl $(systbl)
$(Q)$(SHELL) '$(systbl)' $(sys)/syscall_32.tbl 'x86' > $@
clean::
$(call QUIET_CLEAN, x86) $(RM) -r $(header) $(generated)
archheaders: $(header)
archheaders: $(header) $(header_32)
This diff is collapsed.
This diff is collapsed.
......@@ -15,7 +15,7 @@
#if defined(__x86_64__)
struct perf_event__synthesize_extra_kmaps_cb_args {
struct perf_tool *tool;
const struct perf_tool *tool;
perf_event__handler_t process;
struct machine *machine;
union perf_event *event;
......@@ -65,7 +65,7 @@ static int perf_event__synthesize_extra_kmaps_cb(struct map *map, void *data)
return 0;
}
int perf_event__synthesize_extra_kmaps(struct perf_tool *tool,
int perf_event__synthesize_extra_kmaps(const struct perf_tool *tool,
perf_event__handler_t process,
struct machine *machine)
{
......
......@@ -89,6 +89,12 @@ int arch_evlist__cmp(const struct evsel *lhs, const struct evsel *rhs)
return 1;
}
/* Retire latency event should not be group leader*/
if (lhs->retire_lat && !rhs->retire_lat)
return 1;
if (!lhs->retire_lat && rhs->retire_lat)
return -1;
/* Default ordering by insertion index. */
return lhs->core.idx - rhs->core.idx;
}
......@@ -434,7 +434,6 @@ struct auxtrace_record *intel_bts_recording_init(int *err)
}
btsr->intel_bts_pmu = intel_bts_pmu;
btsr->itr.pmu = intel_bts_pmu;
btsr->itr.recording_options = intel_bts_recording_options;
btsr->itr.info_priv_size = intel_bts_info_priv_size;
btsr->itr.info_fill = intel_bts_info_fill;
......
......@@ -1197,7 +1197,6 @@ struct auxtrace_record *intel_pt_recording_init(int *err)
}
ptr->intel_pt_pmu = intel_pt_pmu;
ptr->itr.pmu = intel_pt_pmu;
ptr->itr.recording_options = intel_pt_recording_options;
ptr->itr.info_priv_size = intel_pt_info_priv_size;
ptr->itr.info_fill = intel_pt_info_fill;
......
......@@ -49,7 +49,7 @@ static const char *const bench_usage[] = {
static atomic_t event_count;
static int process_synthesized_event(struct perf_tool *tool __maybe_unused,
static int process_synthesized_event(const struct perf_tool *tool __maybe_unused,
union perf_event *event __maybe_unused,
struct perf_sample *sample __maybe_unused,
struct machine *machine __maybe_unused)
......
......@@ -221,7 +221,8 @@ static int process_branch_callback(struct evsel *evsel,
if (a.map != NULL)
dso__set_hit(map__dso(a.map));
hist__account_cycles(sample->branch_stack, al, sample, false, NULL);
hist__account_cycles(sample->branch_stack, al, sample, false,
NULL, evsel);
ret = hist_entry_iter__add(&iter, &a, PERF_MAX_STACK_DEPTH, ann);
out:
......@@ -279,7 +280,7 @@ static int evsel__add_sample(struct evsel *evsel, struct perf_sample *sample,
return ret;
}
static int process_sample_event(struct perf_tool *tool,
static int process_sample_event(const struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct evsel *evsel,
......@@ -396,10 +397,10 @@ static void print_annotate_item_stat(struct list_head *head, const char *title)
printf("total %d, ok %d (%.1f%%), bad %d (%.1f%%)\n\n", total,
total_good, 100.0 * total_good / (total ?: 1),
total_bad, 100.0 * total_bad / (total ?: 1));
printf(" %-10s: %5s %5s\n", "Name", "Good", "Bad");
printf(" %-20s: %5s %5s\n", "Name/opcode", "Good", "Bad");
printf("-----------------------------------------------------------\n");
list_for_each_entry(istat, head, list)
printf(" %-10s: %5d %5d\n", istat->name, istat->good, istat->bad);
printf(" %-20s: %5d %5d\n", istat->name, istat->good, istat->bad);
printf("\n");
}
......@@ -632,13 +633,23 @@ static int __cmd_annotate(struct perf_annotate *ann)
evlist__for_each_entry(session->evlist, pos) {
struct hists *hists = evsel__hists(pos);
u32 nr_samples = hists->stats.nr_samples;
struct ui_progress prog;
struct evsel *evsel;
if (nr_samples == 0)
if (!symbol_conf.event_group || !evsel__is_group_leader(pos))
continue;
if (!symbol_conf.event_group || !evsel__is_group_leader(pos))
for_each_group_member(evsel, pos)
nr_samples += evsel__hists(evsel)->stats.nr_samples;
if (nr_samples == 0)
continue;
ui_progress__init(&prog, nr_samples,
"Sorting group events for output...");
evsel__output_resort(pos, &prog);
ui_progress__finish();
hists__find_annotations(hists, pos, ann);
}
......@@ -686,28 +697,7 @@ static const char * const annotate_usage[] = {
int cmd_annotate(int argc, const char **argv)
{
struct perf_annotate annotate = {
.tool = {
.sample = process_sample_event,
.mmap = perf_event__process_mmap,
.mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm,
.exit = perf_event__process_exit,
.fork = perf_event__process_fork,
.namespaces = perf_event__process_namespaces,
.attr = perf_event__process_attr,
.build_id = perf_event__process_build_id,
#ifdef HAVE_LIBTRACEEVENT
.tracing_data = perf_event__process_tracing_data,
#endif
.id_index = perf_event__process_id_index,
.auxtrace_info = perf_event__process_auxtrace_info,
.auxtrace = perf_event__process_auxtrace,
.feature = process_feature_event,
.ordered_events = true,
.ordering_requires_timestamps = true,
},
};
struct perf_annotate annotate = {};
struct perf_data data = {
.mode = PERF_DATA_MODE_READ,
};
......@@ -795,6 +785,8 @@ int cmd_annotate(int argc, const char **argv)
"Show stats for the data type annotation"),
OPT_BOOLEAN(0, "insn-stat", &annotate.insn_stat,
"Show instruction stats for the data type annotation"),
OPT_BOOLEAN(0, "skip-empty", &symbol_conf.skip_empty,
"Do not display empty (or dummy) events in the output"),
OPT_END()
};
int ret;
......@@ -864,6 +856,25 @@ int cmd_annotate(int argc, const char **argv)
data.path = input_name;
perf_tool__init(&annotate.tool, /*ordered_events=*/true);
annotate.tool.sample = process_sample_event;
annotate.tool.mmap = perf_event__process_mmap;
annotate.tool.mmap2 = perf_event__process_mmap2;
annotate.tool.comm = perf_event__process_comm;
annotate.tool.exit = perf_event__process_exit;
annotate.tool.fork = perf_event__process_fork;
annotate.tool.namespaces = perf_event__process_namespaces;
annotate.tool.attr = perf_event__process_attr;
annotate.tool.build_id = perf_event__process_build_id;
#ifdef HAVE_LIBTRACEEVENT
annotate.tool.tracing_data = perf_event__process_tracing_data;
#endif
annotate.tool.id_index = perf_event__process_id_index;
annotate.tool.auxtrace_info = perf_event__process_auxtrace_info;
annotate.tool.auxtrace = perf_event__process_auxtrace;
annotate.tool.feature = process_feature_event;
annotate.tool.ordering_requires_timestamps = true;
annotate.session = perf_session__new(&data, &annotate.tool);
if (IS_ERR(annotate.session))
return PTR_ERR(annotate.session);
......@@ -916,11 +927,15 @@ int cmd_annotate(int argc, const char **argv)
sort_order = "dso,symbol";
/*
* Set SORT_MODE__BRANCH so that annotate display IPC/Cycle
* if branch info is in perf data in TUI mode.
* Set SORT_MODE__BRANCH so that annotate displays IPC/Cycle and
* branch counters, if the corresponding branch info is available
* in the perf data in the TUI mode.
*/
if ((use_browser == 1 || annotate.use_stdio2) && annotate.has_br_stack)
if ((use_browser == 1 || annotate.use_stdio2) && annotate.has_br_stack) {
sort__mode = SORT_MODE__BRANCH;
if (annotate.session->evlist->nr_br_cntr > 0)
annotate_opts.show_br_cntr = true;
}
if (setup_sorting(NULL) < 0)
usage_with_options(annotate_usage, options);
......
......@@ -89,6 +89,7 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
.mode = PERF_DATA_MODE_READ,
.force = force,
};
struct perf_tool build_id__mark_dso_hit_ops;
symbol__elf_init();
/*
......@@ -97,6 +98,15 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
if (filename__fprintf_build_id(input_name, stdout) > 0)
goto out;
perf_tool__init(&build_id__mark_dso_hit_ops, /*ordered_events=*/true);
build_id__mark_dso_hit_ops.sample = build_id__mark_dso_hit;
build_id__mark_dso_hit_ops.mmap = perf_event__process_mmap;
build_id__mark_dso_hit_ops.mmap2 = perf_event__process_mmap2;
build_id__mark_dso_hit_ops.fork = perf_event__process_fork;
build_id__mark_dso_hit_ops.exit = perf_event__exit_del_thread;
build_id__mark_dso_hit_ops.attr = perf_event__process_attr;
build_id__mark_dso_hit_ops.build_id = perf_event__process_build_id;
session = perf_session__new(&data, &build_id__mark_dso_hit_ops);
if (IS_ERR(session))
return PTR_ERR(session);
......
......@@ -273,7 +273,7 @@ static void compute_stats(struct c2c_hist_entry *c2c_he,
update_stats(&cstats->load, weight);
}
static int process_sample_event(struct perf_tool *tool __maybe_unused,
static int process_sample_event(const struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_sample *sample,
struct evsel *evsel,
......@@ -385,24 +385,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
goto out;
}
static struct perf_c2c c2c = {
.tool = {
.sample = process_sample_event,
.mmap = perf_event__process_mmap,
.mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm,
.exit = perf_event__process_exit,
.fork = perf_event__process_fork,
.lost = perf_event__process_lost,
.attr = perf_event__process_attr,
.auxtrace_info = perf_event__process_auxtrace_info,
.auxtrace = perf_event__process_auxtrace,
.auxtrace_error = perf_event__process_auxtrace_error,
.ordered_events = true,
.ordering_requires_timestamps = true,
},
};
static const char * const c2c_usage[] = {
"perf c2c {record|report}",
NULL
......@@ -3070,6 +3052,19 @@ static int perf_c2c__report(int argc, const char **argv)
data.path = input_name;
data.force = symbol_conf.force;
perf_tool__init(&c2c.tool, /*ordered_events=*/true);
c2c.tool.sample = process_sample_event;
c2c.tool.mmap = perf_event__process_mmap;
c2c.tool.mmap2 = perf_event__process_mmap2;
c2c.tool.comm = perf_event__process_comm;
c2c.tool.exit = perf_event__process_exit;
c2c.tool.fork = perf_event__process_fork;
c2c.tool.lost = perf_event__process_lost;
c2c.tool.attr = perf_event__process_attr;
c2c.tool.auxtrace_info = perf_event__process_auxtrace_info;
c2c.tool.auxtrace = perf_event__process_auxtrace;
c2c.tool.auxtrace_error = perf_event__process_auxtrace_error;
c2c.tool.ordering_requires_timestamps = true;
session = perf_session__new(&data, &c2c.tool);
if (IS_ERR(session)) {
err = PTR_ERR(session);
......@@ -3266,7 +3261,7 @@ static int perf_c2c__record(int argc, const char **argv)
return -1;
}
if (perf_pmu__mem_events_init(pmu)) {
if (perf_pmu__mem_events_init()) {
pr_err("failed: memory events not supported\n");
return -1;
}
......@@ -3290,19 +3285,15 @@ static int perf_c2c__record(int argc, const char **argv)
* PERF_MEM_EVENTS__LOAD_STORE if it is supported.
*/
if (e->tag) {
e->record = true;
perf_mem_record[PERF_MEM_EVENTS__LOAD_STORE] = true;
rec_argv[i++] = "-W";
} else {
e = perf_pmu__mem_events_ptr(pmu, PERF_MEM_EVENTS__LOAD);
e->record = true;
e = perf_pmu__mem_events_ptr(pmu, PERF_MEM_EVENTS__STORE);
e->record = true;
perf_mem_record[PERF_MEM_EVENTS__LOAD] = true;
perf_mem_record[PERF_MEM_EVENTS__STORE] = true;
}
}
e = perf_pmu__mem_events_ptr(pmu, PERF_MEM_EVENTS__LOAD);
if (e->record)
if (perf_mem_record[PERF_MEM_EVENTS__LOAD])
rec_argv[i++] = "-W";
rec_argv[i++] = "-d";
......
// SPDX-License-Identifier: GPL-2.0
#include "builtin.h"
#include "color.h"
#include "util/debug.h"
#include "util/header.h"
#include <tools/config.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <subcmd/parse-options.h>
static const char * const check_subcommands[] = { "feature", NULL };
static struct option check_options[] = {
OPT_BOOLEAN('q', "quiet", &quiet, "do not show any warnings or messages"),
OPT_END()
};
static struct option check_feature_options[] = { OPT_PARENT(check_options) };
static const char *check_usage[] = { NULL, NULL };
static const char *check_feature_usage[] = {
"perf check feature <feature_list>",
NULL
};
struct feature_status supported_features[] = {
FEATURE_STATUS("aio", HAVE_AIO_SUPPORT),
FEATURE_STATUS("bpf", HAVE_LIBBPF_SUPPORT),
FEATURE_STATUS("bpf_skeletons", HAVE_BPF_SKEL),
FEATURE_STATUS("debuginfod", HAVE_DEBUGINFOD_SUPPORT),
FEATURE_STATUS("dwarf", HAVE_DWARF_SUPPORT),
FEATURE_STATUS("dwarf_getlocations", HAVE_DWARF_GETLOCATIONS_SUPPORT),
FEATURE_STATUS("dwarf-unwind", HAVE_DWARF_UNWIND_SUPPORT),
FEATURE_STATUS("auxtrace", HAVE_AUXTRACE_SUPPORT),
FEATURE_STATUS("libaudit", HAVE_LIBAUDIT_SUPPORT),
FEATURE_STATUS("libbfd", HAVE_LIBBFD_SUPPORT),
FEATURE_STATUS("libcapstone", HAVE_LIBCAPSTONE_SUPPORT),
FEATURE_STATUS("libcrypto", HAVE_LIBCRYPTO_SUPPORT),
FEATURE_STATUS("libdw-dwarf-unwind", HAVE_DWARF_SUPPORT),
FEATURE_STATUS("libelf", HAVE_LIBELF_SUPPORT),
FEATURE_STATUS("libnuma", HAVE_LIBNUMA_SUPPORT),
FEATURE_STATUS("libopencsd", HAVE_CSTRACE_SUPPORT),
FEATURE_STATUS("libperl", HAVE_LIBPERL_SUPPORT),
FEATURE_STATUS("libpfm4", HAVE_LIBPFM),
FEATURE_STATUS("libpython", HAVE_LIBPYTHON_SUPPORT),
FEATURE_STATUS("libslang", HAVE_SLANG_SUPPORT),
FEATURE_STATUS("libtraceevent", HAVE_LIBTRACEEVENT),
FEATURE_STATUS("libunwind", HAVE_LIBUNWIND_SUPPORT),
FEATURE_STATUS("lzma", HAVE_LZMA_SUPPORT),
FEATURE_STATUS("numa_num_possible_cpus", HAVE_LIBNUMA_SUPPORT),
FEATURE_STATUS("syscall_table", HAVE_SYSCALL_TABLE_SUPPORT),
FEATURE_STATUS("zlib", HAVE_ZLIB_SUPPORT),
FEATURE_STATUS("zstd", HAVE_ZSTD_SUPPORT),
/* this should remain at end, to know the array end */
FEATURE_STATUS(NULL, _)
};
static void on_off_print(const char *status)
{
printf("[ ");
if (!strcmp(status, "OFF"))
color_fprintf(stdout, PERF_COLOR_RED, "%-3s", status);
else
color_fprintf(stdout, PERF_COLOR_GREEN, "%-3s", status);
printf(" ]");
}
/* Helper function to print status of a feature along with name/macro */
static void status_print(const char *name, const char *macro,
const char *status)
{
printf("%22s: ", name);
on_off_print(status);
printf(" # %s\n", macro);
}
#define STATUS(feature) \
do { \
if (feature.is_builtin) \
status_print(feature.name, feature.macro, "on"); \
else \
status_print(feature.name, feature.macro, "OFF"); \
} while (0)
/**
* check whether "feature" is built-in with perf
*
* returns:
* 0: NOT built-in or Feature not known
* 1: Built-in
*/
static int has_support(const char *feature)
{
for (int i = 0; supported_features[i].name; ++i) {
if ((strcasecmp(feature, supported_features[i].name) == 0) ||
(strcasecmp(feature, supported_features[i].macro) == 0)) {
if (!quiet)
STATUS(supported_features[i]);
return supported_features[i].is_builtin;
}
}
if (!quiet)
pr_err("Unknown feature '%s', please use 'perf version --build-options' to see which ones are available.\n", feature);
return 0;
}
/**
* Usage: 'perf check feature <feature_list>'
*
* <feature_list> can be a single feature name/macro, or a comma-separated list
* of feature names/macros
* eg. argument can be "libtraceevent" or "libtraceevent,bpf" etc
*
* In case of a comma-separated list, feature_enabled will be 1, only if
* all features passed in the string are supported
*
* Note that argv will get modified
*/
static int subcommand_feature(int argc, const char **argv)
{
char *feature_list;
char *feature_name;
int feature_enabled;
argc = parse_options(argc, argv, check_feature_options,
check_feature_usage, 0);
if (!argc)
usage_with_options(check_feature_usage, check_feature_options);
if (argc > 1) {
pr_err("Too many arguments passed to 'perf check feature'\n");
return -1;
}
feature_enabled = 1;
/* feature_list is a non-const copy of 'argv[0]' */
feature_list = strdup(argv[0]);
if (!feature_list) {
pr_err("ERROR: failed to allocate memory for feature list\n");
return -1;
}
feature_name = strtok(feature_list, ",");
while (feature_name) {
feature_enabled &= has_support(feature_name);
feature_name = strtok(NULL, ",");
}
free(feature_list);
return !feature_enabled;
}
int cmd_check(int argc, const char **argv)
{
argc = parse_options_subcommand(argc, argv, check_options,
check_subcommands, check_usage, 0);
if (!argc)
usage_with_options(check_usage, check_options);
if (strcmp(argv[0], "feature") == 0)
return subcommand_feature(argc, argv);
/* If no subcommand matched above, print usage help */
pr_err("Unknown subcommand: %s\n", argv[0]);
usage_with_options(check_usage, check_options);
/* free usage string allocated by parse_options_subcommand */
free((void *)check_usage[0]);
return 0;
}
......@@ -1434,7 +1434,7 @@ static int __cmd_signal(struct daemon *daemon, struct option parent_options[],
}
memset(&cmd, 0, sizeof(cmd));
cmd.signal.cmd = CMD_SIGNAL,
cmd.signal.cmd = CMD_SIGNAL;
cmd.signal.sig = SIGUSR2;
strncpy(cmd.signal.name, name, sizeof(cmd.signal.name) - 1);
......
......@@ -388,7 +388,7 @@ struct hist_entry_ops block_hist_ops = {
.free = block_hist_free,
};
static int diff__process_sample_event(struct perf_tool *tool,
static int diff__process_sample_event(const struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct evsel *evsel,
......@@ -431,8 +431,8 @@ static int diff__process_sample_event(struct perf_tool *tool,
goto out;
}
hist__account_cycles(sample->branch_stack, &al, sample, false,
NULL);
hist__account_cycles(sample->branch_stack, &al, sample,
false, NULL, evsel);
break;
case COMPUTE_STREAM:
......@@ -467,21 +467,7 @@ static int diff__process_sample_event(struct perf_tool *tool,
return ret;
}
static struct perf_diff pdiff = {
.tool = {
.sample = diff__process_sample_event,
.mmap = perf_event__process_mmap,
.mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm,
.exit = perf_event__process_exit,
.fork = perf_event__process_fork,
.lost = perf_event__process_lost,
.namespaces = perf_event__process_namespaces,
.cgroup = perf_event__process_cgroup,
.ordered_events = true,
.ordering_requires_timestamps = true,
},
};
static struct perf_diff pdiff;
static struct evsel *evsel_match(struct evsel *evsel,
struct evlist *evlist)
......@@ -705,7 +691,7 @@ static void hists__precompute(struct hists *hists)
if (compute == COMPUTE_CYCLES) {
bh = container_of(he, struct block_hist, he);
init_block_hist(bh);
block_info__process_sym(he, bh, NULL, 0);
block_info__process_sym(he, bh, NULL, 0, 0);
}
data__for_each_file_new(i, d) {
......@@ -728,7 +714,7 @@ static void hists__precompute(struct hists *hists)
pair_bh = container_of(pair, struct block_hist,
he);
init_block_hist(pair_bh);
block_info__process_sym(pair, pair_bh, NULL, 0);
block_info__process_sym(pair, pair_bh, NULL, 0, 0);
bh = container_of(he, struct block_hist, he);
......@@ -1959,6 +1945,18 @@ int cmd_diff(int argc, const char **argv)
if (ret < 0)
return ret;
perf_tool__init(&pdiff.tool, /*ordered_events=*/true);
pdiff.tool.sample = diff__process_sample_event;
pdiff.tool.mmap = perf_event__process_mmap;
pdiff.tool.mmap2 = perf_event__process_mmap2;
pdiff.tool.comm = perf_event__process_comm;
pdiff.tool.exit = perf_event__process_exit;
pdiff.tool.fork = perf_event__process_fork;
pdiff.tool.lost = perf_event__process_lost;
pdiff.tool.namespaces = perf_event__process_namespaces;
pdiff.tool.cgroup = perf_event__process_cgroup;
pdiff.tool.ordering_requires_timestamps = true;
perf_config(diff__config, NULL);
argc = parse_options(argc, argv, options, diff_usage, 0);
......
......@@ -35,13 +35,13 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
.mode = PERF_DATA_MODE_READ,
.force = details->force,
};
struct perf_tool tool = {
/* only needed for pipe mode */
.attr = perf_event__process_attr,
.feature = process_header_feature,
};
bool has_tracepoint = false;
struct perf_tool tool;
bool has_tracepoint = false, has_group = false;
perf_tool__init(&tool, /*ordered_events=*/false);
/* only needed for pipe mode */
tool.attr = perf_event__process_attr;
tool.feature = process_header_feature;
session = perf_session__new(&data, &tool);
if (IS_ERR(session))
return PTR_ERR(session);
......@@ -54,11 +54,17 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
if (pos->core.attr.type == PERF_TYPE_TRACEPOINT)
has_tracepoint = true;
if (!evsel__is_group_leader(pos))
has_group = true;
}
if (has_tracepoint && !details->trace_fields)
printf("# Tip: use 'perf evlist --trace-fields' to show fields for tracepoint events\n");
if (has_group && !details->event_group)
printf("# Tip: use 'perf evlist -g' to show group information\n");
perf_session__delete(session);
return 0;
}
......
This diff is collapsed.
......@@ -417,7 +417,7 @@ static void open_html(const char *path)
static int show_html_page(const char *perf_cmd)
{
const char *page = cmd_to_page(perf_cmd);
char *page_path; /* it leaks but we exec bellow */
char *page_path; /* it leaks but we exec below */
if (get_html_page_path(&page_path, page) < 0)
return -1;
......
This diff is collapsed.
......@@ -955,7 +955,7 @@ static bool perf_kmem__skip_sample(struct perf_sample *sample)
typedef int (*tracepoint_handler)(struct evsel *evsel,
struct perf_sample *sample);
static int process_sample_event(struct perf_tool *tool __maybe_unused,
static int process_sample_event(const struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_sample *sample,
struct evsel *evsel,
......@@ -986,15 +986,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
return err;
}
static struct perf_tool perf_kmem = {
.sample = process_sample_event,
.comm = perf_event__process_comm,
.mmap = perf_event__process_mmap,
.mmap2 = perf_event__process_mmap2,
.namespaces = perf_event__process_namespaces,
.ordered_events = true,
};
static double fragmentation(unsigned long n_req, unsigned long n_alloc)
{
if (n_alloc == 0)
......@@ -1971,6 +1962,7 @@ int cmd_kmem(int argc, const char **argv)
NULL
};
struct perf_session *session;
struct perf_tool perf_kmem;
static const char errmsg[] = "No %s allocation events found. Have you run 'perf kmem record --%s'?\n";
int ret = perf_config(kmem_config, NULL);
......@@ -1998,6 +1990,13 @@ int cmd_kmem(int argc, const char **argv)
data.path = input_name;
perf_tool__init(&perf_kmem, /*ordered_events=*/true);
perf_kmem.sample = process_sample_event;
perf_kmem.comm = perf_event__process_comm;
perf_kmem.mmap = perf_event__process_mmap;
perf_kmem.mmap2 = perf_event__process_mmap2;
perf_kmem.namespaces = perf_event__process_namespaces;
kmem_session = session = perf_session__new(&data, &perf_kmem);
if (IS_ERR(session))
return PTR_ERR(session);
......@@ -2058,7 +2057,8 @@ int cmd_kmem(int argc, const char **argv)
out_delete:
perf_session__delete(session);
/* free usage string allocated by parse_options_subcommand */
free((void *)kmem_usage[0]);
return ret;
}
......@@ -1166,7 +1166,7 @@ static void print_result(struct perf_kvm_stat *kvm)
}
#if defined(HAVE_TIMERFD_SUPPORT) && defined(HAVE_LIBTRACEEVENT)
static int process_lost_event(struct perf_tool *tool,
static int process_lost_event(const struct perf_tool *tool,
union perf_event *event __maybe_unused,
struct perf_sample *sample __maybe_unused,
struct machine *machine __maybe_unused)
......@@ -1187,7 +1187,7 @@ static bool skip_sample(struct perf_kvm_stat *kvm,
return false;
}
static int process_sample_event(struct perf_tool *tool,
static int process_sample_event(const struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct evsel *evsel,
......@@ -1603,19 +1603,17 @@ static int read_events(struct perf_kvm_stat *kvm)
{
int ret;
struct perf_tool eops = {
.sample = process_sample_event,
.comm = perf_event__process_comm,
.namespaces = perf_event__process_namespaces,
.ordered_events = true,
};
struct perf_data file = {
.path = kvm->file_name,
.mode = PERF_DATA_MODE_READ,
.force = kvm->force,
};
kvm->tool = eops;
perf_tool__init(&kvm->tool, /*ordered_events=*/true);
kvm->tool.sample = process_sample_event;
kvm->tool.comm = perf_event__process_comm;
kvm->tool.namespaces = perf_event__process_namespaces;
kvm->session = perf_session__new(&file, &kvm->tool);
if (IS_ERR(kvm->session)) {
pr_err("Initializing perf session failed\n");
......@@ -1919,14 +1917,13 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
/* event handling */
perf_tool__init(&kvm->tool, /*ordered_events=*/true);
kvm->tool.sample = process_sample_event;
kvm->tool.comm = perf_event__process_comm;
kvm->tool.exit = perf_event__process_exit;
kvm->tool.fork = perf_event__process_fork;
kvm->tool.lost = process_lost_event;
kvm->tool.namespaces = perf_event__process_namespaces;
kvm->tool.ordered_events = true;
perf_tool__fill_defaults(&kvm->tool);
/* set defaults */
kvm->display_time = 1;
......@@ -2187,5 +2184,8 @@ int cmd_kvm(int argc, const char **argv)
else
usage_with_options(kvm_usage, kvm_options);
/* free usage string allocated by parse_options_subcommand */
free((void *)kvm_usage[0]);
return 0;
}
......@@ -958,7 +958,7 @@ static int top_sched_switch_event(struct perf_kwork *kwork,
}
static struct kwork_class kwork_irq;
static int process_irq_handler_entry_event(struct perf_tool *tool,
static int process_irq_handler_entry_event(const struct perf_tool *tool,
struct evsel *evsel,
struct perf_sample *sample,
struct machine *machine)
......@@ -971,7 +971,7 @@ static int process_irq_handler_entry_event(struct perf_tool *tool,
return 0;
}
static int process_irq_handler_exit_event(struct perf_tool *tool,
static int process_irq_handler_exit_event(const struct perf_tool *tool,
struct evsel *evsel,
struct perf_sample *sample,
struct machine *machine)
......@@ -1037,7 +1037,7 @@ static struct kwork_class kwork_irq = {
};
static struct kwork_class kwork_softirq;
static int process_softirq_raise_event(struct perf_tool *tool,
static int process_softirq_raise_event(const struct perf_tool *tool,
struct evsel *evsel,
struct perf_sample *sample,
struct machine *machine)
......@@ -1051,7 +1051,7 @@ static int process_softirq_raise_event(struct perf_tool *tool,
return 0;
}
static int process_softirq_entry_event(struct perf_tool *tool,
static int process_softirq_entry_event(const struct perf_tool *tool,
struct evsel *evsel,
struct perf_sample *sample,
struct machine *machine)
......@@ -1065,7 +1065,7 @@ static int process_softirq_entry_event(struct perf_tool *tool,
return 0;
}
static int process_softirq_exit_event(struct perf_tool *tool,
static int process_softirq_exit_event(const struct perf_tool *tool,
struct evsel *evsel,
struct perf_sample *sample,
struct machine *machine)
......@@ -1167,7 +1167,7 @@ static struct kwork_class kwork_softirq = {
};
static struct kwork_class kwork_workqueue;
static int process_workqueue_activate_work_event(struct perf_tool *tool,
static int process_workqueue_activate_work_event(const struct perf_tool *tool,
struct evsel *evsel,
struct perf_sample *sample,
struct machine *machine)
......@@ -1181,7 +1181,7 @@ static int process_workqueue_activate_work_event(struct perf_tool *tool,
return 0;
}
static int process_workqueue_execute_start_event(struct perf_tool *tool,
static int process_workqueue_execute_start_event(const struct perf_tool *tool,
struct evsel *evsel,
struct perf_sample *sample,
struct machine *machine)
......@@ -1195,7 +1195,7 @@ static int process_workqueue_execute_start_event(struct perf_tool *tool,
return 0;
}
static int process_workqueue_execute_end_event(struct perf_tool *tool,
static int process_workqueue_execute_end_event(const struct perf_tool *tool,
struct evsel *evsel,
struct perf_sample *sample,
struct machine *machine)
......@@ -1266,7 +1266,7 @@ static struct kwork_class kwork_workqueue = {
};
static struct kwork_class kwork_sched;
static int process_sched_switch_event(struct perf_tool *tool,
static int process_sched_switch_event(const struct perf_tool *tool,
struct evsel *evsel,
struct perf_sample *sample,
struct machine *machine)
......@@ -1945,12 +1945,12 @@ static int perf_kwork__report(struct perf_kwork *kwork)
return 0;
}
typedef int (*tracepoint_handler)(struct perf_tool *tool,
typedef int (*tracepoint_handler)(const struct perf_tool *tool,
struct evsel *evsel,
struct perf_sample *sample,
struct machine *machine);
static int perf_kwork__process_tracepoint_sample(struct perf_tool *tool,
static int perf_kwork__process_tracepoint_sample(const struct perf_tool *tool,
union perf_event *event __maybe_unused,
struct perf_sample *sample,
struct evsel *evsel,
......@@ -2322,12 +2322,6 @@ int cmd_kwork(int argc, const char **argv)
{
static struct perf_kwork kwork = {
.class_list = LIST_HEAD_INIT(kwork.class_list),
.tool = {
.mmap = perf_event__process_mmap,
.mmap2 = perf_event__process_mmap2,
.sample = perf_kwork__process_tracepoint_sample,
.ordered_events = true,
},
.atom_page_list = LIST_HEAD_INIT(kwork.atom_page_list),
.sort_list = LIST_HEAD_INIT(kwork.sort_list),
.cmp_id = LIST_HEAD_INIT(kwork.cmp_id),
......@@ -2462,6 +2456,11 @@ int cmd_kwork(int argc, const char **argv)
"record", "report", "latency", "timehist", "top", NULL
};
perf_tool__init(&kwork.tool, /*ordered_events=*/true);
kwork.tool.mmap = perf_event__process_mmap;
kwork.tool.mmap2 = perf_event__process_mmap2;
kwork.tool.sample = perf_kwork__process_tracepoint_sample;
argc = parse_options_subcommand(argc, argv, kwork_options,
kwork_subcommands, kwork_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
......@@ -2520,5 +2519,8 @@ int cmd_kwork(int argc, const char **argv)
} else
usage_with_options(kwork_usage, kwork_options);
/* free usage string allocated by parse_options_subcommand */
free((void *)kwork_usage[0]);
return 0;
}
......@@ -173,7 +173,7 @@ static void default_print_event(void *ps, const char *pmu_name, const char *topi
if (pmu_name && strcmp(pmu_name, "default_core")) {
desc_len = strlen(desc);
desc_len = asprintf(&desc_with_unit,
desc[desc_len - 1] != '.'
desc_len > 0 && desc[desc_len - 1] != '.'
? "%s. Unit: %s" : "%s Unit: %s",
desc, pmu_name);
}
......
......@@ -1501,7 +1501,7 @@ static const struct evsel_str_handler contention_tracepoints[] = {
{ "lock:contention_end", evsel__process_contention_end, },
};
static int process_event_update(struct perf_tool *tool,
static int process_event_update(const struct perf_tool *tool,
union perf_event *event,
struct evlist **pevlist)
{
......@@ -1520,7 +1520,7 @@ static int process_event_update(struct perf_tool *tool,
typedef int (*tracepoint_handler)(struct evsel *evsel,
struct perf_sample *sample);
static int process_sample_event(struct perf_tool *tool __maybe_unused,
static int process_sample_event(const struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_sample *sample,
struct evsel *evsel,
......@@ -1933,22 +1933,21 @@ static bool force;
static int __cmd_report(bool display_info)
{
int err = -EINVAL;
struct perf_tool eops = {
.attr = perf_event__process_attr,
.event_update = process_event_update,
.sample = process_sample_event,
.comm = perf_event__process_comm,
.mmap = perf_event__process_mmap,
.namespaces = perf_event__process_namespaces,
.tracing_data = perf_event__process_tracing_data,
.ordered_events = true,
};
struct perf_tool eops;
struct perf_data data = {
.path = input_name,
.mode = PERF_DATA_MODE_READ,
.force = force,
};
perf_tool__init(&eops, /*ordered_events=*/true);
eops.attr = perf_event__process_attr;
eops.event_update = process_event_update;
eops.sample = process_sample_event;
eops.comm = perf_event__process_comm;
eops.mmap = perf_event__process_mmap;
eops.namespaces = perf_event__process_namespaces;
eops.tracing_data = perf_event__process_tracing_data;
session = perf_session__new(&data, &eops);
if (IS_ERR(session)) {
pr_err("Initializing perf session failed\n");
......@@ -2069,15 +2068,7 @@ static int check_lock_contention_options(const struct option *options,
static int __cmd_contention(int argc, const char **argv)
{
int err = -EINVAL;
struct perf_tool eops = {
.attr = perf_event__process_attr,
.event_update = process_event_update,
.sample = process_sample_event,
.comm = perf_event__process_comm,
.mmap = perf_event__process_mmap,
.tracing_data = perf_event__process_tracing_data,
.ordered_events = true,
};
struct perf_tool eops;
struct perf_data data = {
.path = input_name,
.mode = PERF_DATA_MODE_READ,
......@@ -2100,6 +2091,14 @@ static int __cmd_contention(int argc, const char **argv)
con.result = &lockhash_table[0];
perf_tool__init(&eops, /*ordered_events=*/true);
eops.attr = perf_event__process_attr;
eops.event_update = process_event_update;
eops.sample = process_sample_event;
eops.comm = perf_event__process_comm;
eops.mmap = perf_event__process_mmap;
eops.tracing_data = perf_event__process_tracing_data;
session = perf_session__new(use_bpf ? NULL : &data, &eops);
if (IS_ERR(session)) {
pr_err("Initializing perf session failed\n");
......@@ -2713,6 +2712,9 @@ int cmd_lock(int argc, const char **argv)
usage_with_options(lock_usage, lock_options);
}
/* free usage string allocated by parse_options_subcommand */
free((void *)lock_usage[0]);
zfree(&lockhash_table);
return rc;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -320,7 +320,7 @@ static int *cpus_cstate_state;
static u64 *cpus_pstate_start_times;
static u64 *cpus_pstate_state;
static int process_comm_event(struct perf_tool *tool,
static int process_comm_event(const struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample __maybe_unused,
struct machine *machine __maybe_unused)
......@@ -330,7 +330,7 @@ static int process_comm_event(struct perf_tool *tool,
return 0;
}
static int process_fork_event(struct perf_tool *tool,
static int process_fork_event(const struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample __maybe_unused,
struct machine *machine __maybe_unused)
......@@ -340,7 +340,7 @@ static int process_fork_event(struct perf_tool *tool,
return 0;
}
static int process_exit_event(struct perf_tool *tool,
static int process_exit_event(const struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample __maybe_unused,
struct machine *machine __maybe_unused)
......@@ -571,7 +571,7 @@ typedef int (*tracepoint_handler)(struct timechart *tchart,
struct perf_sample *sample,
const char *backtrace);
static int process_sample_event(struct perf_tool *tool,
static int process_sample_event(const struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct evsel *evsel,
......@@ -1606,10 +1606,16 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
.mode = PERF_DATA_MODE_READ,
.force = tchart->force,
};
struct perf_session *session = perf_session__new(&data, &tchart->tool);
struct perf_session *session;
int ret = -EINVAL;
perf_tool__init(&tchart->tool, /*ordered_events=*/true);
tchart->tool.comm = process_comm_event;
tchart->tool.fork = process_fork_event;
tchart->tool.exit = process_exit_event;
tchart->tool.sample = process_sample_event;
session = perf_session__new(&data, &tchart->tool);
if (IS_ERR(session))
return PTR_ERR(session);
......@@ -1924,13 +1930,6 @@ parse_time(const struct option *opt, const char *arg, int __maybe_unused unset)
int cmd_timechart(int argc, const char **argv)
{
struct timechart tchart = {
.tool = {
.comm = process_comm_event,
.fork = process_fork_event,
.exit = process_exit_event,
.sample = process_sample_event,
.ordered_events = true,
},
.proc_num = 15,
.min_time = NSEC_PER_MSEC,
.merge_dist = 1000,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -172,6 +172,7 @@ check lib/ctype.c '-I "^EXPORT_SYMBOL" -I "^#include <linux/export.h>" -B
check lib/list_sort.c '-I "^#include <linux/bug.h>"'
# diff non-symmetric files
check_2 tools/perf/arch/x86/entry/syscalls/syscall_32.tbl arch/x86/entry/syscalls/syscall_32.tbl
check_2 tools/perf/arch/x86/entry/syscalls/syscall_64.tbl arch/x86/entry/syscalls/syscall_64.tbl
check_2 tools/perf/arch/powerpc/entry/syscalls/syscall.tbl arch/powerpc/kernel/syscalls/syscall.tbl
check_2 tools/perf/arch/s390/entry/syscalls/syscall.tbl arch/s390/kernel/syscalls/syscall.tbl
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment