Commit 16b3d851 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'perf-tools-fixes-for-v6.0-2022-08-19' of...

Merge tag 'perf-tools-fixes-for-v6.0-2022-08-19' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux

Pull perf tools fixes from Arnaldo Carvalho de Melo:

 - Fix alignment for cpu map masks in event encoding.

 - Support reading PERF_FORMAT_LOST, perf tool counterpart for a feature
   that was added in this merge window.

 - Sync perf tools copies of kernel headers: socket, msr-index, fscrypt,
   cpufeatures, i915_drm, kvm, vhost, perf_event.

* tag 'perf-tools-fixes-for-v6.0-2022-08-19' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux:
  perf tools: Support reading PERF_FORMAT_LOST
  libperf: Add a test case for read formats
  libperf: Handle read format in perf_evsel__read()
  tools headers UAPI: Sync linux/perf_event.h with the kernel sources
  tools headers UAPI: Sync x86's asm/kvm.h with the kernel sources
  tools headers UAPI: Sync KVM's vmx.h header with the kernel sources
  tools include UAPI: Sync linux/vhost.h with the kernel sources
  tools headers kvm s390: Sync headers with the kernel sources
  tools headers UAPI: Sync linux/kvm.h with the kernel sources
  tools headers UAPI: Sync drm/i915_drm.h with the kernel sources
  tools headers cpufeatures: Sync with the kernel sources
  tools headers UAPI: Sync linux/fscrypt.h with the kernel sources
  tools arch x86: Sync the msr-index.h copy with the kernel sources
  perf beauty: Update copy of linux/socket.h with the kernel sources
  perf cpumap: Fix alignment for masks in event encoding
  perf cpumap: Compute mask size in constant time
  perf cpumap: Synthetic events and const/static
  perf cpumap: Const map for max()
