Skip to content

Commit 21a7632

Browse files
author
John Salem
authored
Implement JitInfo API (#55046)
1 parent d86a382 commit 21a7632

File tree

24 files changed

+464
-42
lines changed

24 files changed

+464
-42
lines changed

src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@
214214
<Compile Include="$(BclSourcesRoot)\System\Runtime\CompilerServices\TypeDependencyAttribute.cs" />
215215
<Compile Include="$(BclSourcesRoot)\System\Runtime\DependentHandle.cs" />
216216
<Compile Include="$(BclSourcesRoot)\System\Runtime\GCSettings.CoreCLR.cs" />
217+
<Compile Include="$(BclSourcesRoot)\System\Runtime\JitInfo.CoreCLR.cs" />
217218
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\ComTypes\IEnumerable.cs" />
218219
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\ComTypes\IEnumerator.cs" />
219220
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\DynamicInterfaceCastableHelpers.cs" />

src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -349,12 +349,6 @@ private static unsafe void DispatchTailCalls(
349349
}
350350
}
351351
}
352-
353-
[MethodImpl(MethodImplOptions.InternalCall)]
354-
internal static extern long GetILBytesJitted();
355-
356-
[MethodImpl(MethodImplOptions.InternalCall)]
357-
internal static extern int GetMethodsJittedCount();
358352
}
359353
// Helper class to assist with unsafe pinning of arbitrary objects.
360354
// It's used by VM code.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Runtime.CompilerServices;
5+
using System.Runtime.InteropServices;
6+
using Internal.Runtime.CompilerServices;
7+
8+
namespace System.Runtime
9+
{
10+
public static partial class JitInfo
11+
{
12+
/// <summary>
13+
/// Get the number of bytes of IL that have been compiled. If <paramref name="currentThread"/> is true,
14+
/// then this value is scoped to the current thread, otherwise, this is a global value.
15+
/// </summary>
16+
/// <param name="currentThread">Whether the returned value should be specific to the current thread. Default: false</param>
17+
/// <returns>The number of bytes of IL the JIT has compiled.</returns>
18+
[MethodImpl(MethodImplOptions.InternalCall)]
19+
public static extern long GetCompiledILBytes(bool currentThread = false);
20+
21+
/// <summary>
22+
/// Get the number of methods that have been compiled. If <paramref name="currentThread"/> is true,
23+
/// then this value is scoped to the current thread, otherwise, this is a global value.
24+
/// </summary>
25+
/// <param name="currentThread">Whether the returned value should be specific to the current thread. Default: false</param>
26+
/// <returns>The number of methods the JIT has compiled.</returns>
27+
[MethodImpl(MethodImplOptions.InternalCall)]
28+
public static extern long GetCompiledMethodCount(bool currentThread = false);
29+
30+
// Normalized to 100ns ticks on vm side
31+
[MethodImpl(MethodImplOptions.InternalCall)]
32+
private static extern long GetCompilationTimeInTicks(bool currentThread = false);
33+
}
34+
}

src/coreclr/vm/ecalllist.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,12 @@ FCFuncStart(gInterlockedFuncs)
834834
QCFuncElement("_MemoryBarrierProcessWide", COMInterlocked::MemoryBarrierProcessWide)
835835
FCFuncEnd()
836836

837+
FCFuncStart(gJitInfoFuncs)
838+
FCFuncElement("GetCompiledILBytes", GetCompiledILBytes)
839+
FCFuncElement("GetCompiledMethodCount", GetCompiledMethodCount)
840+
FCFuncElement("GetCompilationTimeInTicks", GetCompilationTimeInTicks)
841+
FCFuncEnd()
842+
837843
FCFuncStart(gVarArgFuncs)
838844
FCFuncElementSig(COR_CTOR_METHOD_NAME, &gsig_IM_IntPtr_PtrVoid_RetVoid, VarArgsNative::Init2)
839845
FCFuncElementSig(COR_CTOR_METHOD_NAME, &gsig_IM_IntPtr_RetVoid, VarArgsNative::Init)
@@ -879,8 +885,6 @@ FCFuncStart(gRuntimeHelpers)
879885
QCFuncElement("AllocateTypeAssociatedMemory", RuntimeTypeHandle::AllocateTypeAssociatedMemory)
880886
FCFuncElement("AllocTailCallArgBuffer", TailCallHelp::AllocTailCallArgBuffer)
881887
FCFuncElement("GetTailCallInfo", TailCallHelp::GetTailCallInfo)
882-
FCFuncElement("GetILBytesJitted", GetJittedBytes)
883-
FCFuncElement("GetMethodsJittedCount", GetJittedMethodsCount)
884888
FCFuncEnd()
885889

