From 6cfd3b358816722cc51f061f774baa1b36f56233 Mon Sep 17 00:00:00 2001 From: Eduardo Velarde Date: Wed, 20 Mar 2024 17:49:34 -0700 Subject: [PATCH] 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) {