From bd2804c43178ef9e30d39c0686f0ae1dcf55a3f5 Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Wed, 26 Apr 2023 15:15:25 -0700 Subject: [PATCH 1/9] Enabling RuntimeEventSource for counters --- src/coreclr/nativeaot/Runtime/GCHelpers.cpp | 11 +++++ .../src/CompatibilitySuppressions.xml | 46 ++++++++++++++++++- .../src/System/GC.NativeAot.cs | 10 ++++ .../src/System/Runtime/RuntimeImports.cs | 8 ++++ .../Diagnostics/Tracing/CounterPayload.cs | 14 +++++- .../Tracing/IncrementingPollingCounter.cs | 7 ++- .../Diagnostics/Tracing/PollingCounter.cs | 7 ++- .../Diagnostics/Tracing/RuntimeEventSource.cs | 40 ++++++++++++++-- .../tracing/eventcounter/runtimecounters.cs | 4 +- .../eventcounter/runtimecounters.csproj | 15 ++++++ 10 files changed, 151 insertions(+), 11 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime/GCHelpers.cpp b/src/coreclr/nativeaot/Runtime/GCHelpers.cpp index d795d460753ea..40220bf757624 100644 --- a/src/coreclr/nativeaot/Runtime/GCHelpers.cpp +++ b/src/coreclr/nativeaot/Runtime/GCHelpers.cpp @@ -107,6 +107,17 @@ COOP_PINVOKE_HELPER(int32_t, RhGetGeneration, (OBJECTREF obj)) return GCHeapUtilities::GetGCHeap()->WhichGeneration(obj); } +COOP_PINVOKE_HELPER(int64_t, RhGetGenerationSize, (int32_t gen)) +{ + return (int64_t)(GCHeapUtilities::GetGCHeap()->GetLastGCGenerationSize(gen)); +} + +COOP_PINVOKE_HELPER(int64_t, RhGetLastGCPercentTimeInGC, ()) +{ + return GCHeapUtilities::GetGCHeap()->GetLastGCPercentTimeInGC(); +} + + COOP_PINVOKE_HELPER(int32_t, RhGetGcLatencyMode, ()) { return GCHeapUtilities::GetGCHeap()->GetGcLatencyMode(); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml b/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml index 8d13e91b02fee..0167c4ee726b4 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml @@ -956,6 +956,38 @@ CP0001 T:System.Threading.LockHolder + + CP0001 + T:System.Diagnostics.Tracing.CounterPayload + ref/net8.0/System.Private.CoreLib.dll + lib/net8.0/System.Private.CoreLib.dll + + + CP0001 + T:System.Diagnostics.Tracing.IncrementingCounterPayload + ref/net8.0/System.Private.CoreLib.dll + lib/net8.0/System.Private.CoreLib.dll + + + CP0001 + T:System.Diagnostics.Tracing.IncrementingPollingCounterPayloadType + ref/net8.0/System.Private.CoreLib.dll + lib/net8.0/System.Private.CoreLib.dll + + + CP0001 + T:System.Diagnostics.Tracing.PollingPayloadType + ref/net8.0/System.Private.CoreLib.dll + lib/net8.0/System.Private.CoreLib.dll + + + CP0002 + M:System.Diagnostics.Tracing.RuntimeEventSource.LogAppContextSwitch(System.String,System.Int32) + + + CP0002 + M:System.Diagnostics.Tracing.RuntimeEventSource.ProcessorCount(System.Int32) + CP0002 M:System.ModuleHandle.#ctor(System.Reflection.Module) @@ -972,6 +1004,18 @@ CP0002 M:System.TypedReference.get_IsNull + + CP0002 + M:System.GC.GetGenerationSize(System.Int32) + ref/net8.0/System.Private.CoreLib.dll + lib/net8.0/System.Private.CoreLib.dll + + + CP0002 + M:System.GC.GetLastGCPercentTimeInGC + ref/net8.0/System.Private.CoreLib.dll + lib/net8.0/System.Private.CoreLib.dll + CP0014 M:System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(System.Object)->object?:[T:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute] @@ -980,4 +1024,4 @@ CP0016 M:System.Runtime.InteropServices.Marshal.GetObjectForNativeVariant``1(System.IntPtr)->T?:[T:System.Diagnostics.CodeAnalysis.MaybeNullAttribute] - + \ No newline at end of file diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs index 9a4252425b95f..8e31b8bdd4b71 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs @@ -70,6 +70,16 @@ public static int GetGeneration(object obj) return RuntimeImports.RhGetGeneration(obj); } + public static int GetGenerationSize(int gen) + { + return RuntimeImports.RhGetGenerationSize(gen); + } + + public static int GetLastGCPercentTimeInGC() + { + return RuntimeImports.RhGetLastGCPercentTimeInGC(); + } + /// /// Returns the current generation number of the target /// of a specified . diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs index a0b70c8f45a4a..c8499335a4b8f 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs @@ -99,6 +99,14 @@ internal static void RhWaitForPendingFinalizers(bool allowReentrantWait) [RuntimeImport(RuntimeLibrary, "RhGetGeneration")] internal static extern int RhGetGeneration(object obj); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "RhGetGenerationSize")] + internal static extern int RhGetGenerationSize(int gen); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "RhGetLastGCPercentTimeInGC")] + internal static extern int RhGetLastGCPercentTimeInGC(); + [MethodImpl(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhGetGcLatencyMode")] internal static extern GCLatencyMode RhGetGcLatencyMode(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterPayload.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterPayload.cs index 01dac53d2583a..9f5846fe0bbe0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterPayload.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterPayload.cs @@ -7,7 +7,12 @@ namespace System.Diagnostics.Tracing { [EventData] - internal sealed class CounterPayload : IEnumerable> +#if NATIVEAOT + public // On NativeAOT, this must be public to prevent it from getting reflection blocked. +#else + internal +#endif + sealed class CounterPayload : IEnumerable> { public string? Name { get; set; } @@ -68,7 +73,12 @@ IEnumerator IEnumerable.GetEnumerator() } [EventData] - internal sealed class IncrementingCounterPayload : IEnumerable> +#if NATIVEAOT + public // On NativeAOT, this must be public to prevent it from getting reflection blocked. +#else + internal +#endif + sealed class IncrementingCounterPayload : IEnumerable> { public string? Name { get; set; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs index 35256d88f97fb..d7d60a171b8bb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs @@ -90,7 +90,12 @@ internal override void WritePayload(float intervalSec, int pollingIntervalMillis /// This is the payload that is sent in the with EventSource.Write /// [EventData] - internal sealed class IncrementingPollingCounterPayloadType +#if NATIVEAOT + public // On NativeAOT, this must be public to prevent it from getting reflection blocked. +#else + internal +#endif + sealed class IncrementingPollingCounterPayloadType { public IncrementingPollingCounterPayloadType(IncrementingCounterPayload payload) { Payload = payload; } public IncrementingCounterPayload Payload { get; set; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs index c295c260379d8..3610266f0dca3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs @@ -81,7 +81,12 @@ internal override void WritePayload(float intervalSec, int pollingIntervalMillis /// This is the payload that is sent in the with EventSource.Write /// [EventData] - internal sealed class PollingPayloadType +#if NATIVEAOT + public // On NativeAOT, this must be public to prevent it from getting reflection blocked. +#else + internal +#endif + sealed class PollingPayloadType { public PollingPayloadType(CounterPayload payload) { Payload = payload; } public CounterPayload Payload { get; set; } 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 5c01e52e0e467..e56cc4365866e 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 @@ -3,6 +3,7 @@ using System.Threading; using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; namespace System.Diagnostics.Tracing { @@ -36,15 +37,17 @@ public static class Keywords private PollingCounter? _timerCounter; private PollingCounter? _fragmentationCounter; -#if !NATIVEAOT // TODO shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase private PollingCounter? _committedCounter; +#if !NATIVEAOT // TODO shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase private IncrementingPollingCounter? _exceptionCounter; +#endif // !NATIVEAOT private PollingCounter? _gcTimeCounter; private PollingCounter? _gen0SizeCounter; private PollingCounter? _gen1SizeCounter; private PollingCounter? _gen2SizeCounter; private PollingCounter? _lohSizeCounter; private PollingCounter? _pohSizeCounter; +#if !NATIVEAOT // TODO shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase private PollingCounter? _assemblyCounter; #endif // !NATIVEAOT @@ -52,6 +55,23 @@ public static class Keywords private PollingCounter? _methodsJittedCounter; private IncrementingPollingCounter? _jitTimeCounter; +#if NATIVEAOT + /// + /// If EventSource feature is enabled, RuntimeEventSource needs to be initialized + /// In CoreCLR, this is done via StartupHookProvider.CoreCLR.cs + /// +#pragma warning disable CA2255 + [ModuleInitializer] + internal static void NativeAOTtartupHook() + { + if (EventSource.IsSupported) + { + Initialize(); + } + } +#pragma warning restore CA2255 +#endif + public static void Initialize() { // initializing more than once may lead to missing events @@ -71,13 +91,23 @@ private enum EventId : int } [Event((int)EventId.AppContextSwitch, Level = EventLevel.Informational, Keywords = Keywords.AppContext)] - internal void LogAppContextSwitch(string switchName, int value) +#if NATIVEAOT + public +#else + internal +#endif + void LogAppContextSwitch(string switchName, int value) { base.WriteEvent((int)EventId.AppContextSwitch, switchName, value); } [Event((int)EventId.ProcessorCount, Level = EventLevel.Informational, Keywords = Keywords.ProcessorCount)] - internal void ProcessorCount(int processorCount) +#if NATIVEAOT + public +#else + internal +#endif + void ProcessorCount(int processorCount) { base.WriteEvent((int)EventId.ProcessorCount, processorCount); } @@ -108,15 +138,17 @@ protected override void OnEventCommand(EventCommandEventArgs command) return gcInfo.HeapSizeBytes != 0 ? gcInfo.FragmentedBytes * 100d / gcInfo.HeapSizeBytes : 0; }) { DisplayName = "GC Fragmentation", DisplayUnits = "%" }; -#if !NATIVEAOT // TODO _committedCounter ??= new PollingCounter("gc-committed", this, () => ((double)GC.GetGCMemoryInfo().TotalCommittedBytes / 1_000_000)) { DisplayName = "GC Committed Bytes", DisplayUnits = "MB" }; +#if !NATIVEAOT // TODO _exceptionCounter ??= new IncrementingPollingCounter("exception-count", this, () => Exception.GetExceptionCount()) { DisplayName = "Exception Count", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; +#endif // !NATIVEAOT _gcTimeCounter ??= new PollingCounter("time-in-gc", this, () => GC.GetLastGCPercentTimeInGC()) { DisplayName = "% Time in GC since last GC", DisplayUnits = "%" }; _gen0SizeCounter ??= new PollingCounter("gen-0-size", this, () => GC.GetGenerationSize(0)) { DisplayName = "Gen 0 Size", DisplayUnits = "B" }; _gen1SizeCounter ??= new PollingCounter("gen-1-size", this, () => GC.GetGenerationSize(1)) { DisplayName = "Gen 1 Size", DisplayUnits = "B" }; _gen2SizeCounter ??= new PollingCounter("gen-2-size", this, () => GC.GetGenerationSize(2)) { DisplayName = "Gen 2 Size", DisplayUnits = "B" }; _lohSizeCounter ??= new PollingCounter("loh-size", this, () => GC.GetGenerationSize(3)) { DisplayName = "LOH Size", DisplayUnits = "B" }; _pohSizeCounter ??= new PollingCounter("poh-size", this, () => GC.GetGenerationSize(4)) { DisplayName = "POH (Pinned Object Heap) Size", DisplayUnits = "B" }; +#if !NATIVEAOT // TODO _assemblyCounter ??= new PollingCounter("assembly-count", this, () => System.Reflection.Assembly.GetAssemblyCount()) { DisplayName = "Number of Assemblies Loaded" }; #endif // !NATIVEAOT diff --git a/src/tests/tracing/eventcounter/runtimecounters.cs b/src/tests/tracing/eventcounter/runtimecounters.cs index dda0cb7038807..1472e4bee6648 100644 --- a/src/tests/tracing/eventcounter/runtimecounters.cs +++ b/src/tests/tracing/eventcounter/runtimecounters.cs @@ -33,14 +33,14 @@ public RuntimeCounterListener() { "active-timer-count", false }, { "gc-fragmentation", false }, { "gc-committed", false }, - { "exception-count", 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 }, + // { "assembly-count", false }, { "il-bytes-jitted", false }, { "methods-jitted-count", false }, { "time-in-jit", false } diff --git a/src/tests/tracing/eventcounter/runtimecounters.csproj b/src/tests/tracing/eventcounter/runtimecounters.csproj index 44abb2b5f37e6..49bf082a6dfcd 100644 --- a/src/tests/tracing/eventcounter/runtimecounters.csproj +++ b/src/tests/tracing/eventcounter/runtimecounters.csproj @@ -7,9 +7,24 @@ true true + true + + + + + + + + + From a9b8d6f417c7384d26ebf95d74e6993f33797afa Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Thu, 27 Apr 2023 07:18:37 -0700 Subject: [PATCH 2/9] enable exception and assembly count --- .../src/System/Exception.NativeAot.cs | 8 ++++++++ .../Diagnostics/Tracing/RuntimeEventSource.cs | 14 ++++++-------- src/tests/tracing/eventcounter/runtimecounters.cs | 4 ++-- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Exception.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Exception.NativeAot.cs index 0c974b56a5c45..2ab39d99881bb 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Exception.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Exception.NativeAot.cs @@ -95,6 +95,10 @@ private enum RhEHFrameType RH_EH_FIRST_RETHROW_FRAME = 2, } + // Performance metric to count the number of exceptions thrown + private static int s_exceptionCount; + internal static int ExceptionCount => s_exceptionCount; + [RuntimeExport("AppendExceptionStackFrame")] private static void AppendExceptionStackFrame(object exceptionObj, IntPtr IP, int flags) { @@ -112,6 +116,10 @@ private static void AppendExceptionStackFrame(object exceptionObj, IntPtr IP, in bool isFirstFrame = (flags & (int)RhEHFrameType.RH_EH_FIRST_FRAME) != 0; bool isFirstRethrowFrame = (flags & (int)RhEHFrameType.RH_EH_FIRST_RETHROW_FRAME) != 0; + // track count for metrics + if(isFirstFrame && !isFirstRethrowFrame) + s_exceptionCount++; + // When we're throwing an exception object, we first need to clear its stacktrace with two exceptions: // 1. Don't clear if we're rethrowing with `throw;`. // 2. Don't clear if we're throwing through ExceptionDispatchInfo. 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 e56cc4365866e..5f560a8d026e0 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 @@ -36,21 +36,15 @@ public static class Keywords private IncrementingPollingCounter? _allocRateCounter; private PollingCounter? _timerCounter; private PollingCounter? _fragmentationCounter; - private PollingCounter? _committedCounter; -#if !NATIVEAOT // TODO shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase private IncrementingPollingCounter? _exceptionCounter; -#endif // !NATIVEAOT private PollingCounter? _gcTimeCounter; private PollingCounter? _gen0SizeCounter; private PollingCounter? _gen1SizeCounter; private PollingCounter? _gen2SizeCounter; private PollingCounter? _lohSizeCounter; private PollingCounter? _pohSizeCounter; -#if !NATIVEAOT // TODO shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase private PollingCounter? _assemblyCounter; -#endif // !NATIVEAOT - private PollingCounter? _ilBytesJittedCounter; private PollingCounter? _methodsJittedCounter; private IncrementingPollingCounter? _jitTimeCounter; @@ -139,7 +133,9 @@ protected override void OnEventCommand(EventCommandEventArgs command) }) { DisplayName = "GC Fragmentation", DisplayUnits = "%" }; _committedCounter ??= new PollingCounter("gc-committed", this, () => ((double)GC.GetGCMemoryInfo().TotalCommittedBytes / 1_000_000)) { DisplayName = "GC Committed Bytes", DisplayUnits = "MB" }; -#if !NATIVEAOT // TODO +#if NATIVEAOT + _exceptionCounter ??= new IncrementingPollingCounter("exception-count", this, () => Exception.ExceptionCount) { DisplayName = "Exception Count", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; +#else _exceptionCounter ??= new IncrementingPollingCounter("exception-count", this, () => Exception.GetExceptionCount()) { DisplayName = "Exception Count", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; #endif // !NATIVEAOT _gcTimeCounter ??= new PollingCounter("time-in-gc", this, () => GC.GetLastGCPercentTimeInGC()) { DisplayName = "% Time in GC since last GC", DisplayUnits = "%" }; @@ -148,7 +144,9 @@ protected override void OnEventCommand(EventCommandEventArgs command) _gen2SizeCounter ??= new PollingCounter("gen-2-size", this, () => GC.GetGenerationSize(2)) { DisplayName = "Gen 2 Size", DisplayUnits = "B" }; _lohSizeCounter ??= new PollingCounter("loh-size", this, () => GC.GetGenerationSize(3)) { DisplayName = "LOH Size", DisplayUnits = "B" }; _pohSizeCounter ??= new PollingCounter("poh-size", this, () => GC.GetGenerationSize(4)) { DisplayName = "POH (Pinned Object Heap) Size", DisplayUnits = "B" }; -#if !NATIVEAOT // TODO +#if NATIVEAOT + _assemblyCounter ??= new PollingCounter("assembly-count", this, () => AppDomain.CurrentDomain.GetAssemblies().Length) { DisplayName = "Number of Assemblies Loaded" }; +#else _assemblyCounter ??= new PollingCounter("assembly-count", this, () => System.Reflection.Assembly.GetAssemblyCount()) { DisplayName = "Number of Assemblies Loaded" }; #endif // !NATIVEAOT diff --git a/src/tests/tracing/eventcounter/runtimecounters.cs b/src/tests/tracing/eventcounter/runtimecounters.cs index 1472e4bee6648..dda0cb7038807 100644 --- a/src/tests/tracing/eventcounter/runtimecounters.cs +++ b/src/tests/tracing/eventcounter/runtimecounters.cs @@ -33,14 +33,14 @@ public RuntimeCounterListener() { "active-timer-count", false }, { "gc-fragmentation", false }, { "gc-committed", false }, - // { "exception-count", 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 }, + { "assembly-count", false }, { "il-bytes-jitted", false }, { "methods-jitted-count", false }, { "time-in-jit", false } From b9dfe74567e4763b0566b0a636a68aef43ebf019 Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Thu, 27 Apr 2023 10:14:49 -0700 Subject: [PATCH 3/9] FB --- .../src/System/Exception.NativeAot.cs | 4 ++-- .../src/System/Reflection/Assembly.NativeAot.cs | 9 +++++++++ .../src/System/Diagnostics/Tracing/RuntimeEventSource.cs | 8 -------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Exception.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Exception.NativeAot.cs index 2ab39d99881bb..2a02e2c38be24 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Exception.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Exception.NativeAot.cs @@ -96,8 +96,8 @@ private enum RhEHFrameType } // Performance metric to count the number of exceptions thrown - private static int s_exceptionCount; - internal static int ExceptionCount => s_exceptionCount; + private static uint s_exceptionCount; + internal static uint GetExceptionCount() => s_exceptionCount; [RuntimeExport("AppendExceptionStackFrame")] private static void AppendExceptionStackFrame(object exceptionObj, IntPtr IP, int flags) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Assembly.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Assembly.NativeAot.cs index 396db8418cd90..fb159cc2eed7a 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Assembly.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Assembly.NativeAot.cs @@ -35,6 +35,15 @@ public static Assembly Load(string assemblyString) return Load(name); } + // Performance metric to count the number of assemblies + // Caching since in NativeAOT, the number will be the same + private static uint? s_assemblyCount; + internal static uint GetAssemblyCount() + { + s_assemblyCount ??= (uint)AppDomain.CurrentDomain.GetAssemblies().Length; + return (uint)s_assemblyCount; + } + [Obsolete("Assembly.LoadWithPartialName has been deprecated. Use Assembly.Load() instead.")] public static Assembly LoadWithPartialName(string partialName) { 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 5f560a8d026e0..628750566e9cf 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 @@ -133,22 +133,14 @@ protected override void OnEventCommand(EventCommandEventArgs command) }) { DisplayName = "GC Fragmentation", DisplayUnits = "%" }; _committedCounter ??= new PollingCounter("gc-committed", this, () => ((double)GC.GetGCMemoryInfo().TotalCommittedBytes / 1_000_000)) { DisplayName = "GC Committed Bytes", DisplayUnits = "MB" }; -#if NATIVEAOT - _exceptionCounter ??= new IncrementingPollingCounter("exception-count", this, () => Exception.ExceptionCount) { DisplayName = "Exception Count", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; -#else _exceptionCounter ??= new IncrementingPollingCounter("exception-count", this, () => Exception.GetExceptionCount()) { DisplayName = "Exception Count", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; -#endif // !NATIVEAOT _gcTimeCounter ??= new PollingCounter("time-in-gc", this, () => GC.GetLastGCPercentTimeInGC()) { DisplayName = "% Time in GC since last GC", DisplayUnits = "%" }; _gen0SizeCounter ??= new PollingCounter("gen-0-size", this, () => GC.GetGenerationSize(0)) { DisplayName = "Gen 0 Size", DisplayUnits = "B" }; _gen1SizeCounter ??= new PollingCounter("gen-1-size", this, () => GC.GetGenerationSize(1)) { DisplayName = "Gen 1 Size", DisplayUnits = "B" }; _gen2SizeCounter ??= new PollingCounter("gen-2-size", this, () => GC.GetGenerationSize(2)) { DisplayName = "Gen 2 Size", DisplayUnits = "B" }; _lohSizeCounter ??= new PollingCounter("loh-size", this, () => GC.GetGenerationSize(3)) { DisplayName = "LOH Size", DisplayUnits = "B" }; _pohSizeCounter ??= new PollingCounter("poh-size", this, () => GC.GetGenerationSize(4)) { DisplayName = "POH (Pinned Object Heap) Size", DisplayUnits = "B" }; -#if NATIVEAOT - _assemblyCounter ??= new PollingCounter("assembly-count", this, () => AppDomain.CurrentDomain.GetAssemblies().Length) { DisplayName = "Number of Assemblies Loaded" }; -#else _assemblyCounter ??= new PollingCounter("assembly-count", this, () => System.Reflection.Assembly.GetAssemblyCount()) { DisplayName = "Number of Assemblies Loaded" }; -#endif // !NATIVEAOT _ilBytesJittedCounter ??= new PollingCounter("il-bytes-jitted", this, () => System.Runtime.JitInfo.GetCompiledILBytes()) { DisplayName = "IL Bytes Jitted", DisplayUnits = "B" }; _methodsJittedCounter ??= new PollingCounter("methods-jitted-count", this, () => System.Runtime.JitInfo.GetCompiledMethodCount()) { DisplayName = "Number of Methods Jitted" }; From a6314a36692bf384134794ea898fcf2637a40342 Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Mon, 8 May 2023 15:28:46 -0700 Subject: [PATCH 4/9] make the exception count thread safe --- .../System.Private.CoreLib/src/System/Exception.NativeAot.cs | 5 +++-- src/coreclr/vm/exceptionhandling.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Exception.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Exception.NativeAot.cs index 2a02e2c38be24..bbe9a1b9b2f4b 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Exception.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Exception.NativeAot.cs @@ -7,6 +7,7 @@ using System.Runtime; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Threading; using MethodBase = System.Reflection.MethodBase; @@ -117,8 +118,8 @@ private static void AppendExceptionStackFrame(object exceptionObj, IntPtr IP, in bool isFirstRethrowFrame = (flags & (int)RhEHFrameType.RH_EH_FIRST_RETHROW_FRAME) != 0; // track count for metrics - if(isFirstFrame && !isFirstRethrowFrame) - s_exceptionCount++; + if (isFirstFrame && !isFirstRethrowFrame) + Interlocked.Increment(ref s_exceptionCount); // When we're throwing an exception object, we first need to clear its stacktrace with two exceptions: // 1. Don't clear if we're rethrowing with `throw;`. diff --git a/src/coreclr/vm/exceptionhandling.cpp b/src/coreclr/vm/exceptionhandling.cpp index 02c7398a9c994..19f8f559f7bb3 100644 --- a/src/coreclr/vm/exceptionhandling.cpp +++ b/src/coreclr/vm/exceptionhandling.cpp @@ -195,7 +195,7 @@ void FreeTrackerMemory(ExceptionTracker* pTracker, TrackerMemoryType mem) static inline void UpdatePerformanceMetrics(CrawlFrame *pcfThisFrame, BOOL bIsRethrownException, BOOL bIsNewException) { WRAPPER_NO_CONTRACT; - g_exceptionCount++; + InterlockedIncrement(&g_exceptionCount); // Fire an exception thrown ETW event when an exception occurs ETW::ExceptionLog::ExceptionThrown(pcfThisFrame, bIsRethrownException, bIsNewException); From 7fe98a6444d2b6779105f6d8d2c42caa3ce77376 Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Tue, 9 May 2023 14:37:30 -0700 Subject: [PATCH 5/9] revert reflection blocking workaround and open an issue for the CoreCLR exceptioncount fix --- .../src/CompatibilitySuppressions.xml | 32 ------------------- src/coreclr/vm/exceptionhandling.cpp | 3 +- .../Diagnostics/Tracing/CounterPayload.cs | 14 ++------ .../Tracing/IncrementingPollingCounter.cs | 7 +--- .../Diagnostics/Tracing/PollingCounter.cs | 7 +--- .../Diagnostics/Tracing/RuntimeEventSource.cs | 14 ++------ 6 files changed, 8 insertions(+), 69 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml b/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml index 9bb4ab6131948..5a87ba8c55efd 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml @@ -944,38 +944,6 @@ CP0001 T:System.Threading.LockHolder - - CP0001 - T:System.Diagnostics.Tracing.CounterPayload - ref/net8.0/System.Private.CoreLib.dll - lib/net8.0/System.Private.CoreLib.dll - - - CP0001 - T:System.Diagnostics.Tracing.IncrementingCounterPayload - ref/net8.0/System.Private.CoreLib.dll - lib/net8.0/System.Private.CoreLib.dll - - - CP0001 - T:System.Diagnostics.Tracing.IncrementingPollingCounterPayloadType - ref/net8.0/System.Private.CoreLib.dll - lib/net8.0/System.Private.CoreLib.dll - - - CP0001 - T:System.Diagnostics.Tracing.PollingPayloadType - ref/net8.0/System.Private.CoreLib.dll - lib/net8.0/System.Private.CoreLib.dll - - - CP0002 - M:System.Diagnostics.Tracing.RuntimeEventSource.LogAppContextSwitch(System.String,System.Int32) - - - CP0002 - M:System.Diagnostics.Tracing.RuntimeEventSource.ProcessorCount(System.Int32) - CP0002 M:System.ModuleHandle.#ctor(System.Reflection.Module) diff --git a/src/coreclr/vm/exceptionhandling.cpp b/src/coreclr/vm/exceptionhandling.cpp index 19f8f559f7bb3..5308334968cd4 100644 --- a/src/coreclr/vm/exceptionhandling.cpp +++ b/src/coreclr/vm/exceptionhandling.cpp @@ -195,7 +195,8 @@ void FreeTrackerMemory(ExceptionTracker* pTracker, TrackerMemoryType mem) static inline void UpdatePerformanceMetrics(CrawlFrame *pcfThisFrame, BOOL bIsRethrownException, BOOL bIsNewException) { WRAPPER_NO_CONTRACT; - InterlockedIncrement(&g_exceptionCount); + // This should ideally use a threadsafe mechanism for greater accuracy, see https://github.com/dotnet/runtime/issues/85997 + g_exceptionCount++; // Fire an exception thrown ETW event when an exception occurs ETW::ExceptionLog::ExceptionThrown(pcfThisFrame, bIsRethrownException, bIsNewException); diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterPayload.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterPayload.cs index 9f5846fe0bbe0..01dac53d2583a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterPayload.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterPayload.cs @@ -7,12 +7,7 @@ namespace System.Diagnostics.Tracing { [EventData] -#if NATIVEAOT - public // On NativeAOT, this must be public to prevent it from getting reflection blocked. -#else - internal -#endif - sealed class CounterPayload : IEnumerable> + internal sealed class CounterPayload : IEnumerable> { public string? Name { get; set; } @@ -73,12 +68,7 @@ IEnumerator IEnumerable.GetEnumerator() } [EventData] -#if NATIVEAOT - public // On NativeAOT, this must be public to prevent it from getting reflection blocked. -#else - internal -#endif - sealed class IncrementingCounterPayload : IEnumerable> + internal sealed class IncrementingCounterPayload : IEnumerable> { public string? Name { get; set; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs index d7d60a171b8bb..35256d88f97fb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs @@ -90,12 +90,7 @@ internal override void WritePayload(float intervalSec, int pollingIntervalMillis /// This is the payload that is sent in the with EventSource.Write /// [EventData] -#if NATIVEAOT - public // On NativeAOT, this must be public to prevent it from getting reflection blocked. -#else - internal -#endif - sealed class IncrementingPollingCounterPayloadType + internal sealed class IncrementingPollingCounterPayloadType { public IncrementingPollingCounterPayloadType(IncrementingCounterPayload payload) { Payload = payload; } public IncrementingCounterPayload Payload { get; set; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs index 3610266f0dca3..c295c260379d8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs @@ -81,12 +81,7 @@ internal override void WritePayload(float intervalSec, int pollingIntervalMillis /// This is the payload that is sent in the with EventSource.Write /// [EventData] -#if NATIVEAOT - public // On NativeAOT, this must be public to prevent it from getting reflection blocked. -#else - internal -#endif - sealed class PollingPayloadType + internal sealed class PollingPayloadType { public PollingPayloadType(CounterPayload payload) { Payload = payload; } public CounterPayload Payload { get; set; } 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 628750566e9cf..829d11add202e 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 @@ -85,23 +85,13 @@ private enum EventId : int } [Event((int)EventId.AppContextSwitch, Level = EventLevel.Informational, Keywords = Keywords.AppContext)] -#if NATIVEAOT - public -#else - internal -#endif - void LogAppContextSwitch(string switchName, int value) + internal void LogAppContextSwitch(string switchName, int value) { base.WriteEvent((int)EventId.AppContextSwitch, switchName, value); } [Event((int)EventId.ProcessorCount, Level = EventLevel.Informational, Keywords = Keywords.ProcessorCount)] -#if NATIVEAOT - public -#else - internal -#endif - void ProcessorCount(int processorCount) + internal void ProcessorCount(int processorCount) { base.WriteEvent((int)EventId.ProcessorCount, processorCount); } From 8b9bd22106c938a70d131a267acd831e55a5afe2 Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Tue, 9 May 2023 16:06:12 -0700 Subject: [PATCH 6/9] Missed syncing to branch before syncing with main --- .../src/System/Reflection/Assembly.NativeAot.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Assembly.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Assembly.NativeAot.cs index fb159cc2eed7a..6d5664b14f591 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Assembly.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Assembly.NativeAot.cs @@ -37,11 +37,12 @@ public static Assembly Load(string assemblyString) // Performance metric to count the number of assemblies // Caching since in NativeAOT, the number will be the same - private static uint? s_assemblyCount; + private static uint s_assemblyCount; internal static uint GetAssemblyCount() { - s_assemblyCount ??= (uint)AppDomain.CurrentDomain.GetAssemblies().Length; - return (uint)s_assemblyCount; + if (s_assemblyCount == 0) + s_assemblyCount = (uint)AppDomain.CurrentDomain.GetAssemblies().Length; + return s_assemblyCount; } [Obsolete("Assembly.LoadWithPartialName has been deprecated. Use Assembly.Load() instead.")] From 158cc389d1561a842bb1c6040802c47c61b98d8c Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Wed, 10 May 2023 04:37:59 -0700 Subject: [PATCH 7/9] Update src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Assembly.NativeAot.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michal Strehovský --- .../src/System/Reflection/Assembly.NativeAot.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Assembly.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Assembly.NativeAot.cs index 6d5664b14f591..db77f722b5fbf 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Assembly.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Assembly.NativeAot.cs @@ -41,7 +41,7 @@ public static Assembly Load(string assemblyString) internal static uint GetAssemblyCount() { if (s_assemblyCount == 0) - s_assemblyCount = (uint)AppDomain.CurrentDomain.GetAssemblies().Length; + s_assemblyCount = (uint)Internal.Reflection.Core.Execution.ReflectionCoreExecution.ExecutionDomain.ReflectionDomainSetup.AssemblyBinder.GetLoadedAssemblies().Count; return s_assemblyCount; } From a1d34c876a6e184d1567788f20ae21d3ad30c876 Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Wed, 10 May 2023 09:37:59 -0700 Subject: [PATCH 8/9] FB --- .../src/CompatibilitySuppressions.xml | 12 ------------ .../src/System/GC.NativeAot.cs | 4 ++-- .../Diagnostics/Tracing/RuntimeEventSource.cs | 14 ++------------ 3 files changed, 4 insertions(+), 26 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml b/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml index 5a87ba8c55efd..8d7b959b84bb1 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml @@ -960,18 +960,6 @@ CP0002 M:System.TypedReference.get_IsNull - - CP0002 - M:System.GC.GetGenerationSize(System.Int32) - ref/net8.0/System.Private.CoreLib.dll - lib/net8.0/System.Private.CoreLib.dll - - - CP0002 - M:System.GC.GetLastGCPercentTimeInGC - ref/net8.0/System.Private.CoreLib.dll - lib/net8.0/System.Private.CoreLib.dll - CP0014 M:System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(System.Object)->object?:[T:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute] diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs index 8e31b8bdd4b71..483743702f535 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs @@ -70,12 +70,12 @@ public static int GetGeneration(object obj) return RuntimeImports.RhGetGeneration(obj); } - public static int GetGenerationSize(int gen) + internal static int GetGenerationSize(int gen) { return RuntimeImports.RhGetGenerationSize(gen); } - public static int GetLastGCPercentTimeInGC() + internal static int GetLastGCPercentTimeInGC() { return RuntimeImports.RhGetLastGCPercentTimeInGC(); } 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 829d11add202e..2bed9b8b8679f 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 @@ -50,22 +50,12 @@ public static class Keywords private IncrementingPollingCounter? _jitTimeCounter; #if NATIVEAOT - /// - /// If EventSource feature is enabled, RuntimeEventSource needs to be initialized - /// In CoreCLR, this is done via StartupHookProvider.CoreCLR.cs - /// + // If EventSource feature is enabled, RuntimeEventSource needs to be initialized for NativeAOT + // In CoreCLR, this is done via StartupHookProvider.CoreCLR.cs #pragma warning disable CA2255 [ModuleInitializer] - internal static void NativeAOTtartupHook() - { - if (EventSource.IsSupported) - { - Initialize(); - } - } #pragma warning restore CA2255 #endif - public static void Initialize() { // initializing more than once may lead to missing events From fb9d9a71e6ad82f6b0c462a448b2bf854810a9de Mon Sep 17 00:00:00 2001 From: Lakshan Fernando Date: Wed, 10 May 2023 12:55:58 -0700 Subject: [PATCH 9/9] Removing unnecessary whitespace chang --- .../System.Private.CoreLib/src/CompatibilitySuppressions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml b/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml index 8d7b959b84bb1..0883ff244559c 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml @@ -968,4 +968,4 @@ CP0016 M:System.Runtime.InteropServices.Marshal.GetObjectForNativeVariant``1(System.IntPtr)->T?:[T:System.Diagnostics.CodeAnalysis.MaybeNullAttribute] - \ No newline at end of file +