From: Dapeng Mi <dapeng1.mi@linux.intel.com>
To: Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@redhat.com>,
Arnaldo Carvalho de Melo <acme@kernel.org>,
Namhyung Kim <namhyung@kernel.org>,
Thomas Gleixner <tglx@linutronix.de>,
Dave Hansen <dave.hansen@linux.intel.com>,
Ian Rogers <irogers@google.com>,
Adrian Hunter <adrian.hunter@intel.com>,
Jiri Olsa <jolsa@kernel.org>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>,
Kan Liang <kan.liang@linux.intel.com>,
Andi Kleen <ak@linux.intel.com>,
Eranian Stephane <eranian@google.com>
Cc: Mark Rutland <mark.rutland@arm.com>,
broonie@kernel.org, Ravi Bangoria <ravi.bangoria@amd.com>,
linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org,
Dapeng Mi <dapeng1.mi@intel.com>,
Dapeng Mi <dapeng1.mi@linux.intel.com>
Subject: [Patch v4 07/17] perf/x86: Move XMM to sample_simd_vec_regs
Date: Thu, 25 Sep 2025 14:12:03 +0800 [thread overview]
Message-ID: <20250925061213.178796-8-dapeng1.mi@linux.intel.com> (raw)
In-Reply-To: <20250925061213.178796-1-dapeng1.mi@linux.intel.com>
From: Kan Liang <kan.liang@linux.intel.com>
The XMM0-15 are SIMD registers. Move them from sample_regs to
sample_simd_vec_regs. Reject access to the extended space of the
sample_regs if the new sample_simd_vec_regs is used.
The perf_reg_value requires the abi to understand the layout of the
sample_regs. Add the abi information in the struct x86_perf_regs.
Implement the X86-specific perf_simd_reg_validate to validate the SIMD
registers configuration from the user tool. Only the XMM0-15 is
supported now. More registers will be added in the following patches.
Implement the X86-specific perf_simd_reg_value to retrieve the XMM
value.
Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
Co-developed-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
---
arch/x86/events/core.c | 110 ++++++++++++++++++++++++--
arch/x86/events/intel/ds.c | 2 +-
arch/x86/events/perf_event.h | 12 +++
arch/x86/include/asm/perf_event.h | 1 +
arch/x86/include/uapi/asm/perf_regs.h | 17 ++++
arch/x86/kernel/perf_regs.c | 63 ++++++++++++++-
6 files changed, 195 insertions(+), 10 deletions(-)
diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index e363f5f2b37d..7b1b3eb80aa7 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -709,6 +709,22 @@ int x86_pmu_hw_config(struct perf_event *event)
return -EINVAL;
if (!event->attr.precise_ip)
return -EINVAL;
+ if (event->attr.sample_simd_regs_enabled)
+ return -EINVAL;
+ }
+
+ if (event_has_simd_regs(event)) {
+ if (!(event->pmu->capabilities & PERF_PMU_CAP_SIMD_REGS))
+ return -EINVAL;
+ /* Not require any vector registers but set width */
+ if (event->attr.sample_simd_vec_reg_qwords &&
+ !event->attr.sample_simd_vec_reg_intr &&
+ !event->attr.sample_simd_vec_reg_user)
+ return -EINVAL;
+ /* The vector registers set is not supported */
+ if (event_needs_xmm(event) &&
+ !(x86_pmu.ext_regs_mask & XFEATURE_MASK_SSE))
+ return -EINVAL;
}
}
@@ -1749,6 +1765,7 @@ x86_pmu_perf_get_regs_user(struct perf_sample_data *data,
struct x86_perf_regs *x86_regs_user = this_cpu_ptr(&x86_user_regs);
struct perf_regs regs_user;
+ x86_regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
perf_get_regs_user(®s_user, regs);
data->regs_user.abi = regs_user.abi;
if (regs_user.regs) {
@@ -1761,23 +1778,43 @@ x86_pmu_perf_get_regs_user(struct perf_sample_data *data,
static bool x86_pmu_user_req_pt_regs_only(struct perf_event *event)
{
+ if (event->attr.sample_simd_regs_enabled)
+ return false;
return !(event->attr.sample_regs_user & PERF_REG_EXTENDED_MASK);
}
-void x86_pmu_setup_regs_data(struct perf_event *event,
+static inline void
+x86_pmu_update_ext_regs_size(struct perf_event_attr *attr,
struct perf_sample_data *data,
- struct pt_regs *regs,
- u64 ignore_mask)
+ u64 ignore, struct pt_regs *regs,
+ u64 mask, u16 pred_mask)
+{
+ u16 pred_qwords = attr->sample_simd_pred_reg_qwords;
+ u16 vec_qwords = attr->sample_simd_vec_reg_qwords;
+ u16 nr_pred = hweight16(pred_mask);
+ u16 nr_vectors = hweight64(mask);
+
+ perf_simd_reg_check(regs, ignore,
+ mask, &nr_vectors, &vec_qwords,
+ pred_mask, &nr_pred, &pred_qwords);
+ data->dyn_size += (nr_vectors * vec_qwords + nr_pred * pred_qwords) * sizeof(u64);
+}
+
+static void x86_pmu_setup_basic_regs_data(struct perf_event *event,
+ struct perf_sample_data *data,
+ struct pt_regs *regs)
{
- struct x86_perf_regs *perf_regs = container_of(regs, struct x86_perf_regs, regs);
struct perf_event_attr *attr = &event->attr;
u64 sample_type = attr->sample_type;
- u64 mask = 0;
+ struct x86_perf_regs *perf_regs;
if (!(attr->sample_type & (PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_REGS_USER)))
return;
if (sample_type & PERF_SAMPLE_REGS_USER) {
+ perf_regs = container_of(regs, struct x86_perf_regs, regs);
+ perf_regs->abi = PERF_SAMPLE_REGS_ABI_NONE;
+
if (user_mode(regs)) {
data->regs_user.abi = perf_reg_abi(current);
data->regs_user.regs = regs;
@@ -1799,26 +1836,83 @@ void x86_pmu_setup_regs_data(struct perf_event *event,
data->dyn_size += sizeof(u64);
if (data->regs_user.regs)
data->dyn_size += hweight64(attr->sample_regs_user) * sizeof(u64);
+ perf_regs->abi |= data->regs_user.abi;
data->sample_flags |= PERF_SAMPLE_REGS_USER;
}
if (sample_type & PERF_SAMPLE_REGS_INTR) {
+ perf_regs = container_of(regs, struct x86_perf_regs, regs);
+ perf_regs->abi = PERF_SAMPLE_REGS_ABI_NONE;
+
data->regs_intr.regs = regs;
data->regs_intr.abi = perf_reg_abi(current);
data->dyn_size += sizeof(u64);
if (data->regs_intr.regs)
data->dyn_size += hweight64(attr->sample_regs_intr) * sizeof(u64);
+ perf_regs->abi |= data->regs_intr.abi;
data->sample_flags |= PERF_SAMPLE_REGS_INTR;
}
+}
+
+static void x86_pmu_setup_extended_regs_data(struct perf_event *event,
+ struct perf_sample_data *data,
+ struct pt_regs *regs,
+ u64 ignore_mask)
+{
+ struct perf_event_attr *attr = &event->attr;
+ u64 sample_type = attr->sample_type;
+ struct x86_perf_regs *perf_regs;
+ u64 mask = 0;
- if (event_has_extended_regs(event)) {
- perf_regs->xmm_regs = NULL;
+ if (!attr->sample_simd_regs_enabled)
+ return;
+
+ if (!(attr->sample_type & (PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_REGS_USER)))
+ return;
+
+ perf_regs = container_of(regs, struct x86_perf_regs, regs);
+
+ perf_regs->xmm_regs = NULL;
+ if (event_needs_xmm(event))
mask |= XFEATURE_MASK_SSE;
- }
mask &= ~ignore_mask;
if (mask)
x86_pmu_get_ext_regs(perf_regs, mask);
+
+ /* Update the data[] size */
+ if (sample_type & PERF_SAMPLE_REGS_USER && data->regs_user.abi) {
+ /* num and qwords of vector and pred registers */
+ data->dyn_size += sizeof(u64);
+ data->regs_user.abi |= PERF_SAMPLE_REGS_ABI_SIMD;
+ x86_pmu_update_ext_regs_size(attr, data, ignore_mask,
+ data->regs_user.regs,
+ attr->sample_simd_vec_reg_user,
+ attr->sample_simd_pred_reg_user);
+ }
+
+ if (sample_type & PERF_SAMPLE_REGS_INTR && data->regs_intr.abi) {
+ /* num and qwords of vector and pred registers */
+ data->dyn_size += sizeof(u64);
+ data->regs_intr.abi |= PERF_SAMPLE_REGS_ABI_SIMD;
+ x86_pmu_update_ext_regs_size(attr, data, ignore_mask,
+ data->regs_intr.regs,
+ attr->sample_simd_vec_reg_intr,
+ attr->sample_simd_pred_reg_intr);
+ }
+}
+
+void x86_pmu_setup_regs_data(struct perf_event *event,
+ struct perf_sample_data *data,
+ struct pt_regs *regs,
+ u64 ignore_mask)
+{
+ x86_pmu_setup_basic_regs_data(event, data, regs);
+ /*
+ * ignore_mask indicates the PEBS sampled extended regs which is unnessary
+ * to sample again.
+ */
+ x86_pmu_setup_extended_regs_data(event, data, regs, ignore_mask);
}
int x86_pmu_handle_irq(struct pt_regs *regs)
diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c
index f95dfee6adb2..59dbbc1c9968 100644
--- a/arch/x86/events/intel/ds.c
+++ b/arch/x86/events/intel/ds.c
@@ -1415,7 +1415,7 @@ static u64 pebs_update_adaptive_cfg(struct perf_event *event)
if (gprs || (attr->precise_ip < 2) || tsx_weight)
pebs_data_cfg |= PEBS_DATACFG_GP;
- if (event_has_extended_regs(event))
+ if (event_needs_xmm(event))
pebs_data_cfg |= PEBS_DATACFG_XMMS;
if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
index 7bf24842b1dc..6f22ed718a75 100644
--- a/arch/x86/events/perf_event.h
+++ b/arch/x86/events/perf_event.h
@@ -133,6 +133,18 @@ static inline bool is_acr_event_group(struct perf_event *event)
return check_leader_group(event->group_leader, PERF_X86_EVENT_ACR);
}
+static inline bool event_needs_xmm(struct perf_event *event)
+{
+ if (event->attr.sample_simd_regs_enabled &&
+ event->attr.sample_simd_vec_reg_qwords >= PERF_X86_XMM_QWORDS)
+ return true;
+
+ if (!event->attr.sample_simd_regs_enabled &&
+ event_has_extended_regs(event))
+ return true;
+ return false;
+}
+
struct amd_nb {
int nb_id; /* NorthBridge id */
int refcnt; /* reference count */
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index 8f18903ea9d0..fd4fe31e510b 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -596,6 +596,7 @@ extern void perf_events_lapic_init(void);
struct pt_regs;
struct x86_perf_regs {
struct pt_regs regs;
+ u64 abi;
union {
u64 *xmm_regs;
u32 *xmm_space; /* for xsaves */
diff --git a/arch/x86/include/uapi/asm/perf_regs.h b/arch/x86/include/uapi/asm/perf_regs.h
index 7c9d2bb3833b..c3862e5fdd6d 100644
--- a/arch/x86/include/uapi/asm/perf_regs.h
+++ b/arch/x86/include/uapi/asm/perf_regs.h
@@ -55,4 +55,21 @@ enum perf_event_x86_regs {
#define PERF_REG_EXTENDED_MASK (~((1ULL << PERF_REG_X86_XMM0) - 1))
+enum {
+ PERF_REG_X86_XMM,
+ PERF_REG_X86_MAX_SIMD_REGS,
+};
+
+enum {
+ PERF_X86_SIMD_XMM_REGS = 16,
+ PERF_X86_SIMD_VEC_REGS_MAX = PERF_X86_SIMD_XMM_REGS,
+};
+
+#define PERF_X86_SIMD_VEC_MASK GENMASK_ULL(PERF_X86_SIMD_VEC_REGS_MAX - 1, 0)
+
+enum {
+ PERF_X86_XMM_QWORDS = 2,
+ PERF_X86_SIMD_QWORDS_MAX = PERF_X86_XMM_QWORDS,
+};
+
#endif /* _ASM_X86_PERF_REGS_H */
diff --git a/arch/x86/kernel/perf_regs.c b/arch/x86/kernel/perf_regs.c
index 624703af80a1..6fd691cb7e64 100644
--- a/arch/x86/kernel/perf_regs.c
+++ b/arch/x86/kernel/perf_regs.c
@@ -57,12 +57,29 @@ static unsigned int pt_regs_offset[PERF_REG_X86_MAX] = {
#endif
};
+void perf_simd_reg_check(struct pt_regs *regs, u64 ignore,
+ u64 mask, u16 *nr_vectors, u16 *vec_qwords,
+ u16 pred_mask, u16 *nr_pred, u16 *pred_qwords)
+{
+ struct x86_perf_regs *perf_regs = container_of(regs, struct x86_perf_regs, regs);
+
+ if (!(ignore & XFEATURE_MASK_SSE) &&
+ *vec_qwords >= PERF_X86_XMM_QWORDS &&
+ !perf_regs->xmm_regs)
+ *nr_vectors = 0;
+
+ *nr_pred = 0;
+}
+
u64 perf_reg_value(struct pt_regs *regs, int idx)
{
struct x86_perf_regs *perf_regs;
if (idx >= PERF_REG_X86_XMM0 && idx < PERF_REG_X86_XMM_MAX) {
perf_regs = container_of(regs, struct x86_perf_regs, regs);
+ /* SIMD registers are moved to dedicated sample_simd_vec_reg */
+ if (perf_regs->abi & PERF_SAMPLE_REGS_ABI_SIMD)
+ return 0;
if (!perf_regs->xmm_regs)
return 0;
return perf_regs->xmm_regs[idx - PERF_REG_X86_XMM0];
@@ -74,6 +91,49 @@ u64 perf_reg_value(struct pt_regs *regs, int idx)
return regs_get_register(regs, pt_regs_offset[idx]);
}
+u64 perf_simd_reg_value(struct pt_regs *regs, int idx,
+ u16 qwords_idx, bool pred)
+{
+ struct x86_perf_regs *perf_regs = container_of(regs, struct x86_perf_regs, regs);
+
+ if (pred)
+ return 0;
+
+ if (WARN_ON_ONCE(idx >= PERF_X86_SIMD_VEC_REGS_MAX ||
+ qwords_idx >= PERF_X86_SIMD_QWORDS_MAX))
+ return 0;
+
+ if (qwords_idx < PERF_X86_XMM_QWORDS) {
+ if (!perf_regs->xmm_regs)
+ return 0;
+ return perf_regs->xmm_regs[idx * PERF_X86_XMM_QWORDS + qwords_idx];
+ }
+
+ return 0;
+}
+
+int perf_simd_reg_validate(u16 vec_qwords, u64 vec_mask,
+ u16 pred_qwords, u32 pred_mask)
+{
+ /* pred_qwords implies sample_simd_{pred,vec}_reg_* are supported */
+ if (!pred_qwords)
+ return 0;
+
+ if (!vec_qwords) {
+ if (vec_mask)
+ return -EINVAL;
+ } else {
+ if (vec_qwords != PERF_X86_XMM_QWORDS)
+ return -EINVAL;
+ if (vec_mask & ~PERF_X86_SIMD_VEC_MASK)
+ return -EINVAL;
+ }
+ if (pred_mask)
+ return -EINVAL;
+
+ return 0;
+}
+
#define PERF_REG_X86_RESERVED (((1ULL << PERF_REG_X86_XMM0) - 1) & \
~((1ULL << PERF_REG_X86_MAX) - 1))
@@ -114,7 +174,8 @@ void perf_get_regs_user(struct perf_regs *regs_user,
int perf_reg_validate(u64 mask)
{
- if (!mask || (mask & (REG_NOSUPPORT | PERF_REG_X86_RESERVED)))
+ /* The mask could be 0 if only the SIMD registers are interested */
+ if (mask & (REG_NOSUPPORT | PERF_REG_X86_RESERVED))
return -EINVAL;
return 0;
--
2.34.1
next prev parent reply other threads:[~2025-09-25 6:14 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-25 6:11 [Patch v4 00/17] Support vector and more extended registers in perf Dapeng Mi
2025-09-25 6:11 ` [Patch v4 01/17] perf/x86: Use x86_perf_regs in the x86 nmi handler Dapeng Mi
2025-09-25 6:11 ` [Patch v4 02/17] perf/x86: Setup the regs data Dapeng Mi
2025-09-25 6:11 ` [Patch v4 03/17] x86/fpu/xstate: Add xsaves_nmi Dapeng Mi
2025-09-25 15:07 ` Dave Hansen
2025-09-28 5:31 ` Mi, Dapeng
2025-09-29 19:01 ` Dave Hansen
2025-09-30 2:44 ` Mi, Dapeng
2025-09-25 6:12 ` [Patch v4 04/17] perf: Move has_extended_regs() to header file Dapeng Mi
2025-09-25 6:12 ` [Patch v4 05/17] perf/x86: Support XMM register for non-PEBS and REGS_USER Dapeng Mi
2025-09-25 6:12 ` [Patch v4 06/17] perf: Support SIMD registers Dapeng Mi
2025-09-25 6:12 ` Dapeng Mi [this message]
2025-09-25 6:12 ` [Patch v4 08/17] perf/x86: Add YMM into sample_simd_vec_regs Dapeng Mi
2025-09-25 6:12 ` [Patch v4 09/17] perf/x86: Add ZMM " Dapeng Mi
2025-09-25 6:12 ` [Patch v4 10/17] perf/x86: Add OPMASK into sample_simd_pred_reg Dapeng Mi
2025-09-25 6:12 ` [Patch v4 11/17] perf/x86: Add eGPRs into sample_regs Dapeng Mi
2025-09-25 6:12 ` [Patch v4 12/17] perf/x86: Add SSP " Dapeng Mi
2025-09-25 6:12 ` [Patch v4 13/17] perf/x86/intel: Enable PERF_PMU_CAP_SIMD_REGS Dapeng Mi
2025-09-25 6:12 ` [Patch v4 14/17] perf tools: Only support legacy regs for the PT and PERF_REGS_MASK Dapeng Mi
2025-09-25 6:12 ` [Patch v4 15/17] perf tools: headers: Sync with the kernel sources Dapeng Mi
2025-09-25 6:12 ` [Patch v4 16/17] perf tools: parse-regs: Support the new SIMD format Dapeng Mi
2025-09-25 6:12 ` [Patch v4 17/17] perf tools: regs: Support to dump regs for PERF_SAMPLE_REGS_ABI_SIMD Dapeng Mi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250925061213.178796-8-dapeng1.mi@linux.intel.com \
--to=dapeng1.mi@linux.intel.com \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=ak@linux.intel.com \
--cc=alexander.shishkin@linux.intel.com \
--cc=broonie@kernel.org \
--cc=dapeng1.mi@intel.com \
--cc=dave.hansen@linux.intel.com \
--cc=eranian@google.com \
--cc=irogers@google.com \
--cc=jolsa@kernel.org \
--cc=kan.liang@linux.intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mingo@redhat.com \
--cc=namhyung@kernel.org \
--cc=peterz@infradead.org \
--cc=ravi.bangoria@amd.com \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.