From cdebbfec5c4be33d3243f829d934fa5804d177dd Mon Sep 17 00:00:00 2001 From: Eduardo Velarde Date: Wed, 20 Mar 2024 17:49:34 -0700 Subject: [PATCH 1/7] Add initialization for yield normalization --- src/coreclr/vm/ceemain.cpp | 4 ++ src/coreclr/vm/yieldprocessornormalized.cpp | 48 +++++++++++++++------ 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 0e546ffa120630..9fffba0f4f9d57 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -779,6 +779,10 @@ void EEStartupHelper() StubPrecode::StaticInitialize(); FixupPrecode::StaticInitialize(); + // Perform some measurements before garbage collector is initialized + // so GC initialization and the first few GCs can use the normalized yield + YieldProcessorNormalization::PerformMeasurement(); + InitializeGarbageCollector(); if (!GCHandleUtilities::GetGCHandleManager()->Initialize()) diff --git a/src/coreclr/vm/yieldprocessornormalized.cpp b/src/coreclr/vm/yieldprocessornormalized.cpp index 14166de34dd641..282601a435a452 100644 --- a/src/coreclr/vm/yieldprocessornormalized.cpp +++ b/src/coreclr/vm/yieldprocessornormalized.cpp @@ -10,12 +10,14 @@ enum class NormalizationState : UINT8 { Uninitialized, + PartiallyInitialized, Initialized, Failed }; static const int NsPerYieldMeasurementCount = 8; static const unsigned int MeasurementPeriodMs = 4000; +static const int s_partialInitializationMeasurementCount = 2; // number of measurements to be done during partial initialization static const unsigned int NsPerS = 1000 * 1000 * 1000; @@ -118,9 +120,9 @@ void YieldProcessorNormalization::PerformMeasurement() } CONTRACTL_END; - _ASSERTE(s_isMeasurementScheduled); + _ASSERTE(s_isMeasurementScheduled ^ (s_normalizationState == NormalizationState::Uninitialized)); - double latestNsPerYield; + double latestNsPerYield = 0; // initialize to supress error C4701 if (s_normalizationState == NormalizationState::Initialized) { if (GetTickCount() - s_previousNormalizationTimeMs < MeasurementPeriodMs) @@ -137,19 +139,31 @@ void YieldProcessorNormalization::PerformMeasurement() } s_nextMeasurementIndex = nextMeasurementIndex; } - else if (s_normalizationState == NormalizationState::Uninitialized) + else if (s_normalizationState == NormalizationState::Uninitialized || s_normalizationState == NormalizationState::PartiallyInitialized) { - LARGE_INTEGER li; - if (!QueryPerformanceFrequency(&li) || li.QuadPart < 1000 * 1000) + int startIndex, endIndex; + if (s_normalizationState == NormalizationState::Uninitialized) { - // High precision clock not available or clock resolution is too low, resort to defaults - s_normalizationState = NormalizationState::Failed; - return; + LARGE_INTEGER li; + if (!QueryPerformanceFrequency(&li) || li.QuadPart < 1000 * 1000) + { + // High precision clock not available or clock resolution is too low, resort to defaults + s_normalizationState = NormalizationState::Failed; + return; + } + s_performanceCounterTicksPerS = li.QuadPart; + + startIndex = 0; + endIndex = s_partialInitializationMeasurementCount; + } + else + { + startIndex = s_partialInitializationMeasurementCount; + endIndex = NsPerYieldMeasurementCount; } - s_performanceCounterTicksPerS = li.QuadPart; unsigned int measureDurationUs = DetermineMeasureDurationUs(); - for (int i = 0; i < NsPerYieldMeasurementCount; ++i) + for (int i = startIndex; i < endIndex; ++i) { latestNsPerYield = MeasureNsPerYield(measureDurationUs); AtomicStore(&s_nsPerYieldMeasurements[i], latestNsPerYield); @@ -163,6 +177,11 @@ void YieldProcessorNormalization::PerformMeasurement() FireEtwYieldProcessorMeasurement(GetClrInstanceId(), latestNsPerYield, s_establishedNsPerYield); } } + + s_normalizationState = + (s_normalizationState == NormalizationState::Uninitialized) ? + NormalizationState::PartiallyInitialized : + NormalizationState::Initialized; } else { @@ -171,7 +190,11 @@ void YieldProcessorNormalization::PerformMeasurement() } double establishedNsPerYield = s_nsPerYieldMeasurements[0]; - for (int i = 1; i < NsPerYieldMeasurementCount; ++i) + int endIndex = + (s_normalizationState == NormalizationState::PartiallyInitialized) ? + s_partialInitializationMeasurementCount : + NsPerYieldMeasurementCount; + for (int i = 1; i < endIndex; ++i) { double nsPerYield = s_nsPerYieldMeasurements[i]; if (nsPerYield < establishedNsPerYield) @@ -201,7 +224,6 @@ void YieldProcessorNormalization::PerformMeasurement() GCHeapUtilities::GetGCHeap()->SetYieldProcessorScalingFactor((float)yieldsPerNormalizedYield); s_previousNormalizationTimeMs = GetTickCount(); - s_normalizationState = NormalizationState::Initialized; s_isMeasurementScheduled = false; } @@ -217,7 +239,7 @@ void YieldProcessorNormalization::ScheduleMeasurementIfNecessary() CONTRACTL_END; NormalizationState normalizationState = VolatileLoadWithoutBarrier(&s_normalizationState); - if (normalizationState == NormalizationState::Initialized) + if (normalizationState == NormalizationState::Initialized || normalizationState == NormalizationState::PartiallyInitialized) { if (GetTickCount() - s_previousNormalizationTimeMs < MeasurementPeriodMs) { From acd40a5c6027c5b9f6ca347dcdea9bf1a1f5db01 Mon Sep 17 00:00:00 2001 From: Eduardo Velarde Date: Thu, 21 Mar 2024 13:08:53 -0700 Subject: [PATCH 2/7] Fix code --- src/coreclr/vm/yieldprocessornormalized.cpp | 34 ++++++++++++--------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/coreclr/vm/yieldprocessornormalized.cpp b/src/coreclr/vm/yieldprocessornormalized.cpp index 282601a435a452..e4a3558f63d3a1 100644 --- a/src/coreclr/vm/yieldprocessornormalized.cpp +++ b/src/coreclr/vm/yieldprocessornormalized.cpp @@ -16,8 +16,8 @@ enum class NormalizationState : UINT8 }; static const int NsPerYieldMeasurementCount = 8; +static const int PartialInitializationMeasurementCount = 2; // number of measurements to be done during partial initialization static const unsigned int MeasurementPeriodMs = 4000; -static const int s_partialInitializationMeasurementCount = 2; // number of measurements to be done during partial initialization static const unsigned int NsPerS = 1000 * 1000 * 1000; @@ -122,7 +122,7 @@ void YieldProcessorNormalization::PerformMeasurement() _ASSERTE(s_isMeasurementScheduled ^ (s_normalizationState == NormalizationState::Uninitialized)); - double latestNsPerYield = 0; // initialize to supress error C4701 + double latestNsPerYield; if (s_normalizationState == NormalizationState::Initialized) { if (GetTickCount() - s_previousNormalizationTimeMs < MeasurementPeriodMs) @@ -154,15 +154,16 @@ void YieldProcessorNormalization::PerformMeasurement() s_performanceCounterTicksPerS = li.QuadPart; startIndex = 0; - endIndex = s_partialInitializationMeasurementCount; + endIndex = PartialInitializationMeasurementCount; } else { - startIndex = s_partialInitializationMeasurementCount; + startIndex = PartialInitializationMeasurementCount; endIndex = NsPerYieldMeasurementCount; } unsigned int measureDurationUs = DetermineMeasureDurationUs(); + latestNsPerYield = 0; for (int i = startIndex; i < endIndex; ++i) { latestNsPerYield = MeasureNsPerYield(measureDurationUs); @@ -172,16 +173,11 @@ void YieldProcessorNormalization::PerformMeasurement() AtomicStore(&s_establishedNsPerYield, latestNsPerYield); } - if (i < NsPerYieldMeasurementCount - 1) + if (i < endIndex - 1) { FireEtwYieldProcessorMeasurement(GetClrInstanceId(), latestNsPerYield, s_establishedNsPerYield); } } - - s_normalizationState = - (s_normalizationState == NormalizationState::Uninitialized) ? - NormalizationState::PartiallyInitialized : - NormalizationState::Initialized; } else { @@ -191,8 +187,8 @@ void YieldProcessorNormalization::PerformMeasurement() double establishedNsPerYield = s_nsPerYieldMeasurements[0]; int endIndex = - (s_normalizationState == NormalizationState::PartiallyInitialized) ? - s_partialInitializationMeasurementCount : + (s_normalizationState == NormalizationState::Uninitialized) ? + PartialInitializationMeasurementCount : NsPerYieldMeasurementCount; for (int i = 1; i < endIndex; ++i) { @@ -223,7 +219,15 @@ void YieldProcessorNormalization::PerformMeasurement() GCHeapUtilities::GetGCHeap()->SetYieldProcessorScalingFactor((float)yieldsPerNormalizedYield); - s_previousNormalizationTimeMs = GetTickCount(); + if (s_normalizationState != NormalizationState::Uninitialized) + { + s_previousNormalizationTimeMs = GetTickCount(); + } + + s_normalizationState = + (s_normalizationState == NormalizationState::Uninitialized) ? + NormalizationState::PartiallyInitialized : + NormalizationState::Initialized; s_isMeasurementScheduled = false; } @@ -239,14 +243,14 @@ void YieldProcessorNormalization::ScheduleMeasurementIfNecessary() CONTRACTL_END; NormalizationState normalizationState = VolatileLoadWithoutBarrier(&s_normalizationState); - if (normalizationState == NormalizationState::Initialized || normalizationState == NormalizationState::PartiallyInitialized) + if (normalizationState == NormalizationState::Initialized) { if (GetTickCount() - s_previousNormalizationTimeMs < MeasurementPeriodMs) { return; } } - else if (normalizationState == NormalizationState::Uninitialized) + else if (normalizationState == NormalizationState::Uninitialized || normalizationState == NormalizationState::PartiallyInitialized) { } else From b37ffcd86a44f0b7639acf5eaefb17f72c567cd6 Mon Sep 17 00:00:00 2001 From: Eduardo Velarde Date: Tue, 26 Mar 2024 13:43:14 -0700 Subject: [PATCH 3/7] Add yieldprocessornormalized.h --- src/coreclr/vm/ceemain.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 9fffba0f4f9d57..4180b3f6d66008 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -163,6 +163,7 @@ #include "jithost.h" #include "pgo.h" #include "pendingload.h" +#include "yieldprocessornormalized.h" #ifndef TARGET_UNIX #include "dwreport.h" From 1a90ad8dc4ab8311c87ecabd565ba82cc02a902a Mon Sep 17 00:00:00 2001 From: Eduardo Velarde Date: Tue, 26 Mar 2024 18:44:45 -0700 Subject: [PATCH 4/7] Comment changes in ceemain.cpp to see effect on pipelines --- src/coreclr/vm/ceemain.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 4180b3f6d66008..5fefc97d45cc7a 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -163,7 +163,7 @@ #include "jithost.h" #include "pgo.h" #include "pendingload.h" -#include "yieldprocessornormalized.h" +// #include "yieldprocessornormalized.h" #ifndef TARGET_UNIX #include "dwreport.h" @@ -782,7 +782,7 @@ void EEStartupHelper() // Perform some measurements before garbage collector is initialized // so GC initialization and the first few GCs can use the normalized yield - YieldProcessorNormalization::PerformMeasurement(); + // YieldProcessorNormalization::PerformMeasurement(); InitializeGarbageCollector(); From 13c016137f7a8680abf1d557e2a34f5c8493b7f1 Mon Sep 17 00:00:00 2001 From: Eduardo Velarde Date: Wed, 27 Mar 2024 11:20:51 -0700 Subject: [PATCH 5/7] Revert "Comment changes in ceemain.cpp to see effect on pipelines" This reverts commit 1a90ad8dc4ab8311c87ecabd565ba82cc02a902a. --- src/coreclr/vm/ceemain.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 5fefc97d45cc7a..4180b3f6d66008 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -163,7 +163,7 @@ #include "jithost.h" #include "pgo.h" #include "pendingload.h" -// #include "yieldprocessornormalized.h" +#include "yieldprocessornormalized.h" #ifndef TARGET_UNIX #include "dwreport.h" @@ -782,7 +782,7 @@ void EEStartupHelper() // Perform some measurements before garbage collector is initialized // so GC initialization and the first few GCs can use the normalized yield - // YieldProcessorNormalization::PerformMeasurement(); + YieldProcessorNormalization::PerformMeasurement(); InitializeGarbageCollector(); From ea46a9122d5090698a665d75cd593e231a760acb Mon Sep 17 00:00:00 2001 From: Eduardo Velarde Date: Thu, 28 Mar 2024 10:46:52 -0700 Subject: [PATCH 6/7] Check IsGCHeapInitialized --- src/coreclr/inc/yieldprocessornormalized.h | 2 ++ src/coreclr/vm/ceemain.cpp | 2 ++ src/coreclr/vm/yieldprocessornormalized.cpp | 10 +++++++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/coreclr/inc/yieldprocessornormalized.h b/src/coreclr/inc/yieldprocessornormalized.h index 121e60b033356d..774024effe7dad 100644 --- a/src/coreclr/inc/yieldprocessornormalized.h +++ b/src/coreclr/inc/yieldprocessornormalized.h @@ -43,6 +43,8 @@ class YieldProcessorNormalization return s_isMeasurementScheduled; } + static void GCHeapSetYieldProcessorScalingFactor(); + static void PerformMeasurement(); private: diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 4180b3f6d66008..59c97d685a99aa 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -883,6 +883,8 @@ void EEStartupHelper() LogErrorToHost("GC heap initialization failed with error 0x%08X", hr); } + YieldProcessorNormalization::GCHeapSetYieldProcessorScalingFactor(); + IfFailGo(hr); #ifdef FEATURE_PERFTRACING diff --git a/src/coreclr/vm/yieldprocessornormalized.cpp b/src/coreclr/vm/yieldprocessornormalized.cpp index e4a3558f63d3a1..e96dfac57f601f 100644 --- a/src/coreclr/vm/yieldprocessornormalized.cpp +++ b/src/coreclr/vm/yieldprocessornormalized.cpp @@ -110,6 +110,14 @@ static double MeasureNsPerYield(unsigned int measureDurationUs) return Max(MinNsPerYield, Min((double)elapsedTicks * NsPerS / ((double)yieldCount * ticksPerS), MaxNsPerYield)); } +void YieldProcessorNormalization::GCHeapSetYieldProcessorScalingFactor() +{ + if (GCHeapUtilities::IsGCHeapInitialized()) + { + GCHeapUtilities::GetGCHeap()->SetYieldProcessorScalingFactor((float)s_yieldsPerNormalizedYield); + } +} + void YieldProcessorNormalization::PerformMeasurement() { CONTRACTL @@ -217,7 +225,7 @@ void YieldProcessorNormalization::PerformMeasurement() Max(1u, (unsigned int)(TargetMaxNsPerSpinIteration / (yieldsPerNormalizedYield * establishedNsPerYield) + 0.5)); _ASSERTE(s_optimalMaxNormalizedYieldsPerSpinIteration <= MaxOptimalMaxNormalizedYieldsPerSpinIteration); - GCHeapUtilities::GetGCHeap()->SetYieldProcessorScalingFactor((float)yieldsPerNormalizedYield); + GCHeapSetYieldProcessorScalingFactor(); if (s_normalizationState != NormalizationState::Uninitialized) { From c3ffb0a5d95b58ae5e9f7cf747ca6b37ee48ec0b Mon Sep 17 00:00:00 2001 From: Eduardo Velarde Date: Thu, 28 Mar 2024 11:42:58 -0700 Subject: [PATCH 7/7] Rename method --- src/coreclr/inc/yieldprocessornormalized.h | 2 +- src/coreclr/vm/ceemain.cpp | 2 +- src/coreclr/vm/yieldprocessornormalized.cpp | 18 ++++++++++++++---- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/coreclr/inc/yieldprocessornormalized.h b/src/coreclr/inc/yieldprocessornormalized.h index 774024effe7dad..2ef5ac1372ef9e 100644 --- a/src/coreclr/inc/yieldprocessornormalized.h +++ b/src/coreclr/inc/yieldprocessornormalized.h @@ -43,7 +43,7 @@ class YieldProcessorNormalization return s_isMeasurementScheduled; } - static void GCHeapSetYieldProcessorScalingFactor(); + static void NotifyGC(); static void PerformMeasurement(); diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 59c97d685a99aa..a34c774fa96003 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -883,7 +883,7 @@ void EEStartupHelper() LogErrorToHost("GC heap initialization failed with error 0x%08X", hr); } - YieldProcessorNormalization::GCHeapSetYieldProcessorScalingFactor(); + YieldProcessorNormalization::NotifyGC(); IfFailGo(hr); diff --git a/src/coreclr/vm/yieldprocessornormalized.cpp b/src/coreclr/vm/yieldprocessornormalized.cpp index e96dfac57f601f..c52a1e90fe688d 100644 --- a/src/coreclr/vm/yieldprocessornormalized.cpp +++ b/src/coreclr/vm/yieldprocessornormalized.cpp @@ -110,12 +110,19 @@ static double MeasureNsPerYield(unsigned int measureDurationUs) return Max(MinNsPerYield, Min((double)elapsedTicks * NsPerS / ((double)yieldCount * ticksPerS), MaxNsPerYield)); } -void YieldProcessorNormalization::GCHeapSetYieldProcessorScalingFactor() +void YieldProcessorNormalization::NotifyGC() { - if (GCHeapUtilities::IsGCHeapInitialized()) + CONTRACTL { - GCHeapUtilities::GetGCHeap()->SetYieldProcessorScalingFactor((float)s_yieldsPerNormalizedYield); + NOTHROW; + GC_NOTRIGGER; + MODE_PREEMPTIVE; } + CONTRACTL_END; + + _ASSERTE(GCHeapUtilities::IsGCHeapInitialized()); + + GCHeapUtilities::GetGCHeap()->SetYieldProcessorScalingFactor((float)s_yieldsPerNormalizedYield); } void YieldProcessorNormalization::PerformMeasurement() @@ -225,7 +232,10 @@ void YieldProcessorNormalization::PerformMeasurement() Max(1u, (unsigned int)(TargetMaxNsPerSpinIteration / (yieldsPerNormalizedYield * establishedNsPerYield) + 0.5)); _ASSERTE(s_optimalMaxNormalizedYieldsPerSpinIteration <= MaxOptimalMaxNormalizedYieldsPerSpinIteration); - GCHeapSetYieldProcessorScalingFactor(); + if (GCHeapUtilities::IsGCHeapInitialized()) + { + NotifyGC(); + } if (s_normalizationState != NormalizationState::Uninitialized) {