886890
FCFuncStart(gMngdFixedArrayMarshalerFuncs)
@@ -1158,6 +1162,7 @@ FCClassElement("IReflect", "System.Reflection", gStdMngIReflectFuncs)
11581162
FCClassElement("InterfaceMarshaler", "System.StubHelpers", gInterfaceMarshalerFuncs)
11591163
#endif
11601164
FCClassElement("Interlocked", "System.Threading", gInterlockedFuncs)
1165+
FCClassElement("JitInfo", "System.Runtime", gJitInfoFuncs)
11611166
#if TARGET_UNIX
11621167
FCClassElement("Kernel32", "", gPalKernel32Funcs)
11631168
#endif

src/coreclr/vm/jitinterface.cpp

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,23 +102,47 @@ GARY_IMPL(VMHELPDEF, hlpDynamicFuncTable, DYNAMIC_CORINFO_HELP_COUNT);
102102

103103
#else // DACCESS_COMPILE
104104

105-
uint64_t g_cbILJitted = 0;
106-
uint32_t g_cMethodsJitted = 0;
105+
Volatile<int64_t> g_cbILJitted = 0;
106+
Volatile<int64_t> g_cMethodsJitted = 0;
107+
Volatile<int64_t> g_c100nsTicksInJit = 0;
108+
thread_local int64_t t_cbILJittedForThread = 0;
109+
thread_local int64_t t_cMethodsJittedForThread = 0;
110+
thread_local int64_t t_c100nsTicksInJitForThread = 0;
111+
112+
// This prevents tearing of 64 bit values on 32 bit systems
113+
static inline
114+
int64_t AtomicLoad64WithoutTearing(int64_t volatile *valueRef)
115+
{
116+
WRAPPER_NO_CONTRACT;
117+
#if TARGET_64BIT
118+
return VolatileLoad(valueRef);
119+
#else
120+
return InterlockedCompareExchangeT((LONG64 volatile *)valueRef, (LONG64)0, (LONG64)0);
121+
#endif // TARGET_64BIT
122+
}
107123

108124
#ifndef CROSSGEN_COMPILE
109-
FCIMPL0(INT64, GetJittedBytes)
125+
FCIMPL1(INT64, GetCompiledILBytes, CLR_BOOL currentThread)
110126
{
111127
FCALL_CONTRACT;
112128

113-
return g_cbILJitted;
129+
return currentThread ? t_cbILJittedForThread : AtomicLoad64WithoutTearing(&g_cbILJitted);
114130
}
115131
FCIMPLEND
116132

117-
FCIMPL0(INT32, GetJittedMethodsCount)
133+
FCIMPL1(INT64, GetCompiledMethodCount, CLR_BOOL currentThread)
118134
{
119135
FCALL_CONTRACT;
120136

121-
return g_cMethodsJitted;
137+
return currentThread ? t_cMethodsJittedForThread : AtomicLoad64WithoutTearing(&g_cMethodsJitted);
138+
}
139+
FCIMPLEND
140+
141+
FCIMPL1(INT64, GetCompilationTimeInTicks, CLR_BOOL currentThread)
142+
{
143+
FCALL_CONTRACT;
144+
145+
return currentThread ? t_c100nsTicksInJitForThread : AtomicLoad64WithoutTearing(&g_c100nsTicksInJit);
122146
}
123147
FCIMPLEND
124148
#endif
@@ -13030,9 +13054,13 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config,
1303013054
MethodDesc* ftn = nativeCodeVersion.GetMethodDesc();
1303113055

1303213056
PCODE ret = NULL;
13057+
NormalizedTimer timer;
13058+
int64_t c100nsTicksInJit = 0;
1303313059

1303413060
COOPERATIVE_TRANSITION_BEGIN();
1303513061

13062+
timer.Start();
13063+
1303613064
#ifdef FEATURE_PREJIT
1303713065

1303813066
if (g_pConfig->RequireZaps() == EEConfig::REQUIRE_ZAPS_ALL &&
@@ -13394,8 +13422,17 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config,
1339413422
printf(".");
1339513423
#endif // _DEBUG
1339613424

13397-
FastInterlockExchangeAddLong((LONG64*)&g_cbILJitted, methodInfo.ILCodeSize);
13398-
FastInterlockIncrement((LONG*)&g_cMethodsJitted);
13425+
timer.Stop();
13426+
c100nsTicksInJit = timer.Elapsed100nsTicks();
13427+
13428+
InterlockedExchangeAdd64((LONG64*)&g_c100nsTicksInJit, c100nsTicksInJit);
13429+
t_c100nsTicksInJitForThread += c100nsTicksInJit;
13430+
13431+
InterlockedExchangeAdd64((LONG64*)&g_cbILJitted, methodInfo.ILCodeSize);
13432+
t_cbILJittedForThread += methodInfo.ILCodeSize;
13433+
13434+
InterlockedIncrement64((LONG64*)&g_cMethodsJitted);
13435+
t_cMethodsJittedForThread++;
1339913436

1340013437
COOPERATIVE_TRANSITION_END();
1340113438
return ret;

src/coreclr/vm/jitinterface.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,8 +1149,17 @@ CORJIT_FLAGS GetDebuggerCompileFlags(Module* pModule, CORJIT_FLAGS flags);
11491149

11501150
bool __stdcall TrackAllocationsEnabled();
11511151

1152-
FCDECL0(INT64, GetJittedBytes);
1153-
FCDECL0(INT32, GetJittedMethodsCount);
1152+
1153+
extern Volatile<int64_t> g_cbILJitted;
1154+
extern Volatile<int64_t> g_cMethodsJitted;
1155+
extern Volatile<int64_t> g_c100nsTicksInJit;
1156+
extern thread_local int64_t t_cbILJittedForThread;
1157+
extern thread_local int64_t t_cMethodsJittedForThread;
1158+
extern thread_local int64_t t_c100nsTicksInJitForThread;
1159+
1160+
FCDECL1(INT64, GetCompiledILBytes, CLR_BOOL currentThread);
1161+
FCDECL1(INT64, GetCompiledMethodCount, CLR_BOOL currentThread);
1162+
FCDECL1(INT64, GetCompilationTimeInTicks, CLR_BOOL currentThread);
11541163

11551164
#endif // JITINTERFACE_H
11561165

src/coreclr/vm/util.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2272,4 +2272,6 @@ HRESULT GetFileVersion( // S_OK or error
22722272
}
22732273
#endif // !TARGET_UNIX
22742274

2275+
Volatile<double> NormalizedTimer::s_frequency = -1.0;
2276+
22752277
#endif // !DACCESS_COMPILE

src/coreclr/vm/util.hpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,83 @@ class COMCharacter {
918918
static BOOL nativeIsDigit(WCHAR c);
919919
};
920920

921+
// ======================================================================================
922+
// Simple, reusable 100ns timer for normalizing ticks. For use in Q/FCalls to avoid discrepency with
923+
// tick frequency between native and managed.
924+
class NormalizedTimer
925+
{
926+
private:
927+
static const int64_t NormalizedTicksPerSecond = 10000000 /* 100ns ticks per second (1e7) */;
928+
static Volatile<double> s_frequency;
929+
930+
LARGE_INTEGER startTimestamp;
931+
LARGE_INTEGER stopTimestamp;
932+
933+
#if _DEBUG
934+
bool isRunning = false;
935+
#endif // _DEBUG
936+
937+
public:
938+
NormalizedTimer()
939+
{
940+
LIMITED_METHOD_CONTRACT;
941+
if (s_frequency.Load() == -1)
942+
{
943+
double frequency;
944+
LARGE_INTEGER qpfValue;
945+
QueryPerformanceFrequency(&qpfValue);
946+
frequency = static_cast<double>(qpfValue.QuadPart);
947+
frequency /= NormalizedTicksPerSecond;
948+
s_frequency.Store(frequency);
949+
}
950+
951+
startTimestamp.QuadPart = 0;
952+
startTimestamp.QuadPart = 0;
953+
}
954+
955+
// ======================================================================================
956+
// Start the timer
957+
inline
958+
void Start()
959+
{
960+
LIMITED_METHOD_CONTRACT;
961+
_ASSERTE(!isRunning);
962+
QueryPerformanceCounter(&startTimestamp);
963+
964+
#if _DEBUG
965+
isRunning = true;
966+
#endif // _DEBUG
967+
}
968+
969+
// ======================================================================================
970+
// stop the timer. If called before starting, sets the start time to the same as the stop
971+
inline
972+
void Stop()
973+
{
974+
LIMITED_METHOD_CONTRACT;
975+
_ASSERTE(isRunning);
976+
QueryPerformanceCounter(&stopTimestamp);
977+
978+
#if _DEBUG
979+
isRunning = false;
980+
#endif // _DEBUG
981+
}
982+
983+
// ======================================================================================
984+
// Return elapsed ticks. This will stop a running timer.
985+
// Will return 0 if called out of order.
986+
// Only recalculated this value if it has been stopped/started since previous calculation.
987+
inline
988+
int64_t Elapsed100nsTicks()
989+
{
990+
LIMITED_METHOD_CONTRACT;
991+
_ASSERTE(!isRunning);
992+
_ASSERTE(startTimestamp.QuadPart > 0);
993+
_ASSERTE(stopTimestamp.QuadPart > 0);
994+
return static_cast<int64_t>((stopTimestamp.QuadPart - startTimestamp.QuadPart) / s_frequency);
995+
}
996+
};
997+
921998
#ifdef _DEBUG
922999
#define FORCEINLINE_NONDEBUG
9231000
#else

src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public static partial class PlatformDetection
2727
public static bool IsNotMonoRuntime => !IsMonoRuntime;
2828
public static bool IsMonoInterpreter => GetIsRunningOnMonoInterpreter();
2929
public static bool IsMonoAOT => Environment.GetEnvironmentVariable("MONO_AOT_MODE") == "aot";
30+
public static bool IsNotMonoAOT => Environment.GetEnvironmentVariable("MONO_AOT_MODE") != "aot";
3031
public static bool IsFreeBSD => RuntimeInformation.IsOSPlatform(OSPlatform.Create("FREEBSD"));
3132
public static bool IsNetBSD => RuntimeInformation.IsOSPlatform(OSPlatform.Create("NETBSD"));
3233
public static bool IsAndroid => RuntimeInformation.IsOSPlatform(OSPlatform.Create("ANDROID"));

src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,7 @@
867867
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Intrinsics\Vector64_1.cs" />
868868
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Intrinsics\Vector64DebugView_1.cs" />
869869
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Intrinsics\X86\Enums.cs" />
870+
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\JitInfo.cs" />
870871
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Loader\AssemblyLoadContext.cs" />
871872
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Loader\LibraryNameVariation.cs" />
872873
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\MemoryFailPoint.cs" />

src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ internal sealed partial class RuntimeEventSource : EventSource
3939
private PollingCounter? _assemblyCounter;
4040
private PollingCounter? _ilBytesJittedCounter;
4141
private PollingCounter? _methodsJittedCounter;
42+
private IncrementingPollingCounter? _jitTimeCounter;
4243

4344
public static void Initialize()
4445
{
@@ -83,8 +84,9 @@ protected override void OnEventCommand(EventCommandEventArgs command)
8384
_lohSizeCounter ??= new PollingCounter("loh-size", this, () => GC.GetGenerationSize(3)) { DisplayName = "LOH Size", DisplayUnits = "B" };
8485
_pohSizeCounter ??= new PollingCounter("poh-size", this, () => GC.GetGenerationSize(4)) { DisplayName = "POH (Pinned Object Heap) Size", DisplayUnits = "B" };
8586
_assemblyCounter ??= new PollingCounter("assembly-count", this, () => System.Reflection.Assembly.GetAssemblyCount()) { DisplayName = "Number of Assemblies Loaded" };
86-
_ilBytesJittedCounter ??= new PollingCounter("il-bytes-jitted", this, () => System.Runtime.CompilerServices.RuntimeHelpers.GetILBytesJitted()) { DisplayName = "IL Bytes Jitted", DisplayUnits = "B" };
87-
_methodsJittedCounter ??= new PollingCounter("methods-jitted-count", this, () => System.Runtime.CompilerServices.RuntimeHelpers.GetMethodsJittedCount()) { DisplayName = "Number of Methods Jitted" };
87+
_ilBytesJittedCounter ??= new PollingCounter("il-bytes-jitted", this, () => System.Runtime.JitInfo.GetCompiledILBytes()) { DisplayName = "IL Bytes Jitted", DisplayUnits = "B" };
88+
_methodsJittedCounter ??= new PollingCounter("methods-jitted-count", this, () => System.Runtime.JitInfo.GetCompiledMethodCount()) { DisplayName = "Number of Methods Jitted" };
89+
_jitTimeCounter ??= new IncrementingPollingCounter("time-in-jit", this, () => System.Runtime.JitInfo.GetCompilationTime().TotalMilliseconds) { DisplayName = "Time spent in JIT", DisplayUnits = "ms", DisplayRateTimeScale = new TimeSpan(0, 0, 1) };
8890
}
8991

9092
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace System.Runtime
5+
{
6+
/// <summary>
7+
/// A static class for getting information about the Just In Time compiler.
8+
/// </summary>
9+
public static partial class JitInfo
10+
{
11+
/// <summary>
12+
/// Get the amount of time the JIT Compiler has spent compiling methods. If <paramref name="currentThread"/> is true,
13+
/// then this value is scoped to the current thread, otherwise, this is a global value.
14+
/// </summary>
15+
/// <param name="currentThread">Whether the returned value should be specific to the current thread. Default: false</param>
16+
/// <returns>The amount of time the JIT Compiler has spent compiling methods.</returns>
17+
public static TimeSpan GetCompilationTime(bool currentThread = false)
18+
{
19+
// TimeSpan.FromTicks() takes 100ns ticks
20+
return TimeSpan.FromTicks(GetCompilationTimeInTicks(currentThread));
21+
}
22+
}
23+
}

src/libraries/System.Runtime/ref/System.Runtime.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12472,6 +12472,12 @@ public static partial class GCSettings
1247212472
public static System.Runtime.GCLargeObjectHeapCompactionMode LargeObjectHeapCompactionMode { get { throw null; } set { } }
1247312473
public static System.Runtime.GCLatencyMode LatencyMode { get { throw null; } set { } }
1247412474
}
12475+
public static partial class JitInfo
12476+
{
12477+
public static long GetCompiledILBytes(bool currentThread=false) { throw null; }
12478+
public static long GetCompiledMethodCount(bool currentThread=false) { throw null; }
12479+
public static TimeSpan GetCompilationTime(bool currentThread=false) { throw null; }
12480+
}
1247512481
public sealed partial class MemoryFailPoint : System.Runtime.ConstrainedExecution.CriticalFinalizerObject, System.IDisposable
1247612482
{
1247712483
public MemoryFailPoint(int sizeInMegabytes) { }

src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@
223223
<Compile Include="System\Reflection\TypeTests.Get.CornerCases.cs" />
224224
<Compile Include="System\Reflection\TypeTests.GetMember.cs" />
225225
<Compile Include="System\Runtime\DependentHandleTests.cs" />
226+
<Compile Include="System\Runtime\JitInfoTests.cs" />
226227
<Compile Include="System\Runtime\MemoryFailPointTests.cs" />
227228
<Compile Include="System\Runtime\NgenServicingAttributesTests.cs" />
228229
<Compile Include="System\Runtime\CompilerServices\AttributesTests.cs" />

0 commit comments

Comments
 (0)