Skip to content

Unable to accurately capture GC start and end timestamps - EventListener GC event monitoring issues #116361

Closed
@Liangjia0411

Description

@Liangjia0411

Description

Problem Overview

I'm experiencing difficulties trying to precisely measure the start and end times of .NET garbage collection. I need accurate GC duration measurements, but the events currently available through EventListener don't seem to provide complete information about the GC lifecycle.

Questions

  1. Is there a more accurate event to represent the start of GC, rather than GCSuspendEEBegin_V1?
  2. Does the current EventListener API provide sufficient information to accurately measure GC duration?
  3. Is there a recommended approach to measure the complete GC duration?

Reproduction Steps

Reproduction Code

using System;
using System.Diagnostics.Tracing;

public class GCEventListener : EventListener
{
    private long _gcStartTime;
    private DateTime _case9SystemTime;

    protected override void OnEventSourceCreated(EventSource eventSource)
    {
        if (eventSource.Name != "Microsoft-Windows-DotNETRuntime")
            return;

        EnableEvents(eventSource, EventLevel.Informational, (EventKeywords)1);
    }

    protected override void OnEventWritten(EventWrittenEventArgs eventData)
    {
        switch (eventData.EventId)
        {
            case 2: /* GCEnd_V1 */
                {
                    DateTime case2SystemTime = DateTime.Now;
                    var intervalMs = (case2SystemTime - _case9SystemTime).TotalMilliseconds;
                    Console.WriteLine($"Time interval between case 2 and case 9: {intervalMs:F2}ms");

                    var cost = TimeSpan.FromTicks(eventData.TimeStamp.Ticks - _gcStartTime).TotalMilliseconds;
                    Console.WriteLine($"GC ended, time from suspension to end: {cost:F2}ms");
                    break;
                }
            case 9: /* GCSuspendEEBegin_V1 */
                {
                    _case9SystemTime = DateTime.Now;
                    _gcStartTime = eventData.TimeStamp.Ticks;
                    break;
                }
        }
    }
}

class Program
{
    public class ClassA
    { }

    static void Main(string[] args)
    {
        var gcEventListener = new GCEventListener();

        for (int i = 0; i < 10000 * 100; i++)
        {
            var a = new ClassA();
        }

        GC.Collect();

        Console.WriteLine("Press Enter to exit...");
        Console.ReadLine();
    }
}

Expected behavior

I'm looking to capture events that identify the complete GC lifecycle, including:

  1. The event or timestamp when GC truly begins
  2. The event or timestamp when GC ends

Actual behavior

Looking at the output logs, the time difference between eventData.TimeStamp values seems to be the actual GC duration, but I'm not sure if there are more accurate events to identify the true start time of GC. Currently, I'm using GCSuspendEEBegin_V1 (case 9), but this might only be part of the GC process rather than the starting point.

Time interval between case 2 and case 9: 18.96ms
GC ended, time from suspension to end: 23.25ms
Time interval between case 2 and case 9: 0.01ms
GC ended, time from suspension to end: 1.38ms

Regression?

No response

Known Workarounds

No response

Configuration

.NET version: 9.0.2

Other information

I've noticed that the timestamps in EventData seem to reflect the actual GC duration more accurately than system time measured using DateTime.Now. How can I correctly utilize these timestamps to precisely measure GC performance?

Metadata

Metadata

Assignees

Labels

area-System.Diagnostics.Tracingneeds-further-triageIssue has been initially triaged, but needs deeper consideration or reconsiderationquestionAnswer questions and provide assistance, not an issue with source code or documentation.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions