// This event is used to figure out if a collection is compacting or not // Note: last event for background GC (will be GCHeapStats for ephemeral (0/1) and non concurrent gen 2 collections) private void OnGcGlobalHeapHistory(EventWrittenEventArgs e) { var currentGC = GetCurrentGC(_gcInfo); // check unexpected event (we should have received a GCStart first) if (currentGC == null) { return; } // check if the collection was compacting var globalMask = (GCGlobalMechanisms)GetFieldValue <uint>(e, "GlobalMechanisms"); currentGC.IsCompacting = (globalMask & GCGlobalMechanisms.Compaction) == GCGlobalMechanisms.Compaction; // this is the last event for gen 2 background collections if ((GetFieldValue <uint>(e, "CondemnedGeneration") == 2) && (currentGC.Type == GCType.BackgroundGC)) { // check unexpected generation mismatch: should never occur if (currentGC.Generation != GetFieldValue <uint>(e, "CondemnedGeneration")) { return; } GcEvents?.Invoke(this, BuildGcArgs(currentGC)); ClearCollections(_gcInfo); } }
// This event provides the size of each generation after the collection // Note: last event for non background GC (will be GcGlobalHeapHistory for background gen 2) private void OnGcHeapStats(EventWrittenEventArgs e) { var currentGC = GetCurrentGC(_gcInfo); if (currentGC == null) { return; } currentGC.Heaps.Gen0Size = (long)GetFieldValue <ulong>(e, "GenerationSize0"); currentGC.Heaps.Gen1Size = (long)GetFieldValue <ulong>(e, "GenerationSize1"); currentGC.Heaps.Gen2Size = (long)GetFieldValue <ulong>(e, "GenerationSize2"); currentGC.Heaps.LOHSize = (long)GetFieldValue <ulong>(e, "GenerationSize3"); // this is the last event for a gen0/gen1 foreground collection during a background gen2 collections if ( (_gcInfo.CurrentBGC != null) && (currentGC.Generation < 2) ) { Debug.Assert(_gcInfo.GCInProgress == currentGC); GcEvents?.Invoke(this, BuildGcArgs(currentGC)); _gcInfo.GCInProgress = null; } }
private void OnGcRestartEEEnd(EventWrittenEventArgs e) { var currentGC = GetCurrentGC(_gcInfo); if (currentGC == null) { // this should never happen, except if we are unlucky to have missed a GCStart event return; } // compute suspension time double suspensionDuration = 0; if (_gcInfo.SuspensionStart.HasValue) { suspensionDuration = (e.TimeStamp - _gcInfo.SuspensionStart.Value).TotalMilliseconds; _gcInfo.SuspensionStart = null; } else { // bad luck: a xxxBegin event has been missed } currentGC.PauseDuration += suspensionDuration; // could be the end of a gen0/gen1 or of a non concurrent gen2 GC if ( (currentGC.Generation < 2) || (currentGC.Type == GCType.NonConcurrentGC) ) { GcEvents?.Invoke(this, BuildGcArgs(currentGC)); _gcInfo.GCInProgress = null; return; } // in case of background gen2, just need to sum the suspension time // --> its end will be detected during GcGlobalHistory event }