From: Yi Sun <yi.sun@intel.com>
To: dave.hansen@intel.com, mingo@kernel.org,
linux-kernel@vger.kernel.org, x86@kernel.org
Cc: sohil.mehta@intel.com, ak@linux.intel.com,
ilpo.jarvinen@linux.intel.com, heng.su@intel.com,
tony.luck@intel.com, yi.sun@linux.intel.com, yu.c.chen@intel.com,
Yi Sun <yi.sun@intel.com>
Subject: [PATCH v7 1/3] x86/fpu: Measure the Latency of XSAVE and XRSTOR
Date: Thu, 21 Sep 2023 14:28:58 +0800 [thread overview]
Message-ID: <20230921062900.864679-2-yi.sun@intel.com> (raw)
In-Reply-To: <20230921062900.864679-1-yi.sun@intel.com>
Add two trace points x86_fpu_latency_xsave and x86_fpu_latency_xrstor.
The latency dumped by the new trace points can tell when XSAVE/XRSTOR
are getting more or less expensive, and get out the RFBM
(requested-feature bitmap) and XINUSE to figure out the reason.
Calculate the latency of instructions XSAVE and XRSTOR within a
single trace event respectively. Another option considered was to
have 2 separated trace events marking the start and finish of the
XSAVE/XRSTOR. The latency was calculated from the 2 trace points in
user space, but there was significant overhead added by the trace
function itself.
In internal testing, the single trace point option which is
implemented here proved to save big overhead introduced by trace
function.
Make use of trace_clock() to calculate the latency, which is based on
cpu_clock() with precision at most ~1 jiffy between CPUs.
Configure CONFIG_X86_DEBUG_FPU is required. And the compiler will get
rid of all the extra crust when CONFIG_X86_DEBUG_FPU is disabled.
If both of the configs are enabled, the function tracepoint_enabled
would be reduced to a static check for tracing enabled. Thus, in the
fast path there would be only 2 additional static checks.
Since trace points can be enabled dynamically, while the code is
checking tracepoint_enabled(trace_event), the trace_event could be
concurrently enabled. Hence there is probability to get single once
noisy result 'trace_clock() - (-1)' at the moment enabling the trace
points x86_fpu_latency_*. Leave the noise here instead of additional
conditions while calling the x86_fpu_latency_* because it's not worth
for the only once noise. It's easy to filter out by the following
consuming script or other user space tool.
Trace log looks like following:
x86_fpu_latency_xsave: x86/fpu: latency:100 RFBM:0x202e7 XINUSE:0x202
x86_fpu_latency_xrstor: x86/fpu: latency:99 RFBM:0x202e7 XINUSE:0x202
Reviewed-by: Sohil Mehta <sohil.mehta@intel.com>
Reviewed-by: Tony Luck <tony.luck@intel.com>
Signed-off-by: Yi Sun <yi.sun@intel.com>
diff --git a/arch/x86/include/asm/trace/fpu.h b/arch/x86/include/asm/trace/fpu.h
index 4645a6334063..0640fe79edf3 100644
--- a/arch/x86/include/asm/trace/fpu.h
+++ b/arch/x86/include/asm/trace/fpu.h
@@ -89,6 +89,43 @@ DEFINE_EVENT(x86_fpu, x86_fpu_xstate_check_failed,
TP_ARGS(fpu)
);
+#if defined(CONFIG_X86_DEBUG_FPU)
+DECLARE_EVENT_CLASS(x86_fpu_latency,
+ TP_PROTO(struct fpstate *fpstate, u64 latency),
+ TP_ARGS(fpstate, latency),
+
+ TP_STRUCT__entry(
+ __field(struct fpstate *, fpstate)
+ __field(u64, latency)
+ __field(u64, rfbm)
+ __field(u64, xinuse)
+ ),
+
+ TP_fast_assign(
+ __entry->fpstate = fpstate;
+ __entry->latency = latency;
+ __entry->rfbm = fpstate->xfeatures;
+ __entry->xinuse = fpstate->regs.xsave.header.xfeatures;
+ ),
+
+ TP_printk("x86/fpu: latency:%lld RFBM:0x%llx XINUSE:0x%llx",
+ __entry->latency,
+ __entry->rfbm,
+ __entry->xinuse
+ )
+);
+
+DEFINE_EVENT(x86_fpu_latency, x86_fpu_latency_xsave,
+ TP_PROTO(struct fpstate *fpstate, u64 latency),
+ TP_ARGS(fpstate, latency)
+);
+
+DEFINE_EVENT(x86_fpu_latency, x86_fpu_latency_xrstor,
+ TP_PROTO(struct fpstate *fpstate, u64 latency),
+ TP_ARGS(fpstate, latency)
+);
+#endif
+
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH asm/trace/
#undef TRACE_INCLUDE_FILE
diff --git a/arch/x86/kernel/fpu/xstate.h b/arch/x86/kernel/fpu/xstate.h
index a4ecb04d8d64..aa997fb86537 100644
--- a/arch/x86/kernel/fpu/xstate.h
+++ b/arch/x86/kernel/fpu/xstate.h
@@ -5,6 +5,9 @@
#include <asm/cpufeature.h>
#include <asm/fpu/xstate.h>
#include <asm/fpu/xcr.h>
+#include <asm/trace/fpu.h>
+
+#include <linux/trace_clock.h>
#ifdef CONFIG_X86_64
DECLARE_PER_CPU(u64, xfd_state);
@@ -113,7 +116,7 @@ static inline u64 xfeatures_mask_independent(void)
* original instruction which gets replaced. We need to use it here as the
* address of the instruction where we might get an exception at.
*/
-#define XSTATE_XSAVE(st, lmask, hmask, err) \
+#define __XSTATE_XSAVE(st, lmask, hmask, err) \
asm volatile(ALTERNATIVE_3(XSAVE, \
XSAVEOPT, X86_FEATURE_XSAVEOPT, \
XSAVEC, X86_FEATURE_XSAVEC, \
@@ -130,7 +133,7 @@ static inline u64 xfeatures_mask_independent(void)
* Use XRSTORS to restore context if it is enabled. XRSTORS supports compact
* XSAVE area format.
*/
-#define XSTATE_XRESTORE(st, lmask, hmask) \
+#define __XSTATE_XRESTORE(st, lmask, hmask) \
asm volatile(ALTERNATIVE(XRSTOR, \
XRSTORS, X86_FEATURE_XSAVES) \
"\n" \
@@ -140,6 +143,35 @@ static inline u64 xfeatures_mask_independent(void)
: "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \
: "memory")
+#if defined(CONFIG_X86_DEBUG_FPU)
+#define XSTATE_XSAVE(fps, lmask, hmask, err) \
+ do { \
+ struct fpstate *f = fps; \
+ u64 tc = -1; \
+ if (tracepoint_enabled(x86_fpu_latency_xsave)) \
+ tc = trace_clock(); \
+ __XSTATE_XSAVE(&f->regs.xsave, lmask, hmask, err); \
+ if (tracepoint_enabled(x86_fpu_latency_xsave)) \
+ trace_x86_fpu_latency_xsave(f, trace_clock() - tc);\
+ } while (0)
+
+#define XSTATE_XRESTORE(fps, lmask, hmask) \
+ do { \
+ struct fpstate *f = fps; \
+ u64 tc = -1; \
+ if (tracepoint_enabled(x86_fpu_latency_xrstor)) \
+ tc = trace_clock(); \
+ __XSTATE_XRESTORE(&f->regs.xsave, lmask, hmask); \
+ if (tracepoint_enabled(x86_fpu_latency_xrstor)) \
+ trace_x86_fpu_latency_xrstor(f, trace_clock() - tc);\
+ } while (0)
+#else
+#define XSTATE_XSAVE(fps, lmask, hmask, err) \
+ __XSTATE_XSAVE(&(fps)->regs.xsave, lmask, hmask, err)
+#define XSTATE_XRESTORE(fps, lmask, hmask) \
+ __XSTATE_XRESTORE(&(fps)->regs.xsave, lmask, hmask)
+#endif
+
#if defined(CONFIG_X86_64) && defined(CONFIG_X86_DEBUG_FPU)
extern void xfd_validate_state(struct fpstate *fpstate, u64 mask, bool rstor);
#else
@@ -184,7 +216,7 @@ static inline void os_xsave(struct fpstate *fpstate)
WARN_ON_FPU(!alternatives_patched);
xfd_validate_state(fpstate, mask, false);
- XSTATE_XSAVE(&fpstate->regs.xsave, lmask, hmask, err);
+ XSTATE_XSAVE(fpstate, lmask, hmask, err);
/* We should never fault when copying to a kernel buffer: */
WARN_ON_FPU(err);
@@ -201,7 +233,7 @@ static inline void os_xrstor(struct fpstate *fpstate, u64 mask)
u32 hmask = mask >> 32;
xfd_validate_state(fpstate, mask, true);
- XSTATE_XRESTORE(&fpstate->regs.xsave, lmask, hmask);
+ XSTATE_XRESTORE(fpstate, lmask, hmask);
}
/* Restore of supervisor state. Does not require XFD */
@@ -211,7 +243,7 @@ static inline void os_xrstor_supervisor(struct fpstate *fpstate)
u32 lmask = mask;
u32 hmask = mask >> 32;
- XSTATE_XRESTORE(&fpstate->regs.xsave, lmask, hmask);
+ XSTATE_XRESTORE(fpstate, lmask, hmask);
}
/*
--
2.34.1
next prev parent reply other threads:[~2023-09-21 18:53 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-09-21 6:28 [PATCH v7 0/3] x86/fpu Measure the Latency of XSAVES and XRSTORS Yi Sun
2023-09-21 6:28 ` Yi Sun [this message]
2023-09-21 7:03 ` [PATCH v7 1/3] x86/fpu: Measure the Latency of XSAVE and XRSTOR Ingo Molnar
2023-09-21 8:24 ` Yi Sun
2023-09-21 16:52 ` Andi Kleen
2023-09-22 3:44 ` Yi Sun
2023-09-21 6:28 ` [PATCH v7 2/3] tools/testing/fpu: Add script to consume trace log of xsave latency Yi Sun
2023-09-21 6:29 ` [PATCH v7 3/3] tools/testing/fpu: Add a 'count' column Yi Sun
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=20230921062900.864679-2-yi.sun@intel.com \
--to=yi.sun@intel.com \
--cc=ak@linux.intel.com \
--cc=dave.hansen@intel.com \
--cc=heng.su@intel.com \
--cc=ilpo.jarvinen@linux.intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@kernel.org \
--cc=sohil.mehta@intel.com \
--cc=tony.luck@intel.com \
--cc=x86@kernel.org \
--cc=yi.sun@linux.intel.com \
--cc=yu.c.chen@intel.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®