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