From dd50e9d388d22270fd6556d350496cd53c554460 Mon Sep 17 00:00:00 2001 From: Sung Yoon Whang Date: Thu, 1 Apr 2021 12:55:44 -0700 Subject: [PATCH 1/3] Add GC committed bytes counter --- .../src/System/Diagnostics/Tracing/RuntimeEventSource.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs index 053157c01d36c1..8b37a0b70cc115 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs @@ -28,6 +28,7 @@ internal sealed partial class RuntimeEventSource : EventSource private IncrementingPollingCounter? _allocRateCounter; private PollingCounter? _timerCounter; private PollingCounter? _fragmentationCounter; + private PollingCounter? _committedCounter; #if !MONO private IncrementingPollingCounter? _exceptionCounter; @@ -76,6 +77,7 @@ protected override void OnEventCommand(EventCommandEventArgs command) var gcInfo = GC.GetGCMemoryInfo(); return gcInfo.HeapSizeBytes != 0 ? gcInfo.FragmentedBytes * 100d / gcInfo.HeapSizeBytes : 0; }) { DisplayName = "GC Fragmentation", DisplayUnits = "%" }; + _committedCounter ??= new PollingCounter("gc-committed", this, () => GC.GetGCMemoryInfo().TotalCommittedBytes) { DisplayName = "GC Committed Bytes", DisplayUnits = "B" }; #if !MONO _exceptionCounter ??= new IncrementingPollingCounter("exception-count", this, () => Exception.GetExceptionCount()) { DisplayName = "Exception Count", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; _gcTimeCounter ??= new PollingCounter("time-in-gc", this, () => GC.GetLastGCPercentTimeInGC()) { DisplayName = "% Time in GC since last GC", DisplayUnits = "%" }; From 8880bf704c14f5a78ae81ff855b8f59841a0c0a9 Mon Sep 17 00:00:00 2001 From: Sung Yoon Whang Date: Thu, 1 Apr 2021 20:01:21 -0700 Subject: [PATCH 2/3] Add tests --- .../tracing/eventcounter/runtimecounters.cs | 111 ++++++++++++++++++ .../eventcounter/runtimecounters.csproj | 17 +++ 2 files changed, 128 insertions(+) create mode 100644 src/tests/tracing/eventcounter/runtimecounters.cs create mode 100644 src/tests/tracing/eventcounter/runtimecounters.csproj diff --git a/src/tests/tracing/eventcounter/runtimecounters.cs b/src/tests/tracing/eventcounter/runtimecounters.cs new file mode 100644 index 00000000000000..024e897fceaf88 --- /dev/null +++ b/src/tests/tracing/eventcounter/runtimecounters.cs @@ -0,0 +1,111 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if USE_MDT_EVENTSOURCE +using Microsoft.Diagnostics.Tracing; +#else +using System.Diagnostics.Tracing; +#endif +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using System.Diagnostics; + +namespace RuntimeEventCounterTests +{ + public class RuntimeCounterListener : EventListener + { + public RuntimeCounterListener() + { + observedRuntimeCounters = new Dictionary() { + { "cpu-usage" , false }, + { "working-set", false }, + { "gc-heap-size", false }, + { "gen-0-gc-count", false }, + { "gen-1-gc-count", false }, + { "gen-2-gc-count", false }, + { "threadpool-thread-count", false }, + { "monitor-lock-contention-count", false }, + { "threadpool-queue-length", false }, + { "threadpool-completed-items-count", false }, + { "alloc-rate", false }, + { "active-timer-count", false }, + { "gc-fragmentation", false }, + { "gc-committed", false }, + { "exception-count", false }, + { "time-in-gc", false }, + { "gen-0-size", false }, + { "gen-1-size", false }, + { "gen-2-size", false }, + { "loh-size", false }, + { "poh-size", false }, + { "assembly-count", false }, + { "il-bytes-jitted", false }, + { "methods-jitted-count", false } + }; + } + private Dictionary observedRuntimeCounters; + + protected override void OnEventSourceCreated(EventSource source) + { + if (source.Name.Equals("System.Runtime")) + { + Dictionary refreshInterval = new Dictionary(); + refreshInterval.Add("EventCounterIntervalSec", "1"); + EnableEvents(source, EventLevel.Informational, (EventKeywords)(-1), refreshInterval); + } + } + + protected override void OnEventWritten(EventWrittenEventArgs eventData) + { + + for (int i = 0; i < eventData.Payload.Count; i++) + { + IDictionary eventPayload = eventData.Payload[i] as IDictionary; + if (eventPayload != null) + { + foreach (KeyValuePair payload in eventPayload) + { + if (payload.Key.Equals("Name")) + observedRuntimeCounters[payload.Value.ToString()] = true; + } + } + } + } + + public bool Verify() + { + foreach (string counterName in observedRuntimeCounters.Keys) + { + if (!observedRuntimeCounters[counterName]) + { + return false; + } + } + return true; + } + } + + public partial class TestRuntimeEventCounter + { + public static int Main(string[] args) + { + // Create an EventListener. + using (RuntimeCounterListener myListener = new RuntimeCounterListener()) + { + Thread.Sleep(3000); + if (!myListener.Verify()) + { + Console.WriteLine("Test passed"); + return 100; + } + else + { + Console.WriteLine($"Test Failed - did not see one or more of the expected runtime counters."); + return 1; + } + } + } + } +} diff --git a/src/tests/tracing/eventcounter/runtimecounters.csproj b/src/tests/tracing/eventcounter/runtimecounters.csproj new file mode 100644 index 00000000000000..5859eb2f75de2c --- /dev/null +++ b/src/tests/tracing/eventcounter/runtimecounters.csproj @@ -0,0 +1,17 @@ + + + Exe + BuildAndRun + true + 0 + true + + true + + true + + + + + + From 7ab8bffdedf8ddc18988026d0cb5fe5c5dc9678d Mon Sep 17 00:00:00 2001 From: Sung Yoon Whang Date: Fri, 2 Apr 2021 13:52:59 -0700 Subject: [PATCH 3/3] fix test --- src/tests/tracing/eventcounter/runtimecounters.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tests/tracing/eventcounter/runtimecounters.cs b/src/tests/tracing/eventcounter/runtimecounters.cs index 024e897fceaf88..eaa7c87d6d8ab1 100644 --- a/src/tests/tracing/eventcounter/runtimecounters.cs +++ b/src/tests/tracing/eventcounter/runtimecounters.cs @@ -80,8 +80,13 @@ public bool Verify() { if (!observedRuntimeCounters[counterName]) { + Console.WriteLine($"Did not see {counterName}"); return false; } + else + { + Console.WriteLine($"Saw {counterName}"); + } } return true; } @@ -95,7 +100,7 @@ public static int Main(string[] args) using (RuntimeCounterListener myListener = new RuntimeCounterListener()) { Thread.Sleep(3000); - if (!myListener.Verify()) + if (myListener.Verify()) { Console.WriteLine("Test passed"); return 100;