parents cc1807b9 f52679b7
......@@ -74,6 +74,7 @@ struct kvm_s390_io_adapter_req {
#define KVM_S390_VM_CRYPTO 2
#define KVM_S390_VM_CPU_MODEL 3
#define KVM_S390_VM_MIGRATION 4
#define KVM_S390_VM_CPU_TOPOLOGY 5
/* kvm attributes for mem_ctrl */
#define KVM_S390_VM_MEM_ENABLE_CMMA 0
......
......@@ -219,7 +219,7 @@
#define X86_FEATURE_IBRS ( 7*32+25) /* Indirect Branch Restricted Speculation */
#define X86_FEATURE_IBPB ( 7*32+26) /* Indirect Branch Prediction Barrier */
#define X86_FEATURE_STIBP ( 7*32+27) /* Single Thread Indirect Branch Predictors */
#define X86_FEATURE_ZEN ( 7*32+28) /* "" CPU is AMD family 0x17 or above (Zen) */
#define X86_FEATURE_ZEN (7*32+28) /* "" CPU based on Zen microarchitecture */
#define X86_FEATURE_L1TF_PTEINV ( 7*32+29) /* "" L1TF workaround PTE inversion */
#define X86_FEATURE_IBRS_ENHANCED ( 7*32+30) /* Enhanced IBRS */
#define X86_FEATURE_MSR_IA32_FEAT_CTL ( 7*32+31) /* "" MSR IA32_FEAT_CTL configured */
......@@ -303,7 +303,7 @@
#define X86_FEATURE_RETHUNK (11*32+14) /* "" Use REturn THUNK */
#define X86_FEATURE_UNRET (11*32+15) /* "" AMD BTB untrain return */
#define X86_FEATURE_USE_IBPB_FW (11*32+16) /* "" Use IBPB during runtime firmware calls */
#define X86_FEATURE_RSB_VMEXIT_LITE (11*32+17) /* "" Fill RSB on VM-Exit when EIBRS is enabled */
#define X86_FEATURE_RSB_VMEXIT_LITE (11*32+17) /* "" Fill RSB on VM exit when EIBRS is enabled */
/* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
#define X86_FEATURE_AVX_VNNI (12*32+ 4) /* AVX VNNI instructions */
......@@ -354,6 +354,7 @@
#define X86_FEATURE_AVIC (15*32+13) /* Virtual Interrupt Controller */
#define X86_FEATURE_V_VMSAVE_VMLOAD (15*32+15) /* Virtual VMSAVE VMLOAD */
#define X86_FEATURE_VGIF (15*32+16) /* Virtual GIF */
#define X86_FEATURE_X2AVIC (15*32+18) /* Virtual x2apic */
#define X86_FEATURE_V_SPEC_CTRL (15*32+20) /* Virtual SPEC_CTRL */
#define X86_FEATURE_SVME_ADDR_CHK (15*32+28) /* "" SVME addr check */
......@@ -457,5 +458,6 @@
#define X86_BUG_SRBDS X86_BUG(24) /* CPU may leak RNG bits if not mitigated */
#define X86_BUG_MMIO_STALE_DATA X86_BUG(25) /* CPU is affected by Processor MMIO Stale Data vulnerabilities */
#define X86_BUG_RETBLEED X86_BUG(26) /* CPU is affected by RETBleed */
#define X86_BUG_EIBRS_PBRSB X86_BUG(27) /* EIBRS is vulnerable to Post Barrier RSB Predictions */
#endif /* _ASM_X86_CPUFEATURES_H */
......@@ -235,6 +235,12 @@
#define PERF_CAP_PT_IDX 16
#define MSR_PEBS_LD_LAT_THRESHOLD 0x000003f6
#define PERF_CAP_PEBS_TRAP BIT_ULL(6)
#define PERF_CAP_ARCH_REG BIT_ULL(7)
#define PERF_CAP_PEBS_FORMAT 0xf00
#define PERF_CAP_PEBS_BASELINE BIT_ULL(14)
#define PERF_CAP_PEBS_MASK (PERF_CAP_PEBS_TRAP | PERF_CAP_ARCH_REG | \
PERF_CAP_PEBS_FORMAT | PERF_CAP_PEBS_BASELINE)
#define MSR_IA32_RTIT_CTL 0x00000570
#define RTIT_CTL_TRACEEN BIT(0)
......@@ -392,6 +398,7 @@
#define MSR_TURBO_ACTIVATION_RATIO 0x0000064C
#define MSR_PLATFORM_ENERGY_STATUS 0x0000064D
#define MSR_SECONDARY_TURBO_RATIO_LIMIT 0x00000650
#define MSR_PKG_WEIGHTED_CORE_C0_RES 0x00000658
#define MSR_PKG_ANY_CORE_C0_RES 0x00000659
......@@ -1022,6 +1029,7 @@
#define MSR_IA32_VMX_TRUE_EXIT_CTLS 0x0000048f
#define MSR_IA32_VMX_TRUE_ENTRY_CTLS 0x00000490
#define MSR_IA32_VMX_VMFUNC 0x00000491
#define MSR_IA32_VMX_PROCBASED_CTLS3 0x00000492
/* VMX_BASIC bits and bitmasks */
#define VMX_BASIC_VMCS_SIZE_SHIFT 32
......
......@@ -306,7 +306,8 @@ struct kvm_pit_state {
struct kvm_pit_channel_state channels[3];
};
#define KVM_PIT_FLAGS_HPET_LEGACY 0x00000001
#define KVM_PIT_FLAGS_HPET_LEGACY 0x00000001
#define KVM_PIT_FLAGS_SPEAKER_DATA_ON 0x00000002
struct kvm_pit_state2 {
struct kvm_pit_channel_state channels[3];
......@@ -325,6 +326,7 @@ struct kvm_reinject_control {
#define KVM_VCPUEVENT_VALID_SHADOW 0x00000004
#define KVM_VCPUEVENT_VALID_SMM 0x00000008
#define KVM_VCPUEVENT_VALID_PAYLOAD 0x00000010
#define KVM_VCPUEVENT_VALID_TRIPLE_FAULT 0x00000020
/* Interrupt shadow states */
#define KVM_X86_SHADOW_INT_MOV_SS 0x01
......@@ -359,7 +361,10 @@ struct kvm_vcpu_events {
__u8 smm_inside_nmi;
__u8 latched_init;
} smi;
__u8 reserved[27];
struct {
__u8 pending;
} triple_fault;
__u8 reserved[26];
__u8 exception_has_payload;
__u64 exception_payload;
};
......@@ -434,6 +439,7 @@ struct kvm_sync_regs {
#define KVM_X86_QUIRK_OUT_7E_INC_RIP (1 << 3)
#define KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT (1 << 4)
#define KVM_X86_QUIRK_FIX_HYPERCALL_INSN (1 << 5)
#define KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS (1 << 6)
#define KVM_STATE_NESTED_FORMAT_VMX 0
#define KVM_STATE_NESTED_FORMAT_SVM 1
......
......@@ -91,6 +91,7 @@
#define EXIT_REASON_UMWAIT 67
#define EXIT_REASON_TPAUSE 68
#define EXIT_REASON_BUS_LOCK 74
#define EXIT_REASON_NOTIFY 75
#define VMX_EXIT_REASONS \
{ EXIT_REASON_EXCEPTION_NMI, "EXCEPTION_NMI" }, \
......@@ -153,7 +154,8 @@
{ EXIT_REASON_XRSTORS, "XRSTORS" }, \
{ EXIT_REASON_UMWAIT, "UMWAIT" }, \
{ EXIT_REASON_TPAUSE, "TPAUSE" }, \
{ EXIT_REASON_BUS_LOCK, "BUS_LOCK" }
{ EXIT_REASON_BUS_LOCK, "BUS_LOCK" }, \
{ EXIT_REASON_NOTIFY, "NOTIFY" }
#define VMX_EXIT_REASON_FLAGS \
{ VMX_EXIT_REASONS_FAILED_VMENTRY, "FAILED_VMENTRY" }
......
This diff is collapsed.
......@@ -27,7 +27,8 @@
#define FSCRYPT_MODE_AES_128_CBC 5
#define FSCRYPT_MODE_AES_128_CTS 6
#define FSCRYPT_MODE_ADIANTUM 9
/* If adding a mode number > 9, update FSCRYPT_MODE_MAX in fscrypt_private.h */
#define FSCRYPT_MODE_AES_256_HCTR2 10
/* If adding a mode number > 10, update FSCRYPT_MODE_MAX in fscrypt_private.h */
/*
* Legacy policy version; ad-hoc KDF and no key verification.
......
......@@ -270,6 +270,8 @@ struct kvm_xen_exit {
#define KVM_EXIT_X86_BUS_LOCK 33
#define KVM_EXIT_XEN 34
#define KVM_EXIT_RISCV_SBI 35
#define KVM_EXIT_RISCV_CSR 36
#define KVM_EXIT_NOTIFY 37
/* For KVM_EXIT_INTERNAL_ERROR */
/* Emulate instruction failed. */
......@@ -496,6 +498,18 @@ struct kvm_run {
unsigned long args[6];
unsigned long ret[2];
} riscv_sbi;
/* KVM_EXIT_RISCV_CSR */
struct {
unsigned long csr_num;
unsigned long new_value;
unsigned long write_mask;
unsigned long ret_value;
} riscv_csr;
/* KVM_EXIT_NOTIFY */
struct {
#define KVM_NOTIFY_CONTEXT_INVALID (1 << 0)
__u32 flags;
} notify;
/* Fix the size of the union. */
char padding[256];
};
......@@ -1157,6 +1171,12 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_VM_TSC_CONTROL 214
#define KVM_CAP_SYSTEM_EVENT_DATA 215
#define KVM_CAP_ARM_SYSTEM_SUSPEND 216
#define KVM_CAP_S390_PROTECTED_DUMP 217
#define KVM_CAP_X86_TRIPLE_FAULT_EVENT 218
#define KVM_CAP_X86_NOTIFY_VMEXIT 219
#define KVM_CAP_VM_DISABLE_NX_HUGE_PAGES 220
#define KVM_CAP_S390_ZPCI_OP 221
#define KVM_CAP_S390_CPU_TOPOLOGY 222
#ifdef KVM_CAP_IRQ_ROUTING
......@@ -1660,6 +1680,55 @@ struct kvm_s390_pv_unp {
__u64 tweak;
};
enum pv_cmd_dmp_id {
KVM_PV_DUMP_INIT,
KVM_PV_DUMP_CONFIG_STOR_STATE,
KVM_PV_DUMP_COMPLETE,
KVM_PV_DUMP_CPU,
};
struct kvm_s390_pv_dmp {
__u64 subcmd;
__u64 buff_addr;
__u64 buff_len;
__u64 gaddr; /* For dump storage state */
__u64 reserved[4];
};
enum pv_cmd_info_id {
KVM_PV_INFO_VM,
KVM_PV_INFO_DUMP,
};
struct kvm_s390_pv_info_dump {
__u64 dump_cpu_buffer_len;
__u64 dump_config_mem_buffer_per_1m;
__u64 dump_config_finalize_len;
};
struct kvm_s390_pv_info_vm {
__u64 inst_calls_list[4];
__u64 max_cpus;
__u64 max_guests;
__u64 max_guest_addr;
__u64 feature_indication;
};
struct kvm_s390_pv_info_header {
__u32 id;
__u32 len_max;
__u32 len_written;
__u32 reserved;
};
struct kvm_s390_pv_info {
struct kvm_s390_pv_info_header header;
union {
struct kvm_s390_pv_info_dump dump;
struct kvm_s390_pv_info_vm vm;
};
};
enum pv_cmd_id {
KVM_PV_ENABLE,
KVM_PV_DISABLE,
......@@ -1668,6 +1737,8 @@ enum pv_cmd_id {
KVM_PV_VERIFY,
KVM_PV_PREP_RESET,
KVM_PV_UNSHARE_ALL,
KVM_PV_INFO,
KVM_PV_DUMP,
};
struct kvm_pv_cmd {
......@@ -2119,4 +2190,41 @@ struct kvm_stats_desc {
/* Available with KVM_CAP_XSAVE2 */
#define KVM_GET_XSAVE2 _IOR(KVMIO, 0xcf, struct kvm_xsave)
/* Available with KVM_CAP_S390_PROTECTED_DUMP */
#define KVM_S390_PV_CPU_COMMAND _IOWR(KVMIO, 0xd0, struct kvm_pv_cmd)
/* Available with KVM_CAP_X86_NOTIFY_VMEXIT */
#define KVM_X86_NOTIFY_VMEXIT_ENABLED (1ULL << 0)
#define KVM_X86_NOTIFY_VMEXIT_USER (1ULL << 1)
/* Available with KVM_CAP_S390_ZPCI_OP */
#define KVM_S390_ZPCI_OP _IOW(KVMIO, 0xd1, struct kvm_s390_zpci_op)
struct kvm_s390_zpci_op {
/* in */
__u32 fh; /* target device */
__u8 op; /* operation to perform */
__u8 pad[3];
union {
/* for KVM_S390_ZPCIOP_REG_AEN */
struct {
__u64 ibv; /* Guest addr of interrupt bit vector */
__u64 sb; /* Guest addr of summary bit */
__u32 flags;
__u32 noi; /* Number of interrupts */
__u8 isc; /* Guest interrupt subclass */
__u8 sbo; /* Offset of guest summary bit vector */
__u16 pad;
} reg_aen;
__u64 reserved[8];
} u;
};
/* types for kvm_s390_zpci_op->op */
#define KVM_S390_ZPCIOP_REG_AEN 0
#define KVM_S390_ZPCIOP_DEREG_AEN 1
/* flags for kvm_s390_zpci_op->u.reg_aen.flags */
#define KVM_S390_ZPCIOP_REGAEN_HOST (1 << 0)
#endif /* __LINUX_KVM_H */
......@@ -301,6 +301,7 @@ enum {
* { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
* { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
* { u64 id; } && PERF_FORMAT_ID
* { u64 lost; } && PERF_FORMAT_LOST
* } && !PERF_FORMAT_GROUP
*
* { u64 nr;
......@@ -308,6 +309,7 @@ enum {
* { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
* { u64 value;
* { u64 id; } && PERF_FORMAT_ID
* { u64 lost; } && PERF_FORMAT_LOST
* } cntr[nr];
* } && PERF_FORMAT_GROUP
* };
......@@ -317,8 +319,9 @@ enum perf_event_read_format {
PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1,
PERF_FORMAT_ID = 1U << 2,
PERF_FORMAT_GROUP = 1U << 3,
PERF_FORMAT_LOST = 1U << 4,
PERF_FORMAT_MAX = 1U << 4, /* non-ABI */
PERF_FORMAT_MAX = 1U << 5, /* non-ABI */
};
#define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */
......
......@@ -171,4 +171,13 @@
#define VHOST_VDPA_SET_GROUP_ASID _IOW(VHOST_VIRTIO, 0x7C, \
struct vhost_vring_state)
/* Suspend a device so it does not process virtqueue requests anymore
*
* After the return of ioctl the device must preserve all the necessary state
* (the virtqueue vring base plus the possible device specific states) that is
* required for restoring in the future. The device must not change its
* configuration after that point.
*/
#define VHOST_VDPA_SUSPEND _IO(VHOST_VIRTIO, 0x7D)
#endif
......@@ -309,7 +309,7 @@ bool perf_cpu_map__has(const struct perf_cpu_map *cpus, struct perf_cpu cpu)
return perf_cpu_map__idx(cpus, cpu) != -1;
}
struct perf_cpu perf_cpu_map__max(struct perf_cpu_map *map)
struct perf_cpu perf_cpu_map__max(const struct perf_cpu_map *map)
{
struct perf_cpu result = {
.cpu = -1
......
......@@ -305,6 +305,9 @@ int perf_evsel__read_size(struct perf_evsel *evsel)
if (read_format & PERF_FORMAT_ID)
entry += sizeof(u64);
if (read_format & PERF_FORMAT_LOST)
entry += sizeof(u64);
if (read_format & PERF_FORMAT_GROUP) {
nr = evsel->nr_members;
size += sizeof(u64);
......@@ -314,24 +317,98 @@ int perf_evsel__read_size(struct perf_evsel *evsel)
return size;
}
/* This only reads values for the leader */
static int perf_evsel__read_group(struct perf_evsel *evsel, int cpu_map_idx,
int thread, struct perf_counts_values *count)
{
size_t size = perf_evsel__read_size(evsel);
int *fd = FD(evsel, cpu_map_idx, thread);
u64 read_format = evsel->attr.read_format;
u64 *data;
int idx = 1;
if (fd == NULL || *fd < 0)
return -EINVAL;
data = calloc(1, size);
if (data == NULL)
return -ENOMEM;
if (readn(*fd, data, size) <= 0) {
free(data);
return -errno;
}
/*
* This reads only the leader event intentionally since we don't have
* perf counts values for sibling events.
*/
if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
count->ena = data[idx++];
if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
count->run = data[idx++];
/* value is always available */
count->val = data[idx++];
if (read_format & PERF_FORMAT_ID)
count->id = data[idx++];
if (read_format & PERF_FORMAT_LOST)
count->lost = data[idx++];
free(data);
return 0;
}
/*
* The perf read format is very flexible. It needs to set the proper
* values according to the read format.
*/
static void perf_evsel__adjust_values(struct perf_evsel *evsel, u64 *buf,
struct perf_counts_values *count)
{
u64 read_format = evsel->attr.read_format;
int n = 0;
count->val = buf[n++];
if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
count->ena = buf[n++];
if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
count->run = buf[n++];
if (read_format & PERF_FORMAT_ID)
count->id = buf[n++];
if (read_format & PERF_FORMAT_LOST)
count->lost = buf[n++];
}
int perf_evsel__read(struct perf_evsel *evsel, int cpu_map_idx, int thread,
struct perf_counts_values *count)
{
size_t size = perf_evsel__read_size(evsel);
int *fd = FD(evsel, cpu_map_idx, thread);
u64 read_format = evsel->attr.read_format;
struct perf_counts_values buf;
memset(count, 0, sizeof(*count));
if (fd == NULL || *fd < 0)
return -EINVAL;
if (read_format & PERF_FORMAT_GROUP)
return perf_evsel__read_group(evsel, cpu_map_idx, thread, count);
if (MMAP(evsel, cpu_map_idx, thread) &&
!(read_format & (PERF_FORMAT_ID | PERF_FORMAT_LOST)) &&
!perf_mmap__read_self(MMAP(evsel, cpu_map_idx, thread), count))
return 0;
if (readn(*fd, count->values, size) <= 0)
if (readn(*fd, buf.values, size) <= 0)
return -errno;
perf_evsel__adjust_values(evsel, buf.values, count);
return 0;
}
......
......@@ -23,7 +23,7 @@ LIBPERF_API void perf_cpu_map__put(struct perf_cpu_map *map);
LIBPERF_API struct perf_cpu perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx);
LIBPERF_API int perf_cpu_map__nr(const struct perf_cpu_map *cpus);
LIBPERF_API bool perf_cpu_map__empty(const struct perf_cpu_map *map);
LIBPERF_API struct perf_cpu perf_cpu_map__max(struct perf_cpu_map *map);
LIBPERF_API struct perf_cpu perf_cpu_map__max(const struct perf_cpu_map *map);
LIBPERF_API bool perf_cpu_map__has(const struct perf_cpu_map *map, struct perf_cpu cpu);
#define perf_cpu_map__for_each_cpu(cpu, idx, cpus) \
......
......@@ -6,6 +6,7 @@
#include <linux/types.h>
#include <linux/limits.h>
#include <linux/bpf.h>
#include <linux/compiler.h>
#include <sys/types.h> /* pid_t */
#define event_contains(obj, mem) ((obj).header.size > offsetof(typeof(obj), mem))
......@@ -76,7 +77,7 @@ struct perf_record_lost_samples {
};
/*
* PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID
* PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID | PERF_FORMAT_LOST
*/
struct perf_record_read {
struct perf_event_header header;
......@@ -85,6 +86,7 @@ struct perf_record_read {
__u64 time_enabled;
__u64 time_running;
__u64 id;
__u64 lost;
};
struct perf_record_throttle {
......@@ -153,22 +155,60 @@ enum {
PERF_CPU_MAP__MASK = 1,
};
/*
* Array encoding of a perf_cpu_map where nr is the number of entries in cpu[]
* and each entry is a value for a CPU in the map.
*/
struct cpu_map_entries {
__u16 nr;
__u16 cpu[];
};
struct perf_record_record_cpu_map {
/* Bitmap encoding of a perf_cpu_map where bitmap entries are 32-bit. */
struct perf_record_mask_cpu_map32 {
/* Number of mask values. */
__u16 nr;
/* Constant 4. */
__u16 long_size;
/* Bitmap data. */
__u32 mask[];
};
/* Bitmap encoding of a perf_cpu_map where bitmap entries are 64-bit. */
struct perf_record_mask_cpu_map64 {
/* Number of mask values. */
__u16 nr;
/* Constant 8. */
__u16 long_size;
unsigned long mask[];
/* Legacy padding. */
char __pad[4];
/* Bitmap data. */
__u64 mask[];
};
struct perf_record_cpu_map_data {
/*
* 'struct perf_record_cpu_map_data' is packed as unfortunately an earlier
* version had unaligned data and we wish to retain file format compatibility.
* -irogers
*/
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpacked"
#pragma GCC diagnostic ignored "-Wattributes"
struct __packed perf_record_cpu_map_data {
__u16 type;
char data[];
union {
/* Used when type == PERF_CPU_MAP__CPUS. */
struct cpu_map_entries cpus_data;
/* Used when type == PERF_CPU_MAP__MASK and long_size == 4. */
struct perf_record_mask_cpu_map32 mask32_data;
/* Used when type == PERF_CPU_MAP__MASK and long_size == 8. */
struct perf_record_mask_cpu_map64 mask64_data;
};
};
#pragma GCC diagnostic pop
struct perf_record_cpu_map {
struct perf_event_header header;
struct perf_record_cpu_map_data data;
......
......@@ -18,8 +18,10 @@ struct perf_counts_values {
uint64_t val;
uint64_t ena;
uint64_t run;
uint64_t id;
uint64_t lost;
};
uint64_t values[3];
uint64_t values[5];
};
};
......
// SPDX-License-Identifier: GPL-2.0
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <linux/perf_event.h>
#include <linux/kernel.h>
#include <perf/cpumap.h>
#include <perf/threadmap.h>
#include <perf/evsel.h>
#include <internal/evsel.h>
#include <internal/tests.h>
#include "tests.h"
......@@ -189,6 +192,163 @@ static int test_stat_user_read(int event)
return 0;
}
static int test_stat_read_format_single(struct perf_event_attr *attr, struct perf_thread_map *threads)
{
struct perf_evsel *evsel;
struct perf_counts_values counts;
volatile int count = 0x100000;
int err;
evsel = perf_evsel__new(attr);
__T("failed to create evsel", evsel);
/* skip old kernels that don't support the format */
err = perf_evsel__open(evsel, NULL, threads);
if (err < 0)
return 0;
while (count--) ;
memset(&counts, -1, sizeof(counts));
perf_evsel__read(evsel, 0, 0, &counts);
__T("failed to read value", counts.val);
if (attr->read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
__T("failed to read TOTAL_TIME_ENABLED", counts.ena);
if (attr->read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
__T("failed to read TOTAL_TIME_RUNNING", counts.run);
if (attr->read_format & PERF_FORMAT_ID)
__T("failed to read ID", counts.id);
if (attr->read_format & PERF_FORMAT_LOST)
__T("failed to read LOST", counts.lost == 0);
perf_evsel__close(evsel);
perf_evsel__delete(evsel);
return 0;
}
static int test_stat_read_format_group(struct perf_event_attr *attr, struct perf_thread_map *threads)
{
struct perf_evsel *leader, *member;
struct perf_counts_values counts;
volatile int count = 0x100000;
int err;
attr->read_format |= PERF_FORMAT_GROUP;
leader = perf_evsel__new(attr);
__T("failed to create leader", leader);
attr->read_format &= ~PERF_FORMAT_GROUP;
member = perf_evsel__new(attr);
__T("failed to create member", member);
member->leader = leader;
leader->nr_members = 2;
/* skip old kernels that don't support the format */
err = perf_evsel__open(leader, NULL, threads);
if (err < 0)
return 0;
err = perf_evsel__open(member, NULL, threads);
if (err < 0)
return 0;
while (count--) ;
memset(&counts, -1, sizeof(counts));
perf_evsel__read(leader, 0, 0, &counts);
__T("failed to read leader value", counts.val);
if (attr->read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
__T("failed to read leader TOTAL_TIME_ENABLED", counts.ena);
if (attr->read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
__T("failed to read leader TOTAL_TIME_RUNNING", counts.run);
if (attr->read_format & PERF_FORMAT_ID)
__T("failed to read leader ID", counts.id);
if (attr->read_format & PERF_FORMAT_LOST)
__T("failed to read leader LOST", counts.lost == 0);
memset(&counts, -1, sizeof(counts));
perf_evsel__read(member, 0, 0, &counts);
__T("failed to read member value", counts.val);
if (attr->read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
__T("failed to read member TOTAL_TIME_ENABLED", counts.ena);
if (attr->read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
__T("failed to read member TOTAL_TIME_RUNNING", counts.run);
if (attr->read_format & PERF_FORMAT_ID)
__T("failed to read member ID", counts.id);
if (attr->read_format & PERF_FORMAT_LOST)
__T("failed to read member LOST", counts.lost == 0);
perf_evsel__close(member);
perf_evsel__close(leader);
perf_evsel__delete(member);
perf_evsel__delete(leader);
return 0;
}
static int test_stat_read_format(void)
{
struct perf_thread_map *threads;
struct perf_event_attr attr = {
.type = PERF_TYPE_SOFTWARE,
.config = PERF_COUNT_SW_TASK_CLOCK,
};
int err, i;
#define FMT(_fmt) PERF_FORMAT_ ## _fmt
#define FMT_TIME (FMT(TOTAL_TIME_ENABLED) | FMT(TOTAL_TIME_RUNNING))
uint64_t test_formats [] = {
0,
FMT_TIME,
FMT(ID),
FMT(LOST),
FMT_TIME | FMT(ID),
FMT_TIME | FMT(LOST),
FMT_TIME | FMT(ID) | FMT(LOST),
FMT(ID) | FMT(LOST),
};
#undef FMT
#undef FMT_TIME
threads = perf_thread_map__new_dummy();
__T("failed to create threads", threads);
perf_thread_map__set_pid(threads, 0, 0);
for (i = 0; i < (int)ARRAY_SIZE(test_formats); i++) {
attr.read_format = test_formats[i];
__T_VERBOSE("testing single read with read_format: %lx\n",
(unsigned long)test_formats[i]);
err = test_stat_read_format_single(&attr, threads);
__T("failed to read single format", err == 0);
}
perf_thread_map__put(threads);
threads = perf_thread_map__new_array(2, NULL);
__T("failed to create threads", threads);
perf_thread_map__set_pid(threads, 0, 0);
perf_thread_map__set_pid(threads, 1, 0);
for (i = 0; i < (int)ARRAY_SIZE(test_formats); i++) {
attr.read_format = test_formats[i];
__T_VERBOSE("testing group read with read_format: %lx\n",
(unsigned long)test_formats[i]);
err = test_stat_read_format_group(&attr, threads);
__T("failed to read group format", err == 0);
}
perf_thread_map__put(threads);
return 0;
}
int test_evsel(int argc, char **argv)
{
__T_START;
......@@ -200,6 +360,7 @@ int test_evsel(int argc, char **argv)
test_stat_thread_enable();
test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS);
test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES);
test_stat_read_format();
__T_END;
return tests_failed == 0 ? 0 : -1;
......
......@@ -17,21 +17,23 @@ static int process_event_mask(struct perf_tool *tool __maybe_unused,
struct machine *machine __maybe_unused)
{
struct perf_record_cpu_map *map_event = &event->cpu_map;
struct perf_record_record_cpu_map *mask;
struct perf_record_cpu_map_data *data;
struct perf_cpu_map *map;
int i;
unsigned int long_size;
data = &map_event->data;
TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__MASK);
mask = (struct perf_record_record_cpu_map *)data->data;
long_size = data->mask32_data.long_size;
TEST_ASSERT_VAL("wrong nr", mask->nr == 1);
TEST_ASSERT_VAL("wrong long_size", long_size == 4 || long_size == 8);
TEST_ASSERT_VAL("wrong nr", data->mask32_data.nr == 1);
for (i = 0; i < 20; i++) {
TEST_ASSERT_VAL("wrong cpu", test_bit(i, mask->mask));
TEST_ASSERT_VAL("wrong cpu", perf_record_cpu_map_data__test_bit(i, data));
}
map = cpu_map__new_data(data);
......@@ -51,7 +53,6 @@ static int process_event_cpus(struct perf_tool *tool __maybe_unused,
struct machine *machine __maybe_unused)
{
struct perf_record_cpu_map *map_event = &event->cpu_map;
struct cpu_map_entries *cpus;
struct perf_record_cpu_map_data *data;
struct perf_cpu_map *map;
......@@ -59,11 +60,9 @@ static int process_event_cpus(struct perf_tool *tool __maybe_unused,
TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__CPUS);
cpus = (struct cpu_map_entries *)data->data;
TEST_ASSERT_VAL("wrong nr", cpus->nr == 2);
TEST_ASSERT_VAL("wrong cpu", cpus->cpu[0] == 1);
TEST_ASSERT_VAL("wrong cpu", cpus->cpu[1] == 256);
TEST_ASSERT_VAL("wrong nr", data->cpus_data.nr == 2);
TEST_ASSERT_VAL("wrong cpu", data->cpus_data.cpu[0] == 1);
TEST_ASSERT_VAL("wrong cpu", data->cpus_data.cpu[1] == 256);
map = cpu_map__new_data(data);
TEST_ASSERT_VAL("wrong nr", perf_cpu_map__nr(map) == 2);
......
......@@ -86,10 +86,15 @@ static bool samples_same(const struct perf_sample *s1,
COMP(read.time_running);
/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
if (read_format & PERF_FORMAT_GROUP) {
for (i = 0; i < s1->read.group.nr; i++)
MCOMP(read.group.values[i]);
for (i = 0; i < s1->read.group.nr; i++) {
/* FIXME: check values without LOST */
if (read_format & PERF_FORMAT_LOST)
MCOMP(read.group.values[i]);
}
} else {
COMP(read.one.id);
if (read_format & PERF_FORMAT_LOST)
COMP(read.one.lost);
}
}
......@@ -263,7 +268,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
.data = (void *)aux_data,
},
};
struct sample_read_value values[] = {{1, 5}, {9, 3}, {2, 7}, {6, 4},};
struct sample_read_value values[] = {{1, 5, 0}, {9, 3, 0}, {2, 7, 0}, {6, 4, 1},};
struct perf_sample sample_out, sample_out_endian;
size_t i, sz, bufsz;
int err, ret = -1;
......@@ -286,6 +291,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
} else {
sample.read.one.value = 0x08789faeb786aa87ULL;
sample.read.one.id = 99;
sample.read.one.lost = 1;
}
sz = perf_event__sample_event_size(&sample, sample_type, read_format);
......@@ -370,7 +376,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
*/
static int test__sample_parsing(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
{
const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15};
const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 28, 29, 30, 31};
u64 sample_type;
u64 sample_regs;
size_t i;
......
......@@ -14,6 +14,8 @@ struct file;
struct pid;
struct cred;
struct socket;
struct sock;
struct sk_buff;
#define __sockaddr_check_size(size) \
BUILD_BUG_ON(((size) > sizeof(struct __kernel_sockaddr_storage)))
......@@ -69,6 +71,9 @@ struct msghdr {
unsigned int msg_flags; /* flags on received message */
__kernel_size_t msg_controllen; /* ancillary data buffer length */
struct kiocb *msg_iocb; /* ptr to iocb for async requests */
struct ubuf_info *msg_ubuf;
int (*sg_from_iter)(struct sock *sk, struct sk_buff *skb,
struct iov_iter *from, size_t length);
};
struct user_msghdr {
......@@ -416,10 +421,9 @@ extern int recvmsg_copy_msghdr(struct msghdr *msg,
struct user_msghdr __user *umsg, unsigned flags,
struct sockaddr __user **uaddr,
struct iovec **iov);
extern int __copy_msghdr_from_user(struct msghdr *kmsg,
struct user_msghdr __user *umsg,
struct sockaddr __user **save_addr,
struct iovec __user **uiov, size_t *nsegs);
extern int __copy_msghdr(struct msghdr *kmsg,
struct user_msghdr *umsg,
struct sockaddr __user **save_addr);
/* helpers which do the actual work for syscalls */
extern int __sys_recvfrom(int fd, void __user *ubuf, size_t size,
......@@ -428,10 +432,6 @@ extern int __sys_recvfrom(int fd, void __user *ubuf, size_t size,
extern int __sys_sendto(int fd, void __user *buff, size_t len,
unsigned int flags, struct sockaddr __user *addr,
int addr_len);
extern int __sys_accept4_file(struct file *file, unsigned file_flags,
struct sockaddr __user *upeer_sockaddr,
int __user *upeer_addrlen, int flags,
unsigned long nofile);
extern struct file *do_accept(struct file *file, unsigned file_flags,
struct sockaddr __user *upeer_sockaddr,
int __user *upeer_addrlen, int flags);
......
......@@ -22,54 +22,102 @@ static int max_node_num;
*/
static int *cpunode_map;
static struct perf_cpu_map *cpu_map__from_entries(struct cpu_map_entries *cpus)
bool perf_record_cpu_map_data__test_bit(int i,
const struct perf_record_cpu_map_data *data)
{
int bit_word32 = i / 32;
__u32 bit_mask32 = 1U << (i & 31);
int bit_word64 = i / 64;
__u64 bit_mask64 = ((__u64)1) << (i & 63);
return (data->mask32_data.long_size == 4)
? (bit_word32 < data->mask32_data.nr) &&
(data->mask32_data.mask[bit_word32] & bit_mask32) != 0
: (bit_word64 < data->mask64_data.nr) &&
(data->mask64_data.mask[bit_word64] & bit_mask64) != 0;
}
/* Read ith mask value from data into the given 64-bit sized bitmap */
static void perf_record_cpu_map_data__read_one_mask(const struct perf_record_cpu_map_data *data,
int i, unsigned long *bitmap)
{
#if __SIZEOF_LONG__ == 8
if (data->mask32_data.long_size == 4)
bitmap[0] = data->mask32_data.mask[i];
else
bitmap[0] = data->mask64_data.mask[i];
#else
if (data->mask32_data.long_size == 4) {
bitmap[0] = data->mask32_data.mask[i];
bitmap[1] = 0;
} else {
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
bitmap[0] = (unsigned long)(data->mask64_data.mask[i] >> 32);
bitmap[1] = (unsigned long)data->mask64_data.mask[i];
#else
bitmap[0] = (unsigned long)data->mask64_data.mask[i];
bitmap[1] = (unsigned long)(data->mask64_data.mask[i] >> 32);
#endif
}
#endif
}
static struct perf_cpu_map *cpu_map__from_entries(const struct perf_record_cpu_map_data *data)
{
struct perf_cpu_map *map;
map = perf_cpu_map__empty_new(cpus->nr);
map = perf_cpu_map__empty_new(data->cpus_data.nr);
if (map) {
unsigned i;
for (i = 0; i < cpus->nr; i++) {
for (i = 0; i < data->cpus_data.nr; i++) {
/*
* Special treatment for -1, which is not real cpu number,
* and we need to use (int) -1 to initialize map[i],
* otherwise it would become 65535.
*/
if (cpus->cpu[i] == (u16) -1)
if (data->cpus_data.cpu[i] == (u16) -1)
map->map[i].cpu = -1;
else
map->map[i].cpu = (int) cpus->cpu[i];
map->map[i].cpu = (int) data->cpus_data.cpu[i];
}
}
return map;
}
static struct perf_cpu_map *cpu_map__from_mask(struct perf_record_record_cpu_map *mask)
static struct perf_cpu_map *cpu_map__from_mask(const struct perf_record_cpu_map_data *data)
{
DECLARE_BITMAP(local_copy, 64);
int weight = 0, mask_nr = data->mask32_data.nr;
struct perf_cpu_map *map;
int nr, nbits = mask->nr * mask->long_size * BITS_PER_BYTE;
nr = bitmap_weight(mask->mask, nbits);
for (int i = 0; i < mask_nr; i++) {
perf_record_cpu_map_data__read_one_mask(data, i, local_copy);
weight += bitmap_weight(local_copy, 64);
}
map = perf_cpu_map__empty_new(weight);
if (!map)
return NULL;
map = perf_cpu_map__empty_new(nr);
if (map) {
int cpu, i = 0;
for (int i = 0, j = 0; i < mask_nr; i++) {
int cpus_per_i = (i * data->mask32_data.long_size * BITS_PER_BYTE);
int cpu;
for_each_set_bit(cpu, mask->mask, nbits)
map->map[i++].cpu = cpu;
perf_record_cpu_map_data__read_one_mask(data, i, local_copy);
for_each_set_bit(cpu, local_copy, 64)
map->map[j++].cpu = cpu + cpus_per_i;
}
return map;
}
struct perf_cpu_map *cpu_map__new_data(struct perf_record_cpu_map_data *data)
struct perf_cpu_map *cpu_map__new_data(const struct perf_record_cpu_map_data *data)
{
if (data->type == PERF_CPU_MAP__CPUS)
return cpu_map__from_entries((struct cpu_map_entries *)data->data);
return cpu_map__from_entries(data);
else
return cpu_map__from_mask((struct perf_record_record_cpu_map *)data->data);
return cpu_map__from_mask(data);
}
size_t cpu_map__fprintf(struct perf_cpu_map *map, FILE *fp)
......
......@@ -37,9 +37,11 @@ struct cpu_aggr_map {
struct perf_record_cpu_map_data;
bool perf_record_cpu_map_data__test_bit(int i, const struct perf_record_cpu_map_data *data);
struct perf_cpu_map *perf_cpu_map__empty_new(int nr);
struct perf_cpu_map *cpu_map__new_data(struct perf_record_cpu_map_data *data);
struct perf_cpu_map *cpu_map__new_data(const struct perf_record_cpu_map_data *data);
size_t cpu_map__snprint(struct perf_cpu_map *map, char *buf, size_t size);
size_t cpu_map__snprint_mask(struct perf_cpu_map *map, char *buf, size_t size);
size_t cpu_map__fprintf(struct perf_cpu_map *map, FILE *fp);
......
......@@ -65,7 +65,8 @@ struct stack_dump {
struct sample_read_value {
u64 value;
u64 id;
u64 id; /* only if PERF_FORMAT_ID */
u64 lost; /* only if PERF_FORMAT_LOST */
};
struct sample_read {
......@@ -80,6 +81,24 @@ struct sample_read {
};
};
static inline size_t sample_read_value_size(u64 read_format)
{
/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
if (read_format & PERF_FORMAT_LOST)
return sizeof(struct sample_read_value);
else
return offsetof(struct sample_read_value, lost);
}
static inline struct sample_read_value *
next_sample_read_value(struct sample_read_value *v, u64 read_format)
{
return (void *)v + sample_read_value_size(read_format);
}
#define sample_read_group__for_each(v, nr, rf) \
for (int __i = 0; __i < (int)nr; v = next_sample_read_value(v, rf), __i++)
struct ip_callchain {
u64 nr;
u64 ips[];
......@@ -463,10 +482,6 @@ size_t perf_event__fprintf(union perf_event *event, struct machine *machine, FIL
int kallsyms__get_function_start(const char *kallsyms_filename,
const char *symbol_name, u64 *addr);
void *cpu_map_data__alloc(struct perf_cpu_map *map, size_t *size, u16 *type, int *max);
void cpu_map_data__synthesize(struct perf_record_cpu_map_data *data, struct perf_cpu_map *map,
u16 type, int max);
void event_attr_init(struct perf_event_attr *attr);
int perf_event_paranoid(void);
......
......@@ -1541,7 +1541,7 @@ static int evsel__read_one(struct evsel *evsel, int cpu_map_idx, int thread)
}
static void evsel__set_count(struct evsel *counter, int cpu_map_idx, int thread,
u64 val, u64 ena, u64 run)
u64 val, u64 ena, u64 run, u64 lost)
{
struct perf_counts_values *count;
......@@ -1550,6 +1550,7 @@ static void evsel__set_count(struct evsel *counter, int cpu_map_idx, int thread,
count->val = val;
count->ena = ena;
count->run = run;
count->lost = lost;
perf_counts__set_loaded(counter->counts, cpu_map_idx, thread, true);
}
......@@ -1558,7 +1559,7 @@ static int evsel__process_group_data(struct evsel *leader, int cpu_map_idx, int
{
u64 read_format = leader->core.attr.read_format;
struct sample_read_value *v;
u64 nr, ena = 0, run = 0, i;
u64 nr, ena = 0, run = 0, lost = 0;
nr = *data++;
......@@ -1571,18 +1572,18 @@ static int evsel__process_group_data(struct evsel *leader, int cpu_map_idx, int
if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
run = *data++;
v = (struct sample_read_value *) data;
evsel__set_count(leader, cpu_map_idx, thread, v[0].value, ena, run);
for (i = 1; i < nr; i++) {
v = (void *)data;
sample_read_group__for_each(v, nr, read_format) {
struct evsel *counter;
counter = evlist__id2evsel(leader->evlist, v[i].id);
counter = evlist__id2evsel(leader->evlist, v->id);
if (!counter)
return -EINVAL;
evsel__set_count(counter, cpu_map_idx, thread, v[i].value, ena, run);
if (read_format & PERF_FORMAT_LOST)
lost = v->lost;
evsel__set_count(counter, cpu_map_idx, thread, v->value, ena, run, lost);
}
return 0;
......@@ -2475,8 +2476,8 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,
if (data->read.group.nr > max_group_nr)
return -EFAULT;
sz = data->read.group.nr *
sizeof(struct sample_read_value);
sz = data->read.group.nr * sample_read_value_size(read_format);
OVERFLOW_CHECK(array, sz, max_size);
data->read.group.values =
(struct sample_read_value *)array;
......@@ -2485,6 +2486,12 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event,
OVERFLOW_CHECK_u64(array);
data->read.one.id = *array;
array++;
if (read_format & PERF_FORMAT_LOST) {
OVERFLOW_CHECK_u64(array);
data->read.one.lost = *array;
array++;
}
}
}
......
......@@ -642,15 +642,19 @@ static PyObject *python_process_brstacksym(struct perf_sample *sample,
return pylist;
}
static PyObject *get_sample_value_as_tuple(struct sample_read_value *value)
static PyObject *get_sample_value_as_tuple(struct sample_read_value *value,
u64 read_format)
{
PyObject *t;
t = PyTuple_New(2);
t = PyTuple_New(3);
if (!t)
Py_FatalError("couldn't create Python tuple");
PyTuple_SetItem(t, 0, PyLong_FromUnsignedLongLong(value->id));
PyTuple_SetItem(t, 1, PyLong_FromUnsignedLongLong(value->value));
if (read_format & PERF_FORMAT_LOST)
PyTuple_SetItem(t, 2, PyLong_FromUnsignedLongLong(value->lost));
return t;
}
......@@ -681,12 +685,17 @@ static void set_sample_read_in_dict(PyObject *dict_sample,
Py_FatalError("couldn't create Python list");
if (read_format & PERF_FORMAT_GROUP) {
for (i = 0; i < sample->read.group.nr; i++) {
PyObject *t = get_sample_value_as_tuple(&sample->read.group.values[i]);
struct sample_read_value *v = sample->read.group.values;
i = 0;
sample_read_group__for_each(v, sample->read.group.nr, read_format) {
PyObject *t = get_sample_value_as_tuple(v, read_format);
PyList_SET_ITEM(values, i, t);
i++;
}
} else {
PyObject *t = get_sample_value_as_tuple(&sample->read.one);
PyObject *t = get_sample_value_as_tuple(&sample->read.one,
read_format);
PyList_SET_ITEM(values, 0, t);
}
pydict_set_item_string_decref(dict_sample, "values", values);
......
......@@ -916,30 +916,30 @@ static void perf_event__cpu_map_swap(union perf_event *event,
bool sample_id_all __maybe_unused)
{
struct perf_record_cpu_map_data *data = &event->cpu_map.data;
struct cpu_map_entries *cpus;
struct perf_record_record_cpu_map *mask;
unsigned i;
data->type = bswap_16(data->type);
switch (data->type) {
case PERF_CPU_MAP__CPUS:
cpus = (struct cpu_map_entries *)data->data;
cpus->nr = bswap_16(cpus->nr);
data->cpus_data.nr = bswap_16(data->cpus_data.nr);
for (i = 0; i < cpus->nr; i++)
cpus->cpu[i] = bswap_16(cpus->cpu[i]);
for (unsigned i = 0; i < data->cpus_data.nr; i++)
data->cpus_data.cpu[i] = bswap_16(data->cpus_data.cpu[i]);
break;
case PERF_CPU_MAP__MASK:
mask = (struct perf_record_record_cpu_map *)data->data;
mask->nr = bswap_16(mask->nr);
mask->long_size = bswap_16(mask->long_size);
data->mask32_data.long_size = bswap_16(data->mask32_data.long_size);
switch (mask->long_size) {
case 4: mem_bswap_32(&mask->mask, mask->nr); break;
case 8: mem_bswap_64(&mask->mask, mask->nr); break;
switch (data->mask32_data.long_size) {
case 4:
data->mask32_data.nr = bswap_16(data->mask32_data.nr);
for (unsigned i = 0; i < data->mask32_data.nr; i++)
data->mask32_data.mask[i] = bswap_32(data->mask32_data.mask[i]);
break;
case 8:
data->mask64_data.nr = bswap_16(data->mask64_data.nr);
for (unsigned i = 0; i < data->mask64_data.nr; i++)
data->mask64_data.mask[i] = bswap_64(data->mask64_data.mask[i]);
break;
default:
pr_err("cpu_map swap: unsupported long size\n");
}
......@@ -1283,21 +1283,25 @@ static void sample_read__printf(struct perf_sample *sample, u64 read_format)
sample->read.time_running);
if (read_format & PERF_FORMAT_GROUP) {
u64 i;
struct sample_read_value *value = sample->read.group.values;
printf(".... group nr %" PRIu64 "\n", sample->read.group.nr);
for (i = 0; i < sample->read.group.nr; i++) {
struct sample_read_value *value;
value = &sample->read.group.values[i];
sample_read_group__for_each(value, sample->read.group.nr, read_format) {
printf("..... id %016" PRIx64
", value %016" PRIx64 "\n",
", value %016" PRIx64,
value->id, value->value);
if (read_format & PERF_FORMAT_LOST)
printf(", lost %" PRIu64, value->lost);
printf("\n");
}
} else
printf("..... id %016" PRIx64 ", value %016" PRIx64 "\n",
} else {
printf("..... id %016" PRIx64 ", value %016" PRIx64,
sample->read.one.id, sample->read.one.value);
if (read_format & PERF_FORMAT_LOST)
printf(", lost %" PRIu64, sample->read.one.lost);
printf("\n");
}
}
static void dump_event(struct evlist *evlist, union perf_event *event,
......@@ -1411,6 +1415,9 @@ static void dump_read(struct evsel *evsel, union perf_event *event)
if (read_format & PERF_FORMAT_ID)
printf("... id : %" PRI_lu64 "\n", read_event->id);
if (read_format & PERF_FORMAT_LOST)
printf("... lost : %" PRI_lu64 "\n", read_event->lost);
}
static struct machine *machines__find_for_cpumode(struct machines *machines,
......@@ -1479,14 +1486,14 @@ static int deliver_sample_group(struct evlist *evlist,
struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct machine *machine)
struct machine *machine,
u64 read_format)
{
int ret = -EINVAL;
u64 i;
struct sample_read_value *v = sample->read.group.values;
for (i = 0; i < sample->read.group.nr; i++) {
ret = deliver_sample_value(evlist, tool, event, sample,
&sample->read.group.values[i],
sample_read_group__for_each(v, sample->read.group.nr, read_format) {
ret = deliver_sample_value(evlist, tool, event, sample, v,
machine);
if (ret)
break;
......@@ -1510,7 +1517,7 @@ static int evlist__deliver_sample(struct evlist *evlist, struct perf_tool *tool,
/* For PERF_SAMPLE_READ we have either single or group mode. */
if (read_format & PERF_FORMAT_GROUP)
return deliver_sample_group(evlist, tool, event, sample,
machine);
machine, read_format);
else
return deliver_sample_value(evlist, tool, event, sample,
&sample->read.one, machine);
......
......@@ -1184,52 +1184,48 @@ int perf_event__synthesize_thread_map2(struct perf_tool *tool,
return err;
}
static void synthesize_cpus(struct cpu_map_entries *cpus,
struct perf_cpu_map *map)
static void synthesize_cpus(struct perf_record_cpu_map_data *data,
const struct perf_cpu_map *map)
{
int i, map_nr = perf_cpu_map__nr(map);
cpus->nr = map_nr;
data->cpus_data.nr = map_nr;
for (i = 0; i < map_nr; i++)
cpus->cpu[i] = perf_cpu_map__cpu(map, i).cpu;
data->cpus_data.cpu[i] = perf_cpu_map__cpu(map, i).cpu;
}
static void synthesize_mask(struct perf_record_record_cpu_map *mask,
struct perf_cpu_map *map, int max)
static void synthesize_mask(struct perf_record_cpu_map_data *data,
const struct perf_cpu_map *map, int max)
{
int i;
int idx;
struct perf_cpu cpu;
/* Due to padding, the 4bytes per entry mask variant is always smaller. */
data->mask32_data.nr = BITS_TO_U32(max);
data->mask32_data.long_size = 4;
mask->nr = BITS_TO_LONGS(max);
mask->long_size = sizeof(long);
perf_cpu_map__for_each_cpu(cpu, idx, map) {
int bit_word = cpu.cpu / 32;
__u32 bit_mask = 1U << (cpu.cpu & 31);
for (i = 0; i < perf_cpu_map__nr(map); i++)
set_bit(perf_cpu_map__cpu(map, i).cpu, mask->mask);
data->mask32_data.mask[bit_word] |= bit_mask;
}
}
static size_t cpus_size(struct perf_cpu_map *map)
static size_t cpus_size(const struct perf_cpu_map *map)
{
return sizeof(struct cpu_map_entries) + perf_cpu_map__nr(map) * sizeof(u16);
}
static size_t mask_size(struct perf_cpu_map *map, int *max)
static size_t mask_size(const struct perf_cpu_map *map, int *max)
{
int i;
*max = 0;
for (i = 0; i < perf_cpu_map__nr(map); i++) {
/* bit position of the cpu is + 1 */
int bit = perf_cpu_map__cpu(map, i).cpu + 1;
if (bit > *max)
*max = bit;
}
return sizeof(struct perf_record_record_cpu_map) + BITS_TO_LONGS(*max) * sizeof(long);
*max = perf_cpu_map__max(map).cpu;
return sizeof(struct perf_record_mask_cpu_map32) + BITS_TO_U32(*max) * sizeof(__u32);
}
void *cpu_map_data__alloc(struct perf_cpu_map *map, size_t *size, u16 *type, int *max)
static void *cpu_map_data__alloc(const struct perf_cpu_map *map, size_t *size,
u16 *type, int *max)
{
size_t size_cpus, size_mask;
bool is_dummy = perf_cpu_map__empty(map);
......@@ -1258,30 +1254,31 @@ void *cpu_map_data__alloc(struct perf_cpu_map *map, size_t *size, u16 *type, int
*type = PERF_CPU_MAP__MASK;
}
*size += sizeof(struct perf_record_cpu_map_data);
*size += sizeof(__u16); /* For perf_record_cpu_map_data.type. */
*size = PERF_ALIGN(*size, sizeof(u64));
return zalloc(*size);
}
void cpu_map_data__synthesize(struct perf_record_cpu_map_data *data, struct perf_cpu_map *map,
u16 type, int max)
static void cpu_map_data__synthesize(struct perf_record_cpu_map_data *data,
const struct perf_cpu_map *map,
u16 type, int max)
{
data->type = type;
switch (type) {
case PERF_CPU_MAP__CPUS:
synthesize_cpus((struct cpu_map_entries *) data->data, map);
synthesize_cpus(data, map);
break;
case PERF_CPU_MAP__MASK:
synthesize_mask((struct perf_record_record_cpu_map *)data->data, map, max);
synthesize_mask(data, map, max);
default:
break;
}
}
static struct perf_record_cpu_map *cpu_map_event__new(struct perf_cpu_map *map)
static struct perf_record_cpu_map *cpu_map_event__new(const struct perf_cpu_map *map)
{
size_t size = sizeof(struct perf_record_cpu_map);
size_t size = sizeof(struct perf_event_header);
struct perf_record_cpu_map *event;
int max;
u16 type;
......@@ -1299,7 +1296,7 @@ static struct perf_record_cpu_map *cpu_map_event__new(struct perf_cpu_map *map)
}
int perf_event__synthesize_cpu_map(struct perf_tool *tool,
struct perf_cpu_map *map,
const struct perf_cpu_map *map,
perf_event__handler_t process,
struct machine *machine)
{
......@@ -1432,11 +1429,12 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
result += sizeof(u64);
/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
if (read_format & PERF_FORMAT_GROUP) {
sz = sample->read.group.nr *
sizeof(struct sample_read_value);
result += sz;
sz = sample_read_value_size(read_format);
result += sz * sample->read.group.nr;
} else {
result += sizeof(u64);
if (read_format & PERF_FORMAT_LOST)
result += sizeof(u64);
}
}
......@@ -1521,6 +1519,20 @@ void __weak arch_perf_synthesize_sample_weight(const struct perf_sample *data,
*array = data->weight;
}
static __u64 *copy_read_group_values(__u64 *array, __u64 read_format,
const struct perf_sample *sample)
{
size_t sz = sample_read_value_size(read_format);
struct sample_read_value *v = sample->read.group.values;
sample_read_group__for_each(v, sample->read.group.nr, read_format) {
/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
memcpy(array, v, sz);
array = (void *)array + sz;
}
return array;
}
int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format,
const struct perf_sample *sample)
{
......@@ -1602,13 +1614,16 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_fo
/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
if (read_format & PERF_FORMAT_GROUP) {
sz = sample->read.group.nr *
sizeof(struct sample_read_value);
memcpy(array, sample->read.group.values, sz);
array = (void *)array + sz;
array = copy_read_group_values(array, read_format,
sample);
} else {
*array = sample->read.one.id;
array++;
if (read_format & PERF_FORMAT_LOST) {
*array = sample->read.one.lost;
array++;
}
}
}
......
......@@ -46,7 +46,7 @@ typedef int (*perf_event__handler_t)(struct perf_tool *tool, union perf_event *e
int perf_event__synthesize_attrs(struct perf_tool *tool, struct evlist *evlist, perf_event__handler_t process);
int perf_event__synthesize_attr(struct perf_tool *tool, struct perf_event_attr *attr, u32 ids, u64 *id, perf_event__handler_t process);
int perf_event__synthesize_build_id(struct perf_tool *tool, struct dso *pos, u16 misc, perf_event__handler_t process, struct machine *machine);
int perf_event__synthesize_cpu_map(struct perf_tool *tool, struct perf_cpu_map *cpus, perf_event__handler_t process, struct machine *machine);
int perf_event__synthesize_cpu_map(struct perf_tool *tool, const struct perf_cpu_map *cpus, perf_event__handler_t process, struct machine *machine);
int perf_event__synthesize_event_update_cpus(struct perf_tool *tool, struct evsel *evsel, perf_event__handler_t process);
int perf_event__synthesize_event_update_name(struct perf_tool *tool, struct evsel *evsel, perf_event__handler_t process);
int perf_event__synthesize_event_update_scale(struct perf_tool *tool, struct evsel *evsel, perf_event__handler_t process);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment