Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enabling RuntimeEventSource in NativeAOT #85424

Merged
merged 11 commits into from
May 11, 2023
11 changes: 11 additions & 0 deletions src/coreclr/nativeaot/Runtime/GCHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,38 @@
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:System.Threading.LockHolder</Target>
</Suppression>
<Suppression>
LakshanF marked this conversation as resolved.
Show resolved Hide resolved
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:System.Diagnostics.Tracing.CounterPayload</Target>
<Left>ref/net8.0/System.Private.CoreLib.dll</Left>
<Right>lib/net8.0/System.Private.CoreLib.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:System.Diagnostics.Tracing.IncrementingCounterPayload</Target>
<Left>ref/net8.0/System.Private.CoreLib.dll</Left>
<Right>lib/net8.0/System.Private.CoreLib.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:System.Diagnostics.Tracing.IncrementingPollingCounterPayloadType</Target>
<Left>ref/net8.0/System.Private.CoreLib.dll</Left>
<Right>lib/net8.0/System.Private.CoreLib.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:System.Diagnostics.Tracing.PollingPayloadType</Target>
<Left>ref/net8.0/System.Private.CoreLib.dll</Left>
<Right>lib/net8.0/System.Private.CoreLib.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:System.Diagnostics.Tracing.RuntimeEventSource.LogAppContextSwitch(System.String,System.Int32)</Target>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:System.Diagnostics.Tracing.RuntimeEventSource.ProcessorCount(System.Int32)</Target>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:System.ModuleHandle.#ctor(System.Reflection.Module)</Target>
Expand All @@ -972,6 +1004,18 @@
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:System.TypedReference.get_IsNull</Target>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:System.GC.GetGenerationSize(System.Int32)</Target>
<Left>ref/net8.0/System.Private.CoreLib.dll</Left>
<Right>lib/net8.0/System.Private.CoreLib.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:System.GC.GetLastGCPercentTimeInGC</Target>
<Left>ref/net8.0/System.Private.CoreLib.dll</Left>
<Right>lib/net8.0/System.Private.CoreLib.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0014</DiagnosticId>
<Target>M:System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(System.Object)-&gt;object?:[T:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute]</Target>
Expand All @@ -980,4 +1024,4 @@
<DiagnosticId>CP0016</DiagnosticId>
<Target>M:System.Runtime.InteropServices.Marshal.GetObjectForNativeVariant``1(System.IntPtr)-&gt;T?:[T:System.Diagnostics.CodeAnalysis.MaybeNullAttribute]</Target>
</Suppression>
</Suppressions>
</Suppressions>
LakshanF marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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)
LakshanF marked this conversation as resolved.
Show resolved Hide resolved
s_exceptionCount++;
LakshanF marked this conversation as resolved.
Show resolved Hide resolved

// 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ public static int GetGeneration(object obj)
return RuntimeImports.RhGetGeneration(obj);
}

public static int GetGenerationSize(int gen)
LakshanF marked this conversation as resolved.
Show resolved Hide resolved
{
return RuntimeImports.RhGetGenerationSize(gen);
}

public static int GetLastGCPercentTimeInGC()
{
return RuntimeImports.RhGetLastGCPercentTimeInGC();
}

/// <summary>
/// Returns the current generation number of the target
/// of a specified <see cref="System.WeakReference"/>.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
namespace System.Diagnostics.Tracing
{
[EventData]
internal sealed class CounterPayload : IEnumerable<KeyValuePair<string, object?>>
#if NATIVEAOT
public // On NativeAOT, this must be public to prevent it from getting reflection blocked.
LakshanF marked this conversation as resolved.
Show resolved Hide resolved
#else
internal
#endif
sealed class CounterPayload : IEnumerable<KeyValuePair<string, object?>>
{
public string? Name { get; set; }

Expand Down Expand Up @@ -68,7 +73,12 @@ IEnumerator IEnumerable.GetEnumerator()
}

[EventData]
internal sealed class IncrementingCounterPayload : IEnumerable<KeyValuePair<string, object?>>
#if NATIVEAOT
public // On NativeAOT, this must be public to prevent it from getting reflection blocked.
#else
internal
#endif
sealed class IncrementingCounterPayload : IEnumerable<KeyValuePair<string, object?>>
{
public string? Name { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,12 @@ internal override void WritePayload(float intervalSec, int pollingIntervalMillis
/// This is the payload that is sent in the with EventSource.Write
/// </summary>
[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; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,12 @@ internal override void WritePayload(float intervalSec, int pollingIntervalMillis
/// This is the payload that is sent in the with EventSource.Write
/// </summary>
[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; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Threading;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;

namespace System.Diagnostics.Tracing
{
Expand Down Expand Up @@ -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;
Expand All @@ -46,12 +45,27 @@ 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
/// <summary>
/// If EventSource feature is enabled, RuntimeEventSource needs to be initialized
/// In CoreCLR, this is done via StartupHookProvider.CoreCLR.cs
/// </summary>
#pragma warning disable CA2255
[ModuleInitializer]
internal static void NativeAOTtartupHook()
LakshanF marked this conversation as resolved.
Show resolved Hide resolved
{
if (EventSource.IsSupported)
{
Initialize();
}
}
#pragma warning restore CA2255
#endif

public static void Initialize()
{
// initializing more than once may lead to missing events
Expand All @@ -71,13 +85,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);
}
Expand Down Expand Up @@ -108,15 +132,21 @@ 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
LakshanF marked this conversation as resolved.
Show resolved Hide resolved
_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) };
LakshanF marked this conversation as resolved.
Show resolved Hide resolved
#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" };
LakshanF marked this conversation as resolved.
Show resolved Hide resolved
#endif // !NATIVEAOT

Expand Down
15 changes: 15 additions & 0 deletions src/tests/tracing/eventcounter/runtimecounters.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,24 @@
<JitOptimizationSensitive>true</JitOptimizationSensitive>
<!-- This test has a secondary thread with an infinite loop -->
<UnloadabilityIncompatible>true</UnloadabilityIncompatible>
<EventSourceSupport Condition="'$(TestBuildMode)' == 'nativeaot'">true</EventSourceSupport>
</PropertyGroup>
<ItemGroup>
<Compile Include="runtimecounters.cs" />
<ProjectReference Include="../common/common.csproj" />
</ItemGroup>

<!-- Hack to get NativeAOT assemblies into IlcReference
In CoreCLR tests, these assemblies get copied to CORE_ROOT, which NativeAOT doesn't use
-->
<Import Project="$(RepoRoot)eng/liveBuilds.targets" Condition="'$(TestBuildMode)' == 'nativeaot'" />
<!-- Get all the *.dll files that has IsNative != "true"-->
<Target Name="GetRequiredNativeAOTAssemblies"
DependsOnTargets="ResolveLibrariesRuntimeFilesFromLocalBuild"
BeforeTargets="ComputeIlcCompileInputs"
Condition="'$(TestBuildMode)' == 'nativeaot'">
<ItemGroup>
<IlcReference Include="@(LibrariesRuntimeFiles)" Condition="'%(Extension)' == '.dll' and '%(LibrariesRuntimeFiles.IsNative)' != 'true'"/>
</ItemGroup>
</Target>
</Project>