Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar: "Lots of tooling updates - too many to list, here's a few highlights: - Various subcommand updates to 'perf trace', 'perf report', 'perf record', 'perf annotate', 'perf script', 'perf test', etc. - CPU and NUMA topology and affinity handling improvements, - HW tracing and HW support updates: - Intel PT updates - ARM CoreSight updates - vendor HW event updates - BPF updates - Tons of infrastructure updates, both on the build system and the library support side - Documentation updates. - ... and lots of other changes, see the changelog for details. Kernel side updates: - Tighten up kprobes blacklist handling, reduce the number of places where developers can install a kprobe and hang/crash the system. - Fix/enhance vma address filter handling. - Various PMU driver updates, small fixes and additions. - refcount_t conversions - BPF updates - error code propagation enhancements - misc other changes" * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (238 commits) perf script python: Add Python3 support to syscall-counts-by-pid.py perf script python: Add Python3 support to syscall-counts.py perf script python: Add Python3 support to stat-cpi.py perf script python: Add Python3 support to stackcollapse.py perf script python: Add Python3 support to sctop.py perf script python: Add Python3 support to powerpc-hcalls.py perf script python: Add Python3 support to net_dropmonitor.py perf script python: Add Python3 support to mem-phys-addr.py perf script python: Add Python3 support to failed-syscalls-by-pid.py perf script python: Add Python3 support to netdev-times.py perf tools: Add perf_exe() helper to find perf binary perf script: Handle missing fields with -F +.. perf data: Add perf_data__open_dir_data function perf data: Add perf_data__(create_dir|close_dir) functions perf data: Fail check_backup in case of error perf data: Make check_backup work over directories perf tools: Add rm_rf_perf_data function perf tools: Add pattern name checking to rm_rf perf tools: Add depth checking to rm_rf perf data: Add global path holder ...
This commit is contained in:
@@ -46,10 +46,10 @@ CFLAGS_builtin-trace.o += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_
|
||||
CFLAGS_builtin-report.o += -DTIPDIR="BUILD_STR($(tipdir_SQ))"
|
||||
CFLAGS_builtin-report.o += -DDOCDIR="BUILD_STR($(srcdir_SQ)/Documentation)"
|
||||
|
||||
libperf-y += util/
|
||||
libperf-y += arch/
|
||||
libperf-y += ui/
|
||||
libperf-y += scripts/
|
||||
libperf-$(CONFIG_TRACE) += trace/beauty/
|
||||
perf-y += util/
|
||||
perf-y += arch/
|
||||
perf-y += ui/
|
||||
perf-y += scripts/
|
||||
perf-$(CONFIG_TRACE) += trace/beauty/
|
||||
|
||||
gtk-y += ui/gtk/
|
||||
|
@@ -120,6 +120,10 @@ Given a $HOME/.perfconfig like this:
|
||||
children = true
|
||||
group = true
|
||||
|
||||
[llvm]
|
||||
dump-obj = true
|
||||
clang-opt = -g
|
||||
|
||||
You can hide source code of annotate feature setting the config to false with
|
||||
|
||||
% perf config annotate.hide_src_code=true
|
||||
@@ -553,6 +557,33 @@ trace.*::
|
||||
trace.show_zeros::
|
||||
Do not suppress syscall arguments that are equal to zero.
|
||||
|
||||
llvm.*::
|
||||
llvm.clang-path::
|
||||
Path to clang. If omit, search it from $PATH.
|
||||
|
||||
llvm.clang-bpf-cmd-template::
|
||||
Cmdline template. Below lines show its default value. Environment
|
||||
variable is used to pass options.
|
||||
"$CLANG_EXEC -D__KERNEL__ $CLANG_OPTIONS $KERNEL_INC_OPTIONS \
|
||||
-Wno-unused-value -Wno-pointer-sign -working-directory \
|
||||
$WORKING_DIR -c $CLANG_SOURCE -target bpf -O2 -o -"
|
||||
|
||||
llvm.clang-opt::
|
||||
Options passed to clang.
|
||||
|
||||
llvm.kbuild-dir::
|
||||
kbuild directory. If not set, use /lib/modules/`uname -r`/build.
|
||||
If set to "" deliberately, skip kernel header auto-detector.
|
||||
|
||||
llvm.kbuild-opts::
|
||||
Options passed to 'make' when detecting kernel header options.
|
||||
|
||||
llvm.dump-obj::
|
||||
Enable perf dump BPF object files compiled by LLVM.
|
||||
|
||||
llvm.opts::
|
||||
Options passed to llc.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkperf:perf[1]
|
||||
|
@@ -88,6 +88,20 @@ OPTIONS
|
||||
If you want to profile write accesses in [0x1000~1008), just set
|
||||
'mem:0x1000/8:w'.
|
||||
|
||||
- a BPF source file (ending in .c) or a precompiled object file (ending
|
||||
in .o) selects one or more BPF events.
|
||||
The BPF program can attach to various perf events based on the ELF section
|
||||
names.
|
||||
|
||||
When processing a '.c' file, perf searches an installed LLVM to compile it
|
||||
into an object file first. Optional clang options can be passed via the
|
||||
'--clang-opt' command line option, e.g.:
|
||||
|
||||
perf record --clang-opt "-DLINUX_VERSION_CODE=0x50000" \
|
||||
-e tests/bpf-script-example.c
|
||||
|
||||
Note: '--clang-opt' must be placed before '--event/-e'.
|
||||
|
||||
- a group of events surrounded by a pair of brace ("{event1,event2,...}").
|
||||
Each event is separated by commas and the group should be quoted to
|
||||
prevent the shell interpretation. You also need to use --group on
|
||||
@@ -440,6 +454,11 @@ Use <n> control blocks in asynchronous (Posix AIO) trace writing mode (default:
|
||||
Asynchronous mode is supported only when linking Perf tool with libc library
|
||||
providing implementation for Posix AIO API.
|
||||
|
||||
--affinity=mode::
|
||||
Set affinity mask of trace reading thread according to the policy defined by 'mode' value:
|
||||
node - thread affinity mask is set to NUMA node cpu mask of the processed mmap buffer
|
||||
cpu - thread affinity mask is set to cpu of the processed mmap buffer
|
||||
|
||||
--all-kernel::
|
||||
Configure all used events to run in kernel space.
|
||||
|
||||
|
@@ -159,6 +159,12 @@ OPTIONS
|
||||
the override, and the result of the above is that only S/W and H/W
|
||||
events are displayed with the given fields.
|
||||
|
||||
It's possible tp add/remove fields only for specific event type:
|
||||
|
||||
-Fsw:-cpu,-period
|
||||
|
||||
removes cpu and period from software events.
|
||||
|
||||
For the 'wildcard' option if a user selected field is invalid for an
|
||||
event type, a message is displayed to the user that the option is
|
||||
ignored for that type. For example:
|
||||
|
@@ -210,6 +210,14 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
|
||||
may happen, for instance, when a thread gets migrated to a different CPU
|
||||
while processing a syscall.
|
||||
|
||||
--map-dump::
|
||||
Dump BPF maps setup by events passed via -e, for instance the augmented_raw_syscalls
|
||||
living in tools/perf/examples/bpf/augmented_raw_syscalls.c. For now this
|
||||
dumps just boolean map values and integer keys, in time this will print in hex
|
||||
by default and use BTF when available, as well as use functions to do pretty
|
||||
printing using the existing 'perf trace' syscall arg beautifiers to map integer
|
||||
arguments to strings (pid to comm, syscall id to syscall name, etc).
|
||||
|
||||
|
||||
PAGEFAULTS
|
||||
----------
|
||||
|
@@ -43,11 +43,10 @@ struct perf_file_section {
|
||||
|
||||
Flags section:
|
||||
|
||||
The header is followed by different optional headers, described by the bits set
|
||||
in flags. Only headers for which the bit is set are included. Each header
|
||||
consists of a perf_file_section located after the initial header.
|
||||
The respective perf_file_section points to the data of the additional
|
||||
header and defines its size.
|
||||
For each of the optional features a perf_file_section it placed after the data
|
||||
section if the feature bit is set in the perf_header flags bitset. The
|
||||
respective perf_file_section points to the data of the additional header and
|
||||
defines its size.
|
||||
|
||||
Some headers consist of strings, which are defined like this:
|
||||
|
||||
@@ -131,7 +130,7 @@ An uint64_t with the total memory in bytes.
|
||||
|
||||
HEADER_CMDLINE = 11,
|
||||
|
||||
A perf_header_string with the perf command line used to collect the data.
|
||||
A perf_header_string_list with the perf arg-vector used to collect the data.
|
||||
|
||||
HEADER_EVENT_DESC = 12,
|
||||
|
||||
|
@@ -109,6 +109,13 @@ FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIBS)
|
||||
FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS)
|
||||
FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIBS)
|
||||
|
||||
FEATURE_CHECK_LDFLAGS-libunwind-arm = -lunwind -lunwind-arm
|
||||
FEATURE_CHECK_LDFLAGS-libunwind-aarch64 = -lunwind -lunwind-aarch64
|
||||
FEATURE_CHECK_LDFLAGS-libunwind-x86 = -lunwind -llzma -lunwind-x86
|
||||
FEATURE_CHECK_LDFLAGS-libunwind-x86_64 = -lunwind -llzma -lunwind-x86_64
|
||||
|
||||
FEATURE_CHECK_LDFLAGS-libcrypto = -lcrypto
|
||||
|
||||
ifdef CSINCLUDES
|
||||
LIBOPENCSD_CFLAGS := -I$(CSINCLUDES)
|
||||
endif
|
||||
@@ -218,6 +225,8 @@ FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS)
|
||||
FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS)
|
||||
FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS)
|
||||
|
||||
FEATURE_CHECK_LDFLAGS-libaio = -lrt
|
||||
|
||||
CFLAGS += -fno-omit-frame-pointer
|
||||
CFLAGS += -ggdb3
|
||||
CFLAGS += -funwind-tables
|
||||
@@ -386,7 +395,8 @@ ifeq ($(feature-setns), 1)
|
||||
$(call detected,CONFIG_SETNS)
|
||||
endif
|
||||
|
||||
ifndef NO_CORESIGHT
|
||||
ifdef CORESIGHT
|
||||
$(call feature_check,libopencsd)
|
||||
ifeq ($(feature-libopencsd), 1)
|
||||
CFLAGS += -DHAVE_CSTRACE_SUPPORT $(LIBOPENCSD_CFLAGS)
|
||||
LDFLAGS += $(LIBOPENCSD_LDFLAGS)
|
||||
@@ -482,6 +492,7 @@ endif
|
||||
ifndef NO_LIBUNWIND
|
||||
have_libunwind :=
|
||||
|
||||
$(call feature_check,libunwind-x86)
|
||||
ifeq ($(feature-libunwind-x86), 1)
|
||||
$(call detected,CONFIG_LIBUNWIND_X86)
|
||||
CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT
|
||||
@@ -490,6 +501,7 @@ ifndef NO_LIBUNWIND
|
||||
have_libunwind = 1
|
||||
endif
|
||||
|
||||
$(call feature_check,libunwind-aarch64)
|
||||
ifeq ($(feature-libunwind-aarch64), 1)
|
||||
$(call detected,CONFIG_LIBUNWIND_AARCH64)
|
||||
CFLAGS += -DHAVE_LIBUNWIND_AARCH64_SUPPORT
|
||||
|
@@ -102,7 +102,7 @@ include ../scripts/utilities.mak
|
||||
# When selected, pass LLVM_CONFIG=/path/to/llvm-config to `make' if
|
||||
# llvm-config is not in $PATH.
|
||||
#
|
||||
# Define NO_CORESIGHT if you do not want support for CoreSight trace decoding.
|
||||
# Define CORESIGHT if you DO WANT support for CoreSight trace decoding.
|
||||
#
|
||||
# Define NO_AIO if you do not want support of Posix AIO based trace
|
||||
# streaming for record mode. Currently Posix AIO trace streaming is
|
||||
@@ -344,9 +344,9 @@ endif
|
||||
|
||||
export PERL_PATH
|
||||
|
||||
LIB_FILE=$(OUTPUT)libperf.a
|
||||
LIBPERF_A=$(OUTPUT)libperf.a
|
||||
|
||||
PERFLIBS = $(LIB_FILE) $(LIBAPI) $(LIBTRACEEVENT) $(LIBSUBCMD)
|
||||
PERFLIBS = $(LIBAPI) $(LIBTRACEEVENT) $(LIBSUBCMD)
|
||||
ifndef NO_LIBBPF
|
||||
PERFLIBS += $(LIBBPF)
|
||||
endif
|
||||
@@ -549,6 +549,8 @@ JEVENTS_IN := $(OUTPUT)pmu-events/jevents-in.o
|
||||
|
||||
PMU_EVENTS_IN := $(OUTPUT)pmu-events/pmu-events-in.o
|
||||
|
||||
LIBPERF_IN := $(OUTPUT)libperf-in.o
|
||||
|
||||
export JEVENTS
|
||||
|
||||
build := -f $(srctree)/tools/build/Makefile.build dir=. obj
|
||||
@@ -565,9 +567,12 @@ $(JEVENTS): $(JEVENTS_IN)
|
||||
$(PMU_EVENTS_IN): $(JEVENTS) FORCE
|
||||
$(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=pmu-events obj=pmu-events
|
||||
|
||||
$(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(PMU_EVENTS_IN) $(LIBTRACEEVENT_DYNAMIC_LIST)
|
||||
$(LIBPERF_IN): prepare FORCE
|
||||
$(Q)$(MAKE) $(build)=libperf
|
||||
|
||||
$(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(PMU_EVENTS_IN) $(LIBPERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST)
|
||||
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS) \
|
||||
$(PERF_IN) $(PMU_EVENTS_IN) $(LIBS) -o $@
|
||||
$(PERF_IN) $(PMU_EVENTS_IN) $(LIBPERF_IN) $(LIBS) -o $@
|
||||
|
||||
$(GTK_IN): FORCE
|
||||
$(Q)$(MAKE) $(build)=gtk
|
||||
@@ -683,12 +688,7 @@ endif
|
||||
|
||||
$(patsubst perf-%,%.o,$(PROGRAMS)): $(wildcard */*.h)
|
||||
|
||||
LIBPERF_IN := $(OUTPUT)libperf-in.o
|
||||
|
||||
$(LIBPERF_IN): prepare FORCE
|
||||
$(Q)$(MAKE) $(build)=libperf
|
||||
|
||||
$(LIB_FILE): $(LIBPERF_IN)
|
||||
$(LIBPERF_A): $(LIBPERF_IN)
|
||||
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIBPERF_IN) $(LIB_OBJS)
|
||||
|
||||
LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ) 'EXTRA_CFLAGS=$(EXTRA_CFLAGS)' 'LDFLAGS=$(LDFLAGS)'
|
||||
@@ -863,8 +863,8 @@ ifndef NO_LIBPYTHON
|
||||
$(call QUIET_INSTALL, python-scripts) \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'; \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'; \
|
||||
$(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'; \
|
||||
$(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'; \
|
||||
$(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -m 644 -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'; \
|
||||
$(INSTALL) scripts/python/*.py -m 644 -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'; \
|
||||
$(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
|
||||
endif
|
||||
$(call QUIET_INSTALL, perf_completion-script) \
|
||||
@@ -910,7 +910,7 @@ python-clean:
|
||||
$(python-clean)
|
||||
|
||||
clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean config-clean fixdep-clean python-clean
|
||||
$(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)
|
||||
$(call QUIET_CLEAN, core-objs) $(RM) $(LIBPERF_A) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)
|
||||
$(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
|
||||
$(Q)$(RM) $(OUTPUT).config-detected
|
||||
$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 $(OUTPUT)pmu-events/jevents $(OUTPUT)$(LIBJVMTI).so
|
||||
|
@@ -1,2 +1,2 @@
|
||||
libperf-y += common.o
|
||||
libperf-y += $(SRCARCH)/
|
||||
perf-y += common.o
|
||||
perf-y += $(SRCARCH)/
|
||||
|
@@ -1,2 +1,2 @@
|
||||
libperf-y += util/
|
||||
libperf-$(CONFIG_DWARF_UNWIND) += tests/
|
||||
perf-y += util/
|
||||
perf-$(CONFIG_DWARF_UNWIND) += tests/
|
||||
|
@@ -1,5 +1,5 @@
|
||||
libperf-y += regs_load.o
|
||||
libperf-y += dwarf-unwind.o
|
||||
libperf-y += vectors-page.o
|
||||
perf-y += regs_load.o
|
||||
perf-y += dwarf-unwind.o
|
||||
perf-y += vectors-page.o
|
||||
|
||||
libperf-y += arch-tests.o
|
||||
perf-y += arch-tests.o
|
||||
|
@@ -3,6 +3,7 @@
|
||||
#include "perf_regs.h"
|
||||
#include "thread.h"
|
||||
#include "map.h"
|
||||
#include "map_groups.h"
|
||||
#include "event.h"
|
||||
#include "debug.h"
|
||||
#include "tests/tests.h"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
libperf-$(CONFIG_DWARF) += dwarf-regs.o
|
||||
perf-$(CONFIG_DWARF) += dwarf-regs.o
|
||||
|
||||
libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
|
||||
libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
|
||||
perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
|
||||
libperf-$(CONFIG_AUXTRACE) += pmu.o auxtrace.o cs-etm.o
|
||||
perf-$(CONFIG_AUXTRACE) += pmu.o auxtrace.o cs-etm.o
|
||||
|
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <api/fs/fs.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/coresight-pmu.h>
|
||||
@@ -22,12 +23,10 @@
|
||||
#include "../../util/thread_map.h"
|
||||
#include "../../util/cs-etm.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define ENABLE_SINK_MAX 128
|
||||
#define CS_BUS_DEVICE_PATH "/bus/coresight/devices/"
|
||||
|
||||
struct cs_etm_recording {
|
||||
struct auxtrace_record itr;
|
||||
struct perf_pmu *cs_etm_pmu;
|
||||
@@ -60,10 +59,48 @@ static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
|
||||
struct perf_evsel *evsel)
|
||||
{
|
||||
char msg[BUFSIZ], path[PATH_MAX], *sink;
|
||||
struct perf_evsel_config_term *term;
|
||||
int ret = -EINVAL;
|
||||
u32 hash;
|
||||
|
||||
if (evsel->attr.config2 & GENMASK(31, 0))
|
||||
return 0;
|
||||
|
||||
list_for_each_entry(term, &evsel->config_terms, list) {
|
||||
if (term->type != PERF_EVSEL__CONFIG_TERM_DRV_CFG)
|
||||
continue;
|
||||
|
||||
sink = term->val.drv_cfg;
|
||||
snprintf(path, PATH_MAX, "sinks/%s", sink);
|
||||
|
||||
ret = perf_pmu__scan_file(pmu, path, "%x", &hash);
|
||||
if (ret != 1) {
|
||||
pr_err("failed to set sink \"%s\" on event %s with %d (%s)\n",
|
||||
sink, perf_evsel__name(evsel), errno,
|
||||
str_error_r(errno, msg, sizeof(msg)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
evsel->attr.config2 |= hash;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* No sink was provided on the command line - for _now_ treat
|
||||
* this as an error.
|
||||
*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cs_etm_recording_options(struct auxtrace_record *itr,
|
||||
struct perf_evlist *evlist,
|
||||
struct record_opts *opts)
|
||||
{
|
||||
int ret;
|
||||
struct cs_etm_recording *ptr =
|
||||
container_of(itr, struct cs_etm_recording, itr);
|
||||
struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
|
||||
@@ -92,6 +129,10 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
|
||||
if (!cs_etm_evsel)
|
||||
return 0;
|
||||
|
||||
ret = cs_etm_set_sink_attr(cs_etm_pmu, cs_etm_evsel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (opts->use_clockid) {
|
||||
pr_err("Cannot use clockid (-k option) with %s\n",
|
||||
CORESIGHT_ETM_PMU_NAME);
|
||||
@@ -598,54 +639,3 @@ struct auxtrace_record *cs_etm_record_init(int *err)
|
||||
out:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static FILE *cs_device__open_file(const char *name)
|
||||
{
|
||||
struct stat st;
|
||||
char path[PATH_MAX];
|
||||
const char *sysfs;
|
||||
|
||||
sysfs = sysfs__mountpoint();
|
||||
if (!sysfs)
|
||||
return NULL;
|
||||
|
||||
snprintf(path, PATH_MAX,
|
||||
"%s" CS_BUS_DEVICE_PATH "%s", sysfs, name);
|
||||
|
||||
if (stat(path, &st) < 0)
|
||||
return NULL;
|
||||
|
||||
return fopen(path, "w");
|
||||
|
||||
}
|
||||
|
||||
static int __printf(2, 3) cs_device__print_file(const char *name, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
FILE *file;
|
||||
int ret = -EINVAL;
|
||||
|
||||
va_start(args, fmt);
|
||||
file = cs_device__open_file(name);
|
||||
if (file) {
|
||||
ret = vfprintf(file, fmt, args);
|
||||
fclose(file);
|
||||
}
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cs_etm_set_drv_config(struct perf_evsel_config_term *term)
|
||||
{
|
||||
int ret;
|
||||
char enable_sink[ENABLE_SINK_MAX];
|
||||
|
||||
snprintf(enable_sink, ENABLE_SINK_MAX, "%s/%s",
|
||||
term->val.drv_cfg, "enable_sink");
|
||||
|
||||
ret = cs_device__print_file(enable_sink, "%d", 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -7,9 +7,6 @@
|
||||
#ifndef INCLUDE__PERF_CS_ETM_H__
|
||||
#define INCLUDE__PERF_CS_ETM_H__
|
||||
|
||||
#include "../../util/evsel.h"
|
||||
|
||||
struct auxtrace_record *cs_etm_record_init(int *err);
|
||||
int cs_etm_set_drv_config(struct perf_evsel_config_term *term);
|
||||
|
||||
#endif
|
||||
|
@@ -7,8 +7,8 @@
|
||||
#include <string.h>
|
||||
#include <linux/coresight-pmu.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "cs-etm.h"
|
||||
#include "arm-spe.h"
|
||||
#include "../../util/pmu.h"
|
||||
|
||||
@@ -19,7 +19,6 @@ struct perf_event_attr
|
||||
if (!strcmp(pmu->name, CORESIGHT_ETM_PMU_NAME)) {
|
||||
/* add ETM default config here */
|
||||
pmu->selectable = true;
|
||||
pmu->set_drv_config = cs_etm_set_drv_config;
|
||||
#if defined(__aarch64__)
|
||||
} else if (strstarts(pmu->name, ARM_SPE_PMU_NAME)) {
|
||||
return arm_spe_pmu_default_config(pmu);
|
||||
|
@@ -1,2 +1,2 @@
|
||||
libperf-y += util/
|
||||
libperf-$(CONFIG_DWARF_UNWIND) += tests/
|
||||
perf-y += util/
|
||||
perf-$(CONFIG_DWARF_UNWIND) += tests/
|
||||
|
@@ -1,4 +1,4 @@
|
||||
libperf-y += regs_load.o
|
||||
libperf-y += dwarf-unwind.o
|
||||
perf-y += regs_load.o
|
||||
perf-y += dwarf-unwind.o
|
||||
|
||||
libperf-y += arch-tests.o
|
||||
perf-y += arch-tests.o
|
||||
|
@@ -3,6 +3,7 @@
|
||||
#include "perf_regs.h"
|
||||
#include "thread.h"
|
||||
#include "map.h"
|
||||
#include "map_groups.h"
|
||||
#include "event.h"
|
||||
#include "debug.h"
|
||||
#include "tests/tests.h"
|
||||
|
@@ -1,10 +1,10 @@
|
||||
libperf-y += header.o
|
||||
libperf-y += sym-handling.o
|
||||
libperf-$(CONFIG_DWARF) += dwarf-regs.o
|
||||
libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
|
||||
libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
perf-y += header.o
|
||||
perf-y += sym-handling.o
|
||||
perf-$(CONFIG_DWARF) += dwarf-regs.o
|
||||
perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
|
||||
perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
|
||||
libperf-$(CONFIG_AUXTRACE) += ../../arm/util/pmu.o \
|
||||
perf-$(CONFIG_AUXTRACE) += ../../arm/util/pmu.o \
|
||||
../../arm/util/auxtrace.o \
|
||||
../../arm/util/cs-etm.o \
|
||||
arm-spe.o
|
||||
|
@@ -1 +1 @@
|
||||
libperf-y += util/
|
||||
perf-y += util/
|
||||
|
@@ -1 +1 @@
|
||||
libperf-y += header.o
|
||||
perf-y += header.o
|
||||
|
@@ -1,2 +1,2 @@
|
||||
libperf-y += util/
|
||||
libperf-y += tests/
|
||||
perf-y += util/
|
||||
perf-y += tests/
|
||||
|
@@ -1,4 +1,4 @@
|
||||
libperf-$(CONFIG_DWARF_UNWIND) += regs_load.o
|
||||
libperf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
|
||||
perf-$(CONFIG_DWARF_UNWIND) += regs_load.o
|
||||
perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
|
||||
|
||||
libperf-y += arch-tests.o
|
||||
perf-y += arch-tests.o
|
||||
|
@@ -3,6 +3,7 @@
|
||||
#include "perf_regs.h"
|
||||
#include "thread.h"
|
||||
#include "map.h"
|
||||
#include "map_groups.h"
|
||||
#include "event.h"
|
||||
#include "debug.h"
|
||||
#include "tests/tests.h"
|
||||
|
@@ -1,11 +1,11 @@
|
||||
libperf-y += header.o
|
||||
libperf-y += sym-handling.o
|
||||
libperf-y += kvm-stat.o
|
||||
libperf-y += perf_regs.o
|
||||
libperf-y += mem-events.o
|
||||
perf-y += header.o
|
||||
perf-y += sym-handling.o
|
||||
perf-y += kvm-stat.o
|
||||
perf-y += perf_regs.o
|
||||
perf-y += mem-events.o
|
||||
|
||||
libperf-$(CONFIG_DWARF) += dwarf-regs.o
|
||||
libperf-$(CONFIG_DWARF) += skip-callchain-idx.o
|
||||
perf-$(CONFIG_DWARF) += dwarf-regs.o
|
||||
perf-$(CONFIG_DWARF) += skip-callchain-idx.o
|
||||
|
||||
libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
|
||||
libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
perf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
|
||||
perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
|
@@ -3,6 +3,8 @@
|
||||
#include "util/kvm-stat.h"
|
||||
#include "util/parse-events.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/evsel.h"
|
||||
#include "util/evlist.h"
|
||||
|
||||
#include "book3s_hv_exits.h"
|
||||
#include "book3s_hcalls.h"
|
||||
|
@@ -16,6 +16,9 @@
|
||||
#include "util/thread.h"
|
||||
#include "util/callchain.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/dso.h"
|
||||
#include "util/map.h"
|
||||
#include "util/symbol.h"
|
||||
|
||||
/*
|
||||
* When saving the callchain on Power, the kernel conservatively saves
|
||||
|
@@ -1 +1 @@
|
||||
libperf-y += util/
|
||||
perf-y += util/
|
||||
|
@@ -1,9 +1,9 @@
|
||||
libperf-y += header.o
|
||||
libperf-y += kvm-stat.o
|
||||
perf-y += header.o
|
||||
perf-y += kvm-stat.o
|
||||
|
||||
libperf-$(CONFIG_DWARF) += dwarf-regs.o
|
||||
libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
perf-$(CONFIG_DWARF) += dwarf-regs.o
|
||||
perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
|
||||
libperf-y += machine.o
|
||||
perf-y += machine.o
|
||||
|
||||
libperf-$(CONFIG_AUXTRACE) += auxtrace.o
|
||||
perf-$(CONFIG_AUXTRACE) += auxtrace.o
|
||||
|
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include "../../util/kvm-stat.h"
|
||||
#include "../../util/evsel.h"
|
||||
#include <asm/sie.h>
|
||||
|
||||
define_exit_reasons_table(sie_exit_reasons, sie_intercept_code);
|
||||
|
@@ -1 +1 @@
|
||||
libperf-y += util/
|
||||
perf-y += util/
|
||||
|
@@ -1 +1 @@
|
||||
libperf-$(CONFIG_DWARF) += dwarf-regs.o
|
||||
perf-$(CONFIG_DWARF) += dwarf-regs.o
|
||||
|
@@ -1 +1 @@
|
||||
libperf-y += util/
|
||||
perf-y += util/
|
||||
|
@@ -1 +1 @@
|
||||
libperf-$(CONFIG_DWARF) += dwarf-regs.o
|
||||
perf-$(CONFIG_DWARF) += dwarf-regs.o
|
||||
|
@@ -1,2 +1,2 @@
|
||||
libperf-y += util/
|
||||
libperf-y += tests/
|
||||
perf-y += util/
|
||||
perf-y += tests/
|
||||
|
@@ -1,8 +1,8 @@
|
||||
libperf-$(CONFIG_DWARF_UNWIND) += regs_load.o
|
||||
libperf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
|
||||
perf-$(CONFIG_DWARF_UNWIND) += regs_load.o
|
||||
perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
|
||||
|
||||
libperf-y += arch-tests.o
|
||||
libperf-y += rdpmc.o
|
||||
libperf-y += perf-time-to-tsc.o
|
||||
libperf-$(CONFIG_AUXTRACE) += insn-x86.o
|
||||
libperf-$(CONFIG_X86_64) += bp-modify.o
|
||||
perf-y += arch-tests.o
|
||||
perf-y += rdpmc.o
|
||||
perf-y += perf-time-to-tsc.o
|
||||
perf-$(CONFIG_AUXTRACE) += insn-x86.o
|
||||
perf-$(CONFIG_X86_64) += bp-modify.o
|
||||
|
@@ -3,6 +3,7 @@
|
||||
#include "perf_regs.h"
|
||||
#include "thread.h"
|
||||
#include "map.h"
|
||||
#include "map_groups.h"
|
||||
#include "event.h"
|
||||
#include "debug.h"
|
||||
#include "tests/tests.h"
|
||||
|
@@ -1,18 +1,18 @@
|
||||
libperf-y += header.o
|
||||
libperf-y += tsc.o
|
||||
libperf-y += pmu.o
|
||||
libperf-y += kvm-stat.o
|
||||
libperf-y += perf_regs.o
|
||||
libperf-y += group.o
|
||||
libperf-y += machine.o
|
||||
libperf-y += event.o
|
||||
perf-y += header.o
|
||||
perf-y += tsc.o
|
||||
perf-y += pmu.o
|
||||
perf-y += kvm-stat.o
|
||||
perf-y += perf_regs.o
|
||||
perf-y += group.o
|
||||
perf-y += machine.o
|
||||
perf-y += event.o
|
||||
|
||||
libperf-$(CONFIG_DWARF) += dwarf-regs.o
|
||||
libperf-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o
|
||||
perf-$(CONFIG_DWARF) += dwarf-regs.o
|
||||
perf-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o
|
||||
|
||||
libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
|
||||
libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
|
||||
perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
|
||||
libperf-$(CONFIG_AUXTRACE) += auxtrace.o
|
||||
libperf-$(CONFIG_AUXTRACE) += intel-pt.o
|
||||
libperf-$(CONFIG_AUXTRACE) += intel-bts.o
|
||||
perf-$(CONFIG_AUXTRACE) += auxtrace.o
|
||||
perf-$(CONFIG_AUXTRACE) += intel-pt.o
|
||||
perf-$(CONFIG_AUXTRACE) += intel-bts.o
|
||||
|
@@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <errno.h>
|
||||
#include "../../util/kvm-stat.h"
|
||||
#include "../../util/evsel.h"
|
||||
#include <asm/svm.h>
|
||||
#include <asm/vmx.h>
|
||||
#include <asm/kvm.h>
|
||||
|
@@ -1 +1 @@
|
||||
libperf-y += util/
|
||||
perf-y += util/
|
||||
|
@@ -1 +1 @@
|
||||
libperf-$(CONFIG_DWARF) += dwarf-regs.o
|
||||
perf-$(CONFIG_DWARF) += dwarf-regs.o
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include "util/thread.h"
|
||||
#include "util/sort.h"
|
||||
#include "util/hist.h"
|
||||
#include "util/map.h"
|
||||
#include "util/session.h"
|
||||
#include "util/tool.h"
|
||||
#include "util/data.h"
|
||||
@@ -227,7 +228,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
|
||||
* the DSO?
|
||||
*/
|
||||
if (al->sym != NULL) {
|
||||
rb_erase(&al->sym->rb_node,
|
||||
rb_erase_cached(&al->sym->rb_node,
|
||||
&al->map->dso->symbols);
|
||||
symbol__delete(al->sym);
|
||||
dso__reset_find_symbol_cache(al->map->dso);
|
||||
@@ -305,7 +306,7 @@ static void hists__find_annotations(struct hists *hists,
|
||||
struct perf_evsel *evsel,
|
||||
struct perf_annotate *ann)
|
||||
{
|
||||
struct rb_node *nd = rb_first(&hists->entries), *next;
|
||||
struct rb_node *nd = rb_first_cached(&hists->entries), *next;
|
||||
int key = K_RIGHT;
|
||||
|
||||
while (nd) {
|
||||
@@ -440,7 +441,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
|
||||
}
|
||||
|
||||
if (total_nr_samples == 0) {
|
||||
ui__error("The %s file has no samples!\n", session->data->file.path);
|
||||
ui__error("The %s data has no samples!\n", session->data->path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -577,7 +578,7 @@ int cmd_annotate(int argc, const char **argv)
|
||||
if (quiet)
|
||||
perf_quiet_option();
|
||||
|
||||
data.file.path = input_name;
|
||||
data.path = input_name;
|
||||
|
||||
annotate.session = perf_session__new(&data, false, &annotate.tool);
|
||||
if (annotate.session == NULL)
|
||||
|
@@ -416,8 +416,8 @@ int cmd_buildid_cache(int argc, const char **argv)
|
||||
nsi = nsinfo__new(ns_id);
|
||||
|
||||
if (missing_filename) {
|
||||
data.file.path = missing_filename;
|
||||
data.force = force;
|
||||
data.path = missing_filename;
|
||||
data.force = force;
|
||||
|
||||
session = perf_session__new(&data, false, NULL);
|
||||
if (session == NULL)
|
||||
|
@@ -52,11 +52,9 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
|
||||
{
|
||||
struct perf_session *session;
|
||||
struct perf_data data = {
|
||||
.file = {
|
||||
.path = input_name,
|
||||
},
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = force,
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = force,
|
||||
};
|
||||
|
||||
symbol__elf_init();
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#include "ui/browsers/hists.h"
|
||||
#include "thread.h"
|
||||
#include "mem2node.h"
|
||||
#include "symbol.h"
|
||||
|
||||
struct c2c_hists {
|
||||
struct hists hists;
|
||||
@@ -1969,7 +1970,7 @@ static void calc_width(struct c2c_hist_entry *c2c_he)
|
||||
set_nodestr(c2c_he);
|
||||
}
|
||||
|
||||
static int filter_cb(struct hist_entry *he)
|
||||
static int filter_cb(struct hist_entry *he, void *arg __maybe_unused)
|
||||
{
|
||||
struct c2c_hist_entry *c2c_he;
|
||||
|
||||
@@ -1986,7 +1987,7 @@ static int filter_cb(struct hist_entry *he)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int resort_cl_cb(struct hist_entry *he)
|
||||
static int resort_cl_cb(struct hist_entry *he, void *arg __maybe_unused)
|
||||
{
|
||||
struct c2c_hist_entry *c2c_he;
|
||||
struct c2c_hists *c2c_hists;
|
||||
@@ -2073,7 +2074,7 @@ static int setup_nodes(struct perf_session *session)
|
||||
|
||||
#define HAS_HITMS(__h) ((__h)->stats.lcl_hitm || (__h)->stats.rmt_hitm)
|
||||
|
||||
static int resort_hitm_cb(struct hist_entry *he)
|
||||
static int resort_hitm_cb(struct hist_entry *he, void *arg __maybe_unused)
|
||||
{
|
||||
struct c2c_hist_entry *c2c_he;
|
||||
c2c_he = container_of(he, struct c2c_hist_entry, he);
|
||||
@@ -2088,14 +2089,14 @@ static int resort_hitm_cb(struct hist_entry *he)
|
||||
|
||||
static int hists__iterate_cb(struct hists *hists, hists__resort_cb_t cb)
|
||||
{
|
||||
struct rb_node *next = rb_first(&hists->entries);
|
||||
struct rb_node *next = rb_first_cached(&hists->entries);
|
||||
int ret = 0;
|
||||
|
||||
while (next) {
|
||||
struct hist_entry *he;
|
||||
|
||||
he = rb_entry(next, struct hist_entry, rb_node);
|
||||
ret = cb(he);
|
||||
ret = cb(he, NULL);
|
||||
if (ret)
|
||||
break;
|
||||
next = rb_next(&he->rb_node);
|
||||
@@ -2215,7 +2216,7 @@ static void print_pareto(FILE *out)
|
||||
if (WARN_ONCE(ret, "failed to setup sort entries\n"))
|
||||
return;
|
||||
|
||||
nd = rb_first(&c2c.hists.hists.entries);
|
||||
nd = rb_first_cached(&c2c.hists.hists.entries);
|
||||
|
||||
for (; nd; nd = rb_next(nd)) {
|
||||
struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
|
||||
@@ -2283,7 +2284,7 @@ static void perf_c2c__hists_fprintf(FILE *out, struct perf_session *session)
|
||||
static void c2c_browser__update_nr_entries(struct hist_browser *hb)
|
||||
{
|
||||
u64 nr_entries = 0;
|
||||
struct rb_node *nd = rb_first(&hb->hists->entries);
|
||||
struct rb_node *nd = rb_first_cached(&hb->hists->entries);
|
||||
|
||||
while (nd) {
|
||||
struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
|
||||
@@ -2343,7 +2344,7 @@ static int perf_c2c__browse_cacheline(struct hist_entry *he)
|
||||
struct c2c_cacheline_browser *cl_browser;
|
||||
struct hist_browser *browser;
|
||||
int key = -1;
|
||||
const char help[] =
|
||||
static const char help[] =
|
||||
" ENTER Toggle callchains (if present) \n"
|
||||
" n Toggle Node details info \n"
|
||||
" s Toggle full length of symbol and source line columns \n"
|
||||
@@ -2424,7 +2425,7 @@ static int perf_c2c__hists_browse(struct hists *hists)
|
||||
{
|
||||
struct hist_browser *browser;
|
||||
int key = -1;
|
||||
const char help[] =
|
||||
static const char help[] =
|
||||
" d Display cacheline details \n"
|
||||
" ENTER Toggle callchains (if present) \n"
|
||||
" q Quit \n";
|
||||
@@ -2749,8 +2750,8 @@ static int perf_c2c__report(int argc, const char **argv)
|
||||
if (!input_name || !strlen(input_name))
|
||||
input_name = "perf.data";
|
||||
|
||||
data.file.path = input_name;
|
||||
data.force = symbol_conf.force;
|
||||
data.path = input_name;
|
||||
data.force = symbol_conf.force;
|
||||
|
||||
err = setup_display(display);
|
||||
if (err)
|
||||
|
@@ -429,7 +429,7 @@ get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt)
|
||||
|
||||
static void hists__baseline_only(struct hists *hists)
|
||||
{
|
||||
struct rb_root *root;
|
||||
struct rb_root_cached *root;
|
||||
struct rb_node *next;
|
||||
|
||||
if (hists__has(hists, need_collapse))
|
||||
@@ -437,13 +437,13 @@ static void hists__baseline_only(struct hists *hists)
|
||||
else
|
||||
root = hists->entries_in;
|
||||
|
||||
next = rb_first(root);
|
||||
next = rb_first_cached(root);
|
||||
while (next != NULL) {
|
||||
struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
|
||||
|
||||
next = rb_next(&he->rb_node_in);
|
||||
if (!hist_entry__next_pair(he)) {
|
||||
rb_erase(&he->rb_node_in, root);
|
||||
rb_erase_cached(&he->rb_node_in, root);
|
||||
hist_entry__delete(he);
|
||||
}
|
||||
}
|
||||
@@ -451,7 +451,7 @@ static void hists__baseline_only(struct hists *hists)
|
||||
|
||||
static void hists__precompute(struct hists *hists)
|
||||
{
|
||||
struct rb_root *root;
|
||||
struct rb_root_cached *root;
|
||||
struct rb_node *next;
|
||||
|
||||
if (hists__has(hists, need_collapse))
|
||||
@@ -459,7 +459,7 @@ static void hists__precompute(struct hists *hists)
|
||||
else
|
||||
root = hists->entries_in;
|
||||
|
||||
next = rb_first(root);
|
||||
next = rb_first_cached(root);
|
||||
while (next != NULL) {
|
||||
struct hist_entry *he, *pair;
|
||||
struct data__file *d;
|
||||
@@ -708,7 +708,7 @@ static void data__fprintf(void)
|
||||
|
||||
data__for_each_file(i, d)
|
||||
fprintf(stdout, "# [%d] %s %s\n",
|
||||
d->idx, d->data.file.path,
|
||||
d->idx, d->data.path,
|
||||
!d->idx ? "(Baseline)" : "");
|
||||
|
||||
fprintf(stdout, "#\n");
|
||||
@@ -779,14 +779,14 @@ static int __cmd_diff(void)
|
||||
data__for_each_file(i, d) {
|
||||
d->session = perf_session__new(&d->data, false, &tool);
|
||||
if (!d->session) {
|
||||
pr_err("Failed to open %s\n", d->data.file.path);
|
||||
pr_err("Failed to open %s\n", d->data.path);
|
||||
ret = -1;
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
ret = perf_session__process_events(d->session);
|
||||
if (ret) {
|
||||
pr_err("Failed to process %s\n", d->data.file.path);
|
||||
pr_err("Failed to process %s\n", d->data.path);
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
@@ -1289,9 +1289,9 @@ static int data_init(int argc, const char **argv)
|
||||
data__for_each_file(i, d) {
|
||||
struct perf_data *data = &d->data;
|
||||
|
||||
data->file.path = use_default ? defaults[i] : argv[i];
|
||||
data->mode = PERF_DATA_MODE_READ,
|
||||
data->force = force,
|
||||
data->path = use_default ? defaults[i] : argv[i];
|
||||
data->mode = PERF_DATA_MODE_READ,
|
||||
data->force = force,
|
||||
|
||||
d->idx = i;
|
||||
}
|
||||
|
@@ -23,9 +23,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
|
||||
struct perf_session *session;
|
||||
struct perf_evsel *pos;
|
||||
struct perf_data data = {
|
||||
.file = {
|
||||
.path = file_name,
|
||||
},
|
||||
.path = file_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = details->force,
|
||||
};
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include "util/color.h"
|
||||
#include "util/evlist.h"
|
||||
#include "util/evsel.h"
|
||||
#include "util/map.h"
|
||||
#include "util/session.h"
|
||||
#include "util/tool.h"
|
||||
#include "util/debug.h"
|
||||
@@ -19,6 +20,7 @@
|
||||
#include "util/data.h"
|
||||
#include "util/auxtrace.h"
|
||||
#include "util/jit.h"
|
||||
#include "util/symbol.h"
|
||||
#include "util/thread.h"
|
||||
|
||||
#include <subcmd/parse-options.h>
|
||||
@@ -768,10 +770,8 @@ int cmd_inject(int argc, const char **argv)
|
||||
.input_name = "-",
|
||||
.samples = LIST_HEAD_INIT(inject.samples),
|
||||
.output = {
|
||||
.file = {
|
||||
.path = "-",
|
||||
},
|
||||
.mode = PERF_DATA_MODE_WRITE,
|
||||
.path = "-",
|
||||
.mode = PERF_DATA_MODE_WRITE,
|
||||
},
|
||||
};
|
||||
struct perf_data data = {
|
||||
@@ -784,7 +784,7 @@ int cmd_inject(int argc, const char **argv)
|
||||
"Inject build-ids into the output stream"),
|
||||
OPT_STRING('i', "input", &inject.input_name, "file",
|
||||
"input file name"),
|
||||
OPT_STRING('o', "output", &inject.output.file.path, "file",
|
||||
OPT_STRING('o', "output", &inject.output.path, "file",
|
||||
"output file name"),
|
||||
OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
|
||||
"Merge sched-stat and sched-switch for getting events "
|
||||
@@ -832,7 +832,7 @@ int cmd_inject(int argc, const char **argv)
|
||||
|
||||
inject.tool.ordered_events = inject.sched_stat;
|
||||
|
||||
data.file.path = inject.input_name;
|
||||
data.path = inject.input_name;
|
||||
inject.session = perf_session__new(&data, true, &inject.tool);
|
||||
if (inject.session == NULL)
|
||||
return -1;
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "debug.h"
|
||||
#include "machine.h"
|
||||
#include "map.h"
|
||||
#include "symbol.h"
|
||||
|
||||
static int __cmd_kallsyms(int argc, const char **argv)
|
||||
|
@@ -6,6 +6,7 @@
|
||||
#include "util/evsel.h"
|
||||
#include "util/util.h"
|
||||
#include "util/config.h"
|
||||
#include "util/map.h"
|
||||
#include "util/symbol.h"
|
||||
#include "util/thread.h"
|
||||
#include "util/header.h"
|
||||
@@ -334,7 +335,7 @@ static int build_alloc_func_list(void)
|
||||
struct alloc_func *func;
|
||||
struct machine *machine = &kmem_session->machines.host;
|
||||
regex_t alloc_func_regex;
|
||||
const char pattern[] = "^_?_?(alloc|get_free|get_zeroed)_pages?";
|
||||
static const char pattern[] = "^_?_?(alloc|get_free|get_zeroed)_pages?";
|
||||
|
||||
ret = regcomp(&alloc_func_regex, pattern, REG_EXTENDED);
|
||||
if (ret) {
|
||||
@@ -1924,7 +1925,7 @@ int cmd_kmem(int argc, const char **argv)
|
||||
NULL
|
||||
};
|
||||
struct perf_session *session;
|
||||
const char errmsg[] = "No %s allocation events found. Have you run 'perf kmem record --%s'?\n";
|
||||
static const char errmsg[] = "No %s allocation events found. Have you run 'perf kmem record --%s'?\n";
|
||||
int ret = perf_config(kmem_config, NULL);
|
||||
|
||||
if (ret)
|
||||
@@ -1948,7 +1949,7 @@ int cmd_kmem(int argc, const char **argv)
|
||||
return __cmd_record(argc, argv);
|
||||
}
|
||||
|
||||
data.file.path = input_name;
|
||||
data.path = input_name;
|
||||
|
||||
kmem_session = session = perf_session__new(&data, false, &perf_kmem);
|
||||
if (session == NULL)
|
||||
|
@@ -1080,11 +1080,9 @@ static int read_events(struct perf_kvm_stat *kvm)
|
||||
.ordered_events = true,
|
||||
};
|
||||
struct perf_data file = {
|
||||
.file = {
|
||||
.path = kvm->file_name,
|
||||
},
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = kvm->force,
|
||||
.path = kvm->file_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = kvm->force,
|
||||
};
|
||||
|
||||
kvm->tool = eops;
|
||||
|
@@ -82,9 +82,9 @@ int cmd_list(int argc, const char **argv)
|
||||
else if (strcmp(argv[i], "sdt") == 0)
|
||||
print_sdt_events(NULL, NULL, raw_dump);
|
||||
else if (strcmp(argv[i], "metric") == 0)
|
||||
metricgroup__print(true, false, NULL, raw_dump);
|
||||
metricgroup__print(true, false, NULL, raw_dump, details_flag);
|
||||
else if (strcmp(argv[i], "metricgroup") == 0)
|
||||
metricgroup__print(false, true, NULL, raw_dump);
|
||||
metricgroup__print(false, true, NULL, raw_dump, details_flag);
|
||||
else if ((sep = strchr(argv[i], ':')) != NULL) {
|
||||
int sep_idx;
|
||||
|
||||
@@ -102,7 +102,7 @@ int cmd_list(int argc, const char **argv)
|
||||
s[sep_idx] = '\0';
|
||||
print_tracepoint_events(s, s + sep_idx + 1, raw_dump);
|
||||
print_sdt_events(s, s + sep_idx + 1, raw_dump);
|
||||
metricgroup__print(true, true, s, raw_dump);
|
||||
metricgroup__print(true, true, s, raw_dump, details_flag);
|
||||
free(s);
|
||||
} else {
|
||||
if (asprintf(&s, "*%s*", argv[i]) < 0) {
|
||||
@@ -119,7 +119,7 @@ int cmd_list(int argc, const char **argv)
|
||||
details_flag);
|
||||
print_tracepoint_events(NULL, s, raw_dump);
|
||||
print_sdt_events(NULL, s, raw_dump);
|
||||
metricgroup__print(true, true, NULL, raw_dump);
|
||||
metricgroup__print(true, true, NULL, raw_dump, details_flag);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
|
@@ -866,11 +866,9 @@ static int __cmd_report(bool display_info)
|
||||
.ordered_events = true,
|
||||
};
|
||||
struct perf_data data = {
|
||||
.file = {
|
||||
.path = input_name,
|
||||
},
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = force,
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = force,
|
||||
};
|
||||
|
||||
session = perf_session__new(&data, false, &eops);
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include "util/data.h"
|
||||
#include "util/mem-events.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/map.h"
|
||||
#include "util/symbol.h"
|
||||
|
||||
#define MEM_OPERATION_LOAD 0x1
|
||||
@@ -238,11 +239,9 @@ static int process_sample_event(struct perf_tool *tool,
|
||||
static int report_raw_events(struct perf_mem *mem)
|
||||
{
|
||||
struct perf_data data = {
|
||||
.file = {
|
||||
.path = input_name,
|
||||
},
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = mem->force,
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = mem->force,
|
||||
};
|
||||
int ret;
|
||||
struct perf_session *session = perf_session__new(&data, false,
|
||||
|
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "perf.h"
|
||||
#include "builtin.h"
|
||||
#include "namespaces.h"
|
||||
#include "util/util.h"
|
||||
#include "util/strlist.h"
|
||||
#include "util/strfilter.h"
|
||||
|
@@ -23,7 +23,6 @@
|
||||
#include "util/evlist.h"
|
||||
#include "util/evsel.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/drv_configs.h"
|
||||
#include "util/session.h"
|
||||
#include "util/tool.h"
|
||||
#include "util/symbol.h"
|
||||
@@ -39,8 +38,10 @@
|
||||
#include "util/bpf-loader.h"
|
||||
#include "util/trigger.h"
|
||||
#include "util/perf-hooks.h"
|
||||
#include "util/cpu-set-sched.h"
|
||||
#include "util/time-utils.h"
|
||||
#include "util/units.h"
|
||||
#include "util/bpf-event.h"
|
||||
#include "asm/bug.h"
|
||||
|
||||
#include <errno.h>
|
||||
@@ -81,12 +82,17 @@ struct record {
|
||||
bool timestamp_boundary;
|
||||
struct switch_output switch_output;
|
||||
unsigned long long samples;
|
||||
cpu_set_t affinity_mask;
|
||||
};
|
||||
|
||||
static volatile int auxtrace_record__snapshot_started;
|
||||
static DEFINE_TRIGGER(auxtrace_snapshot_trigger);
|
||||
static DEFINE_TRIGGER(switch_output_trigger);
|
||||
|
||||
static const char *affinity_tags[PERF_AFFINITY_MAX] = {
|
||||
"SYS", "NODE", "CPU"
|
||||
};
|
||||
|
||||
static bool switch_output_signal(struct record *rec)
|
||||
{
|
||||
return rec->switch_output.signal &&
|
||||
@@ -531,9 +537,13 @@ static int record__mmap_evlist(struct record *rec,
|
||||
struct record_opts *opts = &rec->opts;
|
||||
char msg[512];
|
||||
|
||||
if (opts->affinity != PERF_AFFINITY_SYS)
|
||||
cpu__setup_cpunode_map();
|
||||
|
||||
if (perf_evlist__mmap_ex(evlist, opts->mmap_pages,
|
||||
opts->auxtrace_mmap_pages,
|
||||
opts->auxtrace_snapshot_mode, opts->nr_cblocks) < 0) {
|
||||
opts->auxtrace_snapshot_mode,
|
||||
opts->nr_cblocks, opts->affinity) < 0) {
|
||||
if (errno == EPERM) {
|
||||
pr_err("Permission error mapping pages.\n"
|
||||
"Consider increasing "
|
||||
@@ -566,7 +576,6 @@ static int record__open(struct record *rec)
|
||||
struct perf_evlist *evlist = rec->evlist;
|
||||
struct perf_session *session = rec->session;
|
||||
struct record_opts *opts = &rec->opts;
|
||||
struct perf_evsel_config_term *err_term;
|
||||
int rc = 0;
|
||||
|
||||
/*
|
||||
@@ -619,14 +628,6 @@ try_again:
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (perf_evlist__apply_drv_configs(evlist, &pos, &err_term)) {
|
||||
pr_err("failed to set config \"%s\" on event %s with %d (%s)\n",
|
||||
err_term->val.drv_cfg, perf_evsel__name(pos), errno,
|
||||
str_error_r(errno, msg, sizeof(msg)));
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = record__mmap(rec);
|
||||
if (rc)
|
||||
goto out;
|
||||
@@ -659,10 +660,9 @@ static int process_sample_event(struct perf_tool *tool,
|
||||
|
||||
static int process_buildids(struct record *rec)
|
||||
{
|
||||
struct perf_data *data = &rec->data;
|
||||
struct perf_session *session = rec->session;
|
||||
|
||||
if (data->size == 0)
|
||||
if (perf_data__size(&rec->data) == 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@@ -722,6 +722,16 @@ static struct perf_event_header finished_round_event = {
|
||||
.type = PERF_RECORD_FINISHED_ROUND,
|
||||
};
|
||||
|
||||
static void record__adjust_affinity(struct record *rec, struct perf_mmap *map)
|
||||
{
|
||||
if (rec->opts.affinity != PERF_AFFINITY_SYS &&
|
||||
!CPU_EQUAL(&rec->affinity_mask, &map->affinity_mask)) {
|
||||
CPU_ZERO(&rec->affinity_mask);
|
||||
CPU_OR(&rec->affinity_mask, &rec->affinity_mask, &map->affinity_mask);
|
||||
sched_setaffinity(0, sizeof(rec->affinity_mask), &rec->affinity_mask);
|
||||
}
|
||||
}
|
||||
|
||||
static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evlist,
|
||||
bool overwrite)
|
||||
{
|
||||
@@ -749,6 +759,7 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli
|
||||
struct perf_mmap *map = &maps[i];
|
||||
|
||||
if (map->base) {
|
||||
record__adjust_affinity(rec, map);
|
||||
if (!record__aio_enabled(rec)) {
|
||||
if (perf_mmap__push(map, rec, record__pushfn) != 0) {
|
||||
rc = -1;
|
||||
@@ -839,7 +850,7 @@ record__finish_output(struct record *rec)
|
||||
return;
|
||||
|
||||
rec->session->header.data_size += rec->bytes_written;
|
||||
data->size = lseek(perf_data__fd(data), 0, SEEK_CUR);
|
||||
data->file.size = lseek(perf_data__fd(data), 0, SEEK_CUR);
|
||||
|
||||
if (!rec->no_buildid) {
|
||||
process_buildids(rec);
|
||||
@@ -907,7 +918,7 @@ record__switch_output(struct record *rec, bool at_exit)
|
||||
|
||||
if (!quiet)
|
||||
fprintf(stderr, "[ perf record: Dump %s.%s ]\n",
|
||||
data->file.path, timestamp);
|
||||
data->path, timestamp);
|
||||
|
||||
/* Output tracking events */
|
||||
if (!at_exit) {
|
||||
@@ -1082,6 +1093,11 @@ static int record__synthesize(struct record *rec, bool tail)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = perf_event__synthesize_bpf_events(tool, process_synthesized_event,
|
||||
machine, opts);
|
||||
if (err < 0)
|
||||
pr_warning("Couldn't synthesize bpf events.\n");
|
||||
|
||||
err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
|
||||
process_synthesized_event, opts->sample_address,
|
||||
1);
|
||||
@@ -1445,7 +1461,7 @@ out_child:
|
||||
|
||||
fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s%s ]\n",
|
||||
perf_data__size(data) / 1024.0 / 1024.0,
|
||||
data->file.path, postfix, samples);
|
||||
data->path, postfix, samples);
|
||||
}
|
||||
|
||||
out_delete_session:
|
||||
@@ -1639,6 +1655,21 @@ static int parse_clockid(const struct option *opt, const char *str, int unset)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int record__parse_affinity(const struct option *opt, const char *str, int unset)
|
||||
{
|
||||
struct record_opts *opts = (struct record_opts *)opt->value;
|
||||
|
||||
if (unset || !str)
|
||||
return 0;
|
||||
|
||||
if (!strcasecmp(str, "node"))
|
||||
opts->affinity = PERF_AFFINITY_NODE;
|
||||
else if (!strcasecmp(str, "cpu"))
|
||||
opts->affinity = PERF_AFFINITY_CPU;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int record__parse_mmap_pages(const struct option *opt,
|
||||
const char *str,
|
||||
int unset __maybe_unused)
|
||||
@@ -1831,7 +1862,7 @@ static struct option __record_options[] = {
|
||||
OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
|
||||
"list of cpus to monitor"),
|
||||
OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
|
||||
OPT_STRING('o', "output", &record.data.file.path, "file",
|
||||
OPT_STRING('o', "output", &record.data.path, "file",
|
||||
"output file name"),
|
||||
OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
|
||||
&record.opts.no_inherit_set,
|
||||
@@ -1839,6 +1870,7 @@ static struct option __record_options[] = {
|
||||
OPT_BOOLEAN(0, "tail-synthesize", &record.opts.tail_synthesize,
|
||||
"synthesize non-sample events at the end of output"),
|
||||
OPT_BOOLEAN(0, "overwrite", &record.opts.overwrite, "use overwrite mode"),
|
||||
OPT_BOOLEAN(0, "bpf-event", &record.opts.bpf_event, "record bpf events"),
|
||||
OPT_BOOLEAN(0, "strict-freq", &record.opts.strict_freq,
|
||||
"Fail if the specified frequency can't be used"),
|
||||
OPT_CALLBACK('F', "freq", &record.opts, "freq or 'max'",
|
||||
@@ -1946,6 +1978,9 @@ static struct option __record_options[] = {
|
||||
&nr_cblocks_default, "n", "Use <n> control blocks in asynchronous trace writing mode (default: 1, max: 4)",
|
||||
record__aio_parse),
|
||||
#endif
|
||||
OPT_CALLBACK(0, "affinity", &record.opts, "node|cpu",
|
||||
"Set affinity mask of trace reading thread to NUMA node cpu mask or cpu of processed mmap buffer",
|
||||
record__parse_affinity),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
@@ -1980,6 +2015,9 @@ int cmd_record(int argc, const char **argv)
|
||||
# undef REASON
|
||||
#endif
|
||||
|
||||
CPU_ZERO(&rec->affinity_mask);
|
||||
rec->opts.affinity = PERF_AFFINITY_SYS;
|
||||
|
||||
rec->evlist = perf_evlist__new();
|
||||
if (rec->evlist == NULL)
|
||||
return -ENOMEM;
|
||||
@@ -2143,6 +2181,8 @@ int cmd_record(int argc, const char **argv)
|
||||
if (verbose > 0)
|
||||
pr_info("nr_cblocks: %d\n", rec->opts.nr_cblocks);
|
||||
|
||||
pr_debug("affinity: %s\n", affinity_tags[rec->opts.affinity]);
|
||||
|
||||
err = __cmd_record(&record, argc, argv);
|
||||
out:
|
||||
perf_evlist__delete(rec->evlist);
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/err.h>
|
||||
#include "util/map.h"
|
||||
#include "util/symbol.h"
|
||||
#include "util/callchain.h"
|
||||
#include "util/values.h"
|
||||
@@ -615,6 +616,21 @@ static int report__collapse_hists(struct report *rep)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hists__resort_cb(struct hist_entry *he, void *arg)
|
||||
{
|
||||
struct report *rep = arg;
|
||||
struct symbol *sym = he->ms.sym;
|
||||
|
||||
if (rep->symbol_ipc && sym && !sym->annotate2) {
|
||||
struct perf_evsel *evsel = hists_to_evsel(he->hists);
|
||||
|
||||
symbol__annotate2(sym, he->ms.map, evsel,
|
||||
&annotation__default_options, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void report__output_resort(struct report *rep)
|
||||
{
|
||||
struct ui_progress prog;
|
||||
@@ -622,8 +638,10 @@ static void report__output_resort(struct report *rep)
|
||||
|
||||
ui_progress__init(&prog, rep->nr_entries, "Sorting events for output...");
|
||||
|
||||
evlist__for_each_entry(rep->session->evlist, pos)
|
||||
perf_evsel__output_resort(pos, &prog);
|
||||
evlist__for_each_entry(rep->session->evlist, pos) {
|
||||
perf_evsel__output_resort_cb(pos, &prog,
|
||||
hists__resort_cb, rep);
|
||||
}
|
||||
|
||||
ui_progress__finish();
|
||||
}
|
||||
@@ -753,7 +771,8 @@ static int tasks_print(struct report *rep, FILE *fp)
|
||||
for (i = 0; i < THREADS__TABLE_SIZE; i++) {
|
||||
struct threads *threads = &machine->threads[i];
|
||||
|
||||
for (nd = rb_first(&threads->entries); nd; nd = rb_next(nd)) {
|
||||
for (nd = rb_first_cached(&threads->entries); nd;
|
||||
nd = rb_next(nd)) {
|
||||
task = tasks + itask++;
|
||||
|
||||
task->thread = rb_entry(nd, struct thread, rb_node);
|
||||
@@ -880,7 +899,7 @@ static int __cmd_report(struct report *rep)
|
||||
rep->nr_entries += evsel__hists(pos)->nr_entries;
|
||||
|
||||
if (rep->nr_entries == 0) {
|
||||
ui__error("The %s file has no samples!\n", data->file.path);
|
||||
ui__error("The %s data has no samples!\n", data->path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -956,9 +975,9 @@ int cmd_report(int argc, const char **argv)
|
||||
int branch_mode = -1;
|
||||
bool branch_call_mode = false;
|
||||
#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent"
|
||||
const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n"
|
||||
CALLCHAIN_REPORT_HELP
|
||||
"\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT;
|
||||
static const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n"
|
||||
CALLCHAIN_REPORT_HELP
|
||||
"\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT;
|
||||
char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT;
|
||||
const char * const report_usage[] = {
|
||||
"perf report [<options>]",
|
||||
@@ -1188,8 +1207,8 @@ int cmd_report(int argc, const char **argv)
|
||||
input_name = "perf.data";
|
||||
}
|
||||
|
||||
data.file.path = input_name;
|
||||
data.force = symbol_conf.force;
|
||||
data.path = input_name;
|
||||
data.force = symbol_conf.force;
|
||||
|
||||
repeat:
|
||||
session = perf_session__new(&data, false, &report.tool);
|
||||
|
@@ -213,7 +213,7 @@ struct perf_sched {
|
||||
u64 all_runtime;
|
||||
u64 all_count;
|
||||
u64 cpu_last_switched[MAX_CPUS];
|
||||
struct rb_root atom_root, sorted_atom_root, merged_atom_root;
|
||||
struct rb_root_cached atom_root, sorted_atom_root, merged_atom_root;
|
||||
struct list_head sort_list, cmp_pid;
|
||||
bool force;
|
||||
bool skip_merge;
|
||||
@@ -271,7 +271,7 @@ struct evsel_runtime {
|
||||
struct idle_thread_runtime {
|
||||
struct thread_runtime tr;
|
||||
struct thread *last_thread;
|
||||
struct rb_root sorted_root;
|
||||
struct rb_root_cached sorted_root;
|
||||
struct callchain_root callchain;
|
||||
struct callchain_cursor cursor;
|
||||
};
|
||||
@@ -950,10 +950,10 @@ thread_lat_cmp(struct list_head *list, struct work_atoms *l, struct work_atoms *
|
||||
}
|
||||
|
||||
static struct work_atoms *
|
||||
thread_atoms_search(struct rb_root *root, struct thread *thread,
|
||||
thread_atoms_search(struct rb_root_cached *root, struct thread *thread,
|
||||
struct list_head *sort_list)
|
||||
{
|
||||
struct rb_node *node = root->rb_node;
|
||||
struct rb_node *node = root->rb_root.rb_node;
|
||||
struct work_atoms key = { .thread = thread };
|
||||
|
||||
while (node) {
|
||||
@@ -976,10 +976,11 @@ thread_atoms_search(struct rb_root *root, struct thread *thread,
|
||||
}
|
||||
|
||||
static void
|
||||
__thread_latency_insert(struct rb_root *root, struct work_atoms *data,
|
||||
__thread_latency_insert(struct rb_root_cached *root, struct work_atoms *data,
|
||||
struct list_head *sort_list)
|
||||
{
|
||||
struct rb_node **new = &(root->rb_node), *parent = NULL;
|
||||
struct rb_node **new = &(root->rb_root.rb_node), *parent = NULL;
|
||||
bool leftmost = true;
|
||||
|
||||
while (*new) {
|
||||
struct work_atoms *this;
|
||||
@@ -992,12 +993,14 @@ __thread_latency_insert(struct rb_root *root, struct work_atoms *data,
|
||||
|
||||
if (cmp > 0)
|
||||
new = &((*new)->rb_left);
|
||||
else
|
||||
else {
|
||||
new = &((*new)->rb_right);
|
||||
leftmost = false;
|
||||
}
|
||||
}
|
||||
|
||||
rb_link_node(&data->node, parent, new);
|
||||
rb_insert_color(&data->node, root);
|
||||
rb_insert_color_cached(&data->node, root, leftmost);
|
||||
}
|
||||
|
||||
static int thread_atoms_insert(struct perf_sched *sched, struct thread *thread)
|
||||
@@ -1447,15 +1450,15 @@ static int sort_dimension__add(const char *tok, struct list_head *list)
|
||||
static void perf_sched__sort_lat(struct perf_sched *sched)
|
||||
{
|
||||
struct rb_node *node;
|
||||
struct rb_root *root = &sched->atom_root;
|
||||
struct rb_root_cached *root = &sched->atom_root;
|
||||
again:
|
||||
for (;;) {
|
||||
struct work_atoms *data;
|
||||
node = rb_first(root);
|
||||
node = rb_first_cached(root);
|
||||
if (!node)
|
||||
break;
|
||||
|
||||
rb_erase(node, root);
|
||||
rb_erase_cached(node, root);
|
||||
data = rb_entry(node, struct work_atoms, node);
|
||||
__thread_latency_insert(&sched->sorted_atom_root, data, &sched->sort_list);
|
||||
}
|
||||
@@ -1782,11 +1785,9 @@ static int perf_sched__read_events(struct perf_sched *sched)
|
||||
};
|
||||
struct perf_session *session;
|
||||
struct perf_data data = {
|
||||
.file = {
|
||||
.path = input_name,
|
||||
},
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = sched->force,
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = sched->force,
|
||||
};
|
||||
int rc = -1;
|
||||
|
||||
@@ -2762,12 +2763,12 @@ static size_t callchain__fprintf_folded(FILE *fp, struct callchain_node *node)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t timehist_print_idlehist_callchain(struct rb_root *root)
|
||||
static size_t timehist_print_idlehist_callchain(struct rb_root_cached *root)
|
||||
{
|
||||
size_t ret = 0;
|
||||
FILE *fp = stdout;
|
||||
struct callchain_node *chain;
|
||||
struct rb_node *rb_node = rb_first(root);
|
||||
struct rb_node *rb_node = rb_first_cached(root);
|
||||
|
||||
printf(" %16s %8s %s\n", "Idle time (msec)", "Count", "Callchains");
|
||||
printf(" %.16s %.8s %.50s\n", graph_dotted_line, graph_dotted_line,
|
||||
@@ -2868,7 +2869,7 @@ static void timehist_print_summary(struct perf_sched *sched,
|
||||
if (itr == NULL)
|
||||
continue;
|
||||
|
||||
callchain_param.sort(&itr->sorted_root, &itr->callchain,
|
||||
callchain_param.sort(&itr->sorted_root.rb_root, &itr->callchain,
|
||||
0, &callchain_param);
|
||||
|
||||
printf(" CPU %2d:", i);
|
||||
@@ -2955,11 +2956,9 @@ static int perf_sched__timehist(struct perf_sched *sched)
|
||||
{ "sched:sched_migrate_task", timehist_migrate_task_event, },
|
||||
};
|
||||
struct perf_data data = {
|
||||
.file = {
|
||||
.path = input_name,
|
||||
},
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = sched->force,
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = sched->force,
|
||||
};
|
||||
|
||||
struct perf_session *session;
|
||||
@@ -3074,11 +3073,12 @@ static void print_bad_events(struct perf_sched *sched)
|
||||
}
|
||||
}
|
||||
|
||||
static void __merge_work_atoms(struct rb_root *root, struct work_atoms *data)
|
||||
static void __merge_work_atoms(struct rb_root_cached *root, struct work_atoms *data)
|
||||
{
|
||||
struct rb_node **new = &(root->rb_node), *parent = NULL;
|
||||
struct rb_node **new = &(root->rb_root.rb_node), *parent = NULL;
|
||||
struct work_atoms *this;
|
||||
const char *comm = thread__comm_str(data->thread), *this_comm;
|
||||
bool leftmost = true;
|
||||
|
||||
while (*new) {
|
||||
int cmp;
|
||||
@@ -3092,6 +3092,7 @@ static void __merge_work_atoms(struct rb_root *root, struct work_atoms *data)
|
||||
new = &((*new)->rb_left);
|
||||
} else if (cmp < 0) {
|
||||
new = &((*new)->rb_right);
|
||||
leftmost = false;
|
||||
} else {
|
||||
this->num_merged++;
|
||||
this->total_runtime += data->total_runtime;
|
||||
@@ -3109,7 +3110,7 @@ static void __merge_work_atoms(struct rb_root *root, struct work_atoms *data)
|
||||
|
||||
data->num_merged++;
|
||||
rb_link_node(&data->node, parent, new);
|
||||
rb_insert_color(&data->node, root);
|
||||
rb_insert_color_cached(&data->node, root, leftmost);
|
||||
}
|
||||
|
||||
static void perf_sched__merge_lat(struct perf_sched *sched)
|
||||
@@ -3120,8 +3121,8 @@ static void perf_sched__merge_lat(struct perf_sched *sched)
|
||||
if (sched->skip_merge)
|
||||
return;
|
||||
|
||||
while ((node = rb_first(&sched->atom_root))) {
|
||||
rb_erase(node, &sched->atom_root);
|
||||
while ((node = rb_first_cached(&sched->atom_root))) {
|
||||
rb_erase_cached(node, &sched->atom_root);
|
||||
data = rb_entry(node, struct work_atoms, node);
|
||||
__merge_work_atoms(&sched->merged_atom_root, data);
|
||||
}
|
||||
@@ -3143,7 +3144,7 @@ static int perf_sched__lat(struct perf_sched *sched)
|
||||
printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms | Maximum delay at |\n");
|
||||
printf(" -----------------------------------------------------------------------------------------------------------------\n");
|
||||
|
||||
next = rb_first(&sched->sorted_atom_root);
|
||||
next = rb_first_cached(&sched->sorted_atom_root);
|
||||
|
||||
while (next) {
|
||||
struct work_atoms *work_list;
|
||||
@@ -3336,7 +3337,7 @@ static int __cmd_record(int argc, const char **argv)
|
||||
|
||||
int cmd_sched(int argc, const char **argv)
|
||||
{
|
||||
const char default_sort_order[] = "avg, max, switch, runtime";
|
||||
static const char default_sort_order[] = "avg, max, switch, runtime";
|
||||
struct perf_sched sched = {
|
||||
.tool = {
|
||||
.sample = perf_sched__process_tracepoint_sample,
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include "util/perf_regs.h"
|
||||
#include "util/session.h"
|
||||
#include "util/tool.h"
|
||||
#include "util/map.h"
|
||||
#include "util/symbol.h"
|
||||
#include "util/thread.h"
|
||||
#include "util/trace-event.h"
|
||||
@@ -148,6 +149,7 @@ static struct {
|
||||
unsigned int print_ip_opts;
|
||||
u64 fields;
|
||||
u64 invalid_fields;
|
||||
u64 user_set_fields;
|
||||
} output[OUTPUT_TYPE_MAX] = {
|
||||
|
||||
[PERF_TYPE_HARDWARE] = {
|
||||
@@ -344,7 +346,7 @@ static int perf_evsel__do_check_stype(struct perf_evsel *evsel,
|
||||
if (attr->sample_type & sample_type)
|
||||
return 0;
|
||||
|
||||
if (output[type].user_set) {
|
||||
if (output[type].user_set_fields & field) {
|
||||
if (allow_user_set)
|
||||
return 0;
|
||||
evname = perf_evsel__name(evsel);
|
||||
@@ -2559,6 +2561,10 @@ static int parse_output_fields(const struct option *opt __maybe_unused,
|
||||
pr_warning("Overriding previous field request for %s events.\n",
|
||||
event_type(type));
|
||||
|
||||
/* Don't override defaults for +- */
|
||||
if (strchr(tok, '+') || strchr(tok, '-'))
|
||||
goto parse;
|
||||
|
||||
output[type].fields = 0;
|
||||
output[type].user_set = true;
|
||||
output[type].wildcard_set = false;
|
||||
@@ -2627,10 +2633,13 @@ parse:
|
||||
pr_warning("\'%s\' not valid for %s events. Ignoring.\n",
|
||||
all_output_options[i].str, event_type(j));
|
||||
} else {
|
||||
if (change == REMOVE)
|
||||
if (change == REMOVE) {
|
||||
output[j].fields &= ~all_output_options[i].field;
|
||||
else
|
||||
output[j].user_set_fields &= ~all_output_options[i].field;
|
||||
} else {
|
||||
output[j].fields |= all_output_options[i].field;
|
||||
output[j].user_set_fields |= all_output_options[i].field;
|
||||
}
|
||||
output[j].user_set = true;
|
||||
output[j].wildcard_set = true;
|
||||
}
|
||||
@@ -2643,6 +2652,10 @@ parse:
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (change == REMOVE)
|
||||
output[type].fields &= ~all_output_options[i].field;
|
||||
else
|
||||
output[type].fields |= all_output_options[i].field;
|
||||
output[type].user_set = true;
|
||||
output[type].wildcard_set = true;
|
||||
}
|
||||
@@ -2942,10 +2955,8 @@ int find_scripts(char **scripts_array, char **scripts_path_array)
|
||||
DIR *scripts_dir, *lang_dir;
|
||||
struct perf_session *session;
|
||||
struct perf_data data = {
|
||||
.file = {
|
||||
.path = input_name,
|
||||
},
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
};
|
||||
char *temp;
|
||||
int i = 0;
|
||||
@@ -3418,8 +3429,8 @@ int cmd_script(int argc, const char **argv)
|
||||
argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
|
||||
data.file.path = input_name;
|
||||
data.force = symbol_conf.force;
|
||||
data.path = input_name;
|
||||
data.force = symbol_conf.force;
|
||||
|
||||
if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
|
||||
rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
|
||||
@@ -3645,7 +3656,7 @@ int cmd_script(int argc, const char **argv)
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
input = open(data.file.path, O_RDONLY); /* input_name */
|
||||
input = open(data.path, O_RDONLY); /* input_name */
|
||||
if (input < 0) {
|
||||
err = -errno;
|
||||
perror("failed to open file");
|
||||
|
@@ -52,7 +52,6 @@
|
||||
#include "util/evlist.h"
|
||||
#include "util/evsel.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/drv_configs.h"
|
||||
#include "util/color.h"
|
||||
#include "util/stat.h"
|
||||
#include "util/header.h"
|
||||
@@ -83,7 +82,6 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "sane_ctype.h"
|
||||
|
||||
@@ -418,7 +416,6 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
|
||||
int status = 0;
|
||||
const bool forks = (argc > 0);
|
||||
bool is_pipe = STAT_RECORD ? perf_stat.data.is_pipe : false;
|
||||
struct perf_evsel_config_term *err_term;
|
||||
|
||||
if (interval) {
|
||||
ts.tv_sec = interval / USEC_PER_MSEC;
|
||||
@@ -515,13 +512,6 @@ try_again:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (perf_evlist__apply_drv_configs(evsel_list, &counter, &err_term)) {
|
||||
pr_err("failed to set config \"%s\" on event %s with %d (%s)\n",
|
||||
err_term->val.drv_cfg, perf_evsel__name(counter), errno,
|
||||
str_error_r(errno, msg, sizeof(msg)));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (STAT_RECORD) {
|
||||
int err, fd = perf_data__fd(&perf_stat.data);
|
||||
|
||||
@@ -1332,7 +1322,7 @@ static int __cmd_record(int argc, const char **argv)
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
|
||||
if (output_name)
|
||||
data->file.path = output_name;
|
||||
data->path = output_name;
|
||||
|
||||
if (stat_config.run_count != 1 || forever) {
|
||||
pr_err("Cannot use -r option with perf stat record.\n");
|
||||
@@ -1533,8 +1523,8 @@ static int __cmd_report(int argc, const char **argv)
|
||||
input_name = "perf.data";
|
||||
}
|
||||
|
||||
perf_stat.data.file.path = input_name;
|
||||
perf_stat.data.mode = PERF_DATA_MODE_READ;
|
||||
perf_stat.data.path = input_name;
|
||||
perf_stat.data.mode = PERF_DATA_MODE_READ;
|
||||
|
||||
session = perf_session__new(&perf_stat.data, false, &perf_stat.tool);
|
||||
if (session == NULL)
|
||||
|
@@ -1602,11 +1602,9 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
|
||||
{ "syscalls:sys_exit_select", process_exit_poll },
|
||||
};
|
||||
struct perf_data data = {
|
||||
.file = {
|
||||
.path = input_name,
|
||||
},
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = tchart->force,
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = tchart->force,
|
||||
};
|
||||
|
||||
struct perf_session *session = perf_session__new(&data, false,
|
||||
|
@@ -22,13 +22,14 @@
|
||||
#include "perf.h"
|
||||
|
||||
#include "util/annotate.h"
|
||||
#include "util/bpf-event.h"
|
||||
#include "util/config.h"
|
||||
#include "util/color.h"
|
||||
#include "util/drv_configs.h"
|
||||
#include "util/evlist.h"
|
||||
#include "util/evsel.h"
|
||||
#include "util/event.h"
|
||||
#include "util/machine.h"
|
||||
#include "util/map.h"
|
||||
#include "util/session.h"
|
||||
#include "util/symbol.h"
|
||||
#include "util/thread.h"
|
||||
@@ -366,7 +367,7 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg)
|
||||
if (p)
|
||||
*p = 0;
|
||||
|
||||
next = rb_first(&hists->entries);
|
||||
next = rb_first_cached(&hists->entries);
|
||||
while (next) {
|
||||
n = rb_entry(next, struct hist_entry, rb_node);
|
||||
if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) {
|
||||
@@ -1184,10 +1185,6 @@ static void init_process_thread(struct perf_top *top)
|
||||
|
||||
static int __cmd_top(struct perf_top *top)
|
||||
{
|
||||
char msg[512];
|
||||
struct perf_evsel *pos;
|
||||
struct perf_evsel_config_term *err_term;
|
||||
struct perf_evlist *evlist = top->evlist;
|
||||
struct record_opts *opts = &top->record_opts;
|
||||
pthread_t thread, thread_process;
|
||||
int ret;
|
||||
@@ -1215,6 +1212,12 @@ static int __cmd_top(struct perf_top *top)
|
||||
|
||||
init_process_thread(top);
|
||||
|
||||
ret = perf_event__synthesize_bpf_events(&top->tool, perf_event__process,
|
||||
&top->session->machines.host,
|
||||
&top->record_opts);
|
||||
if (ret < 0)
|
||||
pr_warning("Couldn't synthesize bpf events.\n");
|
||||
|
||||
machine__synthesize_threads(&top->session->machines.host, &opts->target,
|
||||
top->evlist->threads, false,
|
||||
top->nr_threads_synthesize);
|
||||
@@ -1232,14 +1235,6 @@ static int __cmd_top(struct perf_top *top)
|
||||
if (ret)
|
||||
goto out_delete;
|
||||
|
||||
ret = perf_evlist__apply_drv_configs(evlist, &pos, &err_term);
|
||||
if (ret) {
|
||||
pr_err("failed to set config \"%s\" on event %s with %d (%s)\n",
|
||||
err_term->val.drv_cfg, perf_evsel__name(pos), errno,
|
||||
str_error_r(errno, msg, sizeof(msg)));
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
top->session->evlist = top->evlist;
|
||||
perf_session__set_id_hdr_size(top->session);
|
||||
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include <traceevent/event-parse.h>
|
||||
#include <api/fs/tracing_path.h>
|
||||
#include <bpf/bpf.h>
|
||||
#include "util/bpf_map.h"
|
||||
#include "builtin.h"
|
||||
#include "util/cgroup.h"
|
||||
#include "util/color.h"
|
||||
@@ -29,6 +30,8 @@
|
||||
#include "util/evlist.h"
|
||||
#include <subcmd/exec-cmd.h>
|
||||
#include "util/machine.h"
|
||||
#include "util/map.h"
|
||||
#include "util/symbol.h"
|
||||
#include "util/path.h"
|
||||
#include "util/session.h"
|
||||
#include "util/thread.h"
|
||||
@@ -85,6 +88,9 @@ struct trace {
|
||||
*augmented;
|
||||
} events;
|
||||
} syscalls;
|
||||
struct {
|
||||
struct bpf_map *map;
|
||||
} dump;
|
||||
struct record_opts opts;
|
||||
struct perf_evlist *evlist;
|
||||
struct machine *host;
|
||||
@@ -1039,6 +1045,9 @@ static const size_t trace__entry_str_size = 2048;
|
||||
|
||||
static struct file *thread_trace__files_entry(struct thread_trace *ttrace, int fd)
|
||||
{
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
if (fd > ttrace->files.max) {
|
||||
struct file *nfiles = realloc(ttrace->files.table, (fd + 1) * sizeof(struct file));
|
||||
|
||||
@@ -2766,7 +2775,8 @@ static int trace__set_filter_loop_pids(struct trace *trace)
|
||||
if (parent == NULL)
|
||||
break;
|
||||
|
||||
if (!strcmp(thread__comm_str(parent), "sshd")) {
|
||||
if (!strcmp(thread__comm_str(parent), "sshd") ||
|
||||
strstarts(thread__comm_str(parent), "gnome-terminal")) {
|
||||
pids[nr++] = parent->tid;
|
||||
break;
|
||||
}
|
||||
@@ -2991,6 +3001,9 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
|
||||
if (err < 0)
|
||||
goto out_error_apply_filters;
|
||||
|
||||
if (trace->dump.map)
|
||||
bpf_map__fprintf(trace->dump.map, trace->output);
|
||||
|
||||
err = perf_evlist__mmap(evlist, trace->opts.mmap_pages);
|
||||
if (err < 0)
|
||||
goto out_error_mmap;
|
||||
@@ -3141,11 +3154,9 @@ static int trace__replay(struct trace *trace)
|
||||
{ "probe:vfs_getname", trace__vfs_getname, },
|
||||
};
|
||||
struct perf_data data = {
|
||||
.file = {
|
||||
.path = input_name,
|
||||
},
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = trace->force,
|
||||
.path = input_name,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = trace->force,
|
||||
};
|
||||
struct perf_session *session;
|
||||
struct perf_evsel *evsel;
|
||||
@@ -3680,6 +3691,7 @@ int cmd_trace(int argc, const char **argv)
|
||||
.max_stack = UINT_MAX,
|
||||
.max_events = ULONG_MAX,
|
||||
};
|
||||
const char *map_dump_str = NULL;
|
||||
const char *output_name = NULL;
|
||||
const struct option trace_options[] = {
|
||||
OPT_CALLBACK('e', "event", &trace, "event",
|
||||
@@ -3712,6 +3724,9 @@ int cmd_trace(int argc, const char **argv)
|
||||
OPT_CALLBACK(0, "duration", &trace, "float",
|
||||
"show only events with duration > N.M ms",
|
||||
trace__set_duration),
|
||||
#ifdef HAVE_LIBBPF_SUPPORT
|
||||
OPT_STRING(0, "map-dump", &map_dump_str, "BPF map", "BPF map to periodically dump"),
|
||||
#endif
|
||||
OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
|
||||
OPT_INCR('v', "verbose", &verbose, "be more verbose"),
|
||||
OPT_BOOLEAN('T', "time", &trace.full_time,
|
||||
@@ -3806,6 +3821,14 @@ int cmd_trace(int argc, const char **argv)
|
||||
|
||||
err = -1;
|
||||
|
||||
if (map_dump_str) {
|
||||
trace.dump.map = bpf__find_map_by_name(map_dump_str);
|
||||
if (trace.dump.map == NULL) {
|
||||
pr_err("ERROR: BPF map \"%s\" not found\n", map_dump_str);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (trace.trace_pgfaults) {
|
||||
trace.opts.sample_address = true;
|
||||
trace.opts.sample_time = true;
|
||||
@@ -3865,7 +3888,8 @@ int cmd_trace(int argc, const char **argv)
|
||||
goto init_augmented_syscall_tp;
|
||||
}
|
||||
|
||||
if (strcmp(perf_evsel__name(evsel), "raw_syscalls:sys_enter") == 0) {
|
||||
if (trace.syscalls.events.augmented->priv == NULL &&
|
||||
strstr(perf_evsel__name(evsel), "syscalls:sys_enter")) {
|
||||
struct perf_evsel *augmented = trace.syscalls.events.augmented;
|
||||
if (perf_evsel__init_augmented_syscall_tp(augmented, evsel) ||
|
||||
perf_evsel__init_augmented_syscall_tp_args(augmented))
|
||||
|
@@ -222,6 +222,10 @@ The 'exclude_user', 'exclude_kernel' and 'exclude_hv' bits provide a
|
||||
way to request that counting of events be restricted to times when the
|
||||
CPU is in user, kernel and/or hypervisor mode.
|
||||
|
||||
Furthermore the 'exclude_host' and 'exclude_guest' bits provide a way
|
||||
to request counting of events restricted to guest and host contexts when
|
||||
using Linux as the hypervisor.
|
||||
|
||||
The 'mmap' and 'munmap' bits allow recording of PROT_EXEC mmap/munmap
|
||||
operations, these can be used to relate userspace IP addresses to actual
|
||||
code, even after the mapping (or even the whole process) is gone,
|
||||
|
@@ -18,23 +18,13 @@
|
||||
#include <pid_filter.h>
|
||||
|
||||
/* bpf-output associated map */
|
||||
struct bpf_map SEC("maps") __augmented_syscalls__ = {
|
||||
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(u32),
|
||||
.max_entries = __NR_CPUS__,
|
||||
};
|
||||
bpf_map(__augmented_syscalls__, PERF_EVENT_ARRAY, int, u32, __NR_CPUS__);
|
||||
|
||||
struct syscall {
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
struct bpf_map SEC("maps") syscalls = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(struct syscall),
|
||||
.max_entries = 512,
|
||||
};
|
||||
bpf_map(syscalls, ARRAY, int, struct syscall, 512);
|
||||
|
||||
struct syscall_enter_args {
|
||||
unsigned long long common_tp_fields;
|
||||
@@ -141,8 +131,8 @@ int sys_enter(struct syscall_enter_args *args)
|
||||
len = sizeof(augmented_args.args);
|
||||
}
|
||||
|
||||
perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, &augmented_args, len);
|
||||
return 0;
|
||||
/* If perf_event_output fails, return non-zero so that it gets recorded unaugmented */
|
||||
return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, &augmented_args, len);
|
||||
}
|
||||
|
||||
SEC("raw_syscalls:sys_exit")
|
||||
|
@@ -19,12 +19,8 @@
|
||||
#include <stdio.h>
|
||||
#include <linux/socket.h>
|
||||
|
||||
struct bpf_map SEC("maps") __augmented_syscalls__ = {
|
||||
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(u32),
|
||||
.max_entries = __NR_CPUS__,
|
||||
};
|
||||
/* bpf-output associated map */
|
||||
bpf_map(__augmented_syscalls__, PERF_EVENT_ARRAY, int, u32, __NR_CPUS__);
|
||||
|
||||
struct syscall_exit_args {
|
||||
unsigned long long common_tp_fields;
|
||||
@@ -55,9 +51,9 @@ int syscall_enter(syscall)(struct syscall_enter_##syscall##_args *args) \
|
||||
len -= sizeof(augmented_args.filename.value) - augmented_args.filename.size; \
|
||||
len &= sizeof(augmented_args.filename.value) - 1; \
|
||||
} \
|
||||
perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \
|
||||
&augmented_args, len); \
|
||||
return 0; \
|
||||
/* If perf_event_output fails, return non-zero so that it gets recorded unaugmented */ \
|
||||
return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \
|
||||
&augmented_args, len); \
|
||||
} \
|
||||
int syscall_exit(syscall)(struct syscall_exit_args *args) \
|
||||
{ \
|
||||
@@ -125,10 +121,10 @@ int syscall_enter(syscall)(struct syscall_enter_##syscall##_args *args) \
|
||||
/* addrlen = augmented_args.args.addrlen; */ \
|
||||
/* */ \
|
||||
probe_read(&augmented_args.addr, addrlen, args->addr_ptr); \
|
||||
perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \
|
||||
&augmented_args, \
|
||||
sizeof(augmented_args) - sizeof(augmented_args.addr) + addrlen); \
|
||||
return 0; \
|
||||
/* If perf_event_output fails, return non-zero so that it gets recorded unaugmented */ \
|
||||
return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \
|
||||
&augmented_args, \
|
||||
sizeof(augmented_args) - sizeof(augmented_args.addr) + addrlen);\
|
||||
} \
|
||||
int syscall_exit(syscall)(struct syscall_exit_args *args) \
|
||||
{ \
|
||||
|
@@ -21,12 +21,8 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
struct bpf_map SEC("maps") __augmented_syscalls__ = {
|
||||
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(u32),
|
||||
.max_entries = __NR_CPUS__,
|
||||
};
|
||||
/* bpf-output associated map */
|
||||
bpf_map(__augmented_syscalls__, PERF_EVENT_ARRAY, int, u32, __NR_CPUS__);
|
||||
|
||||
struct augmented_filename {
|
||||
int size;
|
||||
@@ -49,11 +45,11 @@ int syscall_enter(syscall)(struct syscall_enter_##syscall##_args *args) \
|
||||
args->filename_ptr); \
|
||||
if (__builtin_memcmp(augmented_args.filename.value, etc, 4) != 0) \
|
||||
return 0; \
|
||||
perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \
|
||||
&augmented_args, \
|
||||
(sizeof(augmented_args) - sizeof(augmented_args.filename.value) + \
|
||||
augmented_args.filename.size)); \
|
||||
return 0; \
|
||||
/* If perf_event_output fails, return non-zero so that it gets recorded unaugmented */ \
|
||||
return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \
|
||||
&augmented_args, \
|
||||
(sizeof(augmented_args) - sizeof(augmented_args.filename.value) + \
|
||||
augmented_args.filename.size)); \
|
||||
}
|
||||
|
||||
struct syscall_enter_openat_args {
|
||||
|
@@ -18,6 +18,14 @@ struct bpf_map {
|
||||
unsigned int numa_node;
|
||||
};
|
||||
|
||||
#define bpf_map(name, _type, type_key, type_val, _max_entries) \
|
||||
struct bpf_map SEC("maps") name = { \
|
||||
.type = BPF_MAP_TYPE_##_type, \
|
||||
.key_size = sizeof(type_key), \
|
||||
.value_size = sizeof(type_val), \
|
||||
.max_entries = _max_entries, \
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: this should receive .max_entries as a parameter, as careful
|
||||
* tuning of these limits is needed to avoid hitting limits that
|
||||
@@ -26,13 +34,7 @@ struct bpf_map {
|
||||
* For the current need, 'perf trace --filter-pids', 64 should
|
||||
* be good enough, but this surely needs to be revisited.
|
||||
*/
|
||||
#define pid_map(name, value_type) \
|
||||
struct bpf_map SEC("maps") name = { \
|
||||
.type = BPF_MAP_TYPE_HASH, \
|
||||
.key_size = sizeof(pid_t), \
|
||||
.value_size = sizeof(value_type), \
|
||||
.max_entries = 64, \
|
||||
}
|
||||
#define pid_map(name, value_type) bpf_map(name, HASH, pid_t, value_type, 64)
|
||||
|
||||
static int (*bpf_map_update_elem)(struct bpf_map *map, void *key, void *value, u64 flags) = (void *)BPF_FUNC_map_update_elem;
|
||||
static void *(*bpf_map_lookup_elem)(struct bpf_map *map, void *key) = (void *)BPF_FUNC_map_lookup_elem;
|
||||
|
@@ -66,6 +66,7 @@ struct record_opts {
|
||||
bool ignore_missing_thread;
|
||||
bool strict_freq;
|
||||
bool sample_id;
|
||||
bool bpf_event;
|
||||
unsigned int freq;
|
||||
unsigned int mmap_pages;
|
||||
unsigned int auxtrace_mmap_pages;
|
||||
@@ -83,6 +84,14 @@ struct record_opts {
|
||||
clockid_t clockid;
|
||||
u64 clockid_res_ns;
|
||||
int nr_cblocks;
|
||||
int affinity;
|
||||
};
|
||||
|
||||
enum perf_affinity {
|
||||
PERF_AFFINITY_SYS = 0,
|
||||
PERF_AFFINITY_NODE,
|
||||
PERF_AFFINITY_CPU,
|
||||
PERF_AFFINITY_MAX
|
||||
};
|
||||
|
||||
struct option;
|
||||
|
2245
tools/perf/pmu-events/arch/powerpc/power8/metrics.json
Normal file
2245
tools/perf/pmu-events/arch/powerpc/power8/metrics.json
Normal file
File diff suppressed because it is too large
Load Diff
1982
tools/perf/pmu-events/arch/powerpc/power9/metrics.json
Normal file
1982
tools/perf/pmu-events/arch/powerpc/power9/metrics.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -73,7 +73,7 @@
|
||||
},
|
||||
{
|
||||
"BriefDescription": "Actual Average Latency for L1 data-cache miss demand loads",
|
||||
"MetricExpr": "L1D_PEND_MISS.PENDING / ( MEM_LOAD_RETIRED.L1_MISS_PS + MEM_LOAD_RETIRED.FB_HIT_PS )",
|
||||
"MetricExpr": "L1D_PEND_MISS.PENDING / ( MEM_LOAD_RETIRED.L1_MISS + MEM_LOAD_RETIRED.FB_HIT )",
|
||||
"MetricGroup": "Memory_Bound;Memory_Lat",
|
||||
"MetricName": "Load_Miss_Real_Latency"
|
||||
},
|
||||
|
@@ -1,2 +1,2 @@
|
||||
libperf-$(CONFIG_LIBPERL) += perl/Perf-Trace-Util/
|
||||
libperf-$(CONFIG_LIBPYTHON) += python/Perf-Trace-Util/
|
||||
perf-$(CONFIG_LIBPERL) += perl/Perf-Trace-Util/
|
||||
perf-$(CONFIG_LIBPYTHON) += python/Perf-Trace-Util/
|
||||
|
@@ -1,4 +1,4 @@
|
||||
libperf-y += Context.o
|
||||
perf-y += Context.o
|
||||
|
||||
CFLAGS_Context.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes
|
||||
CFLAGS_Context.o += -Wno-unused-parameter -Wno-nested-externs -Wno-undef
|
||||
|
@@ -1,3 +1,3 @@
|
||||
libperf-y += Context.o
|
||||
perf-y += Context.o
|
||||
|
||||
CFLAGS_Context.o += $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs
|
||||
|
@@ -478,7 +478,7 @@ if perf_db_export_calls:
|
||||
'branch_count,'
|
||||
'call_id,'
|
||||
'return_id,'
|
||||
'CASE WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' ELSE \'\' END AS flags,'
|
||||
'CASE WHEN flags=0 THEN \'\' WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' WHEN flags=6 THEN \'jump\' ELSE flags END AS flags,'
|
||||
'parent_call_path_id'
|
||||
' FROM calls INNER JOIN call_paths ON call_paths.id = call_path_id')
|
||||
|
||||
|
@@ -320,7 +320,7 @@ if perf_db_export_calls:
|
||||
'branch_count,'
|
||||
'call_id,'
|
||||
'return_id,'
|
||||
'CASE WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' ELSE \'\' END AS flags,'
|
||||
'CASE WHEN flags=0 THEN \'\' WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' WHEN flags=6 THEN \'jump\' ELSE flags END AS flags,'
|
||||
'parent_call_path_id'
|
||||
' FROM calls INNER JOIN call_paths ON call_paths.id = call_path_id')
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python2
|
||||
#!/usr/bin/env python2
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# exported-sql-viewer.py: view data from sql database
|
||||
# Copyright (c) 2014-2018, Intel Corporation.
|
||||
@@ -1398,18 +1398,28 @@ class BranchModel(TreeModel):
|
||||
def HasMoreRecords(self):
|
||||
return self.more
|
||||
|
||||
# Report Variables
|
||||
|
||||
class ReportVars():
|
||||
|
||||
def __init__(self, name = "", where_clause = "", limit = ""):
|
||||
self.name = name
|
||||
self.where_clause = where_clause
|
||||
self.limit = limit
|
||||
|
||||
def UniqueId(self):
|
||||
return str(self.where_clause + ";" + self.limit)
|
||||
|
||||
# Branch window
|
||||
|
||||
class BranchWindow(QMdiSubWindow):
|
||||
|
||||
def __init__(self, glb, event_id, name, where_clause, parent=None):
|
||||
def __init__(self, glb, event_id, report_vars, parent=None):
|
||||
super(BranchWindow, self).__init__(parent)
|
||||
|
||||
model_name = "Branch Events " + str(event_id)
|
||||
if len(where_clause):
|
||||
model_name = where_clause + " " + model_name
|
||||
model_name = "Branch Events " + str(event_id) + " " + report_vars.UniqueId()
|
||||
|
||||
self.model = LookupCreateModel(model_name, lambda: BranchModel(glb, event_id, where_clause))
|
||||
self.model = LookupCreateModel(model_name, lambda: BranchModel(glb, event_id, report_vars.where_clause))
|
||||
|
||||
self.view = QTreeView()
|
||||
self.view.setUniformRowHeights(True)
|
||||
@@ -1427,7 +1437,7 @@ class BranchWindow(QMdiSubWindow):
|
||||
|
||||
self.setWidget(self.vbox.Widget())
|
||||
|
||||
AddSubWindow(glb.mainwindow.mdi_area, self, name + " Branch Events")
|
||||
AddSubWindow(glb.mainwindow.mdi_area, self, report_vars.name + " Branch Events")
|
||||
|
||||
def ResizeColumnToContents(self, column, n):
|
||||
# Using the view's resizeColumnToContents() here is extrememly slow
|
||||
@@ -1472,47 +1482,134 @@ class BranchWindow(QMdiSubWindow):
|
||||
else:
|
||||
self.find_bar.NotFound()
|
||||
|
||||
# Dialog data item converted and validated using a SQL table
|
||||
# Line edit data item
|
||||
|
||||
class SQLTableDialogDataItem():
|
||||
class LineEditDataItem(object):
|
||||
|
||||
def __init__(self, glb, label, placeholder_text, table_name, match_column, column_name1, column_name2, parent):
|
||||
def __init__(self, glb, label, placeholder_text, parent, id = "", default = ""):
|
||||
self.glb = glb
|
||||
self.label = label
|
||||
self.placeholder_text = placeholder_text
|
||||
self.table_name = table_name
|
||||
self.match_column = match_column
|
||||
self.column_name1 = column_name1
|
||||
self.column_name2 = column_name2
|
||||
self.parent = parent
|
||||
self.id = id
|
||||
|
||||
self.value = ""
|
||||
self.value = default
|
||||
|
||||
self.widget = QLineEdit()
|
||||
self.widget = QLineEdit(default)
|
||||
self.widget.editingFinished.connect(self.Validate)
|
||||
self.widget.textChanged.connect(self.Invalidate)
|
||||
self.red = False
|
||||
self.error = ""
|
||||
self.validated = True
|
||||
|
||||
self.last_id = 0
|
||||
self.first_time = 0
|
||||
self.last_time = 2 ** 64
|
||||
if self.table_name == "<timeranges>":
|
||||
query = QSqlQuery(self.glb.db)
|
||||
QueryExec(query, "SELECT id, time FROM samples ORDER BY id DESC LIMIT 1")
|
||||
if query.next():
|
||||
self.last_id = int(query.value(0))
|
||||
self.last_time = int(query.value(1))
|
||||
QueryExec(query, "SELECT time FROM samples WHERE time != 0 ORDER BY id LIMIT 1")
|
||||
if query.next():
|
||||
self.first_time = int(query.value(0))
|
||||
if placeholder_text:
|
||||
placeholder_text += ", between " + str(self.first_time) + " and " + str(self.last_time)
|
||||
|
||||
if placeholder_text:
|
||||
self.widget.setPlaceholderText(placeholder_text)
|
||||
|
||||
def TurnTextRed(self):
|
||||
if not self.red:
|
||||
palette = QPalette()
|
||||
palette.setColor(QPalette.Text,Qt.red)
|
||||
self.widget.setPalette(palette)
|
||||
self.red = True
|
||||
|
||||
def TurnTextNormal(self):
|
||||
if self.red:
|
||||
palette = QPalette()
|
||||
self.widget.setPalette(palette)
|
||||
self.red = False
|
||||
|
||||
def InvalidValue(self, value):
|
||||
self.value = ""
|
||||
self.TurnTextRed()
|
||||
self.error = self.label + " invalid value '" + value + "'"
|
||||
self.parent.ShowMessage(self.error)
|
||||
|
||||
def Invalidate(self):
|
||||
self.validated = False
|
||||
|
||||
def DoValidate(self, input_string):
|
||||
self.value = input_string.strip()
|
||||
|
||||
def Validate(self):
|
||||
self.validated = True
|
||||
self.error = ""
|
||||
self.TurnTextNormal()
|
||||
self.parent.ClearMessage()
|
||||
input_string = self.widget.text()
|
||||
if not len(input_string.strip()):
|
||||
self.value = ""
|
||||
return
|
||||
self.DoValidate(input_string)
|
||||
|
||||
def IsValid(self):
|
||||
if not self.validated:
|
||||
self.Validate()
|
||||
if len(self.error):
|
||||
self.parent.ShowMessage(self.error)
|
||||
return False
|
||||
return True
|
||||
|
||||
def IsNumber(self, value):
|
||||
try:
|
||||
x = int(value)
|
||||
except:
|
||||
x = 0
|
||||
return str(x) == value
|
||||
|
||||
# Non-negative integer ranges dialog data item
|
||||
|
||||
class NonNegativeIntegerRangesDataItem(LineEditDataItem):
|
||||
|
||||
def __init__(self, glb, label, placeholder_text, column_name, parent):
|
||||
super(NonNegativeIntegerRangesDataItem, self).__init__(glb, label, placeholder_text, parent)
|
||||
|
||||
self.column_name = column_name
|
||||
|
||||
def DoValidate(self, input_string):
|
||||
singles = []
|
||||
ranges = []
|
||||
for value in [x.strip() for x in input_string.split(",")]:
|
||||
if "-" in value:
|
||||
vrange = value.split("-")
|
||||
if len(vrange) != 2 or not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]):
|
||||
return self.InvalidValue(value)
|
||||
ranges.append(vrange)
|
||||
else:
|
||||
if not self.IsNumber(value):
|
||||
return self.InvalidValue(value)
|
||||
singles.append(value)
|
||||
ranges = [("(" + self.column_name + " >= " + r[0] + " AND " + self.column_name + " <= " + r[1] + ")") for r in ranges]
|
||||
if len(singles):
|
||||
ranges.append(self.column_name + " IN (" + ",".join(singles) + ")")
|
||||
self.value = " OR ".join(ranges)
|
||||
|
||||
# Positive integer dialog data item
|
||||
|
||||
class PositiveIntegerDataItem(LineEditDataItem):
|
||||
|
||||
def __init__(self, glb, label, placeholder_text, parent, id = "", default = ""):
|
||||
super(PositiveIntegerDataItem, self).__init__(glb, label, placeholder_text, parent, id, default)
|
||||
|
||||
def DoValidate(self, input_string):
|
||||
if not self.IsNumber(input_string.strip()):
|
||||
return self.InvalidValue(input_string)
|
||||
value = int(input_string.strip())
|
||||
if value <= 0:
|
||||
return self.InvalidValue(input_string)
|
||||
self.value = str(value)
|
||||
|
||||
# Dialog data item converted and validated using a SQL table
|
||||
|
||||
class SQLTableDataItem(LineEditDataItem):
|
||||
|
||||
def __init__(self, glb, label, placeholder_text, table_name, match_column, column_name1, column_name2, parent):
|
||||
super(SQLTableDataItem, self).__init__(glb, label, placeholder_text, parent)
|
||||
|
||||
self.table_name = table_name
|
||||
self.match_column = match_column
|
||||
self.column_name1 = column_name1
|
||||
self.column_name2 = column_name2
|
||||
|
||||
def ValueToIds(self, value):
|
||||
ids = []
|
||||
query = QSqlQuery(self.glb.db)
|
||||
@@ -1523,6 +1620,42 @@ class SQLTableDialogDataItem():
|
||||
ids.append(str(query.value(0)))
|
||||
return ids
|
||||
|
||||
def DoValidate(self, input_string):
|
||||
all_ids = []
|
||||
for value in [x.strip() for x in input_string.split(",")]:
|
||||
ids = self.ValueToIds(value)
|
||||
if len(ids):
|
||||
all_ids.extend(ids)
|
||||
else:
|
||||
return self.InvalidValue(value)
|
||||
self.value = self.column_name1 + " IN (" + ",".join(all_ids) + ")"
|
||||
if self.column_name2:
|
||||
self.value = "( " + self.value + " OR " + self.column_name2 + " IN (" + ",".join(all_ids) + ") )"
|
||||
|
||||
# Sample time ranges dialog data item converted and validated using 'samples' SQL table
|
||||
|
||||
class SampleTimeRangesDataItem(LineEditDataItem):
|
||||
|
||||
def __init__(self, glb, label, placeholder_text, column_name, parent):
|
||||
self.column_name = column_name
|
||||
|
||||
self.last_id = 0
|
||||
self.first_time = 0
|
||||
self.last_time = 2 ** 64
|
||||
|
||||
query = QSqlQuery(glb.db)
|
||||
QueryExec(query, "SELECT id, time FROM samples ORDER BY id DESC LIMIT 1")
|
||||
if query.next():
|
||||
self.last_id = int(query.value(0))
|
||||
self.last_time = int(query.value(1))
|
||||
QueryExec(query, "SELECT time FROM samples WHERE time != 0 ORDER BY id LIMIT 1")
|
||||
if query.next():
|
||||
self.first_time = int(query.value(0))
|
||||
if placeholder_text:
|
||||
placeholder_text += ", between " + str(self.first_time) + " and " + str(self.last_time)
|
||||
|
||||
super(SampleTimeRangesDataItem, self).__init__(glb, label, placeholder_text, parent)
|
||||
|
||||
def IdBetween(self, query, lower_id, higher_id, order):
|
||||
QueryExec(query, "SELECT id FROM samples WHERE id > " + str(lower_id) + " AND id < " + str(higher_id) + " ORDER BY id " + order + " LIMIT 1")
|
||||
if query.next():
|
||||
@@ -1560,7 +1693,6 @@ class SQLTableDialogDataItem():
|
||||
return str(lower_id)
|
||||
|
||||
def ConvertRelativeTime(self, val):
|
||||
print "val ", val
|
||||
mult = 1
|
||||
suffix = val[-2:]
|
||||
if suffix == "ms":
|
||||
@@ -1582,29 +1714,23 @@ class SQLTableDialogDataItem():
|
||||
return str(val)
|
||||
|
||||
def ConvertTimeRange(self, vrange):
|
||||
print "vrange ", vrange
|
||||
if vrange[0] == "":
|
||||
vrange[0] = str(self.first_time)
|
||||
if vrange[1] == "":
|
||||
vrange[1] = str(self.last_time)
|
||||
vrange[0] = self.ConvertRelativeTime(vrange[0])
|
||||
vrange[1] = self.ConvertRelativeTime(vrange[1])
|
||||
print "vrange2 ", vrange
|
||||
if not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]):
|
||||
return False
|
||||
print "ok1"
|
||||
beg_range = max(int(vrange[0]), self.first_time)
|
||||
end_range = min(int(vrange[1]), self.last_time)
|
||||
if beg_range > self.last_time or end_range < self.first_time:
|
||||
return False
|
||||
print "ok2"
|
||||
vrange[0] = self.BinarySearchTime(0, self.last_id, beg_range, True)
|
||||
vrange[1] = self.BinarySearchTime(1, self.last_id + 1, end_range, False)
|
||||
print "vrange3 ", vrange
|
||||
return True
|
||||
|
||||
def AddTimeRange(self, value, ranges):
|
||||
print "value ", value
|
||||
n = value.count("-")
|
||||
if n == 1:
|
||||
pass
|
||||
@@ -1622,111 +1748,31 @@ class SQLTableDialogDataItem():
|
||||
return True
|
||||
return False
|
||||
|
||||
def InvalidValue(self, value):
|
||||
self.value = ""
|
||||
palette = QPalette()
|
||||
palette.setColor(QPalette.Text,Qt.red)
|
||||
self.widget.setPalette(palette)
|
||||
self.red = True
|
||||
self.error = self.label + " invalid value '" + value + "'"
|
||||
self.parent.ShowMessage(self.error)
|
||||
def DoValidate(self, input_string):
|
||||
ranges = []
|
||||
for value in [x.strip() for x in input_string.split(",")]:
|
||||
if not self.AddTimeRange(value, ranges):
|
||||
return self.InvalidValue(value)
|
||||
ranges = [("(" + self.column_name + " >= " + r[0] + " AND " + self.column_name + " <= " + r[1] + ")") for r in ranges]
|
||||
self.value = " OR ".join(ranges)
|
||||
|
||||
def IsNumber(self, value):
|
||||
try:
|
||||
x = int(value)
|
||||
except:
|
||||
x = 0
|
||||
return str(x) == value
|
||||
# Report Dialog Base
|
||||
|
||||
def Invalidate(self):
|
||||
self.validated = False
|
||||
class ReportDialogBase(QDialog):
|
||||
|
||||
def Validate(self):
|
||||
input_string = self.widget.text()
|
||||
self.validated = True
|
||||
if self.red:
|
||||
palette = QPalette()
|
||||
self.widget.setPalette(palette)
|
||||
self.red = False
|
||||
if not len(input_string.strip()):
|
||||
self.error = ""
|
||||
self.value = ""
|
||||
return
|
||||
if self.table_name == "<timeranges>":
|
||||
ranges = []
|
||||
for value in [x.strip() for x in input_string.split(",")]:
|
||||
if not self.AddTimeRange(value, ranges):
|
||||
return self.InvalidValue(value)
|
||||
ranges = [("(" + self.column_name1 + " >= " + r[0] + " AND " + self.column_name1 + " <= " + r[1] + ")") for r in ranges]
|
||||
self.value = " OR ".join(ranges)
|
||||
elif self.table_name == "<ranges>":
|
||||
singles = []
|
||||
ranges = []
|
||||
for value in [x.strip() for x in input_string.split(",")]:
|
||||
if "-" in value:
|
||||
vrange = value.split("-")
|
||||
if len(vrange) != 2 or not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]):
|
||||
return self.InvalidValue(value)
|
||||
ranges.append(vrange)
|
||||
else:
|
||||
if not self.IsNumber(value):
|
||||
return self.InvalidValue(value)
|
||||
singles.append(value)
|
||||
ranges = [("(" + self.column_name1 + " >= " + r[0] + " AND " + self.column_name1 + " <= " + r[1] + ")") for r in ranges]
|
||||
if len(singles):
|
||||
ranges.append(self.column_name1 + " IN (" + ",".join(singles) + ")")
|
||||
self.value = " OR ".join(ranges)
|
||||
elif self.table_name:
|
||||
all_ids = []
|
||||
for value in [x.strip() for x in input_string.split(",")]:
|
||||
ids = self.ValueToIds(value)
|
||||
if len(ids):
|
||||
all_ids.extend(ids)
|
||||
else:
|
||||
return self.InvalidValue(value)
|
||||
self.value = self.column_name1 + " IN (" + ",".join(all_ids) + ")"
|
||||
if self.column_name2:
|
||||
self.value = "( " + self.value + " OR " + self.column_name2 + " IN (" + ",".join(all_ids) + ") )"
|
||||
else:
|
||||
self.value = input_string.strip()
|
||||
self.error = ""
|
||||
self.parent.ClearMessage()
|
||||
|
||||
def IsValid(self):
|
||||
if not self.validated:
|
||||
self.Validate()
|
||||
if len(self.error):
|
||||
self.parent.ShowMessage(self.error)
|
||||
return False
|
||||
return True
|
||||
|
||||
# Selected branch report creation dialog
|
||||
|
||||
class SelectedBranchDialog(QDialog):
|
||||
|
||||
def __init__(self, glb, parent=None):
|
||||
super(SelectedBranchDialog, self).__init__(parent)
|
||||
def __init__(self, glb, title, items, partial, parent=None):
|
||||
super(ReportDialogBase, self).__init__(parent)
|
||||
|
||||
self.glb = glb
|
||||
|
||||
self.name = ""
|
||||
self.where_clause = ""
|
||||
self.report_vars = ReportVars()
|
||||
|
||||
self.setWindowTitle("Selected Branches")
|
||||
self.setWindowTitle(title)
|
||||
self.setMinimumWidth(600)
|
||||
|
||||
items = (
|
||||
("Report name:", "Enter a name to appear in the window title bar", "", "", "", ""),
|
||||
("Time ranges:", "Enter time ranges", "<timeranges>", "", "samples.id", ""),
|
||||
("CPUs:", "Enter CPUs or ranges e.g. 0,5-6", "<ranges>", "", "cpu", ""),
|
||||
("Commands:", "Only branches with these commands will be included", "comms", "comm", "comm_id", ""),
|
||||
("PIDs:", "Only branches with these process IDs will be included", "threads", "pid", "thread_id", ""),
|
||||
("TIDs:", "Only branches with these thread IDs will be included", "threads", "tid", "thread_id", ""),
|
||||
("DSOs:", "Only branches with these DSOs will be included", "dsos", "short_name", "samples.dso_id", "to_dso_id"),
|
||||
("Symbols:", "Only branches with these symbols will be included", "symbols", "name", "symbol_id", "to_symbol_id"),
|
||||
("Raw SQL clause: ", "Enter a raw SQL WHERE clause", "", "", "", ""),
|
||||
)
|
||||
self.data_items = [SQLTableDialogDataItem(glb, *x, parent=self) for x in items]
|
||||
self.data_items = [x(glb, self) for x in items]
|
||||
|
||||
self.partial = partial
|
||||
|
||||
self.grid = QGridLayout()
|
||||
|
||||
@@ -1758,23 +1804,28 @@ class SelectedBranchDialog(QDialog):
|
||||
self.setLayout(self.vbox);
|
||||
|
||||
def Ok(self):
|
||||
self.name = self.data_items[0].value
|
||||
if not self.name:
|
||||
vars = self.report_vars
|
||||
for d in self.data_items:
|
||||
if d.id == "REPORTNAME":
|
||||
vars.name = d.value
|
||||
if not vars.name:
|
||||
self.ShowMessage("Report name is required")
|
||||
return
|
||||
for d in self.data_items:
|
||||
if not d.IsValid():
|
||||
return
|
||||
for d in self.data_items[1:]:
|
||||
if len(d.value):
|
||||
if len(self.where_clause):
|
||||
self.where_clause += " AND "
|
||||
self.where_clause += d.value
|
||||
if len(self.where_clause):
|
||||
self.where_clause = " AND ( " + self.where_clause + " ) "
|
||||
else:
|
||||
self.ShowMessage("No selection")
|
||||
return
|
||||
if d.id == "LIMIT":
|
||||
vars.limit = d.value
|
||||
elif len(d.value):
|
||||
if len(vars.where_clause):
|
||||
vars.where_clause += " AND "
|
||||
vars.where_clause += d.value
|
||||
if len(vars.where_clause):
|
||||
if self.partial:
|
||||
vars.where_clause = " AND ( " + vars.where_clause + " ) "
|
||||
else:
|
||||
vars.where_clause = " WHERE " + vars.where_clause + " "
|
||||
self.accept()
|
||||
|
||||
def ShowMessage(self, msg):
|
||||
@@ -1783,6 +1834,23 @@ class SelectedBranchDialog(QDialog):
|
||||
def ClearMessage(self):
|
||||
self.status.setText("")
|
||||
|
||||
# Selected branch report creation dialog
|
||||
|
||||
class SelectedBranchDialog(ReportDialogBase):
|
||||
|
||||
def __init__(self, glb, parent=None):
|
||||
title = "Selected Branches"
|
||||
items = (lambda g, p: LineEditDataItem(g, "Report name:", "Enter a name to appear in the window title bar", p, "REPORTNAME"),
|
||||
lambda g, p: SampleTimeRangesDataItem(g, "Time ranges:", "Enter time ranges", "samples.id", p),
|
||||
lambda g, p: NonNegativeIntegerRangesDataItem(g, "CPUs:", "Enter CPUs or ranges e.g. 0,5-6", "cpu", p),
|
||||
lambda g, p: SQLTableDataItem(g, "Commands:", "Only branches with these commands will be included", "comms", "comm", "comm_id", "", p),
|
||||
lambda g, p: SQLTableDataItem(g, "PIDs:", "Only branches with these process IDs will be included", "threads", "pid", "thread_id", "", p),
|
||||
lambda g, p: SQLTableDataItem(g, "TIDs:", "Only branches with these thread IDs will be included", "threads", "tid", "thread_id", "", p),
|
||||
lambda g, p: SQLTableDataItem(g, "DSOs:", "Only branches with these DSOs will be included", "dsos", "short_name", "samples.dso_id", "to_dso_id", p),
|
||||
lambda g, p: SQLTableDataItem(g, "Symbols:", "Only branches with these symbols will be included", "symbols", "name", "symbol_id", "to_symbol_id", p),
|
||||
lambda g, p: LineEditDataItem(g, "Raw SQL clause: ", "Enter a raw SQL WHERE clause", p))
|
||||
super(SelectedBranchDialog, self).__init__(glb, title, items, True, parent)
|
||||
|
||||
# Event list
|
||||
|
||||
def GetEventList(db):
|
||||
@@ -1793,6 +1861,16 @@ def GetEventList(db):
|
||||
events.append(query.value(0))
|
||||
return events
|
||||
|
||||
# Is a table selectable
|
||||
|
||||
def IsSelectable(db, table):
|
||||
query = QSqlQuery(db)
|
||||
try:
|
||||
QueryExec(query, "SELECT * FROM " + table + " LIMIT 1")
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
# SQL data preparation
|
||||
|
||||
def SQLTableDataPrep(query, count):
|
||||
@@ -1818,12 +1896,13 @@ class SQLTableModel(TableModel):
|
||||
|
||||
progress = Signal(object)
|
||||
|
||||
def __init__(self, glb, sql, column_count, parent=None):
|
||||
def __init__(self, glb, sql, column_headers, parent=None):
|
||||
super(SQLTableModel, self).__init__(parent)
|
||||
self.glb = glb
|
||||
self.more = True
|
||||
self.populated = 0
|
||||
self.fetcher = SQLFetcher(glb, sql, lambda x, y=column_count: SQLTableDataPrep(x, y), self.AddSample)
|
||||
self.column_headers = column_headers
|
||||
self.fetcher = SQLFetcher(glb, sql, lambda x, y=len(column_headers): SQLTableDataPrep(x, y), self.AddSample)
|
||||
self.fetcher.done.connect(self.Update)
|
||||
self.fetcher.Fetch(glb_chunk_sz)
|
||||
|
||||
@@ -1861,6 +1940,12 @@ class SQLTableModel(TableModel):
|
||||
def HasMoreRecords(self):
|
||||
return self.more
|
||||
|
||||
def columnCount(self, parent=None):
|
||||
return len(self.column_headers)
|
||||
|
||||
def columnHeader(self, column):
|
||||
return self.column_headers[column]
|
||||
|
||||
# SQL automatic table data model
|
||||
|
||||
class SQLAutoTableModel(SQLTableModel):
|
||||
@@ -1870,12 +1955,12 @@ class SQLAutoTableModel(SQLTableModel):
|
||||
if table_name == "comm_threads_view":
|
||||
# For now, comm_threads_view has no id column
|
||||
sql = "SELECT * FROM " + table_name + " WHERE comm_id > $$last_id$$ ORDER BY comm_id LIMIT " + str(glb_chunk_sz)
|
||||
self.column_headers = []
|
||||
column_headers = []
|
||||
query = QSqlQuery(glb.db)
|
||||
if glb.dbref.is_sqlite3:
|
||||
QueryExec(query, "PRAGMA table_info(" + table_name + ")")
|
||||
while query.next():
|
||||
self.column_headers.append(query.value(1))
|
||||
column_headers.append(query.value(1))
|
||||
if table_name == "sqlite_master":
|
||||
sql = "SELECT * FROM " + table_name
|
||||
else:
|
||||
@@ -1888,14 +1973,8 @@ class SQLAutoTableModel(SQLTableModel):
|
||||
schema = "public"
|
||||
QueryExec(query, "SELECT column_name FROM information_schema.columns WHERE table_schema = '" + schema + "' and table_name = '" + select_table_name + "'")
|
||||
while query.next():
|
||||
self.column_headers.append(query.value(0))
|
||||
super(SQLAutoTableModel, self).__init__(glb, sql, len(self.column_headers), parent)
|
||||
|
||||
def columnCount(self, parent=None):
|
||||
return len(self.column_headers)
|
||||
|
||||
def columnHeader(self, column):
|
||||
return self.column_headers[column]
|
||||
column_headers.append(query.value(0))
|
||||
super(SQLAutoTableModel, self).__init__(glb, sql, column_headers, parent)
|
||||
|
||||
# Base class for custom ResizeColumnsToContents
|
||||
|
||||
@@ -1998,6 +2077,103 @@ def GetTableList(glb):
|
||||
tables.append("information_schema.columns")
|
||||
return tables
|
||||
|
||||
# Top Calls data model
|
||||
|
||||
class TopCallsModel(SQLTableModel):
|
||||
|
||||
def __init__(self, glb, report_vars, parent=None):
|
||||
text = ""
|
||||
if not glb.dbref.is_sqlite3:
|
||||
text = "::text"
|
||||
limit = ""
|
||||
if len(report_vars.limit):
|
||||
limit = " LIMIT " + report_vars.limit
|
||||
sql = ("SELECT comm, pid, tid, name,"
|
||||
" CASE"
|
||||
" WHEN (short_name = '[kernel.kallsyms]') THEN '[kernel]'" + text +
|
||||
" ELSE short_name"
|
||||
" END AS dso,"
|
||||
" call_time, return_time, (return_time - call_time) AS elapsed_time, branch_count, "
|
||||
" CASE"
|
||||
" WHEN (calls.flags = 1) THEN 'no call'" + text +
|
||||
" WHEN (calls.flags = 2) THEN 'no return'" + text +
|
||||
" WHEN (calls.flags = 3) THEN 'no call/return'" + text +
|
||||
" ELSE ''" + text +
|
||||
" END AS flags"
|
||||
" FROM calls"
|
||||
" INNER JOIN call_paths ON calls.call_path_id = call_paths.id"
|
||||
" INNER JOIN symbols ON call_paths.symbol_id = symbols.id"
|
||||
" INNER JOIN dsos ON symbols.dso_id = dsos.id"
|
||||
" INNER JOIN comms ON calls.comm_id = comms.id"
|
||||
" INNER JOIN threads ON calls.thread_id = threads.id" +
|
||||
report_vars.where_clause +
|
||||
" ORDER BY elapsed_time DESC" +
|
||||
limit
|
||||
)
|
||||
column_headers = ("Command", "PID", "TID", "Symbol", "Object", "Call Time", "Return Time", "Elapsed Time (ns)", "Branch Count", "Flags")
|
||||
self.alignment = (Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignLeft)
|
||||
super(TopCallsModel, self).__init__(glb, sql, column_headers, parent)
|
||||
|
||||
def columnAlignment(self, column):
|
||||
return self.alignment[column]
|
||||
|
||||
# Top Calls report creation dialog
|
||||
|
||||
class TopCallsDialog(ReportDialogBase):
|
||||
|
||||
def __init__(self, glb, parent=None):
|
||||
title = "Top Calls by Elapsed Time"
|
||||
items = (lambda g, p: LineEditDataItem(g, "Report name:", "Enter a name to appear in the window title bar", p, "REPORTNAME"),
|
||||
lambda g, p: SQLTableDataItem(g, "Commands:", "Only calls with these commands will be included", "comms", "comm", "comm_id", "", p),
|
||||
lambda g, p: SQLTableDataItem(g, "PIDs:", "Only calls with these process IDs will be included", "threads", "pid", "thread_id", "", p),
|
||||
lambda g, p: SQLTableDataItem(g, "TIDs:", "Only calls with these thread IDs will be included", "threads", "tid", "thread_id", "", p),
|
||||
lambda g, p: SQLTableDataItem(g, "DSOs:", "Only calls with these DSOs will be included", "dsos", "short_name", "dso_id", "", p),
|
||||
lambda g, p: SQLTableDataItem(g, "Symbols:", "Only calls with these symbols will be included", "symbols", "name", "symbol_id", "", p),
|
||||
lambda g, p: LineEditDataItem(g, "Raw SQL clause: ", "Enter a raw SQL WHERE clause", p),
|
||||
lambda g, p: PositiveIntegerDataItem(g, "Record limit:", "Limit selection to this number of records", p, "LIMIT", "100"))
|
||||
super(TopCallsDialog, self).__init__(glb, title, items, False, parent)
|
||||
|
||||
# Top Calls window
|
||||
|
||||
class TopCallsWindow(QMdiSubWindow, ResizeColumnsToContentsBase):
|
||||
|
||||
def __init__(self, glb, report_vars, parent=None):
|
||||
super(TopCallsWindow, self).__init__(parent)
|
||||
|
||||
self.data_model = LookupCreateModel("Top Calls " + report_vars.UniqueId(), lambda: TopCallsModel(glb, report_vars))
|
||||
self.model = self.data_model
|
||||
|
||||
self.view = QTableView()
|
||||
self.view.setModel(self.model)
|
||||
self.view.setEditTriggers(QAbstractItemView.NoEditTriggers)
|
||||
self.view.verticalHeader().setVisible(False)
|
||||
|
||||
self.ResizeColumnsToContents()
|
||||
|
||||
self.find_bar = FindBar(self, self, True)
|
||||
|
||||
self.finder = ChildDataItemFinder(self.model)
|
||||
|
||||
self.fetch_bar = FetchMoreRecordsBar(self.data_model, self)
|
||||
|
||||
self.vbox = VBox(self.view, self.find_bar.Widget(), self.fetch_bar.Widget())
|
||||
|
||||
self.setWidget(self.vbox.Widget())
|
||||
|
||||
AddSubWindow(glb.mainwindow.mdi_area, self, report_vars.name)
|
||||
|
||||
def Find(self, value, direction, pattern, context):
|
||||
self.view.setFocus()
|
||||
self.find_bar.Busy()
|
||||
self.finder.Find(value, direction, pattern, context, self.FindDone)
|
||||
|
||||
def FindDone(self, row):
|
||||
self.find_bar.Idle()
|
||||
if row >= 0:
|
||||
self.view.setCurrentIndex(self.model.index(row, 0, QModelIndex()))
|
||||
else:
|
||||
self.find_bar.NotFound()
|
||||
|
||||
# Action Definition
|
||||
|
||||
def CreateAction(label, tip, callback, parent=None, shortcut=None):
|
||||
@@ -2101,6 +2277,7 @@ p.c2 {
|
||||
<p class=c2><a href=#callgraph>1.1 Context-Sensitive Call Graph</a></p>
|
||||
<p class=c2><a href=#allbranches>1.2 All branches</a></p>
|
||||
<p class=c2><a href=#selectedbranches>1.3 Selected branches</a></p>
|
||||
<p class=c2><a href=#topcallsbyelapsedtime>1.4 Top calls by elapsed time</a></p>
|
||||
<p class=c1><a href=#tables>2. Tables</a></p>
|
||||
<h1 id=reports>1. Reports</h1>
|
||||
<h2 id=callgraph>1.1 Context-Sensitive Call Graph</h2>
|
||||
@@ -2176,6 +2353,10 @@ ms, us or ns. Also, negative values are relative to the end of trace. Examples:
|
||||
-10ms- The last 10ms
|
||||
</pre>
|
||||
N.B. Due to the granularity of timestamps, there could be no branches in any given time range.
|
||||
<h2 id=topcallsbyelapsedtime>1.4 Top calls by elapsed time</h2>
|
||||
The Top calls by elapsed time report displays calls in descending order of time elapsed between when the function was called and when it returned.
|
||||
The data is reduced by various selection criteria. A dialog box displays available criteria which are AND'ed together.
|
||||
If not all data is fetched, a Fetch bar is provided. Ctrl-F displays a Find bar.
|
||||
<h1 id=tables>2. Tables</h1>
|
||||
The Tables menu shows all tables and views in the database. Most tables have an associated view
|
||||
which displays the information in a more friendly way. Not all data for large tables is fetched
|
||||
@@ -2305,10 +2486,14 @@ class MainWindow(QMainWindow):
|
||||
edit_menu.addAction(CreateAction("&Enlarge Font", "Make text bigger", self.EnlargeFont, self, [QKeySequence("Ctrl++")]))
|
||||
|
||||
reports_menu = menu.addMenu("&Reports")
|
||||
reports_menu.addAction(CreateAction("Context-Sensitive Call &Graph", "Create a new window containing a context-sensitive call graph", self.NewCallGraph, self))
|
||||
if IsSelectable(glb.db, "calls"):
|
||||
reports_menu.addAction(CreateAction("Context-Sensitive Call &Graph", "Create a new window containing a context-sensitive call graph", self.NewCallGraph, self))
|
||||
|
||||
self.EventMenu(GetEventList(glb.db), reports_menu)
|
||||
|
||||
if IsSelectable(glb.db, "calls"):
|
||||
reports_menu.addAction(CreateAction("&Top calls by elapsed time", "Create a new window displaying top calls by elapsed time", self.NewTopCalls, self))
|
||||
|
||||
self.TableMenu(GetTableList(glb), menu)
|
||||
|
||||
self.window_menu = WindowMenu(self.mdi_area, menu)
|
||||
@@ -2364,14 +2549,20 @@ class MainWindow(QMainWindow):
|
||||
def NewCallGraph(self):
|
||||
CallGraphWindow(self.glb, self)
|
||||
|
||||
def NewTopCalls(self):
|
||||
dialog = TopCallsDialog(self.glb, self)
|
||||
ret = dialog.exec_()
|
||||
if ret:
|
||||
TopCallsWindow(self.glb, dialog.report_vars, self)
|
||||
|
||||
def NewBranchView(self, event_id):
|
||||
BranchWindow(self.glb, event_id, "", "", self)
|
||||
BranchWindow(self.glb, event_id, ReportVars(), self)
|
||||
|
||||
def NewSelectedBranchView(self, event_id):
|
||||
dialog = SelectedBranchDialog(self.glb, self)
|
||||
ret = dialog.exec_()
|
||||
if ret:
|
||||
BranchWindow(self.glb, event_id, dialog.name, dialog.where_clause, self)
|
||||
BranchWindow(self.glb, event_id, dialog.report_vars, self)
|
||||
|
||||
def NewTableView(self, table_name):
|
||||
TableWindow(self.glb, table_name, self)
|
||||
|
@@ -5,6 +5,8 @@
|
||||
# Displays system-wide failed system call totals, broken down by pid.
|
||||
# If a [comm] arg is specified, only syscalls called by [comm] are displayed.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
@@ -32,7 +34,7 @@ if len(sys.argv) > 1:
|
||||
syscalls = autodict()
|
||||
|
||||
def trace_begin():
|
||||
print "Press control+C to stop and show the summary"
|
||||
print("Press control+C to stop and show the summary")
|
||||
|
||||
def trace_end():
|
||||
print_error_totals()
|
||||
@@ -57,22 +59,21 @@ def syscalls__sys_exit(event_name, context, common_cpu,
|
||||
|
||||
def print_error_totals():
|
||||
if for_comm is not None:
|
||||
print "\nsyscall errors for %s:\n\n" % (for_comm),
|
||||
print("\nsyscall errors for %s:\n" % (for_comm))
|
||||
else:
|
||||
print "\nsyscall errors:\n\n",
|
||||
print("\nsyscall errors:\n")
|
||||
|
||||
print "%-30s %10s\n" % ("comm [pid]", "count"),
|
||||
print "%-30s %10s\n" % ("------------------------------", \
|
||||
"----------"),
|
||||
print("%-30s %10s" % ("comm [pid]", "count"))
|
||||
print("%-30s %10s" % ("------------------------------", "----------"))
|
||||
|
||||
comm_keys = syscalls.keys()
|
||||
for comm in comm_keys:
|
||||
pid_keys = syscalls[comm].keys()
|
||||
for pid in pid_keys:
|
||||
print "\n%s [%d]\n" % (comm, pid),
|
||||
print("\n%s [%d]" % (comm, pid))
|
||||
id_keys = syscalls[comm][pid].keys()
|
||||
for id in id_keys:
|
||||
print " syscall: %-16s\n" % syscall_name(id),
|
||||
print(" syscall: %-16s" % syscall_name(id))
|
||||
ret_keys = syscalls[comm][pid][id].keys()
|
||||
for ret, val in sorted(syscalls[comm][pid][id].iteritems(), key = lambda(k, v): (v, k), reverse = True):
|
||||
print " err = %-20s %10d\n" % (strerror(ret), val),
|
||||
for ret, val in sorted(syscalls[comm][pid][id].items(), key = lambda kv: (kv[1], kv[0]), reverse = True):
|
||||
print(" err = %-20s %10d" % (strerror(ret), val))
|
||||
|
@@ -4,6 +4,8 @@
|
||||
# Copyright (c) 2018, Intel Corporation.
|
||||
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import struct
|
||||
@@ -31,21 +33,23 @@ def parse_iomem():
|
||||
for i, j in enumerate(f):
|
||||
m = re.split('-|:',j,2)
|
||||
if m[2].strip() == 'System RAM':
|
||||
system_ram.append(long(m[0], 16))
|
||||
system_ram.append(long(m[1], 16))
|
||||
system_ram.append(int(m[0], 16))
|
||||
system_ram.append(int(m[1], 16))
|
||||
if m[2].strip() == 'Persistent Memory':
|
||||
pmem.append(long(m[0], 16))
|
||||
pmem.append(long(m[1], 16))
|
||||
pmem.append(int(m[0], 16))
|
||||
pmem.append(int(m[1], 16))
|
||||
|
||||
def print_memory_type():
|
||||
print "Event: %s" % (event_name)
|
||||
print "%-40s %10s %10s\n" % ("Memory type", "count", "percentage"),
|
||||
print "%-40s %10s %10s\n" % ("----------------------------------------", \
|
||||
print("Event: %s" % (event_name))
|
||||
print("%-40s %10s %10s\n" % ("Memory type", "count", "percentage"), end='')
|
||||
print("%-40s %10s %10s\n" % ("----------------------------------------",
|
||||
"-----------", "-----------"),
|
||||
end='');
|
||||
total = sum(load_mem_type_cnt.values())
|
||||
for mem_type, count in sorted(load_mem_type_cnt.most_common(), \
|
||||
key = lambda(k, v): (v, k), reverse = True):
|
||||
print "%-40s %10d %10.1f%%\n" % (mem_type, count, 100 * count / total),
|
||||
key = lambda kv: (kv[1], kv[0]), reverse = True):
|
||||
print("%-40s %10d %10.1f%%\n" % (mem_type, count, 100 * count / total),
|
||||
end='')
|
||||
|
||||
def trace_begin():
|
||||
parse_iomem()
|
||||
@@ -80,7 +84,7 @@ def find_memory_type(phys_addr):
|
||||
f.seek(0, 0)
|
||||
for j in f:
|
||||
m = re.split('-|:',j,2)
|
||||
if long(m[0], 16) <= phys_addr <= long(m[1], 16):
|
||||
if int(m[0], 16) <= phys_addr <= int(m[1], 16):
|
||||
return m[2]
|
||||
return "N/A"
|
||||
|
||||
|
@@ -1,6 +1,8 @@
|
||||
# Monitor the system for dropped packets and proudce a report of drop locations and counts
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
@@ -50,19 +52,19 @@ def get_sym(sloc):
|
||||
return (None, 0)
|
||||
|
||||
def print_drop_table():
|
||||
print "%25s %25s %25s" % ("LOCATION", "OFFSET", "COUNT")
|
||||
print("%25s %25s %25s" % ("LOCATION", "OFFSET", "COUNT"))
|
||||
for i in drop_log.keys():
|
||||
(sym, off) = get_sym(i)
|
||||
if sym == None:
|
||||
sym = i
|
||||
print "%25s %25s %25s" % (sym, off, drop_log[i])
|
||||
print("%25s %25s %25s" % (sym, off, drop_log[i]))
|
||||
|
||||
|
||||
def trace_begin():
|
||||
print "Starting trace (Ctrl-C to dump results)"
|
||||
print("Starting trace (Ctrl-C to dump results)")
|
||||
|
||||
def trace_end():
|
||||
print "Gathering kallsyms data"
|
||||
print("Gathering kallsyms data")
|
||||
get_kallsyms_table()
|
||||
print_drop_table()
|
||||
|
||||
|
@@ -8,6 +8,8 @@
|
||||
# dev=: show only thing related to specified device
|
||||
# debug: work with debug mode. It shows buffer status.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
@@ -17,6 +19,7 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \
|
||||
from perf_trace_context import *
|
||||
from Core import *
|
||||
from Util import *
|
||||
from functools import cmp_to_key
|
||||
|
||||
all_event_list = []; # insert all tracepoint event related with this script
|
||||
irq_dic = {}; # key is cpu and value is a list which stacks irqs
|
||||
@@ -61,12 +64,12 @@ def diff_msec(src, dst):
|
||||
def print_transmit(hunk):
|
||||
if dev != 0 and hunk['dev'].find(dev) < 0:
|
||||
return
|
||||
print "%7s %5d %6d.%06dsec %12.3fmsec %12.3fmsec" % \
|
||||
print("%7s %5d %6d.%06dsec %12.3fmsec %12.3fmsec" %
|
||||
(hunk['dev'], hunk['len'],
|
||||
nsecs_secs(hunk['queue_t']),
|
||||
nsecs_nsecs(hunk['queue_t'])/1000,
|
||||
diff_msec(hunk['queue_t'], hunk['xmit_t']),
|
||||
diff_msec(hunk['xmit_t'], hunk['free_t']))
|
||||
diff_msec(hunk['xmit_t'], hunk['free_t'])))
|
||||
|
||||
# Format for displaying rx packet processing
|
||||
PF_IRQ_ENTRY= " irq_entry(+%.3fmsec irq=%d:%s)"
|
||||
@@ -98,55 +101,55 @@ def print_receive(hunk):
|
||||
if show_hunk == 0:
|
||||
return
|
||||
|
||||
print "%d.%06dsec cpu=%d" % \
|
||||
(nsecs_secs(base_t), nsecs_nsecs(base_t)/1000, cpu)
|
||||
print("%d.%06dsec cpu=%d" %
|
||||
(nsecs_secs(base_t), nsecs_nsecs(base_t)/1000, cpu))
|
||||
for i in range(len(irq_list)):
|
||||
print PF_IRQ_ENTRY % \
|
||||
print(PF_IRQ_ENTRY %
|
||||
(diff_msec(base_t, irq_list[i]['irq_ent_t']),
|
||||
irq_list[i]['irq'], irq_list[i]['name'])
|
||||
print PF_JOINT
|
||||
irq_list[i]['irq'], irq_list[i]['name']))
|
||||
print(PF_JOINT)
|
||||
irq_event_list = irq_list[i]['event_list']
|
||||
for j in range(len(irq_event_list)):
|
||||
irq_event = irq_event_list[j]
|
||||
if irq_event['event'] == 'netif_rx':
|
||||
print PF_NET_RX % \
|
||||
print(PF_NET_RX %
|
||||
(diff_msec(base_t, irq_event['time']),
|
||||
irq_event['skbaddr'])
|
||||
print PF_JOINT
|
||||
print PF_SOFT_ENTRY % \
|
||||
diff_msec(base_t, hunk['sirq_ent_t'])
|
||||
print PF_JOINT
|
||||
irq_event['skbaddr']))
|
||||
print(PF_JOINT)
|
||||
print(PF_SOFT_ENTRY %
|
||||
diff_msec(base_t, hunk['sirq_ent_t']))
|
||||
print(PF_JOINT)
|
||||
event_list = hunk['event_list']
|
||||
for i in range(len(event_list)):
|
||||
event = event_list[i]
|
||||
if event['event_name'] == 'napi_poll':
|
||||
print PF_NAPI_POLL % \
|
||||
(diff_msec(base_t, event['event_t']), event['dev'])
|
||||
print(PF_NAPI_POLL %
|
||||
(diff_msec(base_t, event['event_t']), event['dev']))
|
||||
if i == len(event_list) - 1:
|
||||
print ""
|
||||
print("")
|
||||
else:
|
||||
print PF_JOINT
|
||||
print(PF_JOINT)
|
||||
else:
|
||||
print PF_NET_RECV % \
|
||||
print(PF_NET_RECV %
|
||||
(diff_msec(base_t, event['event_t']), event['skbaddr'],
|
||||
event['len'])
|
||||
event['len']))
|
||||
if 'comm' in event.keys():
|
||||
print PF_WJOINT
|
||||
print PF_CPY_DGRAM % \
|
||||
print(PF_WJOINT)
|
||||
print(PF_CPY_DGRAM %
|
||||
(diff_msec(base_t, event['comm_t']),
|
||||
event['pid'], event['comm'])
|
||||
event['pid'], event['comm']))
|
||||
elif 'handle' in event.keys():
|
||||
print PF_WJOINT
|
||||
print(PF_WJOINT)
|
||||
if event['handle'] == "kfree_skb":
|
||||
print PF_KFREE_SKB % \
|
||||
print(PF_KFREE_SKB %
|
||||
(diff_msec(base_t,
|
||||
event['comm_t']),
|
||||
event['location'])
|
||||
event['location']))
|
||||
elif event['handle'] == "consume_skb":
|
||||
print PF_CONS_SKB % \
|
||||
print(PF_CONS_SKB %
|
||||
diff_msec(base_t,
|
||||
event['comm_t'])
|
||||
print PF_JOINT
|
||||
event['comm_t']))
|
||||
print(PF_JOINT)
|
||||
|
||||
def trace_begin():
|
||||
global show_tx
|
||||
@@ -172,8 +175,7 @@ def trace_begin():
|
||||
|
||||
def trace_end():
|
||||
# order all events in time
|
||||
all_event_list.sort(lambda a,b :cmp(a[EINFO_IDX_TIME],
|
||||
b[EINFO_IDX_TIME]))
|
||||
all_event_list.sort(key=cmp_to_key(lambda a,b :a[EINFO_IDX_TIME] < b[EINFO_IDX_TIME]))
|
||||
# process all events
|
||||
for i in range(len(all_event_list)):
|
||||
event_info = all_event_list[i]
|
||||
@@ -210,19 +212,19 @@ def trace_end():
|
||||
print_receive(receive_hunk_list[i])
|
||||
# display transmit hunks
|
||||
if show_tx:
|
||||
print " dev len Qdisc " \
|
||||
" netdevice free"
|
||||
print(" dev len Qdisc "
|
||||
" netdevice free")
|
||||
for i in range(len(tx_free_list)):
|
||||
print_transmit(tx_free_list[i])
|
||||
if debug:
|
||||
print "debug buffer status"
|
||||
print "----------------------------"
|
||||
print "xmit Qdisc:remain:%d overflow:%d" % \
|
||||
(len(tx_queue_list), of_count_tx_queue_list)
|
||||
print "xmit netdevice:remain:%d overflow:%d" % \
|
||||
(len(tx_xmit_list), of_count_tx_xmit_list)
|
||||
print "receive:remain:%d overflow:%d" % \
|
||||
(len(rx_skb_list), of_count_rx_skb_list)
|
||||
print("debug buffer status")
|
||||
print("----------------------------")
|
||||
print("xmit Qdisc:remain:%d overflow:%d" %
|
||||
(len(tx_queue_list), of_count_tx_queue_list))
|
||||
print("xmit netdevice:remain:%d overflow:%d" %
|
||||
(len(tx_xmit_list), of_count_tx_xmit_list))
|
||||
print("receive:remain:%d overflow:%d" %
|
||||
(len(rx_skb_list), of_count_rx_skb_list))
|
||||
|
||||
# called from perf, when it finds a correspoinding event
|
||||
def irq__softirq_entry(name, context, cpu, sec, nsec, pid, comm, callchain, vec):
|
||||
|
@@ -4,6 +4,8 @@
|
||||
#
|
||||
# Hypervisor call statisics
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
@@ -149,7 +151,7 @@ hcall_table = {
|
||||
}
|
||||
|
||||
def hcall_table_lookup(opcode):
|
||||
if (hcall_table.has_key(opcode)):
|
||||
if (opcode in hcall_table):
|
||||
return hcall_table[opcode]
|
||||
else:
|
||||
return opcode
|
||||
@@ -157,8 +159,8 @@ def hcall_table_lookup(opcode):
|
||||
print_ptrn = '%-28s%10s%10s%10s%10s'
|
||||
|
||||
def trace_end():
|
||||
print print_ptrn % ('hcall', 'count', 'min(ns)', 'max(ns)', 'avg(ns)')
|
||||
print '-' * 68
|
||||
print(print_ptrn % ('hcall', 'count', 'min(ns)', 'max(ns)', 'avg(ns)'))
|
||||
print('-' * 68)
|
||||
for opcode in output:
|
||||
h_name = hcall_table_lookup(opcode)
|
||||
time = output[opcode]['time']
|
||||
@@ -166,14 +168,14 @@ def trace_end():
|
||||
min_t = output[opcode]['min']
|
||||
max_t = output[opcode]['max']
|
||||
|
||||
print print_ptrn % (h_name, cnt, min_t, max_t, time/cnt)
|
||||
print(print_ptrn % (h_name, cnt, min_t, max_t, time//cnt))
|
||||
|
||||
def powerpc__hcall_exit(name, context, cpu, sec, nsec, pid, comm, callchain,
|
||||
opcode, retval):
|
||||
if (d_enter.has_key(cpu) and d_enter[cpu].has_key(opcode)):
|
||||
if (cpu in d_enter and opcode in d_enter[cpu]):
|
||||
diff = nsecs(sec, nsec) - d_enter[cpu][opcode]
|
||||
|
||||
if (output.has_key(opcode)):
|
||||
if (opcode in output):
|
||||
output[opcode]['time'] += diff
|
||||
output[opcode]['cnt'] += 1
|
||||
if (output[opcode]['min'] > diff):
|
||||
@@ -190,11 +192,11 @@ def powerpc__hcall_exit(name, context, cpu, sec, nsec, pid, comm, callchain,
|
||||
|
||||
del d_enter[cpu][opcode]
|
||||
# else:
|
||||
# print "Can't find matching hcall_enter event. Ignoring sample"
|
||||
# print("Can't find matching hcall_enter event. Ignoring sample")
|
||||
|
||||
def powerpc__hcall_entry(event_name, context, cpu, sec, nsec, pid, comm,
|
||||
callchain, opcode):
|
||||
if (d_enter.has_key(cpu)):
|
||||
if (cpu in d_enter):
|
||||
d_enter[cpu][opcode] = nsecs(sec, nsec)
|
||||
else:
|
||||
d_enter[cpu] = {opcode: nsecs(sec, nsec)}
|
||||
|
@@ -1,5 +1,3 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Cpu task migration overview toy
|
||||
#
|
||||
# Copyright (C) 2010 Frederic Weisbecker <fweisbec@gmail.com>
|
||||
|
@@ -8,7 +8,14 @@
|
||||
# will be refreshed every [interval] seconds. The default interval is
|
||||
# 3 seconds.
|
||||
|
||||
import os, sys, thread, time
|
||||
from __future__ import print_function
|
||||
|
||||
import os, sys, time
|
||||
|
||||
try:
|
||||
import thread
|
||||
except ImportError:
|
||||
import _thread as thread
|
||||
|
||||
sys.path.append(os.environ['PERF_EXEC_PATH'] + \
|
||||
'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
|
||||
@@ -62,18 +69,19 @@ def print_syscall_totals(interval):
|
||||
while 1:
|
||||
clear_term()
|
||||
if for_comm is not None:
|
||||
print "\nsyscall events for %s:\n\n" % (for_comm),
|
||||
print("\nsyscall events for %s:\n" % (for_comm))
|
||||
else:
|
||||
print "\nsyscall events:\n\n",
|
||||
print("\nsyscall events:\n")
|
||||
|
||||
print "%-40s %10s\n" % ("event", "count"),
|
||||
print "%-40s %10s\n" % ("----------------------------------------", \
|
||||
"----------"),
|
||||
print("%-40s %10s" % ("event", "count"))
|
||||
print("%-40s %10s" %
|
||||
("----------------------------------------",
|
||||
"----------"))
|
||||
|
||||
for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
|
||||
for id, val in sorted(syscalls.items(), key = lambda kv: (kv[1], kv[0]), \
|
||||
reverse = True):
|
||||
try:
|
||||
print "%-40s %10d\n" % (syscall_name(id), val),
|
||||
print("%-40s %10d" % (syscall_name(id), val))
|
||||
except TypeError:
|
||||
pass
|
||||
syscalls.clear()
|
||||
|
@@ -19,6 +19,8 @@
|
||||
# Written by Paolo Bonzini <pbonzini@redhat.com>
|
||||
# Based on Brendan Gregg's stackcollapse-perf.pl script.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
@@ -120,7 +122,6 @@ def process_event(param_dict):
|
||||
lines[stack_string] = lines[stack_string] + 1
|
||||
|
||||
def trace_end():
|
||||
list = lines.keys()
|
||||
list.sort()
|
||||
list = sorted(lines)
|
||||
for stack in list:
|
||||
print "%s %d" % (stack, lines[stack])
|
||||
print("%s %d" % (stack, lines[stack]))
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
data = {}
|
||||
times = []
|
||||
threads = []
|
||||
@@ -20,8 +21,8 @@ def store_key(time, cpu, thread):
|
||||
threads.append(thread)
|
||||
|
||||
def store(time, event, cpu, thread, val, ena, run):
|
||||
#print "event %s cpu %d, thread %d, time %d, val %d, ena %d, run %d" % \
|
||||
# (event, cpu, thread, time, val, ena, run)
|
||||
#print("event %s cpu %d, thread %d, time %d, val %d, ena %d, run %d" %
|
||||
# (event, cpu, thread, time, val, ena, run))
|
||||
|
||||
store_key(time, cpu, thread)
|
||||
key = get_key(time, event, cpu, thread)
|
||||
@@ -59,7 +60,7 @@ def stat__interval(time):
|
||||
if ins != 0:
|
||||
cpi = cyc/float(ins)
|
||||
|
||||
print "%15f: cpu %d, thread %d -> cpi %f (%d/%d)" % (time/(float(1000000000)), cpu, thread, cpi, cyc, ins)
|
||||
print("%15f: cpu %d, thread %d -> cpi %f (%d/%d)" % (time/(float(1000000000)), cpu, thread, cpi, cyc, ins))
|
||||
|
||||
def trace_end():
|
||||
pass
|
||||
@@ -75,4 +76,4 @@ def trace_end():
|
||||
# if ins != 0:
|
||||
# cpi = cyc/float(ins)
|
||||
#
|
||||
# print "time %.9f, cpu %d, thread %d -> cpi %f" % (time/(float(1000000000)), cpu, thread, cpi)
|
||||
# print("time %.9f, cpu %d, thread %d -> cpi %f" % (time/(float(1000000000)), cpu, thread, cpi))
|
||||
|
@@ -5,6 +5,8 @@
|
||||
# Displays system-wide system call totals, broken down by syscall.
|
||||
# If a [comm] arg is specified, only syscalls called by [comm] are displayed.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os, sys
|
||||
|
||||
sys.path.append(os.environ['PERF_EXEC_PATH'] + \
|
||||
@@ -31,7 +33,7 @@ if len(sys.argv) > 1:
|
||||
syscalls = autodict()
|
||||
|
||||
def trace_begin():
|
||||
print "Press control+C to stop and show the summary"
|
||||
print("Press control+C to stop and show the summary")
|
||||
|
||||
def trace_end():
|
||||
print_syscall_totals()
|
||||
@@ -55,20 +57,20 @@ def syscalls__sys_enter(event_name, context, common_cpu,
|
||||
|
||||
def print_syscall_totals():
|
||||
if for_comm is not None:
|
||||
print "\nsyscall events for %s:\n\n" % (for_comm),
|
||||
print("\nsyscall events for %s:\n" % (for_comm))
|
||||
else:
|
||||
print "\nsyscall events by comm/pid:\n\n",
|
||||
print("\nsyscall events by comm/pid:\n")
|
||||
|
||||
print "%-40s %10s\n" % ("comm [pid]/syscalls", "count"),
|
||||
print "%-40s %10s\n" % ("----------------------------------------", \
|
||||
"----------"),
|
||||
print("%-40s %10s" % ("comm [pid]/syscalls", "count"))
|
||||
print("%-40s %10s" % ("----------------------------------------",
|
||||
"----------"))
|
||||
|
||||
comm_keys = syscalls.keys()
|
||||
for comm in comm_keys:
|
||||
pid_keys = syscalls[comm].keys()
|
||||
for pid in pid_keys:
|
||||
print "\n%s [%d]\n" % (comm, pid),
|
||||
print("\n%s [%d]" % (comm, pid))
|
||||
id_keys = syscalls[comm][pid].keys()
|
||||
for id, val in sorted(syscalls[comm][pid].iteritems(), \
|
||||
key = lambda(k, v): (v, k), reverse = True):
|
||||
print " %-38s %10d\n" % (syscall_name(id), val),
|
||||
for id, val in sorted(syscalls[comm][pid].items(), \
|
||||
key = lambda kv: (kv[1], kv[0]), reverse = True):
|
||||
print(" %-38s %10d" % (syscall_name(id), val))
|
||||
|
@@ -5,6 +5,8 @@
|
||||
# Displays system-wide system call totals, broken down by syscall.
|
||||
# If a [comm] arg is specified, only syscalls called by [comm] are displayed.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
@@ -28,7 +30,7 @@ if len(sys.argv) > 1:
|
||||
syscalls = autodict()
|
||||
|
||||
def trace_begin():
|
||||
print "Press control+C to stop and show the summary"
|
||||
print("Press control+C to stop and show the summary")
|
||||
|
||||
def trace_end():
|
||||
print_syscall_totals()
|
||||
@@ -51,14 +53,14 @@ def syscalls__sys_enter(event_name, context, common_cpu,
|
||||
|
||||
def print_syscall_totals():
|
||||
if for_comm is not None:
|
||||
print "\nsyscall events for %s:\n\n" % (for_comm),
|
||||
print("\nsyscall events for %s:\n" % (for_comm))
|
||||
else:
|
||||
print "\nsyscall events:\n\n",
|
||||
print("\nsyscall events:\n")
|
||||
|
||||
print "%-40s %10s\n" % ("event", "count"),
|
||||
print "%-40s %10s\n" % ("----------------------------------------", \
|
||||
"-----------"),
|
||||
print("%-40s %10s" % ("event", "count"))
|
||||
print("%-40s %10s" % ("----------------------------------------",
|
||||
"-----------"))
|
||||
|
||||
for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
|
||||
for id, val in sorted(syscalls.items(), key = lambda kv: (kv[1], kv[0]), \
|
||||
reverse = True):
|
||||
print "%-40s %10d\n" % (syscall_name(id), val),
|
||||
print("%-40s %10d" % (syscall_name(id), val))
|
||||
|
@@ -1,4 +1,3 @@
|
||||
#! /usr/bin/python
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
from __future__ import print_function
|
||||
|
@@ -15,7 +15,6 @@
|
||||
#include <sys/mman.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/hw_breakpoint.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "tests.h"
|
||||
#include "debug.h"
|
||||
|
@@ -15,6 +15,8 @@
|
||||
#include "thread_map.h"
|
||||
#include "cpumap.h"
|
||||
#include "machine.h"
|
||||
#include "map.h"
|
||||
#include "symbol.h"
|
||||
#include "event.h"
|
||||
#include "thread.h"
|
||||
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include "../util/unwind.h"
|
||||
#include "perf_regs.h"
|
||||
#include "map.h"
|
||||
#include "symbol.h"
|
||||
#include "thread.h"
|
||||
#include "callchain.h"
|
||||
|
||||
|
@@ -43,7 +43,7 @@ int test__perf_evsel__tp_sched_test(struct test *test __maybe_unused, int subtes
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (perf_evsel__test_field(evsel, "prev_comm", 16, true))
|
||||
if (perf_evsel__test_field(evsel, "prev_comm", 16, false))
|
||||
ret = -1;
|
||||
|
||||
if (perf_evsel__test_field(evsel, "prev_pid", 4, true))
|
||||
@@ -55,7 +55,7 @@ int test__perf_evsel__tp_sched_test(struct test *test __maybe_unused, int subtes
|
||||
if (perf_evsel__test_field(evsel, "prev_state", sizeof(long), true))
|
||||
ret = -1;
|
||||
|
||||
if (perf_evsel__test_field(evsel, "next_comm", 16, true))
|
||||
if (perf_evsel__test_field(evsel, "next_comm", 16, false))
|
||||
ret = -1;
|
||||
|
||||
if (perf_evsel__test_field(evsel, "next_pid", 4, true))
|
||||
@@ -73,7 +73,7 @@ int test__perf_evsel__tp_sched_test(struct test *test __maybe_unused, int subtes
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (perf_evsel__test_field(evsel, "comm", 16, true))
|
||||
if (perf_evsel__test_field(evsel, "comm", 16, false))
|
||||
ret = -1;
|
||||
|
||||
if (perf_evsel__test_field(evsel, "pid", 4, true))
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#include <inttypes.h>
|
||||
#include "perf.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/map.h"
|
||||
#include "util/symbol.h"
|
||||
#include "util/sort.h"
|
||||
#include "util/evsel.h"
|
||||
@@ -161,7 +162,7 @@ out:
|
||||
void print_hists_in(struct hists *hists)
|
||||
{
|
||||
int i = 0;
|
||||
struct rb_root *root;
|
||||
struct rb_root_cached *root;
|
||||
struct rb_node *node;
|
||||
|
||||
if (hists__has(hists, need_collapse))
|
||||
@@ -170,7 +171,7 @@ void print_hists_in(struct hists *hists)
|
||||
root = hists->entries_in;
|
||||
|
||||
pr_info("----- %s --------\n", __func__);
|
||||
node = rb_first(root);
|
||||
node = rb_first_cached(root);
|
||||
while (node) {
|
||||
struct hist_entry *he;
|
||||
|
||||
@@ -191,13 +192,13 @@ void print_hists_in(struct hists *hists)
|
||||
void print_hists_out(struct hists *hists)
|
||||
{
|
||||
int i = 0;
|
||||
struct rb_root *root;
|
||||
struct rb_root_cached *root;
|
||||
struct rb_node *node;
|
||||
|
||||
root = &hists->entries;
|
||||
|
||||
pr_info("----- %s --------\n", __func__);
|
||||
node = rb_first(root);
|
||||
node = rb_first_cached(root);
|
||||
while (node) {
|
||||
struct hist_entry *he;
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#include "perf.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/event.h"
|
||||
#include "util/map.h"
|
||||
#include "util/symbol.h"
|
||||
#include "util/sort.h"
|
||||
#include "util/evsel.h"
|
||||
@@ -125,8 +126,8 @@ out:
|
||||
static void del_hist_entries(struct hists *hists)
|
||||
{
|
||||
struct hist_entry *he;
|
||||
struct rb_root *root_in;
|
||||
struct rb_root *root_out;
|
||||
struct rb_root_cached *root_in;
|
||||
struct rb_root_cached *root_out;
|
||||
struct rb_node *node;
|
||||
|
||||
if (hists__has(hists, need_collapse))
|
||||
@@ -136,12 +137,12 @@ static void del_hist_entries(struct hists *hists)
|
||||
|
||||
root_out = &hists->entries;
|
||||
|
||||
while (!RB_EMPTY_ROOT(root_out)) {
|
||||
node = rb_first(root_out);
|
||||
while (!RB_EMPTY_ROOT(&root_out->rb_root)) {
|
||||
node = rb_first_cached(root_out);
|
||||
|
||||
he = rb_entry(node, struct hist_entry, rb_node);
|
||||
rb_erase(node, root_out);
|
||||
rb_erase(&he->rb_node_in, root_in);
|
||||
rb_erase_cached(node, root_out);
|
||||
rb_erase_cached(&he->rb_node_in, root_in);
|
||||
hist_entry__delete(he);
|
||||
}
|
||||
}
|
||||
@@ -198,7 +199,7 @@ static int do_test(struct hists *hists, struct result *expected, size_t nr_expec
|
||||
print_hists_out(hists);
|
||||
}
|
||||
|
||||
root = &hists->entries;
|
||||
root = &hists->entries.rb_root;
|
||||
for (node = rb_first(root), i = 0;
|
||||
node && (he = rb_entry(node, struct hist_entry, rb_node));
|
||||
node = rb_next(node), i++) {
|
||||
|
@@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include "perf.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/map.h"
|
||||
#include "util/symbol.h"
|
||||
#include "util/sort.h"
|
||||
#include "util/evsel.h"
|
||||
|
@@ -142,7 +142,7 @@ static int find_sample(struct sample *samples, size_t nr_samples,
|
||||
static int __validate_match(struct hists *hists)
|
||||
{
|
||||
size_t count = 0;
|
||||
struct rb_root *root;
|
||||
struct rb_root_cached *root;
|
||||
struct rb_node *node;
|
||||
|
||||
/*
|
||||
@@ -153,7 +153,7 @@ static int __validate_match(struct hists *hists)
|
||||
else
|
||||
root = hists->entries_in;
|
||||
|
||||
node = rb_first(root);
|
||||
node = rb_first_cached(root);
|
||||
while (node) {
|
||||
struct hist_entry *he;
|
||||
|
||||
@@ -192,7 +192,7 @@ static int __validate_link(struct hists *hists, int idx)
|
||||
size_t count = 0;
|
||||
size_t count_pair = 0;
|
||||
size_t count_dummy = 0;
|
||||
struct rb_root *root;
|
||||
struct rb_root_cached *root;
|
||||
struct rb_node *node;
|
||||
|
||||
/*
|
||||
@@ -205,7 +205,7 @@ static int __validate_link(struct hists *hists, int idx)
|
||||
else
|
||||
root = hists->entries_in;
|
||||
|
||||
node = rb_first(root);
|
||||
node = rb_first_cached(root);
|
||||
while (node) {
|
||||
struct hist_entry *he;
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#include "perf.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/event.h"
|
||||
#include "util/map.h"
|
||||
#include "util/symbol.h"
|
||||
#include "util/sort.h"
|
||||
#include "util/evsel.h"
|
||||
@@ -91,8 +92,8 @@ out:
|
||||
static void del_hist_entries(struct hists *hists)
|
||||
{
|
||||
struct hist_entry *he;
|
||||
struct rb_root *root_in;
|
||||
struct rb_root *root_out;
|
||||
struct rb_root_cached *root_in;
|
||||
struct rb_root_cached *root_out;
|
||||
struct rb_node *node;
|
||||
|
||||
if (hists__has(hists, need_collapse))
|
||||
@@ -102,12 +103,12 @@ static void del_hist_entries(struct hists *hists)
|
||||
|
||||
root_out = &hists->entries;
|
||||
|
||||
while (!RB_EMPTY_ROOT(root_out)) {
|
||||
node = rb_first(root_out);
|
||||
while (!RB_EMPTY_ROOT(&root_out->rb_root)) {
|
||||
node = rb_first_cached(root_out);
|
||||
|
||||
he = rb_entry(node, struct hist_entry, rb_node);
|
||||
rb_erase(node, root_out);
|
||||
rb_erase(&he->rb_node_in, root_in);
|
||||
rb_erase_cached(node, root_out);
|
||||
rb_erase_cached(&he->rb_node_in, root_in);
|
||||
hist_entry__delete(he);
|
||||
}
|
||||
}
|
||||
@@ -126,7 +127,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
|
||||
int err;
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
struct hist_entry *he;
|
||||
struct rb_root *root;
|
||||
struct rb_root_cached *root;
|
||||
struct rb_node *node;
|
||||
|
||||
field_order = NULL;
|
||||
@@ -162,7 +163,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
|
||||
}
|
||||
|
||||
root = &hists->entries;
|
||||
node = rb_first(root);
|
||||
node = rb_first_cached(root);
|
||||
he = rb_entry(node, struct hist_entry, rb_node);
|
||||
TEST_ASSERT_VAL("Invalid hist entry",
|
||||
!strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
|
||||
@@ -228,7 +229,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
|
||||
int err;
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
struct hist_entry *he;
|
||||
struct rb_root *root;
|
||||
struct rb_root_cached *root;
|
||||
struct rb_node *node;
|
||||
|
||||
field_order = "overhead,cpu";
|
||||
@@ -262,7 +263,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
|
||||
}
|
||||
|
||||
root = &hists->entries;
|
||||
node = rb_first(root);
|
||||
node = rb_first_cached(root);
|
||||
he = rb_entry(node, struct hist_entry, rb_node);
|
||||
TEST_ASSERT_VAL("Invalid hist entry",
|
||||
CPU(he) == 1 && PID(he) == 100 && he->stat.period == 300);
|
||||
@@ -284,7 +285,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
|
||||
int err;
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
struct hist_entry *he;
|
||||
struct rb_root *root;
|
||||
struct rb_root_cached *root;
|
||||
struct rb_node *node;
|
||||
|
||||
field_order = "comm,overhead,dso";
|
||||
@@ -316,7 +317,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
|
||||
}
|
||||
|
||||
root = &hists->entries;
|
||||
node = rb_first(root);
|
||||
node = rb_first_cached(root);
|
||||
he = rb_entry(node, struct hist_entry, rb_node);
|
||||
TEST_ASSERT_VAL("Invalid hist entry",
|
||||
!strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
|
||||
@@ -358,7 +359,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
|
||||
int err;
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
struct hist_entry *he;
|
||||
struct rb_root *root;
|
||||
struct rb_root_cached *root;
|
||||
struct rb_node *node;
|
||||
|
||||
field_order = "dso,sym,comm,overhead,dso";
|
||||
@@ -394,7 +395,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
|
||||
}
|
||||
|
||||
root = &hists->entries;
|
||||
node = rb_first(root);
|
||||
node = rb_first_cached(root);
|
||||
he = rb_entry(node, struct hist_entry, rb_node);
|
||||
TEST_ASSERT_VAL("Invalid hist entry",
|
||||
!strcmp(DSO(he), "perf") && !strcmp(SYM(he), "cmd_record") &&
|
||||
@@ -460,7 +461,7 @@ static int test5(struct perf_evsel *evsel, struct machine *machine)
|
||||
int err;
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
struct hist_entry *he;
|
||||
struct rb_root *root;
|
||||
struct rb_root_cached *root;
|
||||
struct rb_node *node;
|
||||
|
||||
field_order = "cpu,pid,comm,dso,sym";
|
||||
@@ -497,7 +498,7 @@ static int test5(struct perf_evsel *evsel, struct machine *machine)
|
||||
}
|
||||
|
||||
root = &hists->entries;
|
||||
node = rb_first(root);
|
||||
node = rb_first_cached(root);
|
||||
he = rb_entry(node, struct hist_entry, rb_node);
|
||||
|
||||
TEST_ASSERT_VAL("Invalid hist entry",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user