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/System/Exception.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Exception.NativeAot.cs index 0c974b56a5c45..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; @@ -95,6 +96,10 @@ private enum RhEHFrameType RH_EH_FIRST_RETHROW_FRAME = 2, } + // Performance metric to count the number of exceptions thrown + private static uint s_exceptionCount; + internal static uint GetExceptionCount() => s_exceptionCount; + [RuntimeExport("AppendExceptionStackFrame")] private static void AppendExceptionStackFrame(object exceptionObj, IntPtr IP, int flags) { @@ -112,6 +117,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) + 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;`. // 2. Don't clear if we're throwing through ExceptionDispatchInfo. 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..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,6 +70,16 @@ public static int GetGeneration(object obj) return RuntimeImports.RhGetGeneration(obj); } + internal static int GetGenerationSize(int gen) + { + return RuntimeImports.RhGetGenerationSize(gen); + } + + internal 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/Reflection/Assembly.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Assembly.NativeAot.cs index 396db8418cd90..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 @@ -35,6 +35,16 @@ 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() + { + if (s_assemblyCount == 0) + s_assemblyCount = (uint)Internal.Reflection.Core.Execution.ReflectionCoreExecution.ExecutionDomain.ReflectionDomainSetup.AssemblyBinder.GetLoadedAssemblies().Count; + return s_assemblyCount; + } + [Obsolete("Assembly.LoadWithPartialName has been deprecated. Use Assembly.Load() instead.")] public static Assembly LoadWithPartialName(string partialName) { 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 54ac631e47d89..ebc9fdbd1ed27 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 @@ -98,6 +98,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/RuntimeEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs index 5c01e52e0e467..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 @@ -3,6 +3,7 @@ using System.Threading; using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; namespace System.Diagnostics.Tracing { @@ -35,8 +36,6 @@ public static class Keywords private IncrementingPollingCounter? _allocRateCounter; private PollingCounter? _timerCounter; private PollingCounter? _fragmentationCounter; - -#if !NATIVEAOT // TODO shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase private PollingCounter? _committedCounter; private IncrementingPollingCounter? _exceptionCounter; private PollingCounter? _gcTimeCounter; @@ -46,12 +45,17 @@ public static class Keywords private PollingCounter? _lohSizeCounter; private PollingCounter? _pohSizeCounter; private PollingCounter? _assemblyCounter; -#endif // !NATIVEAOT - private PollingCounter? _ilBytesJittedCounter; private PollingCounter? _methodsJittedCounter; private IncrementingPollingCounter? _jitTimeCounter; +#if NATIVEAOT + // 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] +#pragma warning restore CA2255 +#endif public static void Initialize() { // initializing more than once may lead to missing events @@ -108,7 +112,6 @@ 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" }; _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 = "%" }; @@ -118,7 +121,6 @@ protected override void OnEventCommand(EventCommandEventArgs command) _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" }; _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" }; diff --git a/src/tests/tracing/eventcounter/runtimecounters.csproj b/src/tests/tracing/eventcounter/runtimecounters.csproj index 0bd33174144b0..5c364fac879ea 100644 --- a/src/tests/tracing/eventcounter/runtimecounters.csproj +++ b/src/tests/tracing/eventcounter/runtimecounters.csproj @@ -7,9 +7,24 @@ true true + true + + + + + + + + +