diff options
4 files changed, 176 insertions, 0 deletions
diff --git a/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/System.Private.CoreLib.csproj index faa24c12a5..5930aa0334 100644 --- a/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -131,6 +131,7 @@ <Compile Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\EventPipeEventProvider.cs" /> <Compile Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\EventPipeMetadataGenerator.cs" /> <Compile Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\EventPipePayloadDecoder.cs" /> + <Compile Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\RuntimeEventSource.cs" Condition="'$(FeaturePerfTracing)' == 'true'"/> <Compile Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\EventSource_CoreCLR.cs" /> <Compile Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\TraceLogging\TraceLoggingEventHandleTable.cs" /> <Compile Include="$(BclSourcesRoot)\System\Diagnostics\ICustomDebuggerNotification.cs" /> diff --git a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeController.cs b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeController.cs index 21a9b925a6..c03ba4f745 100644 --- a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeController.cs +++ b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeController.cs @@ -90,6 +90,7 @@ namespace System.Diagnostics.Tracing s_controllerInstance = new EventPipeController(); } // If enable is explicitly set to 0, then don't start the controller (to avoid overhead). + RuntimeEventSource.Initialize(); } } catch { } diff --git a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/RuntimeEventSource.cs b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/RuntimeEventSource.cs new file mode 100644 index 0000000000..168a6e37bc --- /dev/null +++ b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/RuntimeEventSource.cs @@ -0,0 +1,114 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Threading; + + +namespace System.Diagnostics.Tracing +{ + /// <summary> + /// RuntimeEventSource is an EventSource that represents events emitted by the managed runtime. + /// </summary> + [EventSource(Guid="49592C0F-5A05-516D-AA4B-A64E02026C89", Name = "System.Runtime")] + internal sealed class RuntimeEventSource : EventSource + { + private static RuntimeEventSource s_RuntimeEventSource; + private EventCounter[] _counters; + + private enum Counter { + GCHeapSize, + Gen0GCCount, + Gen1GCCount, + Gen2GCCount + } + + private Timer _timer; + + private const int EnabledPollingIntervalMilliseconds = 1000; // 1 second + + public static void Initialize() + { + s_RuntimeEventSource = new RuntimeEventSource(); + } + + private RuntimeEventSource(): base(new Guid(0x49592C0F, 0x5A05, 0x516D, 0xAA, 0x4B, 0xA6, 0x4E, 0x02, 0x02, 0x6C, 0x89), "System.Runtime", EventSourceSettings.EtwSelfDescribingEventFormat) + { + + } + + protected override void OnEventCommand(System.Diagnostics.Tracing.EventCommandEventArgs command) + { + if (command.Command == EventCommand.Enable) + { + if (_counters == null) + { + // NOTE: These counters will NOT be disposed on disable command because we may be introducing + // a race condition by doing that. We still want to create these lazily so that we aren't adding + // overhead by at all times even when counters aren't enabled. + _counters = new EventCounter[] { + // TODO: process info counters + + // GC info counters + new EventCounter("Total Memory by GC", this), + new EventCounter("Gen 0 GC Count", this), + new EventCounter("Gen 1 GC Count", this), + new EventCounter("Gen 2 GC Count", this), + + // TODO: Exception counter + }; + } + + + // Initialize the timer, but don't set it to run. + // The timer will be set to run each time PollForTracingCommand is called. + + // TODO: We should not need this timer once we are done settling upon a high-level design for + // what EventCounter is capable of doing. Once that decision is made, we should be able to + // get rid of this. + if (_timer == null) + { + _timer = new Timer( + callback: new TimerCallback(PollForCounterUpdate), + state: null, + dueTime: Timeout.Infinite, + period: Timeout.Infinite, + flowExecutionContext: false); + } + // Trigger the first poll operation on when this EventSource is enabled + PollForCounterUpdate(null); + } + else if (command.Command == EventCommand.Disable) + { + _timer.Change(Timeout.Infinite, Timeout.Infinite); // disable the timer from running until System.Runtime is re-enabled + } + } + + public void UpdateAllCounters() + { + // GC counters + _counters[(int)Counter.GCHeapSize].WriteMetric(GC.GetTotalMemory(false)); + _counters[(int)Counter.Gen0GCCount].WriteMetric(GC.CollectionCount(0)); + _counters[(int)Counter.Gen1GCCount].WriteMetric(GC.CollectionCount(1)); + _counters[(int)Counter.Gen2GCCount].WriteMetric(GC.CollectionCount(2)); + } + + private void PollForCounterUpdate(object state) + { + // TODO: Need to confirm with vancem about how to do error-handling here. + // This disables to timer from getting rescheduled to run, which may or may not be + // what we eventually want. + + // Make sure that any transient errors don't cause the listener thread to exit. + try + { + UpdateAllCounters(); + + // Schedule the timer to run again. + _timer.Change(EnabledPollingIntervalMilliseconds, Timeout.Infinite); + } + catch { } + } + } +} diff --git a/tests/CoreFX/CoreFX.issues.json b/tests/CoreFX/CoreFX.issues.json index ef0f725b70..d16c88b67b 100644 --- a/tests/CoreFX/CoreFX.issues.json +++ b/tests/CoreFX/CoreFX.issues.json @@ -158,6 +158,66 @@ { "name": "BasicEventSourceTests.TestsUserErrors.Test_BadEventSource_MismatchedIds", "reason": "Assert.Equal() Failure Expected: 1 Actual: 2" + }, + { + "name": "BasicEventSourceTests.TestsWrite.Test_Write_T_EventListener", + "reason": "Assert.Equal() Failure Expected: Actual: System.Runtime " + }, + { + "name": "BasicEventSourceTests.TestsWrite.Test_Write_T_EventListener_UseEvents", + "reason": "Assert.Equal() Failure Expected: Actual: System.Runtime " + }, + { + "name": "BasicEventSourceTests.TestsUserErrors.Test_BadEventSource_MismatchedIds_WithEtwListener", + "reason": "Assert.Equal() Failure Expected: Actual: System.Runtime " + }, + { + "name": "BasicEventSourceTests.FuzzyTests.Test_Write_Fuzzy", + "reason": "Assert.Equal() Failure Expected: Actual: System.Runtime " + }, + { + "name": "BasicEventSourceTests.TestsWriteEventToListener.Test_WriteEvent_InvalidCalls", + "reason": "Assert.Equal() Failure Expected: Actual: System.Runtime " + }, + { + "name": "BasicEventSourceTests.TestsWriteEventToListener.Test_WriteEvent_ZeroKwds", + "reason": "Assert.Equal() Failure Expected: Actual: System.Runtime " + }, + { + "name": "BasicEventSourceTests.TestsWriteEventToListener.Test_EventSourceCreatedEvents_BeforeListener", + "reason": "Assert.Equal() Failure Expected: Actual: System.Runtime " + }, + { + "name": "BasicEventSourceTests.TestsWriteEventToListener.Test_WriteEvent_ToChannel_Coverage", + "reason": "Assert.Equal() Failure Expected: Actual: System.Runtime " + }, + { + "name": "BasicEventSourceTests.TestsWriteEventToListener.Test_WriteEvent_ArgsCornerCases", + "reason": "Assert.Equal() Failure Expected: Actual: System.Runtime " + }, + { + "name": "BasicEventSourceTests.TestsWriteEventToListener.Test_EventSourceCreatedEvents_AfterListener", + "reason": "Assert.Equal() Failure Expected: Actual: System.Runtime " + }, + { + "name": "BasicEventSourceTests.TestsWriteEventToListener.Test_WriteEvent_ArgsBasicTypes", + "reason": "Assert.Equal() Failure Expected: Actual: System.Runtime " + }, + { + "name": "BasicEventSourceTests.TestsEventSourceLifetime.Test_EventSource_Lifetime", + "reason": "Assert.Equal() Failure Expected: Actual: System.Runtime " + }, + { + "name": "BasicEventSourceTests.TestsManifestNegative.Test_GenerateManifest_InvalidEventSources", + "reason": "Assert.Equal() Failure Expected: Actual: System.Runtime " + }, + { + "name": "BasicEventSourceTests.TestsTraits.Test_EventSource_Traits_Dynamic", + "reason": "Assert.Equal() Failure Expected: Actual: System.Runtime " + }, + { + "name": "BasicEventSourceTests.TestsTraits.Test_EventSource_Traits_Contract", + "reason": "Assert.Equal() Failure Expected: Actual: System.Runtime " } ] } |