From 4f28505f953b177b0ba76b02c3d4a542f24a9b7f Mon Sep 17 00:00:00 2001 From: egorbo Date: Wed, 8 Jul 2026 10:55:36 +0200 Subject: [PATCH 1/5] Arm64: opt-in low-power spin-wait using FEAT_WFxT (WFET) Add an opt-in, disabled-by-default low-power spin-wait for Arm64 based on the FEAT_WFxT WFET (Wait For Event with Timeout) instruction. When the DOTNET_ThreadWfetSpinWait knob is set to 1 and the hardware supports FEAT_WFxT together with FEAT_ECV (for the self-synchronized CNTVCTSS_EL0 counter read), YieldProcessorNormalized and its variants issue a single low-power WFET timed wait for the equivalent duration instead of a busy YieldProcessor loop. CPU utilization stays about the same (the thread remains scheduled) but energy usage while spinning drops substantially. Details: * minipal detects FEAT_WFxT+FEAT_ECV (Linux HWCAP2_WFXT/HWCAP2_ECV, macOS sysctl hw.optional.arm.FEAT_WFxT/FEAT_ECV) as ARM64IntrinsicConstants_Wfxt, and provides minipal_wfet_wait_ns(). The WFET/CNTVCTSS/CNTFRQ/SB instructions are emitted via .inst so the sources build without an Armv8.7 assembler. The wait is scaled by CNTFRQ_EL0 (fixed 1GHz from Armv8.6 in the common case). * The runtime enables the flag in EEJitManager::SetCpuInfo() when the knob is set and the feature is present. Non-Windows Arm64 only (WFET is emitted via GNU inline asm). * When the knob is off (the default), behavior is unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/inc/clrconfigvalues.h | 3 + src/coreclr/inc/yieldprocessornormalized.h | 42 +++++++++- .../Compiler/HardwareIntrinsicHelpers.cs | 3 + src/coreclr/vm/codeman.cpp | 11 +++ src/native/minipal/cpufeatures.c | 83 +++++++++++++++++++ src/native/minipal/cpufeatures.h | 15 ++++ 6 files changed, 154 insertions(+), 3 deletions(-) diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index e923170681b432..aedcd29eacea3d 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -400,6 +400,9 @@ RETAIL_CONFIG_DWORD_INFO(EXTERNAL_SpinLimitProcCap, W("SpinLimitProcCap"), 0xFFF RETAIL_CONFIG_DWORD_INFO(EXTERNAL_SpinLimitProcFactor, W("SpinLimitProcFactor"), 0x4E20, "Hex value specifying the multiplier on NumProcs to use when calculating the maximum spin duration") RETAIL_CONFIG_DWORD_INFO(EXTERNAL_SpinLimitConstant, W("SpinLimitConstant"), 0x0, "Hex value specifying the constant to add when calculating the maximum spin duration") RETAIL_CONFIG_DWORD_INFO(EXTERNAL_SpinRetryCount, W("SpinRetryCount"), 0xA, "Hex value specifying the number of times the entire spin process is repeated (when applicable)") +// Opt-in (disabled by default). On Arm64 hardware with FEAT_WFxT (WFET), issue a low-power timed wait +// during normalized spin-waits instead of a busy YieldProcessor loop. Reduces energy usage while spinning. +RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ThreadWfetSpinWait, W("ThreadWfetSpinWait"), 0, "When set to 1 on Arm64 with FEAT_WFxT, use WFET for low-power spin-waits") /// /// Profiling API / ETW diff --git a/src/coreclr/inc/yieldprocessornormalized.h b/src/coreclr/inc/yieldprocessornormalized.h index e37bf79f0c5089..d86e09d9f52ea4 100644 --- a/src/coreclr/inc/yieldprocessornormalized.h +++ b/src/coreclr/inc/yieldprocessornormalized.h @@ -3,6 +3,8 @@ #pragma once +#include "minipal/cpufeatures.h" + #ifdef FEATURE_NATIVEAOT FORCEINLINE void System_YieldProcessor() { PalYieldProcessor(); } #else @@ -87,6 +89,23 @@ class YieldProcessorNormalizationInfo friend void YieldProcessorWithBackOffNormalized(const YieldProcessorNormalizationInfo &, unsigned int); }; +// When enabled at startup (Arm64 with FEAT_WFxT and the ThreadWfetSpinWait knob), a normalized spin-wait +// issues a single low-power WFET wait for the equivalent duration instead of a busy YieldProcessor loop. +// This trades a small amount of extra wake-up latency for substantially lower energy usage while spinning. +// 'normalizedYields' is the number of normalized yields the caller intended to perform. +FORCEINLINE bool TryYieldProcessorWithWfet(size_t normalizedYields) +{ +#if defined(HOST_ARM64) && !defined(HOST_WINDOWS) + if (g_minipalWfetSpinWaitEnabled) + { + minipal_wfet_wait_ns((uint64_t)normalizedYields * YieldProcessorNormalization::TargetNsPerNormalizedYield); + return true; + } +#endif + (void)normalizedYields; + return false; +} + // See YieldProcessorNormalized() for preliminary info. Typical usage: // if (!condition) // { @@ -98,6 +117,11 @@ class YieldProcessorNormalizationInfo // } FORCEINLINE void YieldProcessorNormalized(const YieldProcessorNormalizationInfo &normalizationInfo) { + if (TryYieldProcessorWithWfet(1)) + { + return; + } + unsigned int n = normalizationInfo.yieldsPerNormalizedYield; _ASSERTE(n != 0); do @@ -141,6 +165,11 @@ FORCEINLINE void YieldProcessorNormalized(const YieldProcessorNormalizationInfo { _ASSERTE(count != 0); + if (TryYieldProcessorWithWfet(count)) + { + return; + } + if (sizeof(size_t) <= sizeof(unsigned int)) { // On platforms with a small size_t, prevent overflow on the multiply below @@ -271,16 +300,23 @@ FORCEINLINE void YieldProcessorWithBackOffNormalized( static_assert( ((unsigned int)1 << (MaxShift + 1)) > YieldProcessorNormalization::MaxOptimalMaxNormalizedYieldsPerSpinIteration, ""); - unsigned int n; + unsigned int normalizedYields; if (spinIteration <= MaxShift && ((unsigned int)1 << spinIteration) < normalizationInfo.optimalMaxNormalizedYieldsPerSpinIteration) { - n = ((unsigned int)1 << spinIteration) * normalizationInfo.yieldsPerNormalizedYield; + normalizedYields = (unsigned int)1 << spinIteration; } else { - n = normalizationInfo.optimalMaxYieldsPerSpinIteration; + normalizedYields = normalizationInfo.optimalMaxNormalizedYieldsPerSpinIteration; } + + if (TryYieldProcessorWithWfet(normalizedYields)) + { + return; + } + + unsigned int n = normalizedYields * normalizationInfo.yieldsPerNormalizedYield; _ASSERTE(n != 0); do { diff --git a/src/coreclr/tools/Common/Compiler/HardwareIntrinsicHelpers.cs b/src/coreclr/tools/Common/Compiler/HardwareIntrinsicHelpers.cs index e40bc64c73a289..182dbd87143f9d 100644 --- a/src/coreclr/tools/Common/Compiler/HardwareIntrinsicHelpers.cs +++ b/src/coreclr/tools/Common/Compiler/HardwareIntrinsicHelpers.cs @@ -232,6 +232,9 @@ private static class Arm64IntrinsicConstants public const int SveAes = (1 << 13); public const int SveSha3 = (1 << 14); public const int SveSm4 = (1 << 15); + // Runtime-only feature (FEAT_WFxT), not a JIT hardware intrinsic ISA. Reserved here to keep the + // bit layout in sync with cpufeatures.h; it is intentionally not mapped to an InstructionSet. + public const int Wfxt = (1 << 16); public static void AddToBuilder(InstructionSetSupportBuilder builder, int flags) { diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index d3a640139b1a2e..d6cda8b233c293 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -1784,6 +1784,17 @@ void EEJitManager::SetCpuInfo() { g_arm64_atomics_present = true; } + + // Opt into low-power WFET-based spin-waits when the hardware supports FEAT_WFxT (+ FEAT_ECV) and the + // ThreadWfetSpinWait knob is set. This is consumed on the spin-wait hot path via YieldProcessorNormalized. + // WFET is emitted via GNU inline asm in the minipal, so it is only available on non-Windows Arm64. +#if !defined(TARGET_WINDOWS) + if (((cpuFeatures & ARM64IntrinsicConstants_Wfxt) != 0) && + (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ThreadWfetSpinWait) != 0)) + { + g_minipalWfetSpinWaitEnabled = 1; + } +#endif // !TARGET_WINDOWS #elif defined(TARGET_RISCV64) if (g_pConfig->EnableHWIntrinsic()) { diff --git a/src/native/minipal/cpufeatures.c b/src/native/minipal/cpufeatures.c index 9456932b62d2b2..b20073f199c71a 100644 --- a/src/native/minipal/cpufeatures.c +++ b/src/native/minipal/cpufeatures.c @@ -83,6 +83,12 @@ #ifndef HWCAP2_SVESM4 #define HWCAP2_SVESM4 (1 << 6) #endif +#ifndef HWCAP2_ECV +#define HWCAP2_ECV (1 << 19) +#endif +#ifndef HWCAP2_WFXT +#define HWCAP2_WFXT (1UL << 31) +#endif #endif @@ -566,6 +572,11 @@ int minipal_getcpufeatures(void) if (hwCap2 & HWCAP2_SVESM4) result |= ARM64IntrinsicConstants_SveSm4; + // WFET is only used together with the self-synchronized CNTVCTSS_EL0 counter read (FEAT_ECV), + // so require both FEAT_WFxT and FEAT_ECV. + if ((hwCap2 & HWCAP2_WFXT) && (hwCap2 & HWCAP2_ECV)) + result |= ARM64IntrinsicConstants_Wfxt; + #else // !HAVE_AUXV_HWCAP_H #if HAVE_SYSCTLBYNAME @@ -636,6 +647,20 @@ int minipal_getcpufeatures(void) if ((sysctlbyname("hw.optional.arm.FEAT_SVE_SM4", &valueFromSysctl, &sz, NULL, 0) == 0) && (valueFromSysctl != 0)) result |= ARM64IntrinsicConstants_SveSm4; + + // WFET is only used together with the self-synchronized CNTVCTSS_EL0 counter read (FEAT_ECV), + // so require both FEAT_WFxT and FEAT_ECV. + { + int64_t hasWfxt = 0; + int64_t hasEcv = 0; + size_t szWfxt = sizeof(hasWfxt); + size_t szEcv = sizeof(hasEcv); + if ((sysctlbyname("hw.optional.arm.FEAT_WFxT", &hasWfxt, &szWfxt, NULL, 0) == 0) && (hasWfxt != 0) && + (sysctlbyname("hw.optional.arm.FEAT_ECV", &hasEcv, &szEcv, NULL, 0) == 0) && (hasEcv != 0)) + { + result |= ARM64IntrinsicConstants_Wfxt; + } + } #endif // HAVE_SYSCTLBYNAME #endif // HAVE_AUXV_HWCAP_H #endif // HOST_UNIX @@ -793,3 +818,61 @@ bool minipal_detect_rosetta(void) return false; } + +#if defined(HOST_ARM64) && !defined(HOST_WINDOWS) +// Opt-in flag set by the runtime once it has verified FEAT_WFxT support and read the configuration knob. +int g_minipalWfetSpinWaitEnabled = 0; + +// Instruction encodings, used via .inst so that the sources build without requiring an assembler that +// understands the Armv8.7 mnemonics: +// WFET Xn : 0xD5031000 | n +// MRS Xn, CNTVCTSS_EL0 : 0xD53BE0C0 | n (self-synchronized virtual counter, FEAT_ECV) +// MRS Xn, CNTFRQ_EL0 : 0xD53BE000 | n +// SB : 0xD50330FF +static inline uint64_t minipal_read_cntvctss_el0(void) +{ + uint64_t value; + __asm__ __volatile__(".inst 0xd53be0c0\n\tmov %0, x0" : "=r"(value) : : "x0", "memory"); // mrs x0, cntvctss_el0 + return value; +} + +static inline uint64_t minipal_read_cntfrq_el0(void) +{ + uint64_t value; + __asm__ __volatile__(".inst 0xd53be000\n\tmov %0, x0" : "=r"(value) : : "x0"); // mrs x0, cntfrq_el0 + return value; +} + +void minipal_wfet_wait_ns(uint64_t ns) +{ + // The system counter frequency is fixed for the lifetime of the process, so read it once. + static uint64_t s_cntfrq = 0; + uint64_t cntfrq = s_cntfrq; + if (cntfrq == 0) + { + cntfrq = minipal_read_cntfrq_el0(); + s_cntfrq = cntfrq; // benign race: all readers observe the same value + } + + // Convert nanoseconds to counter ticks. From Armv8.6 onwards the counter runs at a fixed 1GHz + // (1 tick == 1 ns), which is the common case; scale by CNTFRQ_EL0 otherwise to stay correct. + const uint64_t NsPerSecond = 1000000000ULL; + uint64_t ticks = (cntfrq == NsPerSecond) ? ns : (ns * cntfrq) / NsPerSecond; + if (ticks == 0) + { + ticks = 1; + } + + uint64_t target = minipal_read_cntvctss_el0() + ticks; + uint64_t current; + do + { + // WFET enters a low-power state until an event arrives or CNTVCT_EL0 reaches the target in x9. + // It may also wake spuriously, so re-read the counter and loop until the deadline is reached. + __asm__ __volatile__("mov x9, %0\n\t.inst 0xd5031009" : : "r"(target) : "x9", "memory"); // wfet x9 + current = minipal_read_cntvctss_el0(); + } while (current < target); + + __asm__ __volatile__(".inst 0xd50330ff" : : : "memory"); // sb - prevent speculation past the wait +} +#endif // HOST_ARM64 && !HOST_WINDOWS diff --git a/src/native/minipal/cpufeatures.h b/src/native/minipal/cpufeatures.h index 53d9308f921247..85d70a46a2531b 100644 --- a/src/native/minipal/cpufeatures.h +++ b/src/native/minipal/cpufeatures.h @@ -4,6 +4,8 @@ #ifndef HAVE_MINIPAL_CPUFEATURES_H #define HAVE_MINIPAL_CPUFEATURES_H +#include + // // Should match the constants defined in the compiler in HardwareIntrinsicHelpers.cs // @@ -50,6 +52,9 @@ #define ARM64IntrinsicConstants_SveAes (1 << 13) #define ARM64IntrinsicConstants_SveSha3 (1 << 14) #define ARM64IntrinsicConstants_SveSm4 (1 << 15) +// Runtime-only feature (not a JIT hardware intrinsic ISA). Indicates FEAT_WFxT (WFET/WFIT) is +// available together with FEAT_ECV (required for the self-synchronized CNTVCTSS_EL0 counter read). +#define ARM64IntrinsicConstants_Wfxt (1 << 16) #include @@ -72,6 +77,16 @@ extern "C" int minipal_getcpufeatures(void); bool minipal_detect_rosetta(void); +#if defined(HOST_ARM64) && !defined(HOST_WINDOWS) +// Non-zero when the runtime has opted into using FEAT_WFxT (WFET) for low-power spin-waits. +// Set once during startup; read on the spin-wait hot path. +extern int g_minipalWfetSpinWaitEnabled; + +// Low-power wait for approximately 'ns' nanoseconds using the WFET instruction. The caller must +// ensure ARM64IntrinsicConstants_Wfxt is present (FEAT_WFxT + FEAT_ECV). +void minipal_wfet_wait_ns(uint64_t ns); +#endif // HOST_ARM64 && !HOST_WINDOWS + #ifdef __cplusplus } #endif // __cplusplus From 94c8fe06cd612b275ce938d40868c5a3043b2fb6 Mon Sep 17 00:00:00 2001 From: egorbo Date: Wed, 8 Jul 2026 17:39:33 +0200 Subject: [PATCH 2/5] Arm64 WFET: use roll-over-safe counter comparison Match Arm's recommended WFET delay sequence (nano_delay_v87 from the "Multi-threaded applications" developer.arm.com blog) by comparing the elapsed ticks against the requested duration (current - start < ticks) instead of an absolute (current < target) comparison. This makes the wait loop robust to system counter roll-over. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/native/minipal/cpufeatures.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/native/minipal/cpufeatures.c b/src/native/minipal/cpufeatures.c index b20073f199c71a..f3c1707b73cd87 100644 --- a/src/native/minipal/cpufeatures.c +++ b/src/native/minipal/cpufeatures.c @@ -863,15 +863,15 @@ void minipal_wfet_wait_ns(uint64_t ns) ticks = 1; } - uint64_t target = minipal_read_cntvctss_el0() + ticks; - uint64_t current; + uint64_t start = minipal_read_cntvctss_el0(); + uint64_t target = start + ticks; do { // WFET enters a low-power state until an event arrives or CNTVCT_EL0 reaches the target in x9. // It may also wake spuriously, so re-read the counter and loop until the deadline is reached. __asm__ __volatile__("mov x9, %0\n\t.inst 0xd5031009" : : "r"(target) : "x9", "memory"); // wfet x9 - current = minipal_read_cntvctss_el0(); - } while (current < target); + // Subtract-and-compare against the elapsed ticks so the loop is robust to counter roll-over. + } while ((minipal_read_cntvctss_el0() - start) < ticks); __asm__ __volatile__(".inst 0xd50330ff" : : : "memory"); // sb - prevent speculation past the wait } From bf406f9c3c7f0e7426f98f4500e2fdba82370086 Mon Sep 17 00:00:00 2001 From: egorbo Date: Wed, 8 Jul 2026 18:23:50 +0200 Subject: [PATCH 3/5] Arm64 WFET: address review feedback (data race, overflow) * minipal_wfet_wait_ns: read CNTFRQ_EL0 inline instead of caching it in a racy function-local static. CNTFRQ_EL0 is a constant register, so the per-call mrs is cheap and removes the data race on the shared cache. * Use a 128-bit intermediate for the ns->ticks scaling so the multiply cannot overflow when CNTFRQ_EL0 is not 1GHz. * TryYieldProcessorWithWfet: take 'unsigned int' instead of 'size_t' so that 'normalizedYields * TargetNsPerNormalizedYield' cannot overflow the uint64_t result. All call sites already pass unsigned int. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/inc/yieldprocessornormalized.h | 5 +++-- src/native/minipal/cpufeatures.c | 16 ++++++---------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/coreclr/inc/yieldprocessornormalized.h b/src/coreclr/inc/yieldprocessornormalized.h index d86e09d9f52ea4..daaee2b9b02bc9 100644 --- a/src/coreclr/inc/yieldprocessornormalized.h +++ b/src/coreclr/inc/yieldprocessornormalized.h @@ -92,8 +92,9 @@ class YieldProcessorNormalizationInfo // When enabled at startup (Arm64 with FEAT_WFxT and the ThreadWfetSpinWait knob), a normalized spin-wait // issues a single low-power WFET wait for the equivalent duration instead of a busy YieldProcessor loop. // This trades a small amount of extra wake-up latency for substantially lower energy usage while spinning. -// 'normalizedYields' is the number of normalized yields the caller intended to perform. -FORCEINLINE bool TryYieldProcessorWithWfet(size_t normalizedYields) +// 'normalizedYields' is the number of normalized yields the caller intended to perform. It is 'unsigned int' +// (not size_t) so that 'normalizedYields * TargetNsPerNormalizedYield' cannot overflow the uint64_t result. +FORCEINLINE bool TryYieldProcessorWithWfet(unsigned int normalizedYields) { #if defined(HOST_ARM64) && !defined(HOST_WINDOWS) if (g_minipalWfetSpinWaitEnabled) diff --git a/src/native/minipal/cpufeatures.c b/src/native/minipal/cpufeatures.c index f3c1707b73cd87..44795f4ae32142 100644 --- a/src/native/minipal/cpufeatures.c +++ b/src/native/minipal/cpufeatures.c @@ -845,19 +845,15 @@ static inline uint64_t minipal_read_cntfrq_el0(void) void minipal_wfet_wait_ns(uint64_t ns) { - // The system counter frequency is fixed for the lifetime of the process, so read it once. - static uint64_t s_cntfrq = 0; - uint64_t cntfrq = s_cntfrq; - if (cntfrq == 0) - { - cntfrq = minipal_read_cntfrq_el0(); - s_cntfrq = cntfrq; // benign race: all readers observe the same value - } + // CNTFRQ_EL0 is a constant system register, so reading it per call is a cheap non-trapping mrs and + // avoids any shared cache state (and the associated data race). + uint64_t cntfrq = minipal_read_cntfrq_el0(); // Convert nanoseconds to counter ticks. From Armv8.6 onwards the counter runs at a fixed 1GHz - // (1 tick == 1 ns), which is the common case; scale by CNTFRQ_EL0 otherwise to stay correct. + // (1 tick == 1 ns), which is the common case; scale by CNTFRQ_EL0 otherwise to stay correct. The + // scaling uses a 128-bit intermediate so the multiply cannot overflow for large 'ns'. const uint64_t NsPerSecond = 1000000000ULL; - uint64_t ticks = (cntfrq == NsPerSecond) ? ns : (ns * cntfrq) / NsPerSecond; + uint64_t ticks = (cntfrq == NsPerSecond) ? ns : (uint64_t)(((unsigned __int128)ns * cntfrq) / NsPerSecond); if (ticks == 0) { ticks = 1; From dab44f75857c80f6d1ac1a0c590f868cb8a93850 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Wed, 8 Jul 2026 20:58:09 +0200 Subject: [PATCH 4/5] Update clrconfigvalues.h --- src/coreclr/inc/clrconfigvalues.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index aedcd29eacea3d..d88f5c8b1c614b 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -402,7 +402,7 @@ RETAIL_CONFIG_DWORD_INFO(EXTERNAL_SpinLimitConstant, W("SpinLimitConstant"), 0x0 RETAIL_CONFIG_DWORD_INFO(EXTERNAL_SpinRetryCount, W("SpinRetryCount"), 0xA, "Hex value specifying the number of times the entire spin process is repeated (when applicable)") // Opt-in (disabled by default). On Arm64 hardware with FEAT_WFxT (WFET), issue a low-power timed wait // during normalized spin-waits instead of a busy YieldProcessor loop. Reduces energy usage while spinning. -RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ThreadWfetSpinWait, W("ThreadWfetSpinWait"), 0, "When set to 1 on Arm64 with FEAT_WFxT, use WFET for low-power spin-waits") +RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ThreadWfetSpinWait, W("ThreadWfetSpinWait"), 1, "When set to 1 on Arm64 with FEAT_WFxT, use WFET for low-power spin-waits") /// /// Profiling API / ETW From 5b91ce736019e7c2d8bdb5f8eda567209d491f7f Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Thu, 9 Jul 2026 15:56:11 +0200 Subject: [PATCH 5/5] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/coreclr/inc/clrconfigvalues.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index d88f5c8b1c614b..aedcd29eacea3d 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -402,7 +402,7 @@ RETAIL_CONFIG_DWORD_INFO(EXTERNAL_SpinLimitConstant, W("SpinLimitConstant"), 0x0 RETAIL_CONFIG_DWORD_INFO(EXTERNAL_SpinRetryCount, W("SpinRetryCount"), 0xA, "Hex value specifying the number of times the entire spin process is repeated (when applicable)") // Opt-in (disabled by default). On Arm64 hardware with FEAT_WFxT (WFET), issue a low-power timed wait // during normalized spin-waits instead of a busy YieldProcessor loop. Reduces energy usage while spinning. -RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ThreadWfetSpinWait, W("ThreadWfetSpinWait"), 1, "When set to 1 on Arm64 with FEAT_WFxT, use WFET for low-power spin-waits") +RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ThreadWfetSpinWait, W("ThreadWfetSpinWait"), 0, "When set to 1 on Arm64 with FEAT_WFxT, use WFET for low-power spin-waits") /// /// Profiling API / ETW