summaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/annotate.c16
-rw-r--r--tools/perf/util/arm-spe-decoder/arm-spe-decoder.c59
-rw-r--r--tools/perf/util/arm-spe-decoder/arm-spe-decoder.h17
-rw-r--r--tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c601
-rw-r--r--tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h122
-rw-r--r--tools/perf/util/arm-spe.c2
-rw-r--r--tools/perf/util/auxtrace.c19
-rw-r--r--tools/perf/util/auxtrace.h2
-rw-r--r--tools/perf/util/bpf-event.c2
-rw-r--r--tools/perf/util/bpf-loader.c3
-rw-r--r--tools/perf/util/bpf-loader.h3
-rw-r--r--tools/perf/util/build-id.c127
-rw-r--r--tools/perf/util/build-id.h8
-rw-r--r--tools/perf/util/cgroup.c202
-rw-r--r--tools/perf/util/data.c60
-rw-r--r--tools/perf/util/data.h12
-rw-r--r--tools/perf/util/debug.c9
-rw-r--r--tools/perf/util/debug.h2
-rw-r--r--tools/perf/util/dso.c45
-rw-r--r--tools/perf/util/dso.h2
-rw-r--r--tools/perf/util/env.c15
-rw-r--r--tools/perf/util/env.h4
-rw-r--r--tools/perf/util/event.h4
-rw-r--r--tools/perf/util/evlist.c288
-rw-r--r--tools/perf/util/evlist.h136
-rw-r--r--tools/perf/util/evsel.c60
-rw-r--r--tools/perf/util/evsel.h1
-rw-r--r--tools/perf/util/evswitch.c4
-rw-r--r--tools/perf/util/expr.c68
-rw-r--r--tools/perf/util/expr.h17
-rw-r--r--tools/perf/util/expr.y2
-rw-r--r--tools/perf/util/header.c56
-rw-r--r--tools/perf/util/hist.c5
-rw-r--r--tools/perf/util/hist.h26
-rw-r--r--tools/perf/util/intel-pt.c3
-rw-r--r--tools/perf/util/machine.c69
-rw-r--r--tools/perf/util/map_symbol.h1
-rw-r--r--tools/perf/util/mem-events.c45
-rw-r--r--tools/perf/util/mem-events.h3
-rw-r--r--tools/perf/util/mem2node.c3
-rw-r--r--tools/perf/util/metricgroup.c258
-rw-r--r--tools/perf/util/parse-events.c29
-rw-r--r--tools/perf/util/parse-regs-options.c2
-rw-r--r--tools/perf/util/perf_event_attr_fprintf.c2
-rw-r--r--tools/perf/util/pmu.c96
-rw-r--r--tools/perf/util/pmu.h3
-rw-r--r--tools/perf/util/python.c4
-rw-r--r--tools/perf/util/record.c9
-rw-r--r--tools/perf/util/record.h1
-rw-r--r--tools/perf/util/s390-cpumsf.c6
-rw-r--r--tools/perf/util/s390-sample-raw.c5
-rw-r--r--tools/perf/util/sample-raw.c4
-rw-r--r--tools/perf/util/sample-raw.h7
-rw-r--r--tools/perf/util/session.c57
-rw-r--r--tools/perf/util/sideband_evlist.c14
-rw-r--r--tools/perf/util/sort.c32
-rw-r--r--tools/perf/util/sort.h1
-rw-r--r--tools/perf/util/stat-display.c8
-rw-r--r--tools/perf/util/stat.c20
-rw-r--r--tools/perf/util/stat.h21
-rw-r--r--tools/perf/util/symbol-elf.c37
-rw-r--r--tools/perf/util/symbol.c16
-rw-r--r--tools/perf/util/synthetic-events.c10
-rw-r--r--tools/perf/util/unwind-libdw.c32
64 files changed, 1845 insertions, 952 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 6c8575e182ed..ce8c07bc8c56 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -10,10 +10,6 @@
#include <inttypes.h>
#include <libgen.h>
#include <stdlib.h>
-#include <bpf/bpf.h>
-#include <bpf/btf.h>
-#include <bpf/libbpf.h>
-#include <linux/btf.h>
#include "util.h" // hex_width()
#include "ui/ui.h"
#include "sort.h"
@@ -152,6 +148,7 @@ static int arch__associate_ins_ops(struct arch* arch, const char *name, struct i
#include "arch/arm/annotate/instructions.c"
#include "arch/arm64/annotate/instructions.c"
#include "arch/csky/annotate/instructions.c"
+#include "arch/mips/annotate/instructions.c"
#include "arch/x86/annotate/instructions.c"
#include "arch/powerpc/annotate/instructions.c"
#include "arch/s390/annotate/instructions.c"
@@ -175,6 +172,13 @@ static struct arch architectures[] = {
.init = csky__annotate_init,
},
{
+ .name = "mips",
+ .init = mips__annotate_init,
+ .objdump = {
+ .comment_char = '#',
+ },
+ },
+ {
.name = "x86",
.init = x86__annotate_init,
.instructions = x86__instructions,
@@ -1676,6 +1680,10 @@ fallback:
#define PACKAGE "perf"
#include <bfd.h>
#include <dis-asm.h>
+#include <bpf/bpf.h>
+#include <bpf/btf.h>
+#include <bpf/libbpf.h>
+#include <linux/btf.h>
static int symbol__disassemble_bpf(struct symbol *sym,
struct annotate_args *args)
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c
index 93e063f22be5..90d575cee1b9 100644
--- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c
+++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.c
@@ -12,6 +12,7 @@
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
+#include <linux/bitops.h>
#include <linux/compiler.h>
#include <linux/zalloc.h>
@@ -21,42 +22,51 @@
#include "arm-spe-decoder.h"
-#ifndef BIT
-#define BIT(n) (1UL << (n))
-#endif
-
static u64 arm_spe_calc_ip(int index, u64 payload)
{
- u8 *addr = (u8 *)&payload;
- int ns, el;
+ u64 ns, el, val;
/* Instruction virtual address or Branch target address */
if (index == SPE_ADDR_PKT_HDR_INDEX_INS ||
index == SPE_ADDR_PKT_HDR_INDEX_BRANCH) {
- ns = addr[7] & SPE_ADDR_PKT_NS;
- el = (addr[7] & SPE_ADDR_PKT_EL_MASK) >> SPE_ADDR_PKT_EL_OFFSET;
+ ns = SPE_ADDR_PKT_GET_NS(payload);
+ el = SPE_ADDR_PKT_GET_EL(payload);
+
+ /* Clean highest byte */
+ payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
/* Fill highest byte for EL1 or EL2 (VHE) mode */
if (ns && (el == SPE_ADDR_PKT_EL1 || el == SPE_ADDR_PKT_EL2))
- addr[7] = 0xff;
- /* Clean highest byte for other cases */
- else
- addr[7] = 0x0;
+ payload |= 0xffULL << SPE_ADDR_PKT_ADDR_BYTE7_SHIFT;
/* Data access virtual address */
} else if (index == SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT) {
- /* Fill highest byte if bits [48..55] is 0xff */
- if (addr[6] == 0xff)
- addr[7] = 0xff;
- /* Otherwise, cleanup tags */
- else
- addr[7] = 0x0;
+ /* Clean tags */
+ payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
+
+ /*
+ * Armv8 ARM (ARM DDI 0487F.c), chapter "D10.2.1 Address packet"
+ * defines the data virtual address payload format, the top byte
+ * (bits [63:56]) is assigned as top-byte tag; so we only can
+ * retrieve address value from bits [55:0].
+ *
+ * According to Documentation/arm64/memory.rst, if detects the
+ * specific pattern in bits [55:52] of payload which falls in
+ * the kernel space, should fixup the top byte and this allows
+ * perf tool to parse DSO symbol for data address correctly.
+ *
+ * For this reason, if detects the bits [55:52] is 0xf, will
+ * fill 0xff into the top byte.
+ */
+ val = SPE_ADDR_PKT_ADDR_GET_BYTE_6(payload);
+ if ((val & 0xf0ULL) == 0xf0ULL)
+ payload |= 0xffULL << SPE_ADDR_PKT_ADDR_BYTE7_SHIFT;
/* Data access physical address */
} else if (index == SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS) {
- /* Cleanup byte 7 */
- addr[7] = 0x0;
+ /* Clean highest byte */
+ payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
} else {
pr_err("unsupported address packet index: 0x%x\n", index);
}
@@ -182,16 +192,13 @@ static int arm_spe_read_record(struct arm_spe_decoder *decoder)
if (payload & BIT(EV_TLB_ACCESS))
decoder->record.type |= ARM_SPE_TLB_ACCESS;
- if ((idx == 2 || idx == 4 || idx == 8) &&
- (payload & BIT(EV_LLC_MISS)))
+ if (payload & BIT(EV_LLC_MISS))
decoder->record.type |= ARM_SPE_LLC_MISS;
- if ((idx == 2 || idx == 4 || idx == 8) &&
- (payload & BIT(EV_LLC_ACCESS)))
+ if (payload & BIT(EV_LLC_ACCESS))
decoder->record.type |= ARM_SPE_LLC_ACCESS;
- if ((idx == 2 || idx == 4 || idx == 8) &&
- (payload & BIT(EV_REMOTE_ACCESS)))
+ if (payload & BIT(EV_REMOTE_ACCESS))
decoder->record.type |= ARM_SPE_REMOTE_ACCESS;
if (payload & BIT(EV_MISPRED))
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h
index a5111a8d4360..24727b8ca7ff 100644
--- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h
+++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h
@@ -13,23 +13,6 @@
#include "arm-spe-pkt-decoder.h"
-enum arm_spe_events {
- EV_EXCEPTION_GEN = 0,
- EV_RETIRED = 1,
- EV_L1D_ACCESS = 2,
- EV_L1D_REFILL = 3,
- EV_TLB_ACCESS = 4,
- EV_TLB_WALK = 5,
- EV_NOT_TAKEN = 6,
- EV_MISPRED = 7,
- EV_LLC_ACCESS = 8,
- EV_LLC_MISS = 9,
- EV_REMOTE_ACCESS = 10,
- EV_ALIGNMENT = 11,
- EV_PARTIAL_PREDICATE = 17,
- EV_EMPTY_PREDICATE = 18,
-};
-
enum arm_spe_sample_type {
ARM_SPE_L1D_ACCESS = 1 << 0,
ARM_SPE_L1D_MISS = 1 << 1,
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c
index b94001b756c7..f3ac9d40cebf 100644
--- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c
+++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c
@@ -8,36 +8,11 @@
#include <string.h>
#include <endian.h>
#include <byteswap.h>
+#include <linux/bitops.h>
+#include <stdarg.h>
#include "arm-spe-pkt-decoder.h"
-#define BIT(n) (1ULL << (n))
-
-#define NS_FLAG BIT(63)
-#define EL_FLAG (BIT(62) | BIT(61))
-
-#define SPE_HEADER0_PAD 0x0
-#define SPE_HEADER0_END 0x1
-#define SPE_HEADER0_ADDRESS 0x30 /* address packet (short) */
-#define SPE_HEADER0_ADDRESS_MASK 0x38
-#define SPE_HEADER0_COUNTER 0x18 /* counter packet (short) */
-#define SPE_HEADER0_COUNTER_MASK 0x38
-#define SPE_HEADER0_TIMESTAMP 0x71
-#define SPE_HEADER0_TIMESTAMP 0x71
-#define SPE_HEADER0_EVENTS 0x2
-#define SPE_HEADER0_EVENTS_MASK 0xf
-#define SPE_HEADER0_SOURCE 0x3
-#define SPE_HEADER0_SOURCE_MASK 0xf
-#define SPE_HEADER0_CONTEXT 0x24
-#define SPE_HEADER0_CONTEXT_MASK 0x3c
-#define SPE_HEADER0_OP_TYPE 0x8
-#define SPE_HEADER0_OP_TYPE_MASK 0x3c
-#define SPE_HEADER1_ALIGNMENT 0x0
-#define SPE_HEADER1_ADDRESS 0xb0 /* address packet (extended) */
-#define SPE_HEADER1_ADDRESS_MASK 0xf8
-#define SPE_HEADER1_COUNTER 0x98 /* counter packet (extended) */
-#define SPE_HEADER1_COUNTER_MASK 0xf8
-
#if __BYTE_ORDER == __BIG_ENDIAN
#define le16_to_cpu bswap_16
#define le32_to_cpu bswap_32
@@ -70,27 +45,28 @@ const char *arm_spe_pkt_name(enum arm_spe_pkt_type type)
return arm_spe_packet_name[type];
}
-/* return ARM SPE payload size from its encoding,
- * which is in bits 5:4 of the byte.
- * 00 : byte
- * 01 : halfword (2)
- * 10 : word (4)
- * 11 : doubleword (8)
+/*
+ * Extracts the field "sz" from header bits and converts to bytes:
+ * 00 : byte (1)
+ * 01 : halfword (2)
+ * 10 : word (4)
+ * 11 : doubleword (8)
*/
-static int payloadlen(unsigned char byte)
+static unsigned int arm_spe_payload_len(unsigned char hdr)
{
- return 1 << ((byte & 0x30) >> 4);
+ return 1U << ((hdr & GENMASK_ULL(5, 4)) >> 4);
}
static int arm_spe_get_payload(const unsigned char *buf, size_t len,
+ unsigned char ext_hdr,
struct arm_spe_pkt *packet)
{
- size_t payload_len = payloadlen(buf[0]);
+ size_t payload_len = arm_spe_payload_len(buf[ext_hdr]);
- if (len < 1 + payload_len)
+ if (len < 1 + ext_hdr + payload_len)
return ARM_SPE_NEED_MORE_BYTES;
- buf++;
+ buf += 1 + ext_hdr;
switch (payload_len) {
case 1: packet->payload = *(uint8_t *)buf; break;
@@ -100,7 +76,7 @@ static int arm_spe_get_payload(const unsigned char *buf, size_t len,
default: return ARM_SPE_BAD_PACKET;
}
- return 1 + payload_len;
+ return 1 + ext_hdr + payload_len;
}
static int arm_spe_get_pad(struct arm_spe_pkt *packet)
@@ -131,127 +107,128 @@ static int arm_spe_get_timestamp(const unsigned char *buf, size_t len,
struct arm_spe_pkt *packet)
{
packet->type = ARM_SPE_TIMESTAMP;
- return arm_spe_get_payload(buf, len, packet);
+ return arm_spe_get_payload(buf, len, 0, packet);
}
static int arm_spe_get_events(const unsigned char *buf, size_t len,
struct arm_spe_pkt *packet)
{
- int ret = arm_spe_get_payload(buf, len, packet);
-
packet->type = ARM_SPE_EVENTS;
/* we use index to identify Events with a less number of
* comparisons in arm_spe_pkt_desc(): E.g., the LLC-ACCESS,
- * LLC-REFILL, and REMOTE-ACCESS events are identified iff
+ * LLC-REFILL, and REMOTE-ACCESS events are identified if
* index > 1.
*/
- packet->index = ret - 1;
+ packet->index = arm_spe_payload_len(buf[0]);
- return ret;
+ return arm_spe_get_payload(buf, len, 0, packet);
}
static int arm_spe_get_data_source(const unsigned char *buf, size_t len,
struct arm_spe_pkt *packet)
{
packet->type = ARM_SPE_DATA_SOURCE;
- return arm_spe_get_payload(buf, len, packet);
+ return arm_spe_get_payload(buf, len, 0, packet);
}
static int arm_spe_get_context(const unsigned char *buf, size_t len,
struct arm_spe_pkt *packet)
{
packet->type = ARM_SPE_CONTEXT;
- packet->index = buf[0] & 0x3;
-
- return arm_spe_get_payload(buf, len, packet);
+ packet->index = SPE_CTX_PKT_HDR_INDEX(buf[0]);
+ return arm_spe_get_payload(buf, len, 0, packet);
}
static int arm_spe_get_op_type(const unsigned char *buf, size_t len,
struct arm_spe_pkt *packet)
{
packet->type = ARM_SPE_OP_TYPE;
- packet->index = buf[0] & 0x3;
- return arm_spe_get_payload(buf, len, packet);
+ packet->index = SPE_OP_PKT_HDR_CLASS(buf[0]);
+ return arm_spe_get_payload(buf, len, 0, packet);
}
static int arm_spe_get_counter(const unsigned char *buf, size_t len,
const unsigned char ext_hdr, struct arm_spe_pkt *packet)
{
- if (len < 2)
- return ARM_SPE_NEED_MORE_BYTES;
-
packet->type = ARM_SPE_COUNTER;
+
if (ext_hdr)
- packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7);
+ packet->index = SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]);
else
- packet->index = buf[0] & 0x7;
-
- packet->payload = le16_to_cpu(*(uint16_t *)(buf + 1));
+ packet->index = SPE_HDR_SHORT_INDEX(buf[0]);
- return 1 + ext_hdr + 2;
+ return arm_spe_get_payload(buf, len, ext_hdr, packet);
}
static int arm_spe_get_addr(const unsigned char *buf, size_t len,
const unsigned char ext_hdr, struct arm_spe_pkt *packet)
{
- if (len < 8)
- return ARM_SPE_NEED_MORE_BYTES;
-
packet->type = ARM_SPE_ADDRESS;
+
if (ext_hdr)
- packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7);
+ packet->index = SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]);
else
- packet->index = buf[0] & 0x7;
-
- memcpy_le64(&packet->payload, buf + 1, 8);
+ packet->index = SPE_HDR_SHORT_INDEX(buf[0]);
- return 1 + ext_hdr + 8;
+ return arm_spe_get_payload(buf, len, ext_hdr, packet);
}
static int arm_spe_do_get_packet(const unsigned char *buf, size_t len,
struct arm_spe_pkt *packet)
{
- unsigned int byte;
+ unsigned int hdr;
+ unsigned char ext_hdr = 0;
memset(packet, 0, sizeof(struct arm_spe_pkt));
if (!len)
return ARM_SPE_NEED_MORE_BYTES;
- byte = buf[0];
- if (byte == SPE_HEADER0_PAD)
+ hdr = buf[0];
+
+ if (hdr == SPE_HEADER0_PAD)
return arm_spe_get_pad(packet);
- else if (byte == SPE_HEADER0_END) /* no timestamp at end of record */
+
+ if (hdr == SPE_HEADER0_END) /* no timestamp at end of record */
return arm_spe_get_end(packet);
- else if (byte & 0xc0 /* 0y11xxxxxx */) {
- if (byte & 0x80) {
- if ((byte & SPE_HEADER0_ADDRESS_MASK) == SPE_HEADER0_ADDRESS)
- return arm_spe_get_addr(buf, len, 0, packet);
- if ((byte & SPE_HEADER0_COUNTER_MASK) == SPE_HEADER0_COUNTER)
- return arm_spe_get_counter(buf, len, 0, packet);
- } else
- if (byte == SPE_HEADER0_TIMESTAMP)
- return arm_spe_get_timestamp(buf, len, packet);
- else if ((byte & SPE_HEADER0_EVENTS_MASK) == SPE_HEADER0_EVENTS)
- return arm_spe_get_events(buf, len, packet);
- else if ((byte & SPE_HEADER0_SOURCE_MASK) == SPE_HEADER0_SOURCE)
- return arm_spe_get_data_source(buf, len, packet);
- else if ((byte & SPE_HEADER0_CONTEXT_MASK) == SPE_HEADER0_CONTEXT)
- return arm_spe_get_context(buf, len, packet);
- else if ((byte & SPE_HEADER0_OP_TYPE_MASK) == SPE_HEADER0_OP_TYPE)
- return arm_spe_get_op_type(buf, len, packet);
- } else if ((byte & 0xe0) == 0x20 /* 0y001xxxxx */) {
- /* 16-bit header */
- byte = buf[1];
- if (byte == SPE_HEADER1_ALIGNMENT)
+
+ if (hdr == SPE_HEADER0_TIMESTAMP)
+ return arm_spe_get_timestamp(buf, len, packet);
+
+ if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_EVENTS)
+ return arm_spe_get_events(buf, len, packet);
+
+ if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_SOURCE)
+ return arm_spe_get_data_source(buf, len, packet);
+
+ if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_CONTEXT)
+ return arm_spe_get_context(buf, len, packet);
+
+ if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_OP_TYPE)
+ return arm_spe_get_op_type(buf, len, packet);
+
+ if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_EXTENDED) {
+ /* 16-bit extended format header */
+ ext_hdr = 1;
+
+ hdr = buf[1];
+ if (hdr == SPE_HEADER1_ALIGNMENT)
return arm_spe_get_alignment(buf, len, packet);
- else if ((byte & SPE_HEADER1_ADDRESS_MASK) == SPE_HEADER1_ADDRESS)
- return arm_spe_get_addr(buf, len, 1, packet);
- else if ((byte & SPE_HEADER1_COUNTER_MASK) == SPE_HEADER1_COUNTER)
- return arm_spe_get_counter(buf, len, 1, packet);
}
+ /*
+ * The short format header's byte 0 or the extended format header's
+ * byte 1 has been assigned to 'hdr', which uses the same encoding for
+ * address packet and counter packet, so don't need to distinguish if
+ * it's short format or extended format and handle in once.
+ */
+ if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_ADDRESS)
+ return arm_spe_get_addr(buf, len, ext_hdr, packet);
+
+ if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_COUNTER)
+ return arm_spe_get_counter(buf, len, ext_hdr, packet);
+
return ARM_SPE_BAD_PACKET;
}
@@ -271,192 +248,286 @@ int arm_spe_get_packet(const unsigned char *buf, size_t len,
return ret;
}
+static int arm_spe_pkt_out_string(int *err, char **buf_p, size_t *blen,
+ const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ /* Bail out if any error occurred */
+ if (err && *err)
+ return *err;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(*buf_p, *blen, fmt, ap);
+ va_end(ap);
+
+ if (ret < 0) {
+ if (err && !*err)
+ *err = ret;
+
+ /*
+ * A return value of *blen or more means that the output was
+ * truncated and the buffer is overrun.
+ */
+ } else if ((size_t)ret >= *blen) {
+ (*buf_p)[*blen - 1] = '\0';
+
+ /*
+ * Set *err to 'ret' to avoid overflow if tries to
+ * fill this buffer sequentially.
+ */
+ if (err && !*err)
+ *err = ret;
+ } else {
+ *buf_p += ret;
+ *blen -= ret;
+ }
+
+ return ret;
+}
+
+static int arm_spe_pkt_desc_event(const struct arm_spe_pkt *packet,
+ char *buf, size_t buf_len)
+{
+ u64 payload = packet->payload;
+ int err = 0;
+
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, "EV");
+
+ if (payload & BIT(EV_EXCEPTION_GEN))
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCEPTION-GEN");
+ if (payload & BIT(EV_RETIRED))
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " RETIRED");
+ if (payload & BIT(EV_L1D_ACCESS))
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " L1D-ACCESS");
+ if (payload & BIT(EV_L1D_REFILL))
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " L1D-REFILL");
+ if (payload & BIT(EV_TLB_ACCESS))
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " TLB-ACCESS");
+ if (payload & BIT(EV_TLB_WALK))
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " TLB-REFILL");
+ if (payload & BIT(EV_NOT_TAKEN))
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " NOT-TAKEN");
+ if (payload & BIT(EV_MISPRED))
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " MISPRED");
+ if (payload & BIT(EV_LLC_ACCESS))
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-ACCESS");
+ if (payload & BIT(EV_LLC_MISS))
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-REFILL");
+ if (payload & BIT(EV_REMOTE_ACCESS))
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " REMOTE-ACCESS");
+ if (payload & BIT(EV_ALIGNMENT))
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " ALIGNMENT");
+ if (payload & BIT(EV_PARTIAL_PREDICATE))
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " SVE-PARTIAL-PRED");
+ if (payload & BIT(EV_EMPTY_PREDICATE))
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " SVE-EMPTY-PRED");
+
+ return err;
+}
+
+static int arm_spe_pkt_desc_op_type(const struct arm_spe_pkt *packet,
+ char *buf, size_t buf_len)
+{
+ u64 payload = packet->payload;
+ int err = 0;
+
+ switch (packet->index) {
+ case SPE_OP_PKT_HDR_CLASS_OTHER:
+ if (SPE_OP_PKT_IS_OTHER_SVE_OP(payload)) {
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, "SVE-OTHER");
+
+ /* SVE effective vector length */
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " EVLEN %d",
+ SPE_OP_PKG_SVE_EVL(payload));
+
+ if (payload & SPE_OP_PKT_SVE_FP)
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " FP");
+ if (payload & SPE_OP_PKT_SVE_PRED)
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " PRED");
+ } else {
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, "OTHER");
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " %s",
+ payload & SPE_OP_PKT_COND ?
+ "COND-SELECT" : "INSN-OTHER");
+ }
+ break;
+ case SPE_OP_PKT_HDR_CLASS_LD_ST_ATOMIC:
+ arm_spe_pkt_out_string(&err, &buf, &buf_len,
+ payload & 0x1 ? "ST" : "LD");
+
+ if (SPE_OP_PKT_IS_LDST_ATOMIC(payload)) {
+ if (payload & SPE_OP_PKT_AT)
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " AT");
+ if (payload & SPE_OP_PKT_EXCL)
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCL");
+ if (payload & SPE_OP_PKT_AR)
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " AR");
+ }
+
+ switch (SPE_OP_PKT_LDST_SUBCLASS_GET(payload)) {
+ case SPE_OP_PKT_LDST_SUBCLASS_SIMD_FP:
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " SIMD-FP");
+ break;
+ case SPE_OP_PKT_LDST_SUBCLASS_GP_REG:
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " GP-REG");
+ break;
+ case SPE_OP_PKT_LDST_SUBCLASS_UNSPEC_REG:
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " UNSPEC-REG");
+ break;
+ case SPE_OP_PKT_LDST_SUBCLASS_NV_SYSREG:
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " NV-SYSREG");
+ break;
+ default:
+ break;
+ }
+
+ if (SPE_OP_PKT_IS_LDST_SVE(payload)) {
+ /* SVE effective vector length */
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " EVLEN %d",
+ SPE_OP_PKG_SVE_EVL(payload));
+
+ if (payload & SPE_OP_PKT_SVE_PRED)
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " PRED");
+ if (payload & SPE_OP_PKT_SVE_SG)
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " SG");
+ }
+ break;
+ case SPE_OP_PKT_HDR_CLASS_BR_ERET:
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, "B");
+
+ if (payload & SPE_OP_PKT_COND)
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " COND");
+
+ if (SPE_OP_PKT_IS_INDIRECT_BRANCH(payload))
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, " IND");
+
+ break;
+ default:
+ /* Unknown index */
+ err = -1;
+ break;
+ }
+
+ return err;
+}
+
+static int arm_spe_pkt_desc_addr(const struct arm_spe_pkt *packet,
+ char *buf, size_t buf_len)
+{
+ int ns, el, idx = packet->index;
+ int ch, pat;
+ u64 payload = packet->payload;
+ int err = 0;
+
+ switch (idx) {
+ case SPE_ADDR_PKT_HDR_INDEX_INS:
+ case SPE_ADDR_PKT_HDR_INDEX_BRANCH:
+ ns = !!SPE_ADDR_PKT_GET_NS(payload);
+ el = SPE_ADDR_PKT_GET_EL(payload);
+ payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
+ arm_spe_pkt_out_string(&err, &buf, &buf_len,
+ "%s 0x%llx el%d ns=%d",
+ (idx == 1) ? "TGT" : "PC", payload, el, ns);
+ break;
+ case SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT:
+ arm_spe_pkt_out_string(&err, &buf, &buf_len,
+ "VA 0x%llx", payload);
+ break;
+ case SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS:
+ ns = !!SPE_ADDR_PKT_GET_NS(payload);
+ ch = !!SPE_ADDR_PKT_GET_CH(payload);
+ pat = SPE_ADDR_PKT_GET_PAT(payload);
+ payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
+ arm_spe_pkt_out_string(&err, &buf, &buf_len,
+ "PA 0x%llx ns=%d ch=%d pat=%x",
+ payload, ns, ch, pat);
+ break;
+ default:
+ /* Unknown index */
+ err = -1;
+ break;
+ }
+
+ return err;
+}
+
+static int arm_spe_pkt_desc_counter(const struct arm_spe_pkt *packet,
+ char *buf, size_t buf_len)
+{
+ u64 payload = packet->payload;
+ const char *name = arm_spe_pkt_name(packet->type);
+ int err = 0;
+
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, "%s %d ", name,
+ (unsigned short)payload);
+
+ switch (packet->index) {
+ case SPE_CNT_PKT_HDR_INDEX_TOTAL_LAT:
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, "TOT");
+ break;
+ case SPE_CNT_PKT_HDR_INDEX_ISSUE_LAT:
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, "ISSUE");
+ break;
+ case SPE_CNT_PKT_HDR_INDEX_TRANS_LAT:
+ arm_spe_pkt_out_string(&err, &buf, &buf_len, "XLAT");
+ break;
+ default:
+ break;
+ }
+
+ return err;
+}
+
int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf,
size_t buf_len)
{
- int ret, ns, el, idx = packet->index;
+ int idx = packet->index;
unsigned long long payload = packet->payload;
const char *name = arm_spe_pkt_name(packet->type);
+ char *buf_orig = buf;
+ size_t blen = buf_len;
+ int err = 0;
switch (packet->type) {
case ARM_SPE_BAD:
case ARM_SPE_PAD:
case ARM_SPE_END:
- return snprintf(buf, buf_len, "%s", name);
- case ARM_SPE_EVENTS: {
- size_t blen = buf_len;
-
- ret = 0;
- ret = snprintf(buf, buf_len, "EV");
- buf += ret;
- blen -= ret;
- if (payload & 0x1) {
- ret = snprintf(buf, buf_len, " EXCEPTION-GEN");
- buf += ret;
- blen -= ret;
- }
- if (payload & 0x2) {
- ret = snprintf(buf, buf_len, " RETIRED");
- buf += ret;
- blen -= ret;
- }
- if (payload & 0x4) {
- ret = snprintf(buf, buf_len, " L1D-ACCESS");
- buf += ret;
- blen -= ret;
- }
- if (payload & 0x8) {
- ret = snprintf(buf, buf_len, " L1D-REFILL");
- buf += ret;
- blen -= ret;
- }
- if (payload & 0x10) {
- ret = snprintf(buf, buf_len, " TLB-ACCESS");
- buf += ret;
- blen -= ret;
- }
- if (payload & 0x20) {
- ret = snprintf(buf, buf_len, " TLB-REFILL");
- buf += ret;
- blen -= ret;
- }
- if (payload & 0x40) {
- ret = snprintf(buf, buf_len, " NOT-TAKEN");
- buf += ret;
- blen -= ret;
- }
- if (payload & 0x80) {
- ret = snprintf(buf, buf_len, " MISPRED");
- buf += ret;
- blen -= ret;
- }
- if (idx > 1) {
- if (payload & 0x100) {
- ret = snprintf(buf, buf_len, " LLC-ACCESS");
- buf += ret;
- blen -= ret;
- }
- if (payload & 0x200) {
- ret = snprintf(buf, buf_len, " LLC-REFILL");
- buf += ret;
- blen -= ret;
- }
- if (payload & 0x400) {
- ret = snprintf(buf, buf_len, " REMOTE-ACCESS");
- buf += ret;
- blen -= ret;
- }
- }
- if (ret < 0)
- return ret;
- blen -= ret;
- return buf_len - blen;
- }
+ arm_spe_pkt_out_string(&err, &buf, &blen, "%s", name);
+ break;
+ case ARM_SPE_EVENTS:
+ err = arm_spe_pkt_desc_event(packet, buf, buf_len);
+ break;
case ARM_SPE_OP_TYPE:
- switch (idx) {
- case 0: return snprintf(buf, buf_len, "%s", payload & 0x1 ?
- "COND-SELECT" : "INSN-OTHER");
- case 1: {
- size_t blen = buf_len;
-
- if (payload & 0x1)
- ret = snprintf(buf, buf_len, "ST");
- else
- ret = snprintf(buf, buf_len, "LD");
- buf += ret;
- blen -= ret;
- if (payload & 0x2) {
- if (payload & 0x4) {
- ret = snprintf(buf, buf_len, " AT");
- buf += ret;
- blen -= ret;
- }
- if (payload & 0x8) {
- ret = snprintf(buf, buf_len, " EXCL");
- buf += ret;
- blen -= ret;
- }
- if (payload & 0x10) {
- ret = snprintf(buf, buf_len, " AR");
- buf += ret;
- blen -= ret;
- }
- } else if (payload & 0x4) {
- ret = snprintf(buf, buf_len, " SIMD-FP");
- buf += ret;
- blen -= ret;
- }
- if (ret < 0)
- return ret;
- blen -= ret;
- return buf_len - blen;
- }
- case 2: {
- size_t blen = buf_len;
-
- ret = snprintf(buf, buf_len, "B");
- buf += ret;
- blen -= ret;
- if (payload & 0x1) {
- ret = snprintf(buf, buf_len, " COND");
- buf += ret;
- blen -= ret;
- }
- if (payload & 0x2) {
- ret = snprintf(buf, buf_len, " IND");
- buf += ret;
- blen -= ret;
- }
- if (ret < 0)
- return ret;
- blen -= ret;
- return buf_len - blen;
- }
- default: return 0;
- }
+ err = arm_spe_pkt_desc_op_type(packet, buf, buf_len);
+ break;
case ARM_SPE_DATA_SOURCE:
case ARM_SPE_TIMESTAMP:
- return snprintf(buf, buf_len, "%s %lld", name, payload);
+ arm_spe_pkt_out_string(&err, &buf, &blen, "%s %lld", name, payload);
+ break;
case ARM_SPE_ADDRESS:
- switch (idx) {
- case 0:
- case 1: ns = !!(packet->payload & NS_FLAG);
- el = (packet->payload & EL_FLAG) >> 61;
- payload &= ~(0xffULL << 56);
- return snprintf(buf, buf_len, "%s 0x%llx el%d ns=%d",
- (idx == 1) ? "TGT" : "PC", payload, el, ns);
- case 2: return snprintf(buf, buf_len, "VA 0x%llx", payload);
- case 3: ns = !!(packet->payload & NS_FLAG);
- payload &= ~(0xffULL << 56);
- return snprintf(buf, buf_len, "PA 0x%llx ns=%d",
- payload, ns);
- default: return 0;
- }
+ err = arm_spe_pkt_desc_addr(packet, buf, buf_len);
+ break;
case ARM_SPE_CONTEXT:
- return snprintf(buf, buf_len, "%s 0x%lx el%d", name,
- (unsigned long)payload, idx + 1);
- case ARM_SPE_COUNTER: {
- size_t blen = buf_len;
-
- ret = snprintf(buf, buf_len, "%s %d ", name,
- (unsigned short)payload);
- buf += ret;
- blen -= ret;
- switch (idx) {
- case 0: ret = snprintf(buf, buf_len, "TOT"); break;
- case 1: ret = snprintf(buf, buf_len, "ISSUE"); break;
- case 2: ret = snprintf(buf, buf_len, "XLAT"); break;
- default: ret = 0;
- }
- if (ret < 0)
- return ret;
- blen -= ret;
- return buf_len - blen;
- }
+ arm_spe_pkt_out_string(&err, &buf, &blen, "%s 0x%lx el%d",
+ name, (unsigned long)payload, idx + 1);
+ break;
+ case ARM_SPE_COUNTER:
+ err = arm_spe_pkt_desc_counter(packet, buf, buf_len);
+ break;
default:
+ /* Unknown packet type */
+ err = -1;
break;
}
- return snprintf(buf, buf_len, "%s 0x%llx (%d)",
- name, payload, packet->index);
+ /* Output raw data if detect any error */
+ if (err) {
+ err = 0;
+ arm_spe_pkt_out_string(&err, &buf_orig, &buf_len, "%s 0x%llx (%d)",
+ name, payload, packet->index);
+ }
+
+ return err;
}
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h
index 4c870521b8eb..9b970e7bf1e2 100644
--- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h
+++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.h
@@ -36,19 +36,115 @@ struct arm_spe_pkt {
uint64_t payload;
};
-#define SPE_ADDR_PKT_HDR_INDEX_INS (0x0)
-#define SPE_ADDR_PKT_HDR_INDEX_BRANCH (0x1)
-#define SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT (0x2)
-#define SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS (0x3)
-
-#define SPE_ADDR_PKT_NS BIT(7)
-#define SPE_ADDR_PKT_CH BIT(6)
-#define SPE_ADDR_PKT_EL_OFFSET (5)
-#define SPE_ADDR_PKT_EL_MASK (0x3 << SPE_ADDR_PKT_EL_OFFSET)
-#define SPE_ADDR_PKT_EL0 (0)
-#define SPE_ADDR_PKT_EL1 (1)
-#define SPE_ADDR_PKT_EL2 (2)
-#define SPE_ADDR_PKT_EL3 (3)
+/* Short header (HEADER0) and extended header (HEADER1) */
+#define SPE_HEADER0_PAD 0x0
+#define SPE_HEADER0_END 0x1
+#define SPE_HEADER0_TIMESTAMP 0x71
+/* Mask for event & data source */
+#define SPE_HEADER0_MASK1 (GENMASK_ULL(7, 6) | GENMASK_ULL(3, 0))
+#define SPE_HEADER0_EVENTS 0x42
+#define SPE_HEADER0_SOURCE 0x43
+/* Mask for context & operation */
+#define SPE_HEADER0_MASK2 GENMASK_ULL(7, 2)
+#define SPE_HEADER0_CONTEXT 0x64
+#define SPE_HEADER0_OP_TYPE 0x48
+/* Mask for extended format */
+#define SPE_HEADER0_EXTENDED 0x20
+/* Mask for address & counter */
+#define SPE_HEADER0_MASK3 GENMASK_ULL(7, 3)
+#define SPE_HEADER0_ADDRESS 0xb0
+#define SPE_HEADER0_COUNTER 0x98
+#define SPE_HEADER1_ALIGNMENT 0x0
+
+#define SPE_HDR_SHORT_INDEX(h) ((h) & GENMASK_ULL(2, 0))
+#define SPE_HDR_EXTENDED_INDEX(h0, h1) (((h0) & GENMASK_ULL(1, 0)) << 3 | \
+ SPE_HDR_SHORT_INDEX(h1))
+
+/* Address packet header */
+#define SPE_ADDR_PKT_HDR_INDEX_INS 0x0
+#define SPE_ADDR_PKT_HDR_INDEX_BRANCH 0x1
+#define SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT 0x2
+#define SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS 0x3
+
+/* Address packet payload */
+#define SPE_ADDR_PKT_ADDR_BYTE7_SHIFT 56
+#define SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(v) ((v) & GENMASK_ULL(55, 0))
+#define SPE_ADDR_PKT_ADDR_GET_BYTE_6(v) (((v) & GENMASK_ULL(55, 48)) >> 48)
+
+#define SPE_ADDR_PKT_GET_NS(v) (((v) & BIT_ULL(63)) >> 63)
+#define SPE_ADDR_PKT_GET_EL(v) (((v) & GENMASK_ULL(62, 61)) >> 61)
+#define SPE_ADDR_PKT_GET_CH(v) (((v) & BIT_ULL(62)) >> 62)
+#define SPE_ADDR_PKT_GET_PAT(v) (((v) & GENMASK_ULL(59, 56)) >> 56)
+
+#define SPE_ADDR_PKT_EL0 0
+#define SPE_ADDR_PKT_EL1 1
+#define SPE_ADDR_PKT_EL2 2
+#define SPE_ADDR_PKT_EL3 3
+
+/* Context packet header */
+#define SPE_CTX_PKT_HDR_INDEX(h) ((h) & GENMASK_ULL(1, 0))
+
+/* Counter packet header */
+#define SPE_CNT_PKT_HDR_INDEX_TOTAL_LAT 0x0
+#define SPE_CNT_PKT_HDR_INDEX_ISSUE_LAT 0x1
+#define SPE_CNT_PKT_HDR_INDEX_TRANS_LAT 0x2
+
+/* Event packet payload */
+enum arm_spe_events {
+ EV_EXCEPTION_GEN = 0,
+ EV_RETIRED = 1,
+ EV_L1D_ACCESS = 2,
+ EV_L1D_REFILL = 3,
+ EV_TLB_ACCESS = 4,
+ EV_TLB_WALK = 5,
+ EV_NOT_TAKEN = 6,
+ EV_MISPRED = 7,
+ EV_LLC_ACCESS = 8,
+ EV_LLC_MISS = 9,
+ EV_REMOTE_ACCESS = 10,
+ EV_ALIGNMENT = 11,
+ EV_PARTIAL_PREDICATE = 17,
+ EV_EMPTY_PREDICATE = 18,
+};
+
+/* Operation packet header */
+#define SPE_OP_PKT_HDR_CLASS(h) ((h) & GENMASK_ULL(1, 0))
+#define SPE_OP_PKT_HDR_CLASS_OTHER 0x0
+#define SPE_OP_PKT_HDR_CLASS_LD_ST_ATOMIC 0x1
+#define SPE_OP_PKT_HDR_CLASS_BR_ERET 0x2
+
+#define SPE_OP_PKT_IS_OTHER_SVE_OP(v) (((v) & (BIT(7) | BIT(3) | BIT(0))) == 0x8)
+
+#define SPE_OP_PKT_COND BIT(0)
+
+#define SPE_OP_PKT_LDST_SUBCLASS_GET(v) ((v) & GENMASK_ULL(7, 1))
+#define SPE_OP_PKT_LDST_SUBCLASS_GP_REG 0x0
+#define SPE_OP_PKT_LDST_SUBCLASS_SIMD_FP 0x4
+#define SPE_OP_PKT_LDST_SUBCLASS_UNSPEC_REG 0x10
+#define SPE_OP_PKT_LDST_SUBCLASS_NV_SYSREG 0x30
+
+#define SPE_OP_PKT_IS_LDST_ATOMIC(v) (((v) & (GENMASK_ULL(7, 5) | BIT(1))) == 0x2)
+
+#define SPE_OP_PKT_AR BIT(4)
+#define SPE_OP_PKT_EXCL BIT(3)
+#define SPE_OP_PKT_AT BIT(2)
+#define SPE_OP_PKT_ST BIT(0)
+
+#define SPE_OP_PKT_IS_LDST_SVE(v) (((v) & (BIT(3) | BIT(1))) == 0x8)
+
+#define SPE_OP_PKT_SVE_SG BIT(7)
+/*
+ * SVE effective vector length (EVL) is stored in byte 0 bits [6:4];
+ * the length is rounded up to a power of two and use 32 as one step,
+ * so EVL calculation is:
+ *
+ * 32 * (2 ^ bits [6:4]) = 32 << (bits [6:4])
+ */
+#define SPE_OP_PKG_SVE_EVL(v) (32 << (((v) & GENMASK_ULL(6, 4)) >> 4))
+#define SPE_OP_PKT_SVE_PRED BIT(2)
+#define SPE_OP_PKT_SVE_FP BIT(1)
+
+#define SPE_OP_PKT_IS_INDIRECT_BRANCH(v) (((v) & GENMASK_ULL(7, 1)) == 0x2)
const char *arm_spe_pkt_name(enum arm_spe_pkt_type);
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c
index 3882a5360ada..8901a1656a41 100644
--- a/tools/perf/util/arm-spe.c
+++ b/tools/perf/util/arm-spe.c
@@ -113,7 +113,7 @@ static void arm_spe_dump(struct arm_spe *spe __maybe_unused,
if (ret > 0) {
ret = arm_spe_pkt_desc(&packet, desc,
ARM_SPE_PKT_DESC_MAX);
- if (ret > 0)
+ if (!ret)
color_fprintf(stdout, color, " %s\n", desc);
} else {
color_fprintf(stdout, color, " Bad packet!\n");
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index 42a85c86421d..a60878498139 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -62,9 +62,7 @@
* Make a group from 'leader' to 'last', requiring that the events were not
* already grouped to a different leader.
*/
-static int perf_evlist__regroup(struct evlist *evlist,
- struct evsel *leader,
- struct evsel *last)
+static int evlist__regroup(struct evlist *evlist, struct evsel *leader, struct evsel *last)
{
struct evsel *evsel;
bool grp;
@@ -658,8 +656,7 @@ int auxtrace_record__read_finish(struct auxtrace_record *itr, int idx)
if (evsel->core.attr.type == itr->pmu->type) {
if (evsel->disabled)
return 0;
- return perf_evlist__enable_event_idx(itr->evlist, evsel,
- idx);
+ return evlist__enable_event_idx(itr->evlist, evsel, idx);
}
}
return -EINVAL;
@@ -776,7 +773,7 @@ no_opt:
evsel->core.attr.aux_sample_size = term->val.aux_sample_size;
/* If possible, group with the AUX event */
if (aux_evsel && evsel->core.attr.aux_sample_size)
- perf_evlist__regroup(evlist, aux_evsel, evsel);
+ evlist__regroup(evlist, aux_evsel, evsel);
}
}
@@ -1017,7 +1014,7 @@ struct auxtrace_queue *auxtrace_queues__sample_queue(struct auxtrace_queues *que
if (!id)
return NULL;
- sid = perf_evlist__id2sid(session->evlist, id);
+ sid = evlist__id2sid(session->evlist, id);
if (!sid)
return NULL;
@@ -1047,7 +1044,7 @@ int auxtrace_queues__add_sample(struct auxtrace_queues *queues,
if (!id)
return -EINVAL;
- sid = perf_evlist__id2sid(session->evlist, id);
+ sid = evlist__id2sid(session->evlist, id);
if (!sid)
return -ENOENT;
@@ -1082,7 +1079,7 @@ static int auxtrace_queue_data_cb(struct perf_session *session,
if (!qd->samples || event->header.type != PERF_RECORD_SAMPLE)
return 0;
- err = perf_evlist__parse_sample(session->evlist, event, &sample);
+ err = evlist__parse_sample(session->evlist, event, &sample);
if (err)
return err;
@@ -1333,6 +1330,7 @@ void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts,
synth_opts->flc = true;
synth_opts->llc = true;
synth_opts->tlb = true;
+ synth_opts->mem = true;
synth_opts->remote_access = true;
if (no_sample) {
@@ -1554,6 +1552,9 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str,
case 'a':
synth_opts->remote_access = true;
break;
+ case 'M':
+ synth_opts->mem = true;
+ break;
case 'q':
synth_opts->quick += 1;
break;
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
index 951d2d14cf24..7e5c9e1552bd 100644
--- a/tools/perf/util/auxtrace.h
+++ b/tools/perf/util/auxtrace.h
@@ -88,6 +88,7 @@ enum itrace_period_type {
* @llc: whether to synthesize last level cache events
* @tlb: whether to synthesize TLB events
* @remote_access: whether to synthesize remote access events
+ * @mem: whether to synthesize memory events
* @callchain_sz: maximum callchain size
* @last_branch_sz: branch context size
* @period: 'instructions' events period
@@ -126,6 +127,7 @@ struct itrace_synth_opts {
bool llc;
bool tlb;
bool remote_access;
+ bool mem;
unsigned int callchain_sz;
unsigned int last_branch_sz;
unsigned long long period;
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index 3742511a08d1..57d58c81a5f8 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -526,7 +526,7 @@ int evlist__add_bpf_sb_event(struct evlist *evlist, struct perf_env *env)
*/
attr.wakeup_watermark = 1;
- return perf_evlist__add_sb_event(evlist, &attr, bpf_event__sb_cb, env);
+ return evlist__add_sb_event(evlist, &attr, bpf_event__sb_cb, env);
}
void bpf_event__print_bpf_prog_info(struct bpf_prog_info *info,
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 0374adcb223c..9087f1bffd3d 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -1058,12 +1058,11 @@ __bpf_map__config_event(struct bpf_map *map,
struct parse_events_term *term,
struct evlist *evlist)
{
- struct evsel *evsel;
const struct bpf_map_def *def;
struct bpf_map_op *op;
const char *map_name = bpf_map__name(map);
+ struct evsel *evsel = evlist__find_evsel_by_str(evlist, term->val.str);
- evsel = perf_evlist__find_evsel_by_str(evlist, term->val.str);
if (!evsel) {
pr_debug("Event (for '%s') '%s' doesn't exist\n",
map_name, term->val.str);
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index 25251d63164c..5d1c725cea29 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -8,6 +8,8 @@
#include <linux/compiler.h>
#include <linux/err.h>
+
+#ifdef HAVE_LIBBPF_SUPPORT
#include <bpf/libbpf.h>
enum bpf_loader_errno {
@@ -38,6 +40,7 @@ enum bpf_loader_errno {
BPF_LOADER_ERRNO__OBJCONF_MAP_IDX2BIG, /* Index too large */
__BPF_LOADER_ERRNO__END,
};
+#endif // HAVE_LIBBPF_SUPPORT
struct evsel;
struct evlist;
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 6b410c3d52dc..02df36b30ac5 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -37,6 +37,7 @@
#include <linux/ctype.h>
#include <linux/zalloc.h>
+#include <linux/string.h>
#include <asm/bug.h>
static bool no_buildid_cache;
@@ -260,10 +261,9 @@ static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso,
"debug" : "elf"));
}
-char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size,
- bool is_debug)
+char *__dso__build_id_filename(const struct dso *dso, char *bf, size_t size,
+ bool is_debug, bool is_kallsyms)
{
- bool is_kallsyms = dso__is_kallsyms((struct dso *)dso);
bool is_vdso = dso__is_vdso((struct dso *)dso);
char sbuild_id[SBUILD_ID_SIZE];
char *linkname;
@@ -292,6 +292,14 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size,
return bf;
}
+char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size,
+ bool is_debug)
+{
+ bool is_kallsyms = dso__is_kallsyms((struct dso *)dso);
+
+ return __dso__build_id_filename(dso, bf, size, is_debug, is_kallsyms);
+}
+
#define dsos__for_each_with_build_id(pos, head) \
list_for_each_entry(pos, head, node) \
if (!pos->has_build_id) \
@@ -663,24 +671,15 @@ out:
return realname;
}
-int build_id_cache__add_s(const char *sbuild_id, const char *name,
- struct nsinfo *nsi, bool is_kallsyms, bool is_vdso)
+int
+build_id_cache__add(const char *sbuild_id, const char *name, const char *realname,
+ struct nsinfo *nsi, bool is_kallsyms, bool is_vdso)
{
const size_t size = PATH_MAX;
- char *realname = NULL, *filename = NULL, *dir_name = NULL,
- *linkname = zalloc(size), *tmp;
+ char *filename = NULL, *dir_name = NULL, *linkname = zalloc(size), *tmp;
char *debugfile = NULL;
int err = -1;
- if (!is_kallsyms) {
- if (!is_vdso)
- realname = nsinfo__realpath(name, nsi);
- else
- realname = realpath(name, NULL);
- if (!realname)
- goto out_free;
- }
-
dir_name = build_id_cache__cachedir(sbuild_id, name, nsi, is_kallsyms,
is_vdso);
if (!dir_name)
@@ -754,8 +753,25 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
tmp = dir_name + strlen(buildid_dir) - 5;
memcpy(tmp, "../..", 5);
- if (symlink(tmp, linkname) == 0)
+ if (symlink(tmp, linkname) == 0) {
+ err = 0;
+ } else if (errno == EEXIST) {
+ char path[PATH_MAX];
+ ssize_t len;
+
+ len = readlink(linkname, path, sizeof(path) - 1);
+ if (len <= 0) {
+ pr_err("Cant read link: %s\n", linkname);
+ goto out_free;
+ }
+ path[len] = '\0';
+
+ if (strcmp(tmp, path)) {
+ pr_debug("build <%s> already linked to %s\n",
+ sbuild_id, linkname);
+ }
err = 0;
+ }
/* Update SDT cache : error is just warned */
if (realname &&
@@ -763,8 +779,6 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
pr_debug4("Failed to update/scan SDT cache for %s\n", realname);
out_free:
- if (!is_kallsyms)
- free(realname);
free(filename);
free(debugfile);
free(dir_name);
@@ -772,6 +786,29 @@ out_free:
return err;
}
+int build_id_cache__add_s(const char *sbuild_id, const char *name,
+ struct nsinfo *nsi, bool is_kallsyms, bool is_vdso)
+{
+ char *realname = NULL;
+ int err = -1;
+
+ if (!is_kallsyms) {
+ if (!is_vdso)
+ realname = nsinfo__realpath(name, nsi);
+ else
+ realname = realpath(name, NULL);
+ if (!realname)
+ goto out_free;
+ }
+
+ err = build_id_cache__add(sbuild_id, name, realname, nsi, is_kallsyms, is_vdso);
+
+out_free:
+ if (!is_kallsyms)
+ free(realname);
+ return err;
+}
+
static int build_id_cache__add_b(const struct build_id *bid,
const char *name, struct nsinfo *nsi,
bool is_kallsyms, bool is_vdso)
@@ -834,12 +871,16 @@ out_free:
return err;
}
-static int dso__cache_build_id(struct dso *dso, struct machine *machine)
+static int dso__cache_build_id(struct dso *dso, struct machine *machine,
+ void *priv __maybe_unused)
{
bool is_kallsyms = dso__is_kallsyms(dso);
bool is_vdso = dso__is_vdso(dso);
const char *name = dso->long_name;
+ if (!dso->has_build_id)
+ return 0;
+
if (dso__is_kcore(dso)) {
is_kallsyms = true;
name = machine->mmap_name;
@@ -848,43 +889,36 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine)
is_kallsyms, is_vdso);
}
-static int __dsos__cache_build_ids(struct list_head *head,
- struct machine *machine)
+static int
+machines__for_each_dso(struct machines *machines, machine__dso_t fn, void *priv)
{
- struct dso *pos;
- int err = 0;
-
- dsos__for_each_with_build_id(pos, head)
- if (dso__cache_build_id(pos, machine))
- err = -1;
+ int ret = machine__for_each_dso(&machines->host, fn, priv);
+ struct rb_node *nd;
- return err;
-}
+ for (nd = rb_first_cached(&machines->guests); nd;
+ nd = rb_next(nd)) {
+ struct machine *pos = rb_entry(nd, struct machine, rb_node);
-static int machine__cache_build_ids(struct machine *machine)
-{
- return __dsos__cache_build_ids(&machine->dsos.head, machine);
+ ret |= machine__for_each_dso(pos, fn, priv);
+ }
+ return ret ? -1 : 0;
}
-int perf_session__cache_build_ids(struct perf_session *session)
+int __perf_session__cache_build_ids(struct perf_session *session,
+ machine__dso_t fn, void *priv)
{
- struct rb_node *nd;
- int ret;
-
if (no_buildid_cache)
return 0;
if (mkdir(buildid_dir, 0755) != 0 && errno != EEXIST)
return -1;
- ret = machine__cache_build_ids(&session->machines.host);
+ return machines__for_each_dso(&session->machines, fn, priv) ? -1 : 0;
+}
- for (nd = rb_first_cached(&session->machines.guests); nd;
- nd = rb_next(nd)) {
- struct machine *pos = rb_entry(nd, struct machine, rb_node);
- ret |= machine__cache_build_ids(pos);
- }
- return ret ? -1 : 0;
+int perf_session__cache_build_ids(struct perf_session *session)
+{
+ return __perf_session__cache_build_ids(session, dso__cache_build_id, NULL);
}
static bool machine__read_build_ids(struct machine *machine, bool with_hits)
@@ -912,3 +946,8 @@ void build_id__init(struct build_id *bid, const u8 *data, size_t size)
memcpy(bid->data, data, size);
bid->size = size;
}
+
+bool build_id__is_defined(const struct build_id *bid)
+{
+ return bid && bid->size ? !!memchr_inv(bid->data, 0, bid->size) : false;
+}
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index f293f99d5dba..02613f4b2c29 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -5,6 +5,7 @@
#define BUILD_ID_SIZE 20
#define SBUILD_ID_SIZE (BUILD_ID_SIZE * 2 + 1)
+#include "machine.h"
#include "tool.h"
#include <linux/types.h>
@@ -21,6 +22,7 @@ struct feat_fd;
void build_id__init(struct build_id *bid, const u8 *data, size_t size);
int build_id__sprintf(const struct build_id *build_id, char *bf);
+bool build_id__is_defined(const struct build_id *bid);
int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id);
int filename__sprintf_build_id(const char *pathname, char *sbuild_id);
char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf,
@@ -28,6 +30,8 @@ char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf,
char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size,
bool is_debug);
+char *__dso__build_id_filename(const struct dso *dso, char *bf, size_t size,
+ bool is_debug, bool is_kallsyms);
int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
struct perf_sample *sample, struct evsel *evsel,
@@ -43,6 +47,8 @@ bool perf_session__read_build_ids(struct perf_session *session, bool with_hits);
int perf_session__write_buildid_table(struct perf_session *session,
struct feat_fd *fd);
int perf_session__cache_build_ids(struct perf_session *session);
+int __perf_session__cache_build_ids(struct perf_session *session,
+ machine__dso_t fn, void *priv);
char *build_id_cache__origname(const char *sbuild_id);
char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size);
@@ -57,6 +63,8 @@ char *build_id_cache__complement(const char *incomplete_sbuild_id);
int build_id_cache__list_build_ids(const char *pathname, struct nsinfo *nsi,
struct strlist **result);
bool build_id_cache__cached(const char *sbuild_id);
+int build_id_cache__add(const char *sbuild_id, const char *name, const char *realname,
+ struct nsinfo *nsi, bool is_kallsyms, bool is_vdso);
int build_id_cache__add_s(const char *sbuild_id,
const char *name, struct nsinfo *nsi,
bool is_kallsyms, bool is_vdso);
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index b81324a13a2b..5dff7e489921 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -13,9 +13,19 @@
#include <stdlib.h>
#include <string.h>
#include <api/fs/fs.h>
+#include <ftw.h>
+#include <regex.h>
int nr_cgroups;
+/* used to match cgroup name with patterns */
+struct cgroup_name {
+ struct list_head list;
+ bool used;
+ char name[];
+};
+static LIST_HEAD(cgroup_list);
+
static int open_cgroup(const char *name)
{
char path[PATH_MAX + 1];
@@ -149,6 +159,137 @@ void evlist__set_default_cgroup(struct evlist *evlist, struct cgroup *cgroup)
evsel__set_default_cgroup(evsel, cgroup);
}
+/* helper function for ftw() in match_cgroups and list_cgroups */
+static int add_cgroup_name(const char *fpath, const struct stat *sb __maybe_unused,
+ int typeflag)
+{
+ struct cgroup_name *cn;
+
+ if (typeflag != FTW_D)
+ return 0;
+
+ cn = malloc(sizeof(*cn) + strlen(fpath) + 1);
+ if (cn == NULL)
+ return -1;
+
+ cn->used = false;
+ strcpy(cn->name, fpath);
+
+ list_add_tail(&cn->list, &cgroup_list);
+ return 0;
+}
+
+static void release_cgroup_list(void)
+{
+ struct cgroup_name *cn;
+
+ while (!list_empty(&cgroup_list)) {
+ cn = list_first_entry(&cgroup_list, struct cgroup_name, list);
+ list_del(&cn->list);
+ free(cn);
+ }
+}
+
+/* collect given cgroups only */
+static int list_cgroups(const char *str)
+{
+ const char *p, *e, *eos = str + strlen(str);
+ struct cgroup_name *cn;
+ char *s;
+
+ /* use given name as is - for testing purpose */
+ for (;;) {
+ p = strchr(str, ',');
+ e = p ? p : eos;
+
+ if (e - str) {
+ int ret;
+
+ s = strndup(str, e - str);
+ if (!s)
+ return -1;
+ /* pretend if it's added by ftw() */
+ ret = add_cgroup_name(s, NULL, FTW_D);
+ free(s);
+ if (ret)
+ return -1;
+ } else {
+ if (add_cgroup_name("", NULL, FTW_D) < 0)
+ return -1;
+ }
+
+ if (!p)
+ break;
+ str = p+1;
+ }
+
+ /* these groups will be used */
+ list_for_each_entry(cn, &cgroup_list, list)
+ cn->used = true;
+
+ return 0;
+}
+
+/* collect all cgroups first and then match with the pattern */
+static int match_cgroups(const char *str)
+{
+ char mnt[PATH_MAX];
+ const char *p, *e, *eos = str + strlen(str);
+ struct cgroup_name *cn;
+ regex_t reg;
+ int prefix_len;
+ char *s;
+
+ if (cgroupfs_find_mountpoint(mnt, sizeof(mnt), "perf_event"))
+ return -1;
+
+ /* cgroup_name will have a full path, skip the root directory */
+ prefix_len = strlen(mnt);
+
+ /* collect all cgroups in the cgroup_list */
+ if (ftw(mnt, add_cgroup_name, 20) < 0)
+ return -1;
+
+ for (;;) {
+ p = strchr(str, ',');
+ e = p ? p : eos;
+
+ /* allow empty cgroups, i.e., skip */
+ if (e - str) {
+ /* termination added */
+ s = strndup(str, e - str);
+ if (!s)
+ return -1;
+ if (regcomp(&reg, s, REG_NOSUB)) {
+ free(s);
+ return -1;
+ }
+
+ /* check cgroup name with the pattern */
+ list_for_each_entry(cn, &cgroup_list, list) {
+ char *name = cn->name + prefix_len;
+
+ if (name[0] == '/' && name[1])
+ name++;
+ if (!regexec(&reg, name, 0, NULL, 0))
+ cn->used = true;
+ }
+ regfree(&reg);
+ free(s);
+ } else {
+ /* first entry to root cgroup */
+ cn = list_first_entry(&cgroup_list, struct cgroup_name,
+ list);
+ cn->used = true;
+ }
+
+ if (!p)
+ break;
+ str = p+1;
+ }
+ return prefix_len;
+}
+
int parse_cgroups(const struct option *opt, const char *str,
int unset __maybe_unused)
{
@@ -201,6 +342,11 @@ int parse_cgroups(const struct option *opt, const char *str,
return 0;
}
+static bool has_pattern_string(const char *str)
+{
+ return !!strpbrk(str, "{}[]()|*+?^$");
+}
+
int evlist__expand_cgroup(struct evlist *evlist, const char *str,
struct rblist *metric_events, bool open_cgroup)
{
@@ -208,8 +354,9 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str,
struct evsel *pos, *evsel, *leader;
struct rblist orig_metric_events;
struct cgroup *cgrp = NULL;
- const char *p, *e, *eos = str + strlen(str);
+ struct cgroup_name *cn;
int ret = -1;
+ int prefix_len;
if (evlist->core.nr_entries == 0) {
fprintf(stderr, "must define events before cgroups\n");
@@ -224,7 +371,7 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str,
}
/* save original events and init evlist */
- perf_evlist__splice_list_tail(orig_list, &evlist->core.entries);
+ evlist__splice_list_tail(orig_list, &evlist->core.entries);
evlist->core.nr_entries = 0;
if (metric_events) {
@@ -234,24 +381,27 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str,
rblist__init(&orig_metric_events);
}
- for (;;) {
- p = strchr(str, ',');
- e = p ? p : eos;
+ if (has_pattern_string(str))
+ prefix_len = match_cgroups(str);
+ else
+ prefix_len = list_cgroups(str);
- /* allow empty cgroups, i.e., skip */
- if (e - str) {
- /* termination added */
- char *name = strndup(str, e - str);
- if (!name)
- goto out_err;
+ if (prefix_len < 0)
+ goto out_err;
- cgrp = cgroup__new(name, open_cgroup);
- free(name);
- if (cgrp == NULL)
- goto out_err;
- } else {
- cgrp = NULL;
- }
+ list_for_each_entry(cn, &cgroup_list, list) {
+ char *name;
+
+ if (!cn->used)
+ continue;
+
+ /* cgroup_name might have a full path, skip the prefix */
+ name = cn->name + prefix_len;
+ if (name[0] == '/' && name[1])
+ name++;
+ cgrp = cgroup__new(name, open_cgroup);
+ if (cgrp == NULL)
+ goto out_err;
leader = NULL;
evlist__for_each_entry(orig_list, pos) {
@@ -277,23 +427,25 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str,
if (metricgroup__copy_metric_events(tmp_list, cgrp,
metric_events,
&orig_metric_events) < 0)
- break;
+ goto out_err;
}
- perf_evlist__splice_list_tail(evlist, &tmp_list->core.entries);
+ evlist__splice_list_tail(evlist, &tmp_list->core.entries);
tmp_list->core.nr_entries = 0;
+ }
- if (!p) {
- ret = 0;
- break;
- }
- str = p+1;
+ if (list_empty(&evlist->core.entries)) {
+ fprintf(stderr, "no cgroup matched: %s\n", str);
+ goto out_err;
}
+ ret = 0;
+
out_err:
evlist__delete(orig_list);
evlist__delete(tmp_list);
rblist__exit(&orig_metric_events);
+ release_cgroup_list();
return ret;
}
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index c47aa34fdc0a..f29af4fc3d09 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -174,8 +174,21 @@ static bool check_pipe(struct perf_data *data)
is_pipe = true;
}
- if (is_pipe)
- data->file.fd = fd;
+ if (is_pipe) {
+ if (data->use_stdio) {
+ const char *mode;
+
+ mode = perf_data__is_read(data) ? "r" : "w";
+ data->file.fptr = fdopen(fd, mode);
+
+ if (data->file.fptr == NULL) {
+ data->file.fd = fd;
+ data->use_stdio = false;
+ }
+ } else {
+ data->file.fd = fd;
+ }
+ }
return data->is_pipe = is_pipe;
}
@@ -334,6 +347,9 @@ int perf_data__open(struct perf_data *data)
if (check_pipe(data))
return 0;
+ /* currently it allows stdio for pipe only */
+ data->use_stdio = false;
+
if (!data->path)
data->path = "perf.data";
@@ -353,7 +369,21 @@ void perf_data__close(struct perf_data *data)
perf_data__close_dir(data);
zfree(&data->file.path);
- close(data->file.fd);
+
+ if (data->use_stdio)
+ fclose(data->file.fptr);
+ else
+ close(data->file.fd);
+}
+
+ssize_t perf_data__read(struct perf_data *data, void *buf, size_t size)
+{
+ if (data->use_stdio) {
+ if (fread(buf, size, 1, data->file.fptr) == 1)
+ return size;
+ return feof(data->file.fptr) ? 0 : -1;
+ }
+ return readn(data->file.fd, buf, size);
}
ssize_t perf_data_file__write(struct perf_data_file *file,
@@ -365,6 +395,11 @@ ssize_t perf_data_file__write(struct perf_data_file *file,
ssize_t perf_data__write(struct perf_data *data,
void *buf, size_t size)
{
+ if (data->use_stdio) {
+ if (fwrite(buf, size, 1, data->file.fptr) == 1)
+ return size;
+ return -1;
+ }
return perf_data_file__write(&data->file, buf, size);
}
@@ -457,3 +492,22 @@ char *perf_data__kallsyms_name(struct perf_data *data)
return kallsyms_name;
}
+
+bool is_perf_data(const char *path)
+{
+ bool ret = false;
+ FILE *file;
+ u64 magic;
+
+ file = fopen(path, "r");
+ if (!file)
+ return false;
+
+ if (fread(&magic, 1, 8, file) < 8)
+ goto out;
+
+ ret = is_perf_magic(magic);
+out:
+ fclose(file);
+ return ret;
+}
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 75947ef6bc17..62a3e66fbee8 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -2,6 +2,7 @@
#ifndef __PERF_DATA_H
#define __PERF_DATA_H
+#include <stdio.h>
#include <stdbool.h>
enum perf_data_mode {
@@ -16,7 +17,10 @@ enum perf_dir_version {
struct perf_data_file {
char *path;
- int fd;
+ union {
+ int fd;
+ FILE *fptr;
+ };
unsigned long size;
};
@@ -26,6 +30,7 @@ struct perf_data {
bool is_pipe;
bool is_dir;
bool force;
+ bool use_stdio;
enum perf_data_mode mode;
struct {
@@ -62,11 +67,15 @@ static inline bool perf_data__is_single_file(struct perf_data *data)
static inline int perf_data__fd(struct perf_data *data)
{
+ if (data->use_stdio)
+ return fileno(data->file.fptr);
+
return data->file.fd;
}
int perf_data__open(struct perf_data *data);
void perf_data__close(struct perf_data *data);
+ssize_t perf_data__read(struct perf_data *data, void *buf, size_t size);
ssize_t perf_data__write(struct perf_data *data,
void *buf, size_t size);
ssize_t perf_data_file__write(struct perf_data_file *file,
@@ -89,4 +98,5 @@ int perf_data__update_dir(struct perf_data *data);
unsigned long perf_data__size(struct perf_data *data);
int perf_data__make_kcore_dir(struct perf_data *data, char *buf, size_t buf_sz);
char *perf_data__kallsyms_name(struct perf_data *data);
+bool is_perf_data(const char *path);
#endif /* __PERF_DATA_H */
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 5cda5565777a..50fd6a4be4e0 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -30,6 +30,12 @@ bool dump_trace = false, quiet = false;
int debug_ordered_events;
static int redirect_to_stderr;
int debug_data_convert;
+static FILE *debug_file;
+
+void debug_set_file(FILE *file)
+{
+ debug_file = file;
+}
int veprintf(int level, int var, const char *fmt, va_list args)
{
@@ -39,7 +45,7 @@ int veprintf(int level, int var, const char *fmt, va_list args)
if (use_browser >= 1 && !redirect_to_stderr)
ui_helpline__vshow(fmt, args);
else
- ret = vfprintf(stderr, fmt, args);
+ ret = vfprintf(debug_file, fmt, args);
}
return ret;
@@ -227,6 +233,7 @@ DEBUG_WRAPPER(debug, 1);
void perf_debug_setup(void)
{
+ debug_set_file(stderr);
libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper);
}
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index f1734abd98dd..43f712295645 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -5,6 +5,7 @@
#include <stdarg.h>
#include <stdbool.h>
+#include <stdio.h>
#include <linux/compiler.h>
extern int verbose;
@@ -62,6 +63,7 @@ int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __printf(4, 5)
int veprintf(int level, int var, const char *fmt, va_list args);
int perf_debug_option(const char *str);
+void debug_set_file(FILE *file);
void perf_debug_setup(void);
int perf_quiet_option(void);
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 55c11e854fe4..d786cf6b0cfa 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -11,8 +11,10 @@
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
+#ifdef HAVE_LIBBPF_SUPPORT
#include <bpf/libbpf.h>
#include "bpf-event.h"
+#endif
#include "compress.h"
#include "env.h"
#include "namespaces.h"
@@ -277,18 +279,12 @@ bool dso__needs_decompress(struct dso *dso)
dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
}
-static int decompress_kmodule(struct dso *dso, const char *name,
- char *pathname, size_t len)
+int filename__decompress(const char *name, char *pathname,
+ size_t len, int comp, int *err)
{
char tmpbuf[] = KMOD_DECOMP_NAME;
int fd = -1;
- if (!dso__needs_decompress(dso))
- return -1;
-
- if (dso->comp == COMP_ID__NONE)
- return -1;
-
/*
* We have proper compression id for DSO and yet the file
* behind the 'name' can still be plain uncompressed object.
@@ -302,17 +298,17 @@ static int decompress_kmodule(struct dso *dso, const char *name,
* To keep this transparent, we detect this and return the file
* descriptor to the uncompressed file.
*/
- if (!compressions[dso->comp].is_compressed(name))
+ if (!compressions[comp].is_compressed(name))
return open(name, O_RDONLY);
fd = mkstemp(tmpbuf);
if (fd < 0) {
- dso->load_errno = errno;
+ *err = errno;
return -1;
}
- if (compressions[dso->comp].decompress(name, fd)) {
- dso->load_errno = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE;
+ if (compressions[comp].decompress(name, fd)) {
+ *err = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE;
close(fd);
fd = -1;
}
@@ -326,6 +322,19 @@ static int decompress_kmodule(struct dso *dso, const char *name,
return fd;
}
+static int decompress_kmodule(struct dso *dso, const char *name,
+ char *pathname, size_t len)
+{
+ if (!dso__needs_decompress(dso))
+ return -1;
+
+ if (dso->comp == COMP_ID__NONE)
+ return -1;
+
+ return filename__decompress(name, pathname, len, dso->comp,
+ &dso->load_errno);
+}
+
int dso__decompress_kmodule_fd(struct dso *dso, const char *name)
{
return decompress_kmodule(dso, name, NULL, 0);
@@ -728,6 +737,7 @@ bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by)
return false;
}
+#ifdef HAVE_LIBBPF_SUPPORT
static ssize_t bpf_read(struct dso *dso, u64 offset, char *data)
{
struct bpf_prog_info_node *node;
@@ -765,6 +775,7 @@ static int bpf_size(struct dso *dso)
dso->data.file_size = node->info_linear->info.jited_prog_len;
return 0;
}
+#endif // HAVE_LIBBPF_SUPPORT
static void
dso_cache__free(struct dso *dso)
@@ -894,10 +905,12 @@ static struct dso_cache *dso_cache__populate(struct dso *dso,
*ret = -ENOMEM;
return NULL;
}
-
+#ifdef HAVE_LIBBPF_SUPPORT
if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO)
*ret = bpf_read(dso, cache_offset, cache->data);
- else if (dso->binary_type == DSO_BINARY_TYPE__OOL)
+ else
+#endif
+ if (dso->binary_type == DSO_BINARY_TYPE__OOL)
*ret = DSO__DATA_CACHE_SIZE;
else
*ret = file_read(dso, machine, cache_offset, cache->data);
@@ -1018,10 +1031,10 @@ int dso__data_file_size(struct dso *dso, struct machine *machine)
if (dso->data.status == DSO_DATA_STATUS_ERROR)
return -1;
-
+#ifdef HAVE_LIBBPF_SUPPORT
if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO)
return bpf_size(dso);
-
+#endif
return file_size(dso, machine);
}
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index d8cb4f5680a4..cd2fe64a3c5d 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -274,6 +274,8 @@ bool dso__needs_decompress(struct dso *dso);
int dso__decompress_kmodule_fd(struct dso *dso, const char *name);
int dso__decompress_kmodule_path(struct dso *dso, const char *name,
char *pathname, size_t len);
+int filename__decompress(const char *name, char *pathname,
+ size_t len, int comp, int *err);
#define KMOD_DECOMP_NAME "/tmp/perf-kmod-XXXXXX"
#define KMOD_DECOMP_LEN sizeof(KMOD_DECOMP_NAME)
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index fadc59708ece..9130f6fad8d5 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -5,16 +5,18 @@
#include "util/header.h"
#include <linux/ctype.h>
#include <linux/zalloc.h>
-#include "bpf-event.h"
#include "cgroup.h"
#include <errno.h>
#include <sys/utsname.h>
-#include <bpf/libbpf.h>
#include <stdlib.h>
#include <string.h>
struct perf_env perf_env;
+#ifdef HAVE_LIBBPF_SUPPORT
+#include "bpf-event.h"
+#include <bpf/libbpf.h>
+
void perf_env__insert_bpf_prog_info(struct perf_env *env,
struct bpf_prog_info_node *info_node)
{
@@ -163,6 +165,11 @@ static void perf_env__purge_bpf(struct perf_env *env)
up_write(&env->bpf_progs.lock);
}
+#else // HAVE_LIBBPF_SUPPORT
+static void perf_env__purge_bpf(struct perf_env *env __maybe_unused)
+{
+}
+#endif // HAVE_LIBBPF_SUPPORT
void perf_env__exit(struct perf_env *env)
{
@@ -197,11 +204,13 @@ void perf_env__exit(struct perf_env *env)
zfree(&env->memory_nodes);
}
-void perf_env__init(struct perf_env *env)
+void perf_env__init(struct perf_env *env __maybe_unused)
{
+#ifdef HAVE_LIBBPF_SUPPORT
env->bpf_progs.infos = RB_ROOT;
env->bpf_progs.btfs = RB_ROOT;
init_rwsem(&env->bpf_progs.lock);
+#endif
}
int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index a12972652006..ca249bf5e984 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -77,7 +77,7 @@ struct perf_env {
struct numa_node *numa_nodes;
struct memory_node *memory_nodes;
unsigned long long memory_bsize;
-
+#ifdef HAVE_LIBBPF_SUPPORT
/*
* bpf_info_lock protects bpf rbtrees. This is needed because the
* trees are accessed by different threads in perf-top
@@ -89,7 +89,7 @@ struct perf_env {
struct rb_root btfs;
u32 btfs_cnt;
} bpf_progs;
-
+#endif // HAVE_LIBBPF_SUPPORT
/* same reason as above (for perf-top) */
struct {
struct rw_semaphore lock;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index b828b99176f4..ff403ea578e1 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -135,6 +135,7 @@ struct perf_sample {
u32 raw_size;
u64 data_src;
u64 phys_addr;
+ u64 data_page_size;
u64 cgroup;
u32 flags;
u16 insn_len;
@@ -408,4 +409,7 @@ extern int sysctl_perf_event_max_stack;
extern int sysctl_perf_event_max_contexts_per_stack;
extern unsigned int proc_map_timeout;
+#define PAGE_SIZE_NAME_LEN 32
+char *get_page_size_name(u64 size, char *str);
+
#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 8bdf3d2c907c..05363a7247c4 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -78,7 +78,7 @@ struct evlist *evlist__new(void)
return evlist;
}
-struct evlist *perf_evlist__new_default(void)
+struct evlist *evlist__new_default(void)
{
struct evlist *evlist = evlist__new();
@@ -90,7 +90,7 @@ struct evlist *perf_evlist__new_default(void)
return evlist;
}
-struct evlist *perf_evlist__new_dummy(void)
+struct evlist *evlist__new_dummy(void)
{
struct evlist *evlist = evlist__new();
@@ -103,13 +103,13 @@ struct evlist *perf_evlist__new_dummy(void)
}
/**
- * perf_evlist__set_id_pos - set the positions of event ids.
+ * evlist__set_id_pos - set the positions of event ids.
* @evlist: selected event list
*
* Events with compatible sample types all have the same id_pos
* and is_pos. For convenience, put a copy on evlist.
*/
-void perf_evlist__set_id_pos(struct evlist *evlist)
+void evlist__set_id_pos(struct evlist *evlist)
{
struct evsel *first = evlist__first(evlist);
@@ -117,14 +117,14 @@ void perf_evlist__set_id_pos(struct evlist *evlist)
evlist->is_pos = first->is_pos;
}
-static void perf_evlist__update_id_pos(struct evlist *evlist)
+static void evlist__update_id_pos(struct evlist *evlist)
{
struct evsel *evsel;
evlist__for_each_entry(evlist, evsel)
evsel__calc_id_pos(evsel);
- perf_evlist__set_id_pos(evlist);
+ evlist__set_id_pos(evlist);
}
static void evlist__purge(struct evlist *evlist)
@@ -168,7 +168,7 @@ void evlist__add(struct evlist *evlist, struct evsel *entry)
perf_evlist__add(&evlist->core, &entry->core);
if (evlist->core.nr_entries == 1)
- perf_evlist__set_id_pos(evlist);
+ evlist__set_id_pos(evlist);
}
void evlist__remove(struct evlist *evlist, struct evsel *evsel)
@@ -177,27 +177,36 @@ void evlist__remove(struct evlist *evlist, struct evsel *evsel)
perf_evlist__remove(&evlist->core, &evsel->core);
}
-void perf_evlist__splice_list_tail(struct evlist *evlist,
- struct list_head *list)
+void evlist__splice_list_tail(struct evlist *evlist, struct list_head *list)
{
- struct evsel *evsel, *temp;
+ while (!list_empty(list)) {
+ struct evsel *evsel, *temp, *leader = NULL;
- __evlist__for_each_entry_safe(list, temp, evsel) {
- list_del_init(&evsel->core.node);
- evlist__add(evlist, evsel);
+ __evlist__for_each_entry_safe(list, temp, evsel) {
+ list_del_init(&evsel->core.node);
+ evlist__add(evlist, evsel);
+ leader = evsel;
+ break;
+ }
+
+ __evlist__for_each_entry_safe(list, temp, evsel) {
+ if (evsel->leader == leader) {
+ list_del_init(&evsel->core.node);
+ evlist__add(evlist, evsel);
+ }
+ }
}
}
int __evlist__set_tracepoints_handlers(struct evlist *evlist,
const struct evsel_str_handler *assocs, size_t nr_assocs)
{
- struct evsel *evsel;
size_t i;
int err;
for (i = 0; i < nr_assocs; i++) {
// Adding a handler for an event not in this evlist, just ignore it.
- evsel = perf_evlist__find_tracepoint_by_name(evlist, assocs[i].name);
+ struct evsel *evsel = evlist__find_tracepoint_by_name(evlist, assocs[i].name);
if (evsel == NULL)
continue;
@@ -212,7 +221,7 @@ out:
return err;
}
-void __perf_evlist__set_leader(struct list_head *list)
+void __evlist__set_leader(struct list_head *list)
{
struct evsel *evsel, *leader;
@@ -226,11 +235,11 @@ void __perf_evlist__set_leader(struct list_head *list)
}
}
-void perf_evlist__set_leader(struct evlist *evlist)
+void evlist__set_leader(struct evlist *evlist)
{
if (evlist->core.nr_entries) {
evlist->nr_groups = evlist->core.nr_entries > 1 ? 1 : 0;
- __perf_evlist__set_leader(&evlist->core.entries);
+ __evlist__set_leader(&evlist->core.entries);
}
}
@@ -274,7 +283,7 @@ static int evlist__add_attrs(struct evlist *evlist, struct perf_event_attr *attr
list_add_tail(&evsel->core.node, &head);
}
- perf_evlist__splice_list_tail(evlist, &head);
+ evlist__splice_list_tail(evlist, &head);
return 0;
@@ -294,8 +303,7 @@ int __evlist__add_default_attrs(struct evlist *evlist, struct perf_event_attr *a
return evlist__add_attrs(evlist, attrs, nr_attrs);
}
-struct evsel *
-perf_evlist__find_tracepoint_by_id(struct evlist *evlist, int id)
+struct evsel *evlist__find_tracepoint_by_id(struct evlist *evlist, int id)
{
struct evsel *evsel;
@@ -308,9 +316,7 @@ perf_evlist__find_tracepoint_by_id(struct evlist *evlist, int id)
return NULL;
}
-struct evsel *
-perf_evlist__find_tracepoint_by_name(struct evlist *evlist,
- const char *name)
+struct evsel *evlist__find_tracepoint_by_name(struct evlist *evlist, const char *name)
{
struct evsel *evsel;
@@ -335,8 +341,7 @@ int evlist__add_newtp(struct evlist *evlist, const char *sys, const char *name,
return 0;
}
-static int perf_evlist__nr_threads(struct evlist *evlist,
- struct evsel *evsel)
+static int evlist__nr_threads(struct evlist *evlist, struct evsel *evsel)
{
if (evsel->core.system_wide)
return 1;
@@ -376,7 +381,30 @@ bool evsel__cpu_iter_skip(struct evsel *ev, int cpu)
return true;
}
-void evlist__disable(struct evlist *evlist)
+static int evsel__strcmp(struct evsel *pos, char *evsel_name)
+{
+ if (!evsel_name)
+ return 0;
+ if (evsel__is_dummy_event(pos))
+ return 1;
+ return strcmp(pos->name, evsel_name);
+}
+
+static int evlist__is_enabled(struct evlist *evlist)
+{
+ struct evsel *pos;
+
+ evlist__for_each_entry(evlist, pos) {
+ if (!evsel__is_group_leader(pos) || !pos->core.fd)
+ continue;
+ /* If at least one event is enabled, evlist is enabled. */
+ if (!pos->disabled)
+ return true;
+ }
+ return false;
+}
+
+static void __evlist__disable(struct evlist *evlist, char *evsel_name)
{
struct evsel *pos;
struct affinity affinity;
@@ -392,6 +420,8 @@ void evlist__disable(struct evlist *evlist)
affinity__set(&affinity, cpu);
evlist__for_each_entry(evlist, pos) {
+ if (evsel__strcmp(pos, evsel_name))
+ continue;
if (evsel__cpu_iter_skip(pos, cpu))
continue;
if (pos->disabled || !evsel__is_group_leader(pos) || !pos->core.fd)
@@ -409,15 +439,34 @@ void evlist__disable(struct evlist *evlist)
affinity__cleanup(&affinity);
evlist__for_each_entry(evlist, pos) {
+ if (evsel__strcmp(pos, evsel_name))
+ continue;
if (!evsel__is_group_leader(pos) || !pos->core.fd)
continue;
pos->disabled = true;
}
- evlist->enabled = false;
+ /*
+ * If we disabled only single event, we need to check
+ * the enabled state of the evlist manually.
+ */
+ if (evsel_name)
+ evlist->enabled = evlist__is_enabled(evlist);
+ else
+ evlist->enabled = false;
}
-void evlist__enable(struct evlist *evlist)
+void evlist__disable(struct evlist *evlist)
+{
+ __evlist__disable(evlist, NULL);
+}
+
+void evlist__disable_evsel(struct evlist *evlist, char *evsel_name)
+{
+ __evlist__disable(evlist, evsel_name);
+}
+
+static void __evlist__enable(struct evlist *evlist, char *evsel_name)
{
struct evsel *pos;
struct affinity affinity;
@@ -430,6 +479,8 @@ void evlist__enable(struct evlist *evlist)
affinity__set(&affinity, cpu);
evlist__for_each_entry(evlist, pos) {
+ if (evsel__strcmp(pos, evsel_name))
+ continue;
if (evsel__cpu_iter_skip(pos, cpu))
continue;
if (!evsel__is_group_leader(pos) || !pos->core.fd)
@@ -439,24 +490,40 @@ void evlist__enable(struct evlist *evlist)
}
affinity__cleanup(&affinity);
evlist__for_each_entry(evlist, pos) {
+ if (evsel__strcmp(pos, evsel_name))
+ continue;
if (!evsel__is_group_leader(pos) || !pos->core.fd)
continue;
pos->disabled = false;
}
+ /*
+ * Even single event sets the 'enabled' for evlist,
+ * so the toggle can work properly and toggle to
+ * 'disabled' state.
+ */
evlist->enabled = true;
}
-void perf_evlist__toggle_enable(struct evlist *evlist)
+void evlist__enable(struct evlist *evlist)
+{
+ __evlist__enable(evlist, NULL);
+}
+
+void evlist__enable_evsel(struct evlist *evlist, char *evsel_name)
+{
+ __evlist__enable(evlist, evsel_name);
+}
+
+void evlist__toggle_enable(struct evlist *evlist)
{
(evlist->enabled ? evlist__disable : evlist__enable)(evlist);
}
-static int perf_evlist__enable_event_cpu(struct evlist *evlist,
- struct evsel *evsel, int cpu)
+static int evlist__enable_event_cpu(struct evlist *evlist, struct evsel *evsel, int cpu)
{
int thread;
- int nr_threads = perf_evlist__nr_threads(evlist, evsel);
+ int nr_threads = evlist__nr_threads(evlist, evsel);
if (!evsel->core.fd)
return -EINVAL;
@@ -469,9 +536,7 @@ static int perf_evlist__enable_event_cpu(struct evlist *evlist,
return 0;
}
-static int perf_evlist__enable_event_thread(struct evlist *evlist,
- struct evsel *evsel,
- int thread)
+static int evlist__enable_event_thread(struct evlist *evlist, struct evsel *evsel, int thread)
{
int cpu;
int nr_cpus = perf_cpu_map__nr(evlist->core.cpus);
@@ -487,15 +552,14 @@ static int perf_evlist__enable_event_thread(struct evlist *evlist,
return 0;
}
-int perf_evlist__enable_event_idx(struct evlist *evlist,
- struct evsel *evsel, int idx)
+int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel, int idx)
{
bool per_cpu_mmaps = !perf_cpu_map__empty(evlist->core.cpus);
if (per_cpu_mmaps)
- return perf_evlist__enable_event_cpu(evlist, evsel, idx);
- else
- return perf_evlist__enable_event_thread(evlist, evsel, idx);
+ return evlist__enable_event_cpu(evlist, evsel, idx);
+
+ return evlist__enable_event_thread(evlist, evsel, idx);
}
int evlist__add_pollfd(struct evlist *evlist, int fd)
@@ -513,7 +577,7 @@ int evlist__poll(struct evlist *evlist, int timeout)
return perf_evlist__poll(&evlist->core, timeout);
}
-struct perf_sample_id *perf_evlist__id2sid(struct evlist *evlist, u64 id)
+struct perf_sample_id *evlist__id2sid(struct evlist *evlist, u64 id)
{
struct hlist_head *head;
struct perf_sample_id *sid;
@@ -529,14 +593,14 @@ struct perf_sample_id *perf_evlist__id2sid(struct evlist *evlist, u64 id)
return NULL;
}
-struct evsel *perf_evlist__id2evsel(struct evlist *evlist, u64 id)
+struct evsel *evlist__id2evsel(struct evlist *evlist, u64 id)
{
struct perf_sample_id *sid;
if (evlist->core.nr_entries == 1 || !id)
return evlist__first(evlist);
- sid = perf_evlist__id2sid(evlist, id);
+ sid = evlist__id2sid(evlist, id);
if (sid)
return container_of(sid->evsel, struct evsel, core);
@@ -546,23 +610,21 @@ struct evsel *perf_evlist__id2evsel(struct evlist *evlist, u64 id)
return NULL;
}
-struct evsel *perf_evlist__id2evsel_strict(struct evlist *evlist,
- u64 id)
+struct evsel *evlist__id2evsel_strict(struct evlist *evlist, u64 id)
{
struct perf_sample_id *sid;
if (!id)
return NULL;
- sid = perf_evlist__id2sid(evlist, id);
+ sid = evlist__id2sid(evlist, id);
if (sid)
return container_of(sid->evsel, struct evsel, core);
return NULL;
}
-static int perf_evlist__event2id(struct evlist *evlist,
- union perf_event *event, u64 *id)
+static int evlist__event2id(struct evlist *evlist, union perf_event *event, u64 *id)
{
const __u64 *array = event->sample.array;
ssize_t n;
@@ -582,8 +644,7 @@ static int perf_evlist__event2id(struct evlist *evlist,
return 0;
}
-struct evsel *perf_evlist__event2evsel(struct evlist *evlist,
- union perf_event *event)
+struct evsel *evlist__event2evsel(struct evlist *evlist, union perf_event *event)
{
struct evsel *first = evlist__first(evlist);
struct hlist_head *head;
@@ -598,7 +659,7 @@ struct evsel *perf_evlist__event2evsel(struct evlist *evlist,
event->header.type != PERF_RECORD_SAMPLE)
return first;
- if (perf_evlist__event2id(evlist, event, &id))
+ if (evlist__event2id(evlist, event, &id))
return NULL;
/* Synthesized events have an id of zero */
@@ -615,7 +676,7 @@ struct evsel *perf_evlist__event2evsel(struct evlist *evlist,
return NULL;
}
-static int perf_evlist__set_paused(struct evlist *evlist, bool value)
+static int evlist__set_paused(struct evlist *evlist, bool value)
{
int i;
@@ -635,14 +696,14 @@ static int perf_evlist__set_paused(struct evlist *evlist, bool value)
return 0;
}
-static int perf_evlist__pause(struct evlist *evlist)
+static int evlist__pause(struct evlist *evlist)
{
- return perf_evlist__set_paused(evlist, true);
+ return evlist__set_paused(evlist, true);
}
-static int perf_evlist__resume(struct evlist *evlist)
+static int evlist__resume(struct evlist *evlist)
{
- return perf_evlist__set_paused(evlist, false);
+ return evlist__set_paused(evlist, false);
}
static void evlist__munmap_nofree(struct evlist *evlist)
@@ -727,7 +788,7 @@ perf_evlist__mmap_cb_get(struct perf_evlist *_evlist, bool overwrite, int idx)
if (overwrite) {
evlist->overwrite_mmap = maps;
if (evlist->bkw_mmap_state == BKW_MMAP_NOTREADY)
- perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_RUNNING);
+ evlist__toggle_bkw_mmap(evlist, BKW_MMAP_RUNNING);
} else {
evlist->mmap = maps;
}
@@ -827,7 +888,7 @@ static long parse_pages_arg(const char *str, unsigned long min,
return pages;
}
-int __perf_evlist__parse_mmap_pages(unsigned int *mmap_pages, const char *str)
+int __evlist__parse_mmap_pages(unsigned int *mmap_pages, const char *str)
{
unsigned long max = UINT_MAX;
long pages;
@@ -845,10 +906,9 @@ int __perf_evlist__parse_mmap_pages(unsigned int *mmap_pages, const char *str)
return 0;
}
-int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,
- int unset __maybe_unused)
+int evlist__parse_mmap_pages(const struct option *opt, const char *str, int unset __maybe_unused)
{
- return __perf_evlist__parse_mmap_pages(opt->value, str);
+ return __evlist__parse_mmap_pages(opt->value, str);
}
/**
@@ -904,7 +964,7 @@ int evlist__mmap(struct evlist *evlist, unsigned int pages)
return evlist__mmap_ex(evlist, pages, 0, false, 0, PERF_AFFINITY_SYS, 1, 0);
}
-int perf_evlist__create_maps(struct evlist *evlist, struct target *target)
+int evlist__create_maps(struct evlist *evlist, struct target *target)
{
bool all_threads = (target->per_thread && target->system_wide);
struct perf_cpu_map *cpus;
@@ -957,25 +1017,7 @@ out_delete_threads:
return -1;
}
-void __perf_evlist__set_sample_bit(struct evlist *evlist,
- enum perf_event_sample_format bit)
-{
- struct evsel *evsel;
-
- evlist__for_each_entry(evlist, evsel)
- __evsel__set_sample_bit(evsel, bit);
-}
-
-void __perf_evlist__reset_sample_bit(struct evlist *evlist,
- enum perf_event_sample_format bit)
-{
- struct evsel *evsel;
-
- evlist__for_each_entry(evlist, evsel)
- __evsel__reset_sample_bit(evsel, bit);
-}
-
-int perf_evlist__apply_filters(struct evlist *evlist, struct evsel **err_evsel)
+int evlist__apply_filters(struct evlist *evlist, struct evsel **err_evsel)
{
struct evsel *evsel;
int err = 0;
@@ -998,7 +1040,7 @@ int perf_evlist__apply_filters(struct evlist *evlist, struct evsel **err_evsel)
return err;
}
-int perf_evlist__set_tp_filter(struct evlist *evlist, const char *filter)
+int evlist__set_tp_filter(struct evlist *evlist, const char *filter)
{
struct evsel *evsel;
int err = 0;
@@ -1018,7 +1060,7 @@ int perf_evlist__set_tp_filter(struct evlist *evlist, const char *filter)
return err;
}
-int perf_evlist__append_tp_filter(struct evlist *evlist, const char *filter)
+int evlist__append_tp_filter(struct evlist *evlist, const char *filter)
{
struct evsel *evsel;
int err = 0;
@@ -1064,32 +1106,32 @@ out_free:
return NULL;
}
-int perf_evlist__set_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids)
+int evlist__set_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids)
{
char *filter = asprintf__tp_filter_pids(npids, pids);
- int ret = perf_evlist__set_tp_filter(evlist, filter);
+ int ret = evlist__set_tp_filter(evlist, filter);
free(filter);
return ret;
}
-int perf_evlist__set_tp_filter_pid(struct evlist *evlist, pid_t pid)
+int evlist__set_tp_filter_pid(struct evlist *evlist, pid_t pid)
{
- return perf_evlist__set_tp_filter_pids(evlist, 1, &pid);
+ return evlist__set_tp_filter_pids(evlist, 1, &pid);
}
-int perf_evlist__append_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids)
+int evlist__append_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids)
{
char *filter = asprintf__tp_filter_pids(npids, pids);
- int ret = perf_evlist__append_tp_filter(evlist, filter);
+ int ret = evlist__append_tp_filter(evlist, filter);
free(filter);
return ret;
}
-int perf_evlist__append_tp_filter_pid(struct evlist *evlist, pid_t pid)
+int evlist__append_tp_filter_pid(struct evlist *evlist, pid_t pid)
{
- return perf_evlist__append_tp_filter_pids(evlist, 1, &pid);
+ return evlist__append_tp_filter_pids(evlist, 1, &pid);
}
bool evlist__valid_sample_type(struct evlist *evlist)
@@ -1140,7 +1182,7 @@ u64 evlist__combined_branch_type(struct evlist *evlist)
return branch_type;
}
-bool perf_evlist__valid_read_format(struct evlist *evlist)
+bool evlist__valid_read_format(struct evlist *evlist)
{
struct evsel *first = evlist__first(evlist), *pos = first;
u64 read_format = first->core.attr.read_format;
@@ -1162,7 +1204,7 @@ bool perf_evlist__valid_read_format(struct evlist *evlist)
return true;
}
-u16 perf_evlist__id_hdr_size(struct evlist *evlist)
+u16 evlist__id_hdr_size(struct evlist *evlist)
{
struct evsel *first = evlist__first(evlist);
struct perf_sample *data;
@@ -1213,8 +1255,7 @@ bool evlist__sample_id_all(struct evlist *evlist)
return first->core.attr.sample_id_all;
}
-void perf_evlist__set_selected(struct evlist *evlist,
- struct evsel *evsel)
+void evlist__set_selected(struct evlist *evlist, struct evsel *evsel)
{
evlist->selected = evsel;
}
@@ -1253,7 +1294,7 @@ void evlist__close(struct evlist *evlist)
}
}
-static int perf_evlist__create_syswide_maps(struct evlist *evlist)
+static int evlist__create_syswide_maps(struct evlist *evlist)
{
struct perf_cpu_map *cpus;
struct perf_thread_map *threads;
@@ -1295,12 +1336,12 @@ int evlist__open(struct evlist *evlist)
* as sys_perf_event_open(cpu = -1, thread = -1) is EINVAL
*/
if (evlist->core.threads == NULL && evlist->core.cpus == NULL) {
- err = perf_evlist__create_syswide_maps(evlist);
+ err = evlist__create_syswide_maps(evlist);
if (err < 0)
goto out_err;
}
- perf_evlist__update_id_pos(evlist);
+ evlist__update_id_pos(evlist);
evlist__for_each_entry(evlist, evsel) {
err = evsel__open(evsel, evsel->core.cpus, evsel->core.threads);
@@ -1315,9 +1356,8 @@ out_err:
return err;
}
-int perf_evlist__prepare_workload(struct evlist *evlist, struct target *target,
- const char *argv[], bool pipe_output,
- void (*exec_error)(int signo, siginfo_t *info, void *ucontext))
+int evlist__prepare_workload(struct evlist *evlist, struct target *target, const char *argv[],
+ bool pipe_output, void (*exec_error)(int signo, siginfo_t *info, void *ucontext))
{
int child_ready_pipe[2], go_pipe[2];
char bf;
@@ -1362,7 +1402,7 @@ int perf_evlist__prepare_workload(struct evlist *evlist, struct target *target,
/*
* The parent will ask for the execvp() to be performed by
* writing exactly one byte, in workload.cork_fd, usually via
- * perf_evlist__start_workload().
+ * evlist__start_workload().
*
* For cancelling the workload without actually running it,
* the parent will just close workload.cork_fd, without writing
@@ -1429,7 +1469,7 @@ out_close_ready_pipe:
return -1;
}
-int perf_evlist__start_workload(struct evlist *evlist)
+int evlist__start_workload(struct evlist *evlist)
{
if (evlist->workload.cork_fd > 0) {
char bf = 0;
@@ -1448,21 +1488,18 @@ int perf_evlist__start_workload(struct evlist *evlist)
return 0;
}
-int perf_evlist__parse_sample(struct evlist *evlist, union perf_event *event,
- struct perf_sample *sample)
+int evlist__parse_sample(struct evlist *evlist, union perf_event *event, struct perf_sample *sample)
{
- struct evsel *evsel = perf_evlist__event2evsel(evlist, event);
+ struct evsel *evsel = evlist__event2evsel(evlist, event);
if (!evsel)
return -EFAULT;
return evsel__parse_sample(evsel, event, sample);
}
-int perf_evlist__parse_sample_timestamp(struct evlist *evlist,
- union perf_event *event,
- u64 *timestamp)
+int evlist__parse_sample_timestamp(struct evlist *evlist, union perf_event *event, u64 *timestamp)
{
- struct evsel *evsel = perf_evlist__event2evsel(evlist, event);
+ struct evsel *evsel = evlist__event2evsel(evlist, event);
if (!evsel)
return -EFAULT;
@@ -1553,8 +1590,7 @@ int evlist__strerror_mmap(struct evlist *evlist, int err, char *buf, size_t size
return 0;
}
-void perf_evlist__to_front(struct evlist *evlist,
- struct evsel *move_evsel)
+void evlist__to_front(struct evlist *evlist, struct evsel *move_evsel)
{
struct evsel *evsel, *n;
LIST_HEAD(move);
@@ -1570,7 +1606,7 @@ void perf_evlist__to_front(struct evlist *evlist,
list_splice(&move, &evlist->core.entries);
}
-struct evsel *perf_evlist__get_tracking_event(struct evlist *evlist)
+struct evsel *evlist__get_tracking_event(struct evlist *evlist)
{
struct evsel *evsel;
@@ -1582,8 +1618,7 @@ struct evsel *perf_evlist__get_tracking_event(struct evlist *evlist)
return evlist__first(evlist);
}
-void perf_evlist__set_tracking_event(struct evlist *evlist,
- struct evsel *tracking_evsel)
+void evlist__set_tracking_event(struct evlist *evlist, struct evsel *tracking_evsel)
{
struct evsel *evsel;
@@ -1598,9 +1633,7 @@ void perf_evlist__set_tracking_event(struct evlist *evlist,
tracking_evsel->tracking = true;
}
-struct evsel *
-perf_evlist__find_evsel_by_str(struct evlist *evlist,
- const char *str)
+struct evsel *evlist__find_evsel_by_str(struct evlist *evlist, const char *str)
{
struct evsel *evsel;
@@ -1614,8 +1647,7 @@ perf_evlist__find_evsel_by_str(struct evlist *evlist,
return NULL;
}
-void perf_evlist__toggle_bkw_mmap(struct evlist *evlist,
- enum bkw_mmap_state state)
+void evlist__toggle_bkw_mmap(struct evlist *evlist, enum bkw_mmap_state state)
{
enum bkw_mmap_state old_state = evlist->bkw_mmap_state;
enum action {
@@ -1658,10 +1690,10 @@ void perf_evlist__toggle_bkw_mmap(struct evlist *evlist,
switch (action) {
case PAUSE:
- perf_evlist__pause(evlist);
+ evlist__pause(evlist);
break;
case RESUME:
- perf_evlist__resume(evlist);
+ evlist__resume(evlist);
break;
case NONE:
default:
@@ -1672,7 +1704,7 @@ state_err:
return;
}
-bool perf_evlist__exclude_kernel(struct evlist *evlist)
+bool evlist__exclude_kernel(struct evlist *evlist)
{
struct evsel *evsel;
@@ -1689,19 +1721,17 @@ bool perf_evlist__exclude_kernel(struct evlist *evlist)
* the group display. Set the artificial group and set the leader's
* forced_leader flag to notify the display code.
*/
-void perf_evlist__force_leader(struct evlist *evlist)
+void evlist__force_leader(struct evlist *evlist)
{
if (!evlist->nr_groups) {
struct evsel *leader = evlist__first(evlist);
- perf_evlist__set_leader(evlist);
+ evlist__set_leader(evlist);
leader->forced_leader = true;
}
}
-struct evsel *perf_evlist__reset_weak_group(struct evlist *evsel_list,
- struct evsel *evsel,
- bool close)
+struct evsel *evlist__reset_weak_group(struct evlist *evsel_list, struct evsel *evsel, bool close)
{
struct evsel *c2, *leader;
bool is_open = true;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index e1a450322bc5..1aae75895dea 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -87,8 +87,8 @@ struct evsel_str_handler {
};
struct evlist *evlist__new(void);
-struct evlist *perf_evlist__new_default(void);
-struct evlist *perf_evlist__new_dummy(void);
+struct evlist *evlist__new_default(void);
+struct evlist *evlist__new_dummy(void);
void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
struct perf_thread_map *threads);
void evlist__exit(struct evlist *evlist);
@@ -112,14 +112,11 @@ int __evlist__add_default_attrs(struct evlist *evlist,
int evlist__add_dummy(struct evlist *evlist);
-int perf_evlist__add_sb_event(struct evlist *evlist,
- struct perf_event_attr *attr,
- evsel__sb_cb_t cb,
- void *data);
+int evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr,
+ evsel__sb_cb_t cb, void *data);
void evlist__set_cb(struct evlist *evlist, evsel__sb_cb_t cb, void *data);
-int perf_evlist__start_sb_thread(struct evlist *evlist,
- struct target *target);
-void perf_evlist__stop_sb_thread(struct evlist *evlist);
+int evlist__start_sb_thread(struct evlist *evlist, struct target *target);
+void evlist__stop_sb_thread(struct evlist *evlist);
int evlist__add_newtp(struct evlist *evlist, const char *sys, const char *name, void *handler);
@@ -130,45 +127,29 @@ int __evlist__set_tracepoints_handlers(struct evlist *evlist,
#define evlist__set_tracepoints_handlers(evlist, array) \
__evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array))
-void __perf_evlist__set_sample_bit(struct evlist *evlist,
- enum perf_event_sample_format bit);
-void __perf_evlist__reset_sample_bit(struct evlist *evlist,
- enum perf_event_sample_format bit);
+int evlist__set_tp_filter(struct evlist *evlist, const char *filter);
+int evlist__set_tp_filter_pid(struct evlist *evlist, pid_t pid);
+int evlist__set_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids);
-#define perf_evlist__set_sample_bit(evlist, bit) \
- __perf_evlist__set_sample_bit(evlist, PERF_SAMPLE_##bit)
+int evlist__append_tp_filter(struct evlist *evlist, const char *filter);
-#define perf_evlist__reset_sample_bit(evlist, bit) \
- __perf_evlist__reset_sample_bit(evlist, PERF_SAMPLE_##bit)
+int evlist__append_tp_filter_pid(struct evlist *evlist, pid_t pid);
+int evlist__append_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids);
-int perf_evlist__set_tp_filter(struct evlist *evlist, const char *filter);
-int perf_evlist__set_tp_filter_pid(struct evlist *evlist, pid_t pid);
-int perf_evlist__set_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids);
-
-int perf_evlist__append_tp_filter(struct evlist *evlist, const char *filter);
-
-int perf_evlist__append_tp_filter_pid(struct evlist *evlist, pid_t pid);
-int perf_evlist__append_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids);
-
-struct evsel *
-perf_evlist__find_tracepoint_by_id(struct evlist *evlist, int id);
-
-struct evsel *
-perf_evlist__find_tracepoint_by_name(struct evlist *evlist,
- const char *name);
+struct evsel *evlist__find_tracepoint_by_id(struct evlist *evlist, int id);
+struct evsel *evlist__find_tracepoint_by_name(struct evlist *evlist, const char *name);
int evlist__add_pollfd(struct evlist *evlist, int fd);
int evlist__filter_pollfd(struct evlist *evlist, short revents_and_mask);
int evlist__poll(struct evlist *evlist, int timeout);
-struct evsel *perf_evlist__id2evsel(struct evlist *evlist, u64 id);
-struct evsel *perf_evlist__id2evsel_strict(struct evlist *evlist,
- u64 id);
+struct evsel *evlist__id2evsel(struct evlist *evlist, u64 id);
+struct evsel *evlist__id2evsel_strict(struct evlist *evlist, u64 id);
-struct perf_sample_id *perf_evlist__id2sid(struct evlist *evlist, u64 id);
+struct perf_sample_id *evlist__id2sid(struct evlist *evlist, u64 id);
-void perf_evlist__toggle_bkw_mmap(struct evlist *evlist, enum bkw_mmap_state state);
+void evlist__toggle_bkw_mmap(struct evlist *evlist, enum bkw_mmap_state state);
void evlist__mmap_consume(struct evlist *evlist, int idx);
@@ -177,24 +158,19 @@ void evlist__close(struct evlist *evlist);
struct callchain_param;
-void perf_evlist__set_id_pos(struct evlist *evlist);
-void perf_evlist__config(struct evlist *evlist, struct record_opts *opts,
- struct callchain_param *callchain);
+void evlist__set_id_pos(struct evlist *evlist);
+void evlist__config(struct evlist *evlist, struct record_opts *opts, struct callchain_param *callchain);
int record_opts__config(struct record_opts *opts);
-int perf_evlist__prepare_workload(struct evlist *evlist,
- struct target *target,
- const char *argv[], bool pipe_output,
- void (*exec_error)(int signo, siginfo_t *info,
- void *ucontext));
-int perf_evlist__start_workload(struct evlist *evlist);
+int evlist__prepare_workload(struct evlist *evlist, struct target *target,
+ const char *argv[], bool pipe_output,
+ void (*exec_error)(int signo, siginfo_t *info, void *ucontext));
+int evlist__start_workload(struct evlist *evlist);
struct option;
-int __perf_evlist__parse_mmap_pages(unsigned int *mmap_pages, const char *str);
-int perf_evlist__parse_mmap_pages(const struct option *opt,
- const char *str,
- int unset);
+int __evlist__parse_mmap_pages(unsigned int *mmap_pages, const char *str);
+int evlist__parse_mmap_pages(const struct option *opt, const char *str, int unset);
unsigned long perf_event_mlock_kb_in_pages(void);
@@ -209,41 +185,36 @@ size_t evlist__mmap_size(unsigned long pages);
void evlist__disable(struct evlist *evlist);
void evlist__enable(struct evlist *evlist);
-void perf_evlist__toggle_enable(struct evlist *evlist);
+void evlist__toggle_enable(struct evlist *evlist);
+void evlist__disable_evsel(struct evlist *evlist, char *evsel_name);
+void evlist__enable_evsel(struct evlist *evlist, char *evsel_name);
-int perf_evlist__enable_event_idx(struct evlist *evlist,
- struct evsel *evsel, int idx);
+int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel, int idx);
-void perf_evlist__set_selected(struct evlist *evlist,
- struct evsel *evsel);
+void evlist__set_selected(struct evlist *evlist, struct evsel *evsel);
-int perf_evlist__create_maps(struct evlist *evlist, struct target *target);
-int perf_evlist__apply_filters(struct evlist *evlist, struct evsel **err_evsel);
+int evlist__create_maps(struct evlist *evlist, struct target *target);
+int evlist__apply_filters(struct evlist *evlist, struct evsel **err_evsel);
-void __perf_evlist__set_leader(struct list_head *list);
-void perf_evlist__set_leader(struct evlist *evlist);
+void __evlist__set_leader(struct list_head *list);
+void evlist__set_leader(struct evlist *evlist);
u64 __evlist__combined_sample_type(struct evlist *evlist);
u64 evlist__combined_sample_type(struct evlist *evlist);
u64 evlist__combined_branch_type(struct evlist *evlist);
bool evlist__sample_id_all(struct evlist *evlist);
-u16 perf_evlist__id_hdr_size(struct evlist *evlist);
-
-int perf_evlist__parse_sample(struct evlist *evlist, union perf_event *event,
- struct perf_sample *sample);
+u16 evlist__id_hdr_size(struct evlist *evlist);
-int perf_evlist__parse_sample_timestamp(struct evlist *evlist,
- union perf_event *event,
- u64 *timestamp);
+int evlist__parse_sample(struct evlist *evlist, union perf_event *event, struct perf_sample *sample);
+int evlist__parse_sample_timestamp(struct evlist *evlist, union perf_event *event, u64 *timestamp);
bool evlist__valid_sample_type(struct evlist *evlist);
bool evlist__valid_sample_id_all(struct evlist *evlist);
-bool perf_evlist__valid_read_format(struct evlist *evlist);
+bool evlist__valid_read_format(struct evlist *evlist);
-void perf_evlist__splice_list_tail(struct evlist *evlist,
- struct list_head *list);
+void evlist__splice_list_tail(struct evlist *evlist, struct list_head *list);
-static inline bool perf_evlist__empty(struct evlist *evlist)
+static inline bool evlist__empty(struct evlist *evlist)
{
return list_empty(&evlist->core.entries);
}
@@ -265,9 +236,8 @@ static inline struct evsel *evlist__last(struct evlist *evlist)
int evlist__strerror_open(struct evlist *evlist, int err, char *buf, size_t size);
int evlist__strerror_mmap(struct evlist *evlist, int err, char *buf, size_t size);
-bool perf_evlist__can_select_event(struct evlist *evlist, const char *str);
-void perf_evlist__to_front(struct evlist *evlist,
- struct evsel *move_evsel);
+bool evlist__can_select_event(struct evlist *evlist, const char *str);
+void evlist__to_front(struct evlist *evlist, struct evsel *move_evsel);
/**
* __evlist__for_each_entry - iterate thru all the evsels
@@ -339,27 +309,23 @@ void perf_evlist__to_front(struct evlist *evlist,
evlist__cpu_iter_start(evlist); \
perf_cpu_map__for_each_cpu (cpu, index, (evlist)->core.all_cpus)
-struct evsel *perf_evlist__get_tracking_event(struct evlist *evlist);
-void perf_evlist__set_tracking_event(struct evlist *evlist,
- struct evsel *tracking_evsel);
+struct evsel *evlist__get_tracking_event(struct evlist *evlist);
+void evlist__set_tracking_event(struct evlist *evlist, struct evsel *tracking_evsel);
void evlist__cpu_iter_start(struct evlist *evlist);
bool evsel__cpu_iter_skip(struct evsel *ev, int cpu);
bool evsel__cpu_iter_skip_no_inc(struct evsel *ev, int cpu);
-struct evsel *
-perf_evlist__find_evsel_by_str(struct evlist *evlist, const char *str);
+struct evsel *evlist__find_evsel_by_str(struct evlist *evlist, const char *str);
+
+struct evsel *evlist__event2evsel(struct evlist *evlist, union perf_event *event);
-struct evsel *perf_evlist__event2evsel(struct evlist *evlist,
- union perf_event *event);
+bool evlist__exclude_kernel(struct evlist *evlist);
-bool perf_evlist__exclude_kernel(struct evlist *evlist);
+void evlist__force_leader(struct evlist *evlist);
-void perf_evlist__force_leader(struct evlist *evlist);
+struct evsel *evlist__reset_weak_group(struct evlist *evlist, struct evsel *evsel, bool close);
-struct evsel *perf_evlist__reset_weak_group(struct evlist *evlist,
- struct evsel *evsel,
- bool close);
#define EVLIST_CTL_CMD_ENABLE_TAG "enable"
#define EVLIST_CTL_CMD_DISABLE_TAG "disable"
#define EVLIST_CTL_CMD_ACK_TAG "ack\n"
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 1cad6051d8b0..c26ea82220bd 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -497,7 +497,7 @@ static const char *__evsel__hw_name(u64 config)
return "unknown-hardware";
}
-static int perf_evsel__add_modifiers(struct evsel *evsel, char *bf, size_t size)
+static int evsel__add_modifiers(struct evsel *evsel, char *bf, size_t size)
{
int colon = 0, r = 0;
struct perf_event_attr *attr = &evsel->core.attr;
@@ -536,7 +536,7 @@ static int perf_evsel__add_modifiers(struct evsel *evsel, char *bf, size_t size)
static int evsel__hw_name(struct evsel *evsel, char *bf, size_t size)
{
int r = scnprintf(bf, size, "%s", __evsel__hw_name(evsel->core.attr.config));
- return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
+ return r + evsel__add_modifiers(evsel, bf + r, size - r);
}
const char *evsel__sw_names[PERF_COUNT_SW_MAX] = {
@@ -562,7 +562,7 @@ static const char *__evsel__sw_name(u64 config)
static int evsel__sw_name(struct evsel *evsel, char *bf, size_t size)
{
int r = scnprintf(bf, size, "%s", __evsel__sw_name(evsel->core.attr.config));
- return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
+ return r + evsel__add_modifiers(evsel, bf + r, size - r);
}
static int __evsel__bp_name(char *bf, size_t size, u64 addr, u64 type)
@@ -587,7 +587,7 @@ static int evsel__bp_name(struct evsel *evsel, char *bf, size_t size)
{
struct perf_event_attr *attr = &evsel->core.attr;
int r = __evsel__bp_name(bf, size, attr->bp_addr, attr->bp_type);
- return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
+ return r + evsel__add_modifiers(evsel, bf + r, size - r);
}
const char *evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX][EVSEL__MAX_ALIASES] = {
@@ -682,13 +682,13 @@ out_err:
static int evsel__hw_cache_name(struct evsel *evsel, char *bf, size_t size)
{
int ret = __evsel__hw_cache_name(evsel->core.attr.config, bf, size);
- return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret);
+ return ret + evsel__add_modifiers(evsel, bf + ret, size - ret);
}
static int evsel__raw_name(struct evsel *evsel, char *bf, size_t size)
{
int ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->core.attr.config);
- return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret);
+ return ret + evsel__add_modifiers(evsel, bf + ret, size - ret);
}
static int evsel__tool_name(char *bf, size_t size)
@@ -850,9 +850,7 @@ void evsel__config_callchain(struct evsel *evsel, struct record_opts *opts,
return __evsel__config_callchain(evsel, opts, param);
}
-static void
-perf_evsel__reset_callgraph(struct evsel *evsel,
- struct callchain_param *param)
+static void evsel__reset_callgraph(struct evsel *evsel, struct callchain_param *param)
{
struct perf_event_attr *attr = &evsel->core.attr;
@@ -988,7 +986,7 @@ static void evsel__apply_config_terms(struct evsel *evsel,
/* If global callgraph set, clear it */
if (callchain_param.enabled)
- perf_evsel__reset_callgraph(evsel, &callchain_param);
+ evsel__reset_callgraph(evsel, &callchain_param);
/* set perf-event callgraph */
if (param.enabled) {
@@ -1190,6 +1188,9 @@ void evsel__config(struct evsel *evsel, struct record_opts *opts,
evsel__set_sample_bit(evsel, CGROUP);
}
+ if (opts->sample_data_page_size)
+ evsel__set_sample_bit(evsel, DATA_PAGE_SIZE);
+
if (opts->record_switch_events)
attr->context_switch = track;
@@ -1434,9 +1435,7 @@ static int evsel__read_one(struct evsel *evsel, int cpu, int thread)
return perf_evsel__read(&evsel->core, cpu, thread, count);
}
-static void
-perf_evsel__set_count(struct evsel *counter, int cpu, int thread,
- u64 val, u64 ena, u64 run)
+static void evsel__set_count(struct evsel *counter, int cpu, int thread, u64 val, u64 ena, u64 run)
{
struct perf_counts_values *count;
@@ -1449,9 +1448,7 @@ perf_evsel__set_count(struct evsel *counter, int cpu, int thread,
perf_counts__set_loaded(counter->counts, cpu, thread, true);
}
-static int
-perf_evsel__process_group_data(struct evsel *leader,
- int cpu, int thread, u64 *data)
+static int evsel__process_group_data(struct evsel *leader, int cpu, int thread, u64 *data)
{
u64 read_format = leader->core.attr.read_format;
struct sample_read_value *v;
@@ -1470,18 +1467,16 @@ perf_evsel__process_group_data(struct evsel *leader,
v = (struct sample_read_value *) data;
- perf_evsel__set_count(leader, cpu, thread,
- v[0].value, ena, run);
+ evsel__set_count(leader, cpu, thread, v[0].value, ena, run);
for (i = 1; i < nr; i++) {
struct evsel *counter;
- counter = perf_evlist__id2evsel(leader->evlist, v[i].id);
+ counter = evlist__id2evsel(leader->evlist, v[i].id);
if (!counter)
return -EINVAL;
- perf_evsel__set_count(counter, cpu, thread,
- v[i].value, ena, run);
+ evsel__set_count(counter, cpu, thread, v[i].value, ena, run);
}
return 0;
@@ -1514,7 +1509,7 @@ static int evsel__read_group(struct evsel *leader, int cpu, int thread)
if (readn(FD(leader, cpu, thread), data, size) <= 0)
return -errno;
- return perf_evsel__process_group_data(leader, cpu, thread, data);
+ return evsel__process_group_data(leader, cpu, thread, data);
}
int evsel__read_counter(struct evsel *evsel, int cpu, int thread)
@@ -1567,9 +1562,7 @@ static int get_group_fd(struct evsel *evsel, int cpu, int thread)
return fd;
}
-static void perf_evsel__remove_fd(struct evsel *pos,
- int nr_cpus, int nr_threads,
- int thread_idx)
+static void evsel__remove_fd(struct evsel *pos, int nr_cpus, int nr_threads, int thread_idx)
{
for (int cpu = 0; cpu < nr_cpus; cpu++)
for (int thread = thread_idx; thread < nr_threads - 1; thread++)
@@ -1588,7 +1581,7 @@ static int update_fds(struct evsel *evsel,
evlist__for_each_entry(evsel->evlist, pos) {
nr_cpus = pos != evsel ? nr_cpus : cpu_idx;
- perf_evsel__remove_fd(pos, nr_cpus, nr_threads, thread_idx);
+ evsel__remove_fd(pos, nr_cpus, nr_threads, thread_idx);
/*
* Since fds for next evsel has not been created,
@@ -1880,7 +1873,12 @@ try_fallback:
* Must probe features in the order they were added to the
* perf_event_attr interface.
*/
- if (!perf_missing_features.cgroup && evsel->core.attr.cgroup) {
+ if (!perf_missing_features.data_page_size &&
+ (evsel->core.attr.sample_type & PERF_SAMPLE_DATA_PAGE_SIZE)) {
+ perf_missing_features.data_page_size = true;
+ pr_debug2_peo("Kernel has no PERF_SAMPLE_DATA_PAGE_SIZE support, bailing out\n");
+ goto out_close;
+ } else if (!perf_missing_features.cgroup && evsel->core.attr.cgroup) {
perf_missing_features.cgroup = true;
pr_debug2_peo("Kernel has no cgroup sampling support, bailing out\n");
goto out_close;
@@ -2365,6 +2363,12 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,
array++;
}
+ data->data_page_size = 0;
+ if (type & PERF_SAMPLE_DATA_PAGE_SIZE) {
+ data->data_page_size = *array;
+ array++;
+ }
+
if (type & PERF_SAMPLE_AUX) {
OVERFLOW_CHECK_u64(array);
sz = *array++;
@@ -2674,6 +2678,8 @@ int evsel__open_strerror(struct evsel *evsel, struct target *target,
"We found oprofile daemon running, please stop it and try again.");
break;
case EINVAL:
+ if (evsel->core.attr.sample_type & PERF_SAMPLE_DATA_PAGE_SIZE && perf_missing_features.data_page_size)
+ return scnprintf(msg, size, "Asking for the data page size isn't supported by this kernel.");
if (evsel->core.attr.write_backward && perf_missing_features.write_backward)
return scnprintf(msg, size, "Reading from overwrite event is not supported by this kernel.");
if (perf_missing_features.clockid)
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 79a860d8e3ee..cd1d8dd43199 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -144,6 +144,7 @@ struct perf_missing_features {
bool aux_output;
bool branch_hw_idx;
bool cgroup;
+ bool data_page_size;
};
extern struct perf_missing_features perf_missing_features;
diff --git a/tools/perf/util/evswitch.c b/tools/perf/util/evswitch.c
index 3ba72f743d3c..40cb56a9347d 100644
--- a/tools/perf/util/evswitch.c
+++ b/tools/perf/util/evswitch.c
@@ -41,7 +41,7 @@ static int evswitch__fprintf_enoent(FILE *fp, const char *evtype, const char *ev
int evswitch__init(struct evswitch *evswitch, struct evlist *evlist, FILE *fp)
{
if (evswitch->on_name) {
- evswitch->on = perf_evlist__find_evsel_by_str(evlist, evswitch->on_name);
+ evswitch->on = evlist__find_evsel_by_str(evlist, evswitch->on_name);
if (evswitch->on == NULL) {
evswitch__fprintf_enoent(fp, "on", evswitch->on_name);
return -ENOENT;
@@ -50,7 +50,7 @@ int evswitch__init(struct evswitch *evswitch, struct evlist *evlist, FILE *fp)
}
if (evswitch->off_name) {
- evswitch->off = perf_evlist__find_evsel_by_str(evlist, evswitch->off_name);
+ evswitch->off = evlist__find_evsel_by_str(evlist, evswitch->off_name);
if (evswitch->off == NULL) {
evswitch__fprintf_enoent(fp, "off", evswitch->off_name);
return -ENOENT;
diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
index 53482ef53c41..a850fd0be3ee 100644
--- a/tools/perf/util/expr.c
+++ b/tools/perf/util/expr.c
@@ -17,6 +17,29 @@
extern int expr_debug;
#endif
+struct expr_id_data {
+ union {
+ double val;
+ struct {
+ double val;
+ const char *metric_name;
+ const char *metric_expr;
+ } ref;
+ struct expr_id *parent;
+ };
+
+ enum {
+ /* Holding a double value. */
+ EXPR_ID_DATA__VALUE,
+ /* Reference to another metric. */
+ EXPR_ID_DATA__REF,
+ /* A reference but the value has been computed. */
+ EXPR_ID_DATA__REF_VALUE,
+ /* A parent is remembered for the recursion check. */
+ EXPR_ID_DATA__PARENT,
+ } kind;
+};
+
static size_t key_hash(const void *key, void *ctx __maybe_unused)
{
const char *str = (const char *)key;
@@ -48,6 +71,7 @@ int expr__add_id(struct expr_parse_ctx *ctx, const char *id)
return -ENOMEM;
data_ptr->parent = ctx->parent;
+ data_ptr->kind = EXPR_ID_DATA__PARENT;
ret = hashmap__set(&ctx->ids, id, data_ptr,
(const void **)&old_key, (void **)&old_data);
@@ -69,7 +93,7 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val)
if (!data_ptr)
return -ENOMEM;
data_ptr->val = val;
- data_ptr->is_ref = false;
+ data_ptr->kind = EXPR_ID_DATA__VALUE;
ret = hashmap__set(&ctx->ids, id, data_ptr,
(const void **)&old_key, (void **)&old_data);
@@ -114,8 +138,7 @@ int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref)
*/
data_ptr->ref.metric_name = ref->metric_name;
data_ptr->ref.metric_expr = ref->metric_expr;
- data_ptr->ref.counted = false;
- data_ptr->is_ref = true;
+ data_ptr->kind = EXPR_ID_DATA__REF;
ret = hashmap__set(&ctx->ids, name, data_ptr,
(const void **)&old_key, (void **)&old_data);
@@ -148,17 +171,30 @@ int expr__resolve_id(struct expr_parse_ctx *ctx, const char *id,
data = *datap;
- pr_debug2("lookup: is_ref %d, counted %d, val %f: %s\n",
- data->is_ref, data->ref.counted, data->val, id);
-
- if (data->is_ref && !data->ref.counted) {
- data->ref.counted = true;
+ switch (data->kind) {
+ case EXPR_ID_DATA__VALUE:
+ pr_debug2("lookup(%s): val %f\n", id, data->val);
+ break;
+ case EXPR_ID_DATA__PARENT:
+ pr_debug2("lookup(%s): parent %s\n", id, data->parent->id);
+ break;
+ case EXPR_ID_DATA__REF:
+ pr_debug2("lookup(%s): ref metric name %s\n", id,
+ data->ref.metric_name);
pr_debug("processing metric: %s ENTRY\n", id);
- if (expr__parse(&data->val, ctx, data->ref.metric_expr, 1)) {
+ data->kind = EXPR_ID_DATA__REF_VALUE;
+ if (expr__parse(&data->ref.val, ctx, data->ref.metric_expr, 1)) {
pr_debug("%s failed to count\n", id);
return -1;
}
pr_debug("processing metric: %s EXIT: %f\n", id, data->val);
+ break;
+ case EXPR_ID_DATA__REF_VALUE:
+ pr_debug2("lookup(%s): ref val %f metric name %s\n", id,
+ data->ref.val, data->ref.metric_name);
+ break;
+ default:
+ assert(0); /* Unreachable. */
}
return 0;
@@ -241,3 +277,17 @@ int expr__find_other(const char *expr, const char *one,
return ret;
}
+
+double expr_id_data__value(const struct expr_id_data *data)
+{
+ if (data->kind == EXPR_ID_DATA__VALUE)
+ return data->val;
+ assert(data->kind == EXPR_ID_DATA__REF_VALUE);
+ return data->ref.val;
+}
+
+struct expr_id *expr_id_data__parent(struct expr_id_data *data)
+{
+ assert(data->kind == EXPR_ID_DATA__PARENT);
+ return data->parent;
+}
diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
index fc2b5e824a66..dcf8d19b83c8 100644
--- a/tools/perf/util/expr.h
+++ b/tools/perf/util/expr.h
@@ -23,19 +23,7 @@ struct expr_parse_ctx {
struct expr_id *parent;
};
-struct expr_id_data {
- union {
- double val;
- struct {
- const char *metric_name;
- const char *metric_expr;
- bool counted;
- } ref;
- struct expr_id *parent;
- };
-
- bool is_ref;
-};
+struct expr_id_data;
struct expr_scanner_ctx {
int start_token;
@@ -57,4 +45,7 @@ int expr__parse(double *final_val, struct expr_parse_ctx *ctx,
int expr__find_other(const char *expr, const char *one,
struct expr_parse_ctx *ids, int runtime);
+double expr_id_data__value(const struct expr_id_data *data);
+struct expr_id *expr_id_data__parent(struct expr_id_data *data);
+
#endif
diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y
index d34b370391c6..b2ada8f8309a 100644
--- a/tools/perf/util/expr.y
+++ b/tools/perf/util/expr.y
@@ -93,7 +93,7 @@ expr: NUMBER
YYABORT;
}
- $$ = data->val;
+ $$ = expr_id_data__value(data);
free($1);
}
| expr '|' expr { $$ = (long)$1 | (long)$3; }
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index be850e9f8852..062383e225a3 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -19,7 +19,9 @@
#include <sys/utsname.h>
#include <linux/time64.h>
#include <dirent.h>
+#ifdef HAVE_LIBBPF_SUPPORT
#include <bpf/libbpf.h>
+#endif
#include <perf/cpumap.h>
#include "dso.h"
@@ -987,13 +989,6 @@ out:
up_read(&env->bpf_progs.lock);
return ret;
}
-#else // HAVE_LIBBPF_SUPPORT
-static int write_bpf_prog_info(struct feat_fd *ff __maybe_unused,
- struct evlist *evlist __maybe_unused)
-{
- return 0;
-}
-#endif // HAVE_LIBBPF_SUPPORT
static int write_bpf_btf(struct feat_fd *ff,
struct evlist *evlist __maybe_unused)
@@ -1027,6 +1022,7 @@ out:
up_read(&env->bpf_progs.lock);
return ret;
}
+#endif // HAVE_LIBBPF_SUPPORT
static int cpu_cache_level__sort(const void *a, const void *b)
{
@@ -1638,6 +1634,7 @@ static void print_dir_format(struct feat_fd *ff, FILE *fp)
fprintf(fp, "# directory data version : %"PRIu64"\n", data->dir.version);
}
+#ifdef HAVE_LIBBPF_SUPPORT
static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
{
struct perf_env *env = &ff->ph->env;
@@ -1683,6 +1680,7 @@ static void print_bpf_btf(struct feat_fd *ff, FILE *fp)
up_read(&env->bpf_progs.lock);
}
+#endif // HAVE_LIBBPF_SUPPORT
static void free_event_desc(struct evsel *events)
{
@@ -2265,8 +2263,7 @@ static int process_total_mem(struct feat_fd *ff, void *data __maybe_unused)
return 0;
}
-static struct evsel *
-perf_evlist__find_by_index(struct evlist *evlist, int idx)
+static struct evsel *evlist__find_by_index(struct evlist *evlist, int idx)
{
struct evsel *evsel;
@@ -2278,16 +2275,14 @@ perf_evlist__find_by_index(struct evlist *evlist, int idx)
return NULL;
}
-static void
-perf_evlist__set_event_name(struct evlist *evlist,
- struct evsel *event)
+static void evlist__set_event_name(struct evlist *evlist, struct evsel *event)
{
struct evsel *evsel;
if (!event->name)
return;
- evsel = perf_evlist__find_by_index(evlist, event->idx);
+ evsel = evlist__find_by_index(evlist, event->idx);
if (!evsel)
return;
@@ -2315,7 +2310,7 @@ process_event_desc(struct feat_fd *ff, void *data __maybe_unused)
}
for (evsel = events; evsel->core.attr.size; evsel++)
- perf_evlist__set_event_name(session->evlist, evsel);
+ evlist__set_event_name(session->evlist, evsel);
if (!session->data->is_pipe)
free_event_desc(events);
@@ -2938,12 +2933,6 @@ out:
up_write(&env->bpf_progs.lock);
return err;
}
-#else // HAVE_LIBBPF_SUPPORT
-static int process_bpf_prog_info(struct feat_fd *ff __maybe_unused, void *data __maybe_unused)
-{
- return 0;
-}
-#endif // HAVE_LIBBPF_SUPPORT
static int process_bpf_btf(struct feat_fd *ff, void *data __maybe_unused)
{
@@ -2990,6 +2979,7 @@ out:
free(node);
return err;
}
+#endif // HAVE_LIBBPF_SUPPORT
static int process_compressed(struct feat_fd *ff,
void *data __maybe_unused)
@@ -3120,8 +3110,10 @@ const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE] = {
FEAT_OPR(MEM_TOPOLOGY, mem_topology, true),
FEAT_OPR(CLOCKID, clockid, false),
FEAT_OPN(DIR_FORMAT, dir_format, false),
+#ifdef HAVE_LIBBPF_SUPPORT
FEAT_OPR(BPF_PROG_INFO, bpf_prog_info, false),
FEAT_OPR(BPF_BTF, bpf_btf, false),
+#endif
FEAT_OPR(COMPRESSED, compressed, false),
FEAT_OPR(CPU_PMU_CAPS, cpu_pmu_caps, false),
FEAT_OPR(CLOCK_DATA, clock_data, false),
@@ -3652,7 +3644,8 @@ static int perf_file_section__process(struct perf_file_section *section,
}
static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
- struct perf_header *ph, int fd,
+ struct perf_header *ph,
+ struct perf_data* data,
bool repipe)
{
struct feat_fd ff = {
@@ -3661,7 +3654,7 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
};
ssize_t ret;
- ret = readn(fd, header, sizeof(*header));
+ ret = perf_data__read(data, header, sizeof(*header));
if (ret <= 0)
return -1;
@@ -3684,8 +3677,7 @@ static int perf_header__read_pipe(struct perf_session *session)
struct perf_header *header = &session->header;
struct perf_pipe_file_header f_header;
- if (perf_file_header__read_pipe(&f_header, header,
- perf_data__fd(session->data),
+ if (perf_file_header__read_pipe(&f_header, header, session->data,
session->repipe) < 0) {
pr_debug("incompatible file format\n");
return -EINVAL;
@@ -3740,8 +3732,7 @@ static int read_attr(int fd, struct perf_header *ph,
return ret <= 0 ? -1 : 0;
}
-static int perf_evsel__prepare_tracepoint_event(struct evsel *evsel,
- struct tep_handle *pevent)
+static int evsel__prepare_tracepoint_event(struct evsel *evsel, struct tep_handle *pevent)
{
struct tep_event *event;
char bf[128];
@@ -3772,14 +3763,13 @@ static int perf_evsel__prepare_tracepoint_event(struct evsel *evsel,
return 0;
}
-static int perf_evlist__prepare_tracepoint_events(struct evlist *evlist,
- struct tep_handle *pevent)
+static int evlist__prepare_tracepoint_events(struct evlist *evlist, struct tep_handle *pevent)
{
struct evsel *pos;
evlist__for_each_entry(evlist, pos) {
if (pos->core.attr.type == PERF_TYPE_TRACEPOINT &&
- perf_evsel__prepare_tracepoint_event(pos, pevent))
+ evsel__prepare_tracepoint_event(pos, pevent))
return -1;
}
@@ -3888,8 +3878,7 @@ int perf_session__read_header(struct perf_session *session)
perf_header__process_sections(header, fd, &session->tevent,
perf_file_section__process);
- if (perf_evlist__prepare_tracepoint_events(session->evlist,
- session->tevent.pevent))
+ if (evlist__prepare_tracepoint_events(session->evlist, session->tevent.pevent))
goto out_delete_evlist;
return 0;
@@ -4037,7 +4026,7 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused,
evlist = *pevlist;
- evsel = perf_evlist__id2evsel(evlist, ev->id);
+ evsel = evlist__id2evsel(evlist, ev->id);
if (evsel == NULL)
return -EINVAL;
@@ -4110,8 +4099,7 @@ int perf_event__process_tracing_data(struct perf_session *session,
return -1;
}
- perf_evlist__prepare_tracepoint_events(session->evlist,
- session->tevent.pevent);
+ evlist__prepare_tracepoint_events(session->evlist, session->tevent.pevent);
return size_read + padding;
}
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 8a793e4c9400..a08fb9ea411b 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -188,6 +188,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
hists__new_col_len(hists, HISTC_MEM_PHYS_DADDR,
unresolved_col_width + 4 + 2);
+ hists__new_col_len(hists, HISTC_MEM_DATA_PAGE_SIZE,
+ unresolved_col_width + 4 + 2);
+
} else {
symlen = unresolved_col_width + 4 + 2;
hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, symlen);
@@ -2654,7 +2657,7 @@ void hist__account_cycles(struct branch_stack *bs, struct addr_location *al,
}
}
-size_t perf_evlist__fprintf_nr_events(struct evlist *evlist, FILE *fp)
+size_t evlist__fprintf_nr_events(struct evlist *evlist, FILE *fp)
{
struct evsel *pos;
size_t ret = 0;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 96b1c13bbccc..14f66330923d 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -56,6 +56,7 @@ enum hist_column {
HISTC_MEM_DADDR_SYMBOL,
HISTC_MEM_DADDR_DSO,
HISTC_MEM_PHYS_DADDR,
+ HISTC_MEM_DATA_PAGE_SIZE,
HISTC_MEM_LOCKED,
HISTC_MEM_TLB,
HISTC_MEM_LVL,
@@ -196,7 +197,7 @@ void hists__inc_nr_samples(struct hists *hists, bool filtered);
size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
int max_cols, float min_pcnt, FILE *fp,
bool ignore_callchains);
-size_t perf_evlist__fprintf_nr_events(struct evlist *evlist, FILE *fp);
+size_t evlist__fprintf_nr_events(struct evlist *evlist, FILE *fp);
void hists__filter_by_dso(struct hists *hists);
void hists__filter_by_thread(struct hists *hists);
@@ -464,12 +465,9 @@ int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel,
struct hist_browser_timer *hbt,
struct annotation_options *annotation_opts);
-int perf_evlist__tui_browse_hists(struct evlist *evlist, const char *help,
- struct hist_browser_timer *hbt,
- float min_pcnt,
- struct perf_env *env,
- bool warn_lost_event,
- struct annotation_options *annotation_options);
+int evlist__tui_browse_hists(struct evlist *evlist, const char *help, struct hist_browser_timer *hbt,
+ float min_pcnt, struct perf_env *env, bool warn_lost_event,
+ struct annotation_options *annotation_options);
int script_browse(const char *script_opt, struct evsel *evsel);
@@ -483,13 +481,13 @@ int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel,
struct annotation_options *annotation_opts);
#else
static inline
-int perf_evlist__tui_browse_hists(struct evlist *evlist __maybe_unused,
- const char *help __maybe_unused,
- struct hist_browser_timer *hbt __maybe_unused,
- float min_pcnt __maybe_unused,
- struct perf_env *env __maybe_unused,
- bool warn_lost_event __maybe_unused,
- struct annotation_options *annotation_options __maybe_unused)
+int evlist__tui_browse_hists(struct evlist *evlist __maybe_unused,
+ const char *help __maybe_unused,
+ struct hist_browser_timer *hbt __maybe_unused,
+ float min_pcnt __maybe_unused,
+ struct perf_env *env __maybe_unused,
+ bool warn_lost_event __maybe_unused,
+ struct annotation_options *annotation_options __maybe_unused)
{
return 0;
}
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index 3a0348caec7d..60214de42f31 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -2520,11 +2520,10 @@ static int intel_pt_sync_switch(struct intel_pt *pt, int cpu, pid_t tid,
static int intel_pt_process_switch(struct intel_pt *pt,
struct perf_sample *sample)
{
- struct evsel *evsel;
pid_t tid;
int cpu, ret;
+ struct evsel *evsel = evlist__id2evsel(pt->session->evlist, sample->id);
- evsel = perf_evlist__id2evsel(pt->session->evlist, sample->id);
if (evsel != pt->switch_evsel)
return 0;
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 15385ea00190..f841f3503cae 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1581,32 +1581,25 @@ static bool machine__uses_kcore(struct machine *machine)
}
static bool perf_event__is_extra_kernel_mmap(struct machine *machine,
- union perf_event *event)
+ struct extra_kernel_map *xm)
{
return machine__is(machine, "x86_64") &&
- is_entry_trampoline(event->mmap.filename);
+ is_entry_trampoline(xm->name);
}
static int machine__process_extra_kernel_map(struct machine *machine,
- union perf_event *event)
+ struct extra_kernel_map *xm)
{
struct dso *kernel = machine__kernel_dso(machine);
- struct extra_kernel_map xm = {
- .start = event->mmap.start,
- .end = event->mmap.start + event->mmap.len,
- .pgoff = event->mmap.pgoff,
- };
if (kernel == NULL)
return -1;
- strlcpy(xm.name, event->mmap.filename, KMAP_NAME_LEN);
-
- return machine__create_extra_kernel_map(machine, kernel, &xm);
+ return machine__create_extra_kernel_map(machine, kernel, xm);
}
static int machine__process_kernel_mmap_event(struct machine *machine,
- union perf_event *event)
+ struct extra_kernel_map *xm)
{
struct map *map;
enum dso_space_type dso_space;
@@ -1621,20 +1614,18 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
else
dso_space = DSO_SPACE__KERNEL_GUEST;
- is_kernel_mmap = memcmp(event->mmap.filename,
- machine->mmap_name,
+ is_kernel_mmap = memcmp(xm->name, machine->mmap_name,
strlen(machine->mmap_name) - 1) == 0;
- if (event->mmap.filename[0] == '/' ||
- (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
- map = machine__addnew_module_map(machine, event->mmap.start,
- event->mmap.filename);
+ if (xm->name[0] == '/' ||
+ (!is_kernel_mmap && xm->name[0] == '[')) {
+ map = machine__addnew_module_map(machine, xm->start,
+ xm->name);
if (map == NULL)
goto out_problem;
- map->end = map->start + event->mmap.len;
+ map->end = map->start + xm->end - xm->start;
} else if (is_kernel_mmap) {
- const char *symbol_name = (event->mmap.filename +
- strlen(machine->mmap_name));
+ const char *symbol_name = (xm->name + strlen(machine->mmap_name));
/*
* Should be there already, from the build-id table in
* the header.
@@ -1688,18 +1679,17 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
if (strstr(kernel->long_name, "vmlinux"))
dso__set_short_name(kernel, "[kernel.vmlinux]", false);
- machine__update_kernel_mmap(machine, event->mmap.start,
- event->mmap.start + event->mmap.len);
+ machine__update_kernel_mmap(machine, xm->start, xm->end);
/*
* Avoid using a zero address (kptr_restrict) for the ref reloc
* symbol. Effectively having zero here means that at record
* time /proc/sys/kernel/kptr_restrict was non zero.
*/
- if (event->mmap.pgoff != 0) {
+ if (xm->pgoff != 0) {
map__set_kallsyms_ref_reloc_sym(machine->vmlinux_map,
symbol_name,
- event->mmap.pgoff);
+ xm->pgoff);
}
if (machine__is_default_guest(machine)) {
@@ -1708,8 +1698,8 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
*/
dso__load(kernel, machine__kernel_map(machine));
}
- } else if (perf_event__is_extra_kernel_mmap(machine, event)) {
- return machine__process_extra_kernel_map(machine, event);
+ } else if (perf_event__is_extra_kernel_mmap(machine, xm)) {
+ return machine__process_extra_kernel_map(machine, xm);
}
return 0;
out_problem:
@@ -1735,7 +1725,14 @@ int machine__process_mmap2_event(struct machine *machine,
if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
sample->cpumode == PERF_RECORD_MISC_KERNEL) {
- ret = machine__process_kernel_mmap_event(machine, event);
+ struct extra_kernel_map xm = {
+ .start = event->mmap2.start,
+ .end = event->mmap2.start + event->mmap2.len,
+ .pgoff = event->mmap2.pgoff,
+ };
+
+ strlcpy(xm.name, event->mmap2.filename, KMAP_NAME_LEN);
+ ret = machine__process_kernel_mmap_event(machine, &xm);
if (ret < 0)
goto out_problem;
return 0;
@@ -1785,7 +1782,14 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
sample->cpumode == PERF_RECORD_MISC_KERNEL) {
- ret = machine__process_kernel_mmap_event(machine, event);
+ struct extra_kernel_map xm = {
+ .start = event->mmap.start,
+ .end = event->mmap.start + event->mmap.len,
+ .pgoff = event->mmap.pgoff,
+ };
+
+ strlcpy(xm.name, event->mmap.filename, KMAP_NAME_LEN);
+ ret = machine__process_kernel_mmap_event(machine, &xm);
if (ret < 0)
goto out_problem;
return 0;
@@ -2019,11 +2023,12 @@ static void ip__resolve_ams(struct thread *thread,
ams->ms.sym = al.sym;
ams->ms.map = al.map;
ams->phys_addr = 0;
+ ams->data_page_size = 0;
}
static void ip__resolve_data(struct thread *thread,
u8 m, struct addr_map_symbol *ams,
- u64 addr, u64 phys_addr)
+ u64 addr, u64 phys_addr, u64 daddr_page_size)
{
struct addr_location al;
@@ -2037,6 +2042,7 @@ static void ip__resolve_data(struct thread *thread,
ams->ms.sym = al.sym;
ams->ms.map = al.map;
ams->phys_addr = phys_addr;
+ ams->data_page_size = daddr_page_size;
}
struct mem_info *sample__resolve_mem(struct perf_sample *sample,
@@ -2049,7 +2055,8 @@ struct mem_info *sample__resolve_mem(struct perf_sample *sample,
ip__resolve_ams(al->thread, &mi->iaddr, sample->ip);
ip__resolve_data(al->thread, al->cpumode, &mi->daddr,
- sample->addr, sample->phys_addr);
+ sample->addr, sample->phys_addr,
+ sample->data_page_size);
mi->data_src.val = sample->data_src;
return mi;
diff --git a/tools/perf/util/map_symbol.h b/tools/perf/util/map_symbol.h
index 5b8ca93798e9..7d22ade082c8 100644
--- a/tools/perf/util/map_symbol.h
+++ b/tools/perf/util/map_symbol.h
@@ -19,5 +19,6 @@ struct addr_map_symbol {
u64 addr;
u64 al_addr;
u64 phys_addr;
+ u64 data_page_size;
};
#endif // __PERF_MAP_SYMBOL
diff --git a/tools/perf/util/mem-events.c b/tools/perf/util/mem-events.c
index ea0af0bc4314..19007e463b8a 100644
--- a/tools/perf/util/mem-events.c
+++ b/tools/perf/util/mem-events.c
@@ -17,9 +17,10 @@ unsigned int perf_mem_events__loads_ldlat = 30;
#define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
-struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
- E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "mem-loads"),
- E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"),
+static struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
+ E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "cpu/events/mem-loads"),
+ E("ldlat-stores", "cpu/mem-stores/P", "cpu/events/mem-stores"),
+ E(NULL, NULL, NULL),
};
#undef E
@@ -28,19 +29,31 @@ struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
static char mem_loads_name[100];
static bool mem_loads_name__init;
+struct perf_mem_event * __weak perf_mem_events__ptr(int i)
+{
+ if (i >= PERF_MEM_EVENTS__MAX)
+ return NULL;
+
+ return &perf_mem_events[i];
+}
+
char * __weak perf_mem_events__name(int i)
{
+ struct perf_mem_event *e = perf_mem_events__ptr(i);
+
+ if (!e)
+ return NULL;
+
if (i == PERF_MEM_EVENTS__LOAD) {
if (!mem_loads_name__init) {
mem_loads_name__init = true;
scnprintf(mem_loads_name, sizeof(mem_loads_name),
- perf_mem_events[i].name,
- perf_mem_events__loads_ldlat);
+ e->name, perf_mem_events__loads_ldlat);
}
return mem_loads_name;
}
- return (char *)perf_mem_events[i].name;
+ return (char *)e->name;
}
int perf_mem_events__parse(const char *str)
@@ -61,7 +74,10 @@ int perf_mem_events__parse(const char *str)
while (tok) {
for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
- struct perf_mem_event *e = &perf_mem_events[j];
+ struct perf_mem_event *e = perf_mem_events__ptr(j);
+
+ if (!e->tag)
+ continue;
if (strstr(e->tag, tok))
e->record = found = true;
@@ -90,10 +106,17 @@ int perf_mem_events__init(void)
for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
char path[PATH_MAX];
- struct perf_mem_event *e = &perf_mem_events[j];
+ struct perf_mem_event *e = perf_mem_events__ptr(j);
struct stat st;
- scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s",
+ /*
+ * If the event entry isn't valid, skip initialization
+ * and "e->supported" will keep false.
+ */
+ if (!e->tag)
+ continue;
+
+ scnprintf(path, PATH_MAX, "%s/devices/%s",
mnt, e->sysfs_name);
if (!stat(path, &st))
@@ -108,10 +131,10 @@ void perf_mem_events__list(void)
int j;
for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
- struct perf_mem_event *e = &perf_mem_events[j];
+ struct perf_mem_event *e = perf_mem_events__ptr(j);
fprintf(stderr, "%-13s%-*s%s\n",
- e->tag,
+ e->tag ?: "",
verbose > 0 ? 25 : 0,
verbose > 0 ? perf_mem_events__name(j) : "",
e->supported ? ": available" : "");
diff --git a/tools/perf/util/mem-events.h b/tools/perf/util/mem-events.h
index 904dad34f7f7..5ef178278909 100644
--- a/tools/perf/util/mem-events.h
+++ b/tools/perf/util/mem-events.h
@@ -28,16 +28,17 @@ struct mem_info {
enum {
PERF_MEM_EVENTS__LOAD,
PERF_MEM_EVENTS__STORE,
+ PERF_MEM_EVENTS__LOAD_STORE,
PERF_MEM_EVENTS__MAX,
};
-extern struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX];
extern unsigned int perf_mem_events__loads_ldlat;
int perf_mem_events__parse(const char *str);
int perf_mem_events__init(void);
char *perf_mem_events__name(int i);
+struct perf_mem_event *perf_mem_events__ptr(int i);
void perf_mem_events__list(void);
diff --git a/tools/perf/util/mem2node.c b/tools/perf/util/mem2node.c
index c84f5841c7ab..03a7d7b27737 100644
--- a/tools/perf/util/mem2node.c
+++ b/tools/perf/util/mem2node.c
@@ -96,7 +96,8 @@ int mem2node__init(struct mem2node *map, struct perf_env *env)
/* Cut unused entries, due to merging. */
tmp_entries = realloc(entries, sizeof(*entries) * j);
- if (tmp_entries || WARN_ON_ONCE(j == 0))
+ if (tmp_entries ||
+ WARN_ONCE(j == 0, "No memory nodes, is CONFIG_MEMORY_HOTPLUG enabled?\n"))
entries = tmp_entries;
for (i = 0; i < j; i++) {
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 060454a17293..ee94d3e8dd65 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -279,7 +279,9 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist,
* when then group is left.
*/
if (!has_constraint &&
- ev->leader != metric_events[i]->leader)
+ ev->leader != metric_events[i]->leader &&
+ !strcmp(ev->leader->pmu_name,
+ metric_events[i]->leader->pmu_name))
break;
if (!strcmp(metric_events[i]->name, ev->name)) {
set_bit(ev->idx, evlist_used);
@@ -413,6 +415,12 @@ static bool match_metric(const char *n, const char *list)
return false;
}
+static bool match_pe_metric(struct pmu_event *pe, const char *metric)
+{
+ return match_metric(pe->metric_group, metric) ||
+ match_metric(pe->metric_name, metric);
+}
+
struct mep {
struct rb_node nd;
const char *name;
@@ -491,6 +499,115 @@ static void metricgroup__print_strlist(struct strlist *metrics, bool raw)
putchar('\n');
}
+static int metricgroup__print_pmu_event(struct pmu_event *pe,
+ bool metricgroups, char *filter,
+ bool raw, bool details,
+ struct rblist *groups,
+ struct strlist *metriclist)
+{
+ const char *g;
+ char *omg, *mg;
+
+ g = pe->metric_group;
+ if (!g && pe->metric_name) {
+ if (pe->name)
+ return 0;
+ g = "No_group";
+ }
+
+ if (!g)
+ return 0;
+
+ mg = strdup(g);
+
+ if (!mg)
+ return -ENOMEM;
+ omg = mg;
+ while ((g = strsep(&mg, ";")) != NULL) {
+ struct mep *me;
+ char *s;
+
+ g = skip_spaces(g);
+ if (*g == 0)
+ g = "No_group";
+ if (filter && !strstr(g, filter))
+ continue;
+ if (raw)
+ s = (char *)pe->metric_name;
+ else {
+ if (asprintf(&s, "%s\n%*s%s]",
+ pe->metric_name, 8, "[", pe->desc) < 0)
+ return -1;
+ if (details) {
+ if (asprintf(&s, "%s\n%*s%s]",
+ s, 8, "[", pe->metric_expr) < 0)
+ return -1;
+ }
+ }
+
+ if (!s)
+ continue;
+
+ if (!metricgroups) {
+ strlist__add(metriclist, s);
+ } else {
+ me = mep_lookup(groups, g);
+ if (!me)
+ continue;
+ strlist__add(me->metrics, s);
+ }
+
+ if (!raw)
+ free(s);
+ }
+ free(omg);
+
+ return 0;
+}
+
+struct metricgroup_print_sys_idata {
+ struct strlist *metriclist;
+ char *filter;
+ struct rblist *groups;
+ bool metricgroups;
+ bool raw;
+ bool details;
+};
+
+typedef int (*metricgroup_sys_event_iter_fn)(struct pmu_event *pe, void *);
+
+struct metricgroup_iter_data {
+ metricgroup_sys_event_iter_fn fn;
+ void *data;
+};
+
+static int metricgroup__sys_event_iter(struct pmu_event *pe, void *data)
+{
+ struct metricgroup_iter_data *d = data;
+ struct perf_pmu *pmu = NULL;
+
+ if (!pe->metric_expr || !pe->compat)
+ return 0;
+
+ while ((pmu = perf_pmu__scan(pmu))) {
+
+ if (!pmu->id || strcmp(pmu->id, pe->compat))
+ continue;
+
+ return d->fn(pe, d->data);
+ }
+
+ return 0;
+}
+
+static int metricgroup__print_sys_event_iter(struct pmu_event *pe, void *data)
+{
+ struct metricgroup_print_sys_idata *d = data;
+
+ return metricgroup__print_pmu_event(pe, d->metricgroups, d->filter, d->raw,
+ d->details, d->groups, d->metriclist);
+}
+
void metricgroup__print(bool metrics, bool metricgroups, char *filter,
bool raw, bool details)
{
@@ -501,9 +618,6 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
struct rb_node *node, *next;
struct strlist *metriclist = NULL;
- if (!map)
- return;
-
if (!metricgroups) {
metriclist = strlist__new(NULL, NULL);
if (!metriclist)
@@ -514,67 +628,33 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
groups.node_new = mep_new;
groups.node_cmp = mep_cmp;
groups.node_delete = mep_delete;
- for (i = 0; ; i++) {
- const char *g;
+ for (i = 0; map; i++) {
pe = &map->table[i];
if (!pe->name && !pe->metric_group && !pe->metric_name)
break;
if (!pe->metric_expr)
continue;
- g = pe->metric_group;
- if (!g && pe->metric_name) {
- if (pe->name)
- continue;
- g = "No_group";
- }
- if (g) {
- char *omg;
- char *mg = strdup(g);
-
- if (!mg)
- return;
- omg = mg;
- while ((g = strsep(&mg, ";")) != NULL) {
- struct mep *me;
- char *s;
-
- g = skip_spaces(g);
- if (*g == 0)
- g = "No_group";
- if (filter && !strstr(g, filter))
- continue;
- if (raw)
- s = (char *)pe->metric_name;
- else {
- if (asprintf(&s, "%s\n%*s%s]",
- pe->metric_name, 8, "[", pe->desc) < 0)
- return;
-
- if (details) {
- if (asprintf(&s, "%s\n%*s%s]",
- s, 8, "[", pe->metric_expr) < 0)
- return;
- }
- }
-
- if (!s)
- continue;
+ if (metricgroup__print_pmu_event(pe, metricgroups, filter,
+ raw, details, &groups,
+ metriclist) < 0)
+ return;
+ }
- if (!metricgroups) {
- strlist__add(metriclist, s);
- } else {
- me = mep_lookup(&groups, g);
- if (!me)
- continue;
- strlist__add(me->metrics, s);
- }
+ {
+ struct metricgroup_iter_data data = {
+ .fn = metricgroup__print_sys_event_iter,
+ .data = (void *) &(struct metricgroup_print_sys_idata){
+ .metriclist = metriclist,
+ .metricgroups = metricgroups,
+ .filter = filter,
+ .raw = raw,
+ .details = details,
+ .groups = &groups,
+ },
+ };
- if (!raw)
- free(s);
- }
- free(omg);
- }
+ pmu_for_each_sys_event(metricgroup__sys_event_iter, &data);
}
if (!filter || !rblist__empty(&groups)) {
@@ -683,6 +763,16 @@ int __weak arch_get_runtimeparam(struct pmu_event *pe __maybe_unused)
return 1;
}
+struct metricgroup_add_iter_data {
+ struct list_head *metric_list;
+ const char *metric;
+ struct metric **m;
+ struct expr_ids *ids;
+ int *ret;
+ bool *has_match;
+ bool metric_no_group;
+};
+
static int __add_metric(struct list_head *metric_list,
struct pmu_event *pe,
bool metric_no_group,
@@ -792,10 +882,11 @@ static int __add_metric(struct list_head *metric_list,
return 0;
}
-#define map_for_each_event(__pe, __idx, __map) \
- for (__idx = 0, __pe = &__map->table[__idx]; \
- __pe->name || __pe->metric_group || __pe->metric_name; \
- __pe = &__map->table[++__idx])
+#define map_for_each_event(__pe, __idx, __map) \
+ if (__map) \
+ for (__idx = 0, __pe = &__map->table[__idx]; \
+ __pe->name || __pe->metric_group || __pe->metric_name; \
+ __pe = &__map->table[++__idx])
#define map_for_each_metric(__pe, __idx, __map, __metric) \
map_for_each_event(__pe, __idx, __map) \
@@ -833,7 +924,7 @@ static int recursion_check(struct metric *m, const char *id, struct expr_id **pa
if (ret)
return ret;
- p = data->parent;
+ p = expr_id_data__parent(data);
while (p->parent) {
if (!strcmp(p->id, id)) {
@@ -854,7 +945,7 @@ static int recursion_check(struct metric *m, const char *id, struct expr_id **pa
}
p->id = strdup(id);
- p->parent = data->parent;
+ p->parent = expr_id_data__parent(data);
*parent = p;
return p->id ? 0 : -ENOMEM;
@@ -963,6 +1054,29 @@ static int add_metric(struct list_head *metric_list,
return ret;
}
+static int metricgroup__add_metric_sys_event_iter(struct pmu_event *pe,
+ void *data)
+{
+ struct metricgroup_add_iter_data *d = data;
+ int ret;
+
+ if (!match_pe_metric(pe, d->metric))
+ return 0;
+
+ ret = add_metric(d->metric_list, pe, d->metric_no_group, d->m, NULL, d->ids);
+ if (ret)
+ return ret;
+
+ ret = resolve_metric(d->metric_no_group,
+ d->metric_list, NULL, d->ids);
+ if (ret)
+ return ret;
+
+ *(d->has_match) = true;
+
+ return *d->ret;
+}
+
static int metricgroup__add_metric(const char *metric, bool metric_no_group,
struct strbuf *events,
struct list_head *metric_list,
@@ -993,6 +1107,22 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group,
goto out;
}
+ {
+ struct metricgroup_iter_data data = {
+ .fn = metricgroup__add_metric_sys_event_iter,
+ .data = (void *) &(struct metricgroup_add_iter_data) {
+ .metric_list = &list,
+ .metric = metric,
+ .metric_no_group = metric_no_group,
+ .m = &m,
+ .ids = &ids,
+ .has_match = &has_match,
+ .ret = &ret,
+ },
+ };
+
+ pmu_for_each_sys_event(metricgroup__sys_event_iter, &data);
+ }
/* End of pmu events. */
if (!has_match) {
ret = -EINVAL;
@@ -1119,8 +1249,6 @@ int metricgroup__parse_groups(const struct option *opt,
struct evlist *perf_evlist = *(struct evlist **)opt->value;
struct pmu_events_map *map = perf_pmu__find_map(NULL);
- if (!map)
- return 0;
return parse_groups(perf_evlist, str, metric_no_group,
metric_no_merge, NULL, metric_events, map);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 3b273580fb84..42c84adeb2fb 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -668,6 +668,7 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx,
return ret;
}
+#ifdef HAVE_LIBBPF_SUPPORT
struct __add_bpf_event_param {
struct parse_events_state *parse_state;
struct list_head *list;
@@ -900,6 +901,30 @@ int parse_events_load_bpf(struct parse_events_state *parse_state,
list_splice_tail(&obj_head_config, head_config);
return err;
}
+#else // HAVE_LIBBPF_SUPPORT
+int parse_events_load_bpf_obj(struct parse_events_state *parse_state,
+ struct list_head *list __maybe_unused,
+ struct bpf_object *obj __maybe_unused,
+ struct list_head *head_config __maybe_unused)
+{
+ parse_events__handle_error(parse_state->error, 0,
+ strdup("BPF support is not compiled"),
+ strdup("Make sure libbpf-devel is available at build time."));
+ return -ENOTSUP;
+}
+
+int parse_events_load_bpf(struct parse_events_state *parse_state,
+ struct list_head *list __maybe_unused,
+ char *bpf_file_name __maybe_unused,
+ bool source __maybe_unused,
+ struct list_head *head_config __maybe_unused)
+{
+ parse_events__handle_error(parse_state->error, 0,
+ strdup("BPF support is not compiled"),
+ strdup("Make sure libbpf-devel is available at build time."));
+ return -ENOTSUP;
+}
+#endif // HAVE_LIBBPF_SUPPORT
static int
parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
@@ -1744,7 +1769,7 @@ void parse_events__set_leader(char *name, struct list_head *list,
if (parse_events__set_leader_for_uncore_aliase(name, list, parse_state))
return;
- __perf_evlist__set_leader(list);
+ __evlist__set_leader(list);
leader = list_entry(list->next, struct evsel, core.node);
leader->group_name = name ? strdup(name) : NULL;
}
@@ -2158,7 +2183,7 @@ int __parse_events(struct evlist *evlist, const char *str,
/*
* Add list to the evlist even with errors to allow callers to clean up.
*/
- perf_evlist__splice_list_tail(evlist, &parse_state.list);
+ evlist__splice_list_tail(evlist, &parse_state.list);
if (!ret) {
struct evsel *last;
diff --git a/tools/perf/util/parse-regs-options.c b/tools/perf/util/parse-regs-options.c
index e687497b3aac..a4a100425b3a 100644
--- a/tools/perf/util/parse-regs-options.c
+++ b/tools/perf/util/parse-regs-options.c
@@ -54,7 +54,7 @@ __parse_regs(const struct option *opt, const char *str, int unset, bool intr)
#endif
fputc('\n', stderr);
/* just printing available regs */
- return -1;
+ goto error;
}
#ifdef HAVE_PERF_REGS_SUPPORT
for (r = sample_reg_masks; r->name; r++) {
diff --git a/tools/perf/util/perf_event_attr_fprintf.c b/tools/perf/util/perf_event_attr_fprintf.c
index e67a227c0ce7..fb0bb6684438 100644
--- a/tools/perf/util/perf_event_attr_fprintf.c
+++ b/tools/perf/util/perf_event_attr_fprintf.c
@@ -35,7 +35,7 @@ static void __p_sample_type(char *buf, size_t size, u64 value)
bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
bit_name(IDENTIFIER), bit_name(REGS_INTR), bit_name(DATA_SRC),
bit_name(WEIGHT), bit_name(PHYS_ADDR), bit_name(AUX),
- bit_name(CGROUP),
+ bit_name(CGROUP), bit_name(DATA_PAGE_SIZE),
{ .name = NULL, }
};
#undef bit_name
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index d41caeb35cf6..44ef28302fc7 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -597,6 +597,7 @@ static struct perf_cpu_map *__pmu_cpumask(const char *path)
* Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64)
* may have a "cpus" file.
*/
+#define SYS_TEMPLATE_ID "./bus/event_source/devices/%s/identifier"
#define CPUS_TEMPLATE_UNCORE "%s/bus/event_source/devices/%s/cpumask"
#define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus"
@@ -635,6 +636,21 @@ static bool pmu_is_uncore(const char *name)
return file_available(path);
}
+static char *pmu_id(const char *name)
+{
+ char path[PATH_MAX], *str;
+ size_t len;
+
+ snprintf(path, PATH_MAX, SYS_TEMPLATE_ID, name);
+
+ if (sysfs__read_str(path, &str, &len) < 0)
+ return NULL;
+
+ str[len - 1] = 0; /* remove line feed */
+
+ return str;
+}
+
/*
* PMU CORE devices have different name other than cpu in sysfs on some
* platforms.
@@ -796,6 +812,83 @@ static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
pmu_add_cpu_aliases_map(head, pmu, map);
}
+void pmu_for_each_sys_event(pmu_sys_event_iter_fn fn, void *data)
+{
+ int i = 0;
+
+ while (1) {
+ struct pmu_sys_events *event_table;
+ int j = 0;
+
+ event_table = &pmu_sys_event_tables[i++];
+
+ if (!event_table->table)
+ break;
+
+ while (1) {
+ struct pmu_event *pe = &event_table->table[j++];
+ int ret;
+
+ if (!pe->name && !pe->metric_group && !pe->metric_name)
+ break;
+
+ ret = fn(pe, data);
+ if (ret)
+ break;
+ }
+ }
+}
+
+struct pmu_sys_event_iter_data {
+ struct list_head *head;
+ struct perf_pmu *pmu;
+};
+
+static int pmu_add_sys_aliases_iter_fn(struct pmu_event *pe, void *data)
+{
+ struct pmu_sys_event_iter_data *idata = data;
+ struct perf_pmu *pmu = idata->pmu;
+
+ if (!pe->name) {
+ if (pe->metric_group || pe->metric_name)
+ return 0;
+ return -EINVAL;
+ }
+
+ if (!pe->compat || !pe->pmu)
+ return 0;
+
+ if (!strcmp(pmu->id, pe->compat) &&
+ pmu_uncore_alias_match(pe->pmu, pmu->name)) {
+ __perf_pmu__new_alias(idata->head, NULL,
+ (char *)pe->name,
+ (char *)pe->desc,
+ (char *)pe->event,
+ (char *)pe->long_desc,
+ (char *)pe->topic,
+ (char *)pe->unit,
+ (char *)pe->perpkg,
+ (char *)pe->metric_expr,
+ (char *)pe->metric_name,
+ (char *)pe->deprecated);
+ }
+
+ return 0;
+}
+
+static void pmu_add_sys_aliases(struct list_head *head, struct perf_pmu *pmu)
+{
+ struct pmu_sys_event_iter_data idata = {
+ .head = head,
+ .pmu = pmu,
+ };
+
+ if (!pmu->id)
+ return;
+
+ pmu_for_each_sys_event(pmu_add_sys_aliases_iter_fn, &idata);
+}
+
struct perf_event_attr * __weak
perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
{
@@ -847,8 +940,11 @@ static struct perf_pmu *pmu_lookup(const char *name)
pmu->name = strdup(name);
pmu->type = type;
pmu->is_uncore = pmu_is_uncore(name);
+ if (pmu->is_uncore)
+ pmu->id = pmu_id(name);
pmu->max_precise = pmu_max_precise(name);
pmu_add_cpu_aliases(&aliases, pmu);
+ pmu_add_sys_aliases(&aliases, pmu);
INIT_LIST_HEAD(&pmu->format);
INIT_LIST_HEAD(&pmu->aliases);
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index a64e9c9ce731..8164388478c6 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -30,6 +30,7 @@ struct perf_pmu_caps {
struct perf_pmu {
char *name;
+ char *id;
__u32 type;
bool selectable;
bool is_uncore;
@@ -116,6 +117,8 @@ struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu);
bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
void perf_pmu_free_alias(struct perf_pmu_alias *alias);
+typedef int (*pmu_sys_event_iter_fn)(struct pmu_event *pe, void *data);
+void pmu_for_each_sys_event(pmu_sys_event_iter_fn fn, void *data);
int perf_pmu__convert_scale(const char *scale, char **end, double *sval);
int perf_pmu__caps_parse(struct perf_pmu *pmu);
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index ae8edde7c50e..cc5ade85a33f 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -1055,7 +1055,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
if (pyevent == NULL)
return PyErr_NoMemory();
- evsel = perf_evlist__event2evsel(evlist, event);
+ evsel = evlist__event2evsel(evlist, event);
if (!evsel) {
Py_INCREF(Py_None);
return Py_None;
@@ -1089,7 +1089,7 @@ static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
return NULL;
if (group)
- perf_evlist__set_leader(evlist);
+ evlist__set_leader(evlist);
if (evlist__open(evlist) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index 07e4b96a6625..e70c9dd04567 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -89,8 +89,7 @@ static void evsel__config_leader_sampling(struct evsel *evsel, struct evlist *ev
leader->core.attr.sample_type;
}
-void perf_evlist__config(struct evlist *evlist, struct record_opts *opts,
- struct callchain_param *callchain)
+void evlist__config(struct evlist *evlist, struct record_opts *opts, struct callchain_param *callchain)
{
struct evsel *evsel;
bool use_sample_identifier = false;
@@ -102,7 +101,7 @@ void perf_evlist__config(struct evlist *evlist, struct record_opts *opts,
* since some might depend on this info.
*/
if (opts->group)
- perf_evlist__set_leader(evlist);
+ evlist__set_leader(evlist);
if (evlist->core.cpus->map[0] < 0)
opts->no_inherit = true;
@@ -144,7 +143,7 @@ void perf_evlist__config(struct evlist *evlist, struct record_opts *opts,
evsel__set_sample_id(evsel, use_sample_identifier);
}
- perf_evlist__set_id_pos(evlist);
+ evlist__set_id_pos(evlist);
}
static int get_max_rate(unsigned int *rate)
@@ -217,7 +216,7 @@ int record_opts__config(struct record_opts *opts)
return record_opts__config_freq(opts);
}
-bool perf_evlist__can_select_event(struct evlist *evlist, const char *str)
+bool evlist__can_select_event(struct evlist *evlist, const char *str)
{
struct evlist *temp_evlist;
struct evsel *evsel;
diff --git a/tools/perf/util/record.h b/tools/perf/util/record.h
index 266760ac9143..694b351dcd27 100644
--- a/tools/perf/util/record.h
+++ b/tools/perf/util/record.h
@@ -22,6 +22,7 @@ struct record_opts {
bool raw_samples;
bool sample_address;
bool sample_phys_addr;
+ bool sample_data_page_size;
bool sample_weight;
bool sample_time;
bool sample_time_set;
diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c
index f8861998e5bd..078a71773565 100644
--- a/tools/perf/util/s390-cpumsf.c
+++ b/tools/perf/util/s390-cpumsf.c
@@ -96,9 +96,9 @@
* | than PERF_RECORD_USER_TYPE_START) are handled by
* | perf_session__process_user_event(see below)
* | - Those generated by the kernel are handled by
- * | perf_evlist__parse_sample_timestamp()
+ * | evlist__parse_sample_timestamp()
* |
- * perf_evlist__parse_sample_timestamp()
+ * evlist__parse_sample_timestamp()
* | Extract time stamp from sample data.
* |
* perf_session__queue_event()
@@ -932,7 +932,7 @@ s390_cpumsf_process_event(struct perf_session *session,
if (event->header.type == PERF_RECORD_SAMPLE &&
sample->raw_size) {
/* Handle event with raw data */
- ev_bc000 = perf_evlist__event2evsel(session->evlist, event);
+ ev_bc000 = evlist__event2evsel(session->evlist, event);
if (ev_bc000 &&
ev_bc000->core.attr.config == PERF_EVENT_CPUM_CF_DIAG)
err = s390_cpumcf_dumpctr(sf, sample);
diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
index 05b43ab4eeef..cfcf8d534d76 100644
--- a/tools/perf/util/s390-sample-raw.c
+++ b/tools/perf/util/s390-sample-raw.c
@@ -197,15 +197,14 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
* its raw data.
* The function is only invoked when the dump flag -D is set.
*/
-void perf_evlist__s390_sample_raw(struct evlist *evlist, union perf_event *event,
- struct perf_sample *sample)
+void evlist__s390_sample_raw(struct evlist *evlist, union perf_event *event, struct perf_sample *sample)
{
struct evsel *ev_bc000;
if (event->header.type != PERF_RECORD_SAMPLE)
return;
- ev_bc000 = perf_evlist__event2evsel(evlist, event);
+ ev_bc000 = evlist__event2evsel(evlist, event);
if (ev_bc000 == NULL ||
ev_bc000->core.attr.config != PERF_EVENT_CPUM_CF_DIAG)
return;
diff --git a/tools/perf/util/sample-raw.c b/tools/perf/util/sample-raw.c
index e84bbe0e441a..cde5cd3ce49b 100644
--- a/tools/perf/util/sample-raw.c
+++ b/tools/perf/util/sample-raw.c
@@ -9,10 +9,10 @@
* Check platform the perf data file was created on and perform platform
* specific interpretation.
*/
-void perf_evlist__init_trace_event_sample_raw(struct evlist *evlist)
+void evlist__init_trace_event_sample_raw(struct evlist *evlist)
{
const char *arch_pf = perf_env__arch(evlist->env);
if (arch_pf && !strcmp("s390", arch_pf))
- evlist->trace_event_sample_raw = perf_evlist__s390_sample_raw;
+ evlist->trace_event_sample_raw = evlist__s390_sample_raw;
}
diff --git a/tools/perf/util/sample-raw.h b/tools/perf/util/sample-raw.h
index afe1491a117e..4be84a5510cf 100644
--- a/tools/perf/util/sample-raw.h
+++ b/tools/perf/util/sample-raw.h
@@ -6,9 +6,6 @@ struct evlist;
union perf_event;
struct perf_sample;
-void perf_evlist__s390_sample_raw(struct evlist *evlist,
- union perf_event *event,
- struct perf_sample *sample);
-
-void perf_evlist__init_trace_event_sample_raw(struct evlist *evlist);
+void evlist__s390_sample_raw(struct evlist *evlist, union perf_event *event, struct perf_sample *sample);
+void evlist__init_trace_event_sample_raw(struct evlist *evlist);
#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 098080287c68..50ff9795a4f1 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -32,6 +32,7 @@
#include "ui/progress.h"
#include "../perf.h"
#include "arch/common.h"
+#include "units.h"
#include <internal/lib.h>
#ifdef HAVE_ZSTD_SUPPORT
@@ -125,7 +126,7 @@ static int perf_session__open(struct perf_session *session)
return -1;
}
- if (!perf_evlist__valid_read_format(session->evlist)) {
+ if (!evlist__valid_read_format(session->evlist)) {
pr_err("non matching read_format\n");
return -1;
}
@@ -135,7 +136,7 @@ static int perf_session__open(struct perf_session *session)
void perf_session__set_id_hdr_size(struct perf_session *session)
{
- u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist);
+ u16 id_hdr_size = evlist__id_hdr_size(session->evlist);
machines__set_id_hdr_size(&session->machines, id_hdr_size);
}
@@ -221,7 +222,7 @@ struct perf_session *perf_session__new(struct perf_data *data,
perf_session__set_comm_exec(session);
}
- perf_evlist__init_trace_event_sample_raw(session->evlist);
+ evlist__init_trace_event_sample_raw(session->evlist);
/* Open the directory data. */
if (data->is_dir) {
@@ -1191,9 +1192,7 @@ static void stack_user__printf(struct stack_dump *dump)
dump->size, dump->offset);
}
-static void perf_evlist__print_tstamp(struct evlist *evlist,
- union perf_event *event,
- struct perf_sample *sample)
+static void evlist__print_tstamp(struct evlist *evlist, union perf_event *event, struct perf_sample *sample)
{
u64 sample_type = __evlist__combined_sample_type(evlist);
@@ -1254,16 +1253,25 @@ static void dump_event(struct evlist *evlist, union perf_event *event,
evlist->trace_event_sample_raw(evlist, event, sample);
if (sample)
- perf_evlist__print_tstamp(evlist, event, sample);
+ evlist__print_tstamp(evlist, event, sample);
printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset,
event->header.size, perf_event__name(event->header.type));
}
+char *get_page_size_name(u64 size, char *str)
+{
+ if (!size || !unit_number__scnprintf(str, PAGE_SIZE_NAME_LEN, size))
+ snprintf(str, PAGE_SIZE_NAME_LEN, "%s", "N/A");
+
+ return str;
+}
+
static void dump_sample(struct evsel *evsel, union perf_event *event,
struct perf_sample *sample)
{
u64 sample_type;
+ char str[PAGE_SIZE_NAME_LEN];
if (!dump_trace)
return;
@@ -1298,6 +1306,9 @@ static void dump_sample(struct evsel *evsel, union perf_event *event,
if (sample_type & PERF_SAMPLE_PHYS_ADDR)
printf(" .. phys_addr: 0x%"PRIx64"\n", sample->phys_addr);
+ if (sample_type & PERF_SAMPLE_DATA_PAGE_SIZE)
+ printf(" .. data page size: %s\n", get_page_size_name(sample->data_page_size, str));
+
if (sample_type & PERF_SAMPLE_TRANSACTION)
printf("... transaction: %" PRIx64 "\n", sample->transaction);
@@ -1364,7 +1375,7 @@ static int deliver_sample_value(struct evlist *evlist,
struct sample_read_value *v,
struct machine *machine)
{
- struct perf_sample_id *sid = perf_evlist__id2sid(evlist, v->id);
+ struct perf_sample_id *sid = evlist__id2sid(evlist, v->id);
struct evsel *evsel;
if (sid) {
@@ -1409,13 +1420,9 @@ static int deliver_sample_group(struct evlist *evlist,
return ret;
}
-static int
- perf_evlist__deliver_sample(struct evlist *evlist,
- struct perf_tool *tool,
- union perf_event *event,
- struct perf_sample *sample,
- struct evsel *evsel,
- struct machine *machine)
+static int evlist__deliver_sample(struct evlist *evlist, struct perf_tool *tool,
+ union perf_event *event, struct perf_sample *sample,
+ struct evsel *evsel, struct machine *machine)
{
/* We know evsel != NULL. */
u64 sample_type = evsel->core.attr.sample_type;
@@ -1445,7 +1452,7 @@ static int machines__deliver_event(struct machines *machines,
dump_event(evlist, event, file_offset, sample);
- evsel = perf_evlist__id2evsel(evlist, sample->id);
+ evsel = evlist__id2evsel(evlist, sample->id);
machine = machines__find_for_cpumode(machines, event, sample);
@@ -1460,7 +1467,7 @@ static int machines__deliver_event(struct machines *machines,
++evlist->stats.nr_unprocessable_samples;
return 0;
}
- return perf_evlist__deliver_sample(evlist, tool, event, sample, evsel, machine);
+ return evlist__deliver_sample(evlist, tool, event, sample, evsel, machine);
case PERF_RECORD_MMAP:
return tool->mmap(tool, event, sample, machine);
case PERF_RECORD_MMAP2:
@@ -1523,9 +1530,8 @@ static int perf_session__deliver_event(struct perf_session *session,
u64 file_offset)
{
struct perf_sample sample;
- int ret;
+ int ret = evlist__parse_sample(session->evlist, event, &sample);
- ret = perf_evlist__parse_sample(session->evlist, event, &sample);
if (ret) {
pr_err("Can't parse sample, err = %d\n", ret);
return ret;
@@ -1697,7 +1703,7 @@ int perf_session__peek_event(struct perf_session *session, off_t file_offset,
out_parse_sample:
if (sample && event->header.type < PERF_RECORD_USER_TYPE_START &&
- perf_evlist__parse_sample(session->evlist, event, sample))
+ evlist__parse_sample(session->evlist, event, sample))
return -1;
*event_ptr = event;
@@ -1754,7 +1760,7 @@ static s64 perf_session__process_event(struct perf_session *session,
if (tool->ordered_events) {
u64 timestamp = -1ULL;
- ret = perf_evlist__parse_sample_timestamp(evlist, event, &timestamp);
+ ret = evlist__parse_sample_timestamp(evlist, event, &timestamp);
if (ret && ret != -1)
return ret;
@@ -1937,7 +1943,6 @@ static int __perf_session__process_pipe_events(struct perf_session *session)
{
struct ordered_events *oe = &session->ordered_events;
struct perf_tool *tool = session->tool;
- int fd = perf_data__fd(session->data);
union perf_event *event;
uint32_t size, cur_size = 0;
void *buf = NULL;
@@ -1957,7 +1962,8 @@ static int __perf_session__process_pipe_events(struct perf_session *session)
ordered_events__set_copy_on_queue(oe, true);
more:
event = buf;
- err = readn(fd, event, sizeof(struct perf_event_header));
+ err = perf_data__read(session->data, event,
+ sizeof(struct perf_event_header));
if (err <= 0) {
if (err == 0)
goto done;
@@ -1989,7 +1995,8 @@ more:
p += sizeof(struct perf_event_header);
if (size - sizeof(struct perf_event_header)) {
- err = readn(fd, p, size - sizeof(struct perf_event_header));
+ err = perf_data__read(session->data, p,
+ size - sizeof(struct perf_event_header));
if (err <= 0) {
if (err == 0) {
pr_err("unexpected end of event stream\n");
@@ -2476,7 +2483,7 @@ int perf_event__process_id_index(struct perf_session *session,
fprintf(stdout, " tid: %"PRI_ld64"\n", e->tid);
}
- sid = perf_evlist__id2sid(evlist, e->id);
+ sid = evlist__id2sid(evlist, e->id);
if (!sid)
return -ENOENT;
sid->idx = e->idx;
diff --git a/tools/perf/util/sideband_evlist.c b/tools/perf/util/sideband_evlist.c
index ded9ced02797..748371ac22be 100644
--- a/tools/perf/util/sideband_evlist.c
+++ b/tools/perf/util/sideband_evlist.c
@@ -12,8 +12,8 @@
#include <sched.h>
#include <stdbool.h>
-int perf_evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr,
- evsel__sb_cb_t cb, void *data)
+int evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr,
+ evsel__sb_cb_t cb, void *data)
{
struct evsel *evsel;
@@ -62,7 +62,7 @@ static void *perf_evlist__poll_thread(void *arg)
if (perf_mmap__read_init(&map->core))
continue;
while ((event = perf_mmap__read_event(&map->core)) != NULL) {
- struct evsel *evsel = perf_evlist__event2evsel(evlist, event);
+ struct evsel *evsel = evlist__event2evsel(evlist, event);
if (evsel && evsel->side_band.cb)
evsel->side_band.cb(event, evsel->side_band.data);
@@ -94,14 +94,14 @@ void evlist__set_cb(struct evlist *evlist, evsel__sb_cb_t cb, void *data)
}
}
-int perf_evlist__start_sb_thread(struct evlist *evlist, struct target *target)
+int evlist__start_sb_thread(struct evlist *evlist, struct target *target)
{
struct evsel *counter;
if (!evlist)
return 0;
- if (perf_evlist__create_maps(evlist, target))
+ if (evlist__create_maps(evlist, target))
goto out_delete_evlist;
if (evlist->core.nr_entries > 1) {
@@ -110,7 +110,7 @@ int perf_evlist__start_sb_thread(struct evlist *evlist, struct target *target)
evlist__for_each_entry(evlist, counter)
evsel__set_sample_id(counter, can_sample_identifier);
- perf_evlist__set_id_pos(evlist);
+ evlist__set_id_pos(evlist);
}
evlist__for_each_entry(evlist, counter) {
@@ -138,7 +138,7 @@ out_delete_evlist:
return -1;
}
-void perf_evlist__stop_sb_thread(struct evlist *evlist)
+void evlist__stop_sb_thread(struct evlist *evlist)
{
if (!evlist)
return;
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index d42339df20f8..80907bc32683 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1463,6 +1463,35 @@ struct sort_entry sort_mem_phys_daddr = {
};
static int64_t
+sort__data_page_size_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ uint64_t l = 0, r = 0;
+
+ if (left->mem_info)
+ l = left->mem_info->daddr.data_page_size;
+ if (right->mem_info)
+ r = right->mem_info->daddr.data_page_size;
+
+ return (int64_t)(r - l);
+}
+
+static int hist_entry__data_page_size_snprintf(struct hist_entry *he, char *bf,
+ size_t size, unsigned int width)
+{
+ char str[PAGE_SIZE_NAME_LEN];
+
+ return repsep_snprintf(bf, size, "%-*s", width,
+ get_page_size_name(he->mem_info->daddr.data_page_size, str));
+}
+
+struct sort_entry sort_mem_data_page_size = {
+ .se_header = "Data Page Size",
+ .se_cmp = sort__data_page_size_cmp,
+ .se_snprintf = hist_entry__data_page_size_snprintf,
+ .se_width_idx = HISTC_MEM_DATA_PAGE_SIZE,
+};
+
+static int64_t
sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
{
if (!left->branch_info || !right->branch_info)
@@ -1740,6 +1769,7 @@ static struct sort_dimension memory_sort_dimensions[] = {
DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
DIM(SORT_MEM_PHYS_DADDR, "phys_daddr", sort_mem_phys_daddr),
+ DIM(SORT_MEM_DATA_PAGE_SIZE, "data_page_size", sort_mem_data_page_size),
};
#undef DIM
@@ -2756,7 +2786,7 @@ static const char *get_default_sort_order(struct evlist *evlist)
BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
- if (evlist == NULL || perf_evlist__empty(evlist))
+ if (evlist == NULL || evlist__empty(evlist))
goto out_no_evlist;
evlist__for_each_entry(evlist, evsel) {
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 66d39c4cfe2b..e50f2b695bc4 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -255,6 +255,7 @@ enum sort_type {
SORT_MEM_DCACHELINE,
SORT_MEM_IADDR_SYMBOL,
SORT_MEM_PHYS_DADDR,
+ SORT_MEM_DATA_PAGE_SIZE,
};
/*
diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c
index a963b5b8eb72..fee7543843a8 100644
--- a/tools/perf/util/stat-display.c
+++ b/tools/perf/util/stat-display.c
@@ -1184,12 +1184,8 @@ static void print_percore(struct perf_stat_config *config,
fputc('\n', output);
}
-void
-perf_evlist__print_counters(struct evlist *evlist,
- struct perf_stat_config *config,
- struct target *_target,
- struct timespec *ts,
- int argc, const char **argv)
+void evlist__print_counters(struct evlist *evlist, struct perf_stat_config *config,
+ struct target *_target, struct timespec *ts, int argc, const char **argv)
{
bool metric_only = config->metric_only;
int interval = config->interval;
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index bd0decd6d753..1e125e39ff84 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -184,7 +184,7 @@ static int evsel__alloc_stats(struct evsel *evsel, bool alloc_raw)
return 0;
}
-int perf_evlist__alloc_stats(struct evlist *evlist, bool alloc_raw)
+int evlist__alloc_stats(struct evlist *evlist, bool alloc_raw)
{
struct evsel *evsel;
@@ -196,11 +196,11 @@ int perf_evlist__alloc_stats(struct evlist *evlist, bool alloc_raw)
return 0;
out_free:
- perf_evlist__free_stats(evlist);
+ evlist__free_stats(evlist);
return -1;
}
-void perf_evlist__free_stats(struct evlist *evlist)
+void evlist__free_stats(struct evlist *evlist)
{
struct evsel *evsel;
@@ -211,7 +211,7 @@ void perf_evlist__free_stats(struct evlist *evlist)
}
}
-void perf_evlist__reset_stats(struct evlist *evlist)
+void evlist__reset_stats(struct evlist *evlist)
{
struct evsel *evsel;
@@ -221,7 +221,7 @@ void perf_evlist__reset_stats(struct evlist *evlist)
}
}
-void perf_evlist__reset_prev_raw_counts(struct evlist *evlist)
+void evlist__reset_prev_raw_counts(struct evlist *evlist)
{
struct evsel *evsel;
@@ -229,7 +229,7 @@ void perf_evlist__reset_prev_raw_counts(struct evlist *evlist)
evsel__reset_prev_raw_counts(evsel);
}
-static void perf_evsel__copy_prev_raw_counts(struct evsel *evsel)
+static void evsel__copy_prev_raw_counts(struct evsel *evsel)
{
int ncpus = evsel__nr_cpus(evsel);
int nthreads = perf_thread_map__nr(evsel->core.threads);
@@ -245,15 +245,15 @@ static void perf_evsel__copy_prev_raw_counts(struct evsel *evsel)
evsel->counts->aggr = evsel->prev_raw_counts->aggr;
}
-void perf_evlist__copy_prev_raw_counts(struct evlist *evlist)
+void evlist__copy_prev_raw_counts(struct evlist *evlist)
{
struct evsel *evsel;
evlist__for_each_entry(evlist, evsel)
- perf_evsel__copy_prev_raw_counts(evsel);
+ evsel__copy_prev_raw_counts(evsel);
}
-void perf_evlist__save_aggr_prev_raw_counts(struct evlist *evlist)
+void evlist__save_aggr_prev_raw_counts(struct evlist *evlist)
{
struct evsel *evsel;
@@ -458,7 +458,7 @@ int perf_event__process_stat_event(struct perf_session *session,
count.ena = st->ena;
count.run = st->run;
- counter = perf_evlist__id2evsel(session->evlist, st->id);
+ counter = evlist__id2evsel(session->evlist, st->id);
if (!counter) {
pr_err("Failed to resolve counter for stat event.\n");
return -EINVAL;
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 487010c624be..9979b4b100f2 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -122,6 +122,7 @@ struct perf_stat_config {
bool metric_no_group;
bool metric_no_merge;
bool stop_read_counter;
+ bool quiet;
FILE *output;
unsigned int interval;
unsigned int timeout;
@@ -212,12 +213,12 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
struct runtime_stat *st);
void perf_stat__collect_metric_expr(struct evlist *);
-int perf_evlist__alloc_stats(struct evlist *evlist, bool alloc_raw);
-void perf_evlist__free_stats(struct evlist *evlist);
-void perf_evlist__reset_stats(struct evlist *evlist);
-void perf_evlist__reset_prev_raw_counts(struct evlist *evlist);
-void perf_evlist__copy_prev_raw_counts(struct evlist *evlist);
-void perf_evlist__save_aggr_prev_raw_counts(struct evlist *evlist);
+int evlist__alloc_stats(struct evlist *evlist, bool alloc_raw);
+void evlist__free_stats(struct evlist *evlist);
+void evlist__reset_stats(struct evlist *evlist);
+void evlist__reset_prev_raw_counts(struct evlist *evlist);
+void evlist__copy_prev_raw_counts(struct evlist *evlist);
+void evlist__save_aggr_prev_raw_counts(struct evlist *evlist);
int perf_stat_process_counter(struct perf_stat_config *config,
struct evsel *counter);
@@ -237,12 +238,8 @@ int create_perf_stat_counter(struct evsel *evsel,
struct perf_stat_config *config,
struct target *target,
int cpu);
-void
-perf_evlist__print_counters(struct evlist *evlist,
- struct perf_stat_config *config,
- struct target *_target,
- struct timespec *ts,
- int argc, const char **argv);
+void evlist__print_counters(struct evlist *evlist, struct perf_stat_config *config,
+ struct target *_target, struct timespec *ts, int argc, const char **argv);
struct metric_expr;
double test_generic_metric(struct metric_expr *mexp, int cpu, struct runtime_stat *st);
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 44dd86a4f25f..f3577f7d72fe 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -534,7 +534,7 @@ out:
#ifdef HAVE_LIBBFD_BUILDID_SUPPORT
-int filename__read_build_id(const char *filename, struct build_id *bid)
+static int read_build_id(const char *filename, struct build_id *bid)
{
size_t size = sizeof(bid->data);
int err = -1;
@@ -563,7 +563,7 @@ out_close:
#else // HAVE_LIBBFD_BUILDID_SUPPORT
-int filename__read_build_id(const char *filename, struct build_id *bid)
+static int read_build_id(const char *filename, struct build_id *bid)
{
size_t size = sizeof(bid->data);
int fd, err = -1;
@@ -595,6 +595,39 @@ out:
#endif // HAVE_LIBBFD_BUILDID_SUPPORT
+int filename__read_build_id(const char *filename, struct build_id *bid)
+{
+ struct kmod_path m = { .name = NULL, };
+ char path[PATH_MAX];
+ int err;
+
+ if (!filename)
+ return -EFAULT;
+
+ err = kmod_path__parse(&m, filename);
+ if (err)
+ return -1;
+
+ if (m.comp) {
+ int error = 0, fd;
+
+ fd = filename__decompress(filename, path, sizeof(path), m.comp, &error);
+ if (fd < 0) {
+ pr_debug("Failed to decompress (error %d) %s\n",
+ error, filename);
+ return -1;
+ }
+ close(fd);
+ filename = path;
+ }
+
+ err = read_build_id(filename, bid);
+
+ if (m.comp)
+ unlink(filename);
+ return err;
+}
+
int sysfs__read_build_id(const char *filename, struct build_id *bid)
{
size_t size = sizeof(bid->data);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 0d14abdf3d72..64a039cbba1b 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -2189,6 +2189,8 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map)
int err;
const char *kallsyms_filename = NULL;
char *kallsyms_allocated_filename = NULL;
+ char *filename = NULL;
+
/*
* Step 1: if the user specified a kallsyms or vmlinux filename, use
* it and only it, reporting errors to the user if it cannot be used.
@@ -2213,6 +2215,20 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map)
return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, false);
}
+ /*
+ * Before checking on common vmlinux locations, check if it's
+ * stored as standard build id binary (not kallsyms) under
+ * .debug cache.
+ */
+ if (!symbol_conf.ignore_vmlinux_buildid)
+ filename = __dso__build_id_filename(dso, NULL, 0, false, false);
+ if (filename != NULL) {
+ err = dso__load_vmlinux(dso, map, filename, true);
+ if (err > 0)
+ return err;
+ free(filename);
+ }
+
if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) {
err = dso__load_vmlinux_path(dso, map);
if (err > 0)
diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c
index d9c624377da7..2947e3f3c6d9 100644
--- a/tools/perf/util/synthetic-events.c
+++ b/tools/perf/util/synthetic-events.c
@@ -1409,6 +1409,9 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
if (type & PERF_SAMPLE_CGROUP)
result += sizeof(u64);
+ if (type & PERF_SAMPLE_DATA_PAGE_SIZE)
+ result += sizeof(u64);
+
if (type & PERF_SAMPLE_AUX) {
result += sizeof(u64);
result += sample->aux_sample.size;
@@ -1588,6 +1591,11 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_fo
array++;
}
+ if (type & PERF_SAMPLE_DATA_PAGE_SIZE) {
+ *array = sample->data_page_size;
+ array++;
+ }
+
if (type & PERF_SAMPLE_AUX) {
sz = sample->aux_sample.size;
*array++ = sz;
@@ -1643,7 +1651,7 @@ int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_
e->id = evsel->core.id[j];
- sid = perf_evlist__id2sid(evlist, e->id);
+ sid = evlist__id2sid(evlist, e->id);
if (!sid) {
free(ev);
return -ENOENT;
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 7a3dbc259cec..0ada907c60d4 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -20,10 +20,24 @@
static char *debuginfo_path;
+static int __find_debuginfo(Dwfl_Module *mod __maybe_unused, void **userdata,
+ const char *modname __maybe_unused, Dwarf_Addr base __maybe_unused,
+ const char *file_name, const char *debuglink_file __maybe_unused,
+ GElf_Word debuglink_crc __maybe_unused, char **debuginfo_file_name)
+{
+ const struct dso *dso = *userdata;
+
+ assert(dso);
+ if (dso->symsrc_filename && strcmp (file_name, dso->symsrc_filename))
+ *debuginfo_file_name = strdup(dso->symsrc_filename);
+ return -1;
+}
+
static const Dwfl_Callbacks offline_callbacks = {
- .find_debuginfo = dwfl_standard_find_debuginfo,
+ .find_debuginfo = __find_debuginfo,
.debuginfo_path = &debuginfo_path,
.section_address = dwfl_offline_section_address,
+ // .find_elf is not set as we use dwfl_report_elf() instead.
};
static int __report_module(struct addr_location *al, u64 ip,
@@ -46,16 +60,24 @@ static int __report_module(struct addr_location *al, u64 ip,
mod = dwfl_addrmodule(ui->dwfl, ip);
if (mod) {
Dwarf_Addr s;
+ void **userdatap;
- dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL);
+ dwfl_module_info(mod, &userdatap, &s, NULL, NULL, NULL, NULL, NULL);
+ *userdatap = dso;
if (s != al->map->start - al->map->pgoff)
mod = 0;
}
if (!mod)
- mod = dwfl_report_elf(ui->dwfl, dso->short_name,
- (dso->symsrc_filename ? dso->symsrc_filename : dso->long_name), -1, al->map->start - al->map->pgoff,
- false);
+ mod = dwfl_report_elf(ui->dwfl, dso->short_name, dso->long_name, -1,
+ al->map->start - al->map->pgoff, false);
+ if (!mod) {
+ char filename[PATH_MAX];
+
+ if (dso__build_id_filename(dso, filename, sizeof(filename), false))
+ mod = dwfl_report_elf(ui->dwfl, dso->short_name, filename, -1,
+ al->map->start - al->map->pgoff, false);
+ }
return mod && dwfl_addrmodule(ui->dwfl, ip) == mod ? 0 : -1;
}