Skip to content

Commit

Permalink
Implement JitInfo API (#55046)
Browse files Browse the repository at this point in the history
  • Loading branch information
John Salem authored Jul 14, 2021
1 parent d86a382 commit 21a7632
Show file tree
Hide file tree
Showing 24 changed files with 464 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@
<Compile Include="$(BclSourcesRoot)\System\Runtime\CompilerServices\TypeDependencyAttribute.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\DependentHandle.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\GCSettings.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\JitInfo.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\ComTypes\IEnumerable.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\ComTypes\IEnumerator.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\DynamicInterfaceCastableHelpers.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,12 +349,6 @@ private static unsafe void DispatchTailCalls(
}
}
}

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern long GetILBytesJitted();

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern int GetMethodsJittedCount();
}
// Helper class to assist with unsafe pinning of arbitrary objects.
// It's used by VM code.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Internal.Runtime.CompilerServices;

namespace System.Runtime
{
public static partial class JitInfo
{
/// <summary>
/// Get the number of bytes of IL that have been compiled. If <paramref name="currentThread"/> is true,
/// then this value is scoped to the current thread, otherwise, this is a global value.
/// </summary>
/// <param name="currentThread">Whether the returned value should be specific to the current thread. Default: false</param>
/// <returns>The number of bytes of IL the JIT has compiled.</returns>
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern long GetCompiledILBytes(bool currentThread = false);

/// <summary>
/// Get the number of methods that have been compiled. If <paramref name="currentThread"/> is true,
/// then this value is scoped to the current thread, otherwise, this is a global value.
/// </summary>
/// <param name="currentThread">Whether the returned value should be specific to the current thread. Default: false</param>
/// <returns>The number of methods the JIT has compiled.</returns>
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern long GetCompiledMethodCount(bool currentThread = false);

// Normalized to 100ns ticks on vm side
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern long GetCompilationTimeInTicks(bool currentThread = false);
}
}
9 changes: 7 additions & 2 deletions src/coreclr/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,12 @@ FCFuncStart(gInterlockedFuncs)
QCFuncElement("_MemoryBarrierProcessWide", COMInterlocked::MemoryBarrierProcessWide)
FCFuncEnd()

FCFuncStart(gJitInfoFuncs)
FCFuncElement("GetCompiledILBytes", GetCompiledILBytes)
FCFuncElement("GetCompiledMethodCount", GetCompiledMethodCount)
FCFuncElement("GetCompilationTimeInTicks", GetCompilationTimeInTicks)
FCFuncEnd()

FCFuncStart(gVarArgFuncs)
FCFuncElementSig(COR_CTOR_METHOD_NAME, &gsig_IM_IntPtr_PtrVoid_RetVoid, VarArgsNative::Init2)
FCFuncElementSig(COR_CTOR_METHOD_NAME, &gsig_IM_IntPtr_RetVoid, VarArgsNative::Init)
Expand Down Expand Up @@ -879,8 +885,6 @@ FCFuncStart(gRuntimeHelpers)
QCFuncElement("AllocateTypeAssociatedMemory", RuntimeTypeHandle::AllocateTypeAssociatedMemory)
FCFuncElement("AllocTailCallArgBuffer", TailCallHelp::AllocTailCallArgBuffer)
FCFuncElement("GetTailCallInfo", TailCallHelp::GetTailCallInfo)
FCFuncElement("GetILBytesJitted", GetJittedBytes)
FCFuncElement("GetMethodsJittedCount", GetJittedMethodsCount)
FCFuncEnd()

FCFuncStart(gMngdFixedArrayMarshalerFuncs)
Expand Down Expand Up @@ -1158,6 +1162,7 @@ FCClassElement("IReflect", "System.Reflection", gStdMngIReflectFuncs)
FCClassElement("InterfaceMarshaler", "System.StubHelpers", gInterfaceMarshalerFuncs)
#endif
FCClassElement("Interlocked", "System.Threading", gInterlockedFuncs)
FCClassElement("JitInfo", "System.Runtime", gJitInfoFuncs)
#if TARGET_UNIX
FCClassElement("Kernel32", "", gPalKernel32Funcs)
#endif
Expand Down
53 changes: 45 additions & 8 deletions src/coreclr/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,23 +102,47 @@ GARY_IMPL(VMHELPDEF, hlpDynamicFuncTable, DYNAMIC_CORINFO_HELP_COUNT);

#else // DACCESS_COMPILE

uint64_t g_cbILJitted = 0;
uint32_t g_cMethodsJitted = 0;
Volatile<int64_t> g_cbILJitted = 0;
Volatile<int64_t> g_cMethodsJitted = 0;
Volatile<int64_t> g_c100nsTicksInJit = 0;
thread_local int64_t t_cbILJittedForThread = 0;
thread_local int64_t t_cMethodsJittedForThread = 0;
thread_local int64_t t_c100nsTicksInJitForThread = 0;

// This prevents tearing of 64 bit values on 32 bit systems
static inline
int64_t AtomicLoad64WithoutTearing(int64_t volatile *valueRef)
{
WRAPPER_NO_CONTRACT;
#if TARGET_64BIT
return VolatileLoad(valueRef);
#else
return InterlockedCompareExchangeT((LONG64 volatile *)valueRef, (LONG64)0, (LONG64)0);
#endif // TARGET_64BIT
}

#ifndef CROSSGEN_COMPILE
FCIMPL0(INT64, GetJittedBytes)
FCIMPL1(INT64, GetCompiledILBytes, CLR_BOOL currentThread)
{
FCALL_CONTRACT;

return g_cbILJitted;
return currentThread ? t_cbILJittedForThread : AtomicLoad64WithoutTearing(&g_cbILJitted);
}
FCIMPLEND

FCIMPL0(INT32, GetJittedMethodsCount)
FCIMPL1(INT64, GetCompiledMethodCount, CLR_BOOL currentThread)
{
FCALL_CONTRACT;

return g_cMethodsJitted;
return currentThread ? t_cMethodsJittedForThread : AtomicLoad64WithoutTearing(&g_cMethodsJitted);
}
FCIMPLEND

FCIMPL1(INT64, GetCompilationTimeInTicks, CLR_BOOL currentThread)
{
FCALL_CONTRACT;

return currentThread ? t_c100nsTicksInJitForThread : AtomicLoad64WithoutTearing(&g_c100nsTicksInJit);
}
FCIMPLEND
#endif
Expand Down Expand Up @@ -13030,9 +13054,13 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config,
MethodDesc* ftn = nativeCodeVersion.GetMethodDesc();

PCODE ret = NULL;
NormalizedTimer timer;
int64_t c100nsTicksInJit = 0;

COOPERATIVE_TRANSITION_BEGIN();

timer.Start();

#ifdef FEATURE_PREJIT

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

FastInterlockExchangeAddLong((LONG64*)&g_cbILJitted, methodInfo.ILCodeSize);
FastInterlockIncrement((LONG*)&g_cMethodsJitted);
timer.Stop();
c100nsTicksInJit = timer.Elapsed100nsTicks();

InterlockedExchangeAdd64((LONG64*)&g_c100nsTicksInJit, c100nsTicksInJit);
t_c100nsTicksInJitForThread += c100nsTicksInJit;

InterlockedExchangeAdd64((LONG64*)&g_cbILJitted, methodInfo.ILCodeSize);
t_cbILJittedForThread += methodInfo.ILCodeSize;

InterlockedIncrement64((LONG64*)&g_cMethodsJitted);
t_cMethodsJittedForThread++;

COOPERATIVE_TRANSITION_END();
return ret;
Expand Down
13 changes: 11 additions & 2 deletions src/coreclr/vm/jitinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -1149,8 +1149,17 @@ CORJIT_FLAGS GetDebuggerCompileFlags(Module* pModule, CORJIT_FLAGS flags);

bool __stdcall TrackAllocationsEnabled();

FCDECL0(INT64, GetJittedBytes);
FCDECL0(INT32, GetJittedMethodsCount);

extern Volatile<int64_t> g_cbILJitted;
extern Volatile<int64_t> g_cMethodsJitted;
extern Volatile<int64_t> g_c100nsTicksInJit;
extern thread_local int64_t t_cbILJittedForThread;
extern thread_local int64_t t_cMethodsJittedForThread;
extern thread_local int64_t t_c100nsTicksInJitForThread;

FCDECL1(INT64, GetCompiledILBytes, CLR_BOOL currentThread);
FCDECL1(INT64, GetCompiledMethodCount, CLR_BOOL currentThread);
FCDECL1(INT64, GetCompilationTimeInTicks, CLR_BOOL currentThread);

#endif // JITINTERFACE_H

2 changes: 2 additions & 0 deletions src/coreclr/vm/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2272,4 +2272,6 @@ HRESULT GetFileVersion( // S_OK or error
}
#endif // !TARGET_UNIX

Volatile<double> NormalizedTimer::s_frequency = -1.0;

#endif // !DACCESS_COMPILE
77 changes: 77 additions & 0 deletions src/coreclr/vm/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,83 @@ class COMCharacter {
static BOOL nativeIsDigit(WCHAR c);
};

// ======================================================================================
// Simple, reusable 100ns timer for normalizing ticks. For use in Q/FCalls to avoid discrepency with
// tick frequency between native and managed.
class NormalizedTimer
{
private:
static const int64_t NormalizedTicksPerSecond = 10000000 /* 100ns ticks per second (1e7) */;
static Volatile<double> s_frequency;

LARGE_INTEGER startTimestamp;
LARGE_INTEGER stopTimestamp;

#if _DEBUG
bool isRunning = false;
#endif // _DEBUG

public:
NormalizedTimer()
{
LIMITED_METHOD_CONTRACT;
if (s_frequency.Load() == -1)
{
double frequency;
LARGE_INTEGER qpfValue;
QueryPerformanceFrequency(&qpfValue);
frequency = static_cast<double>(qpfValue.QuadPart);
frequency /= NormalizedTicksPerSecond;
s_frequency.Store(frequency);
}

startTimestamp.QuadPart = 0;
startTimestamp.QuadPart = 0;
}

// ======================================================================================
// Start the timer
inline
void Start()
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(!isRunning);
QueryPerformanceCounter(&startTimestamp);

#if _DEBUG
isRunning = true;
#endif // _DEBUG
}

// ======================================================================================
// stop the timer. If called before starting, sets the start time to the same as the stop
inline
void Stop()
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(isRunning);
QueryPerformanceCounter(&stopTimestamp);

#if _DEBUG
isRunning = false;
#endif // _DEBUG
}

// ======================================================================================
// Return elapsed ticks. This will stop a running timer.
// Will return 0 if called out of order.
// Only recalculated this value if it has been stopped/started since previous calculation.
inline
int64_t Elapsed100nsTicks()
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(!isRunning);
_ASSERTE(startTimestamp.QuadPart > 0);
_ASSERTE(stopTimestamp.QuadPart > 0);
return static_cast<int64_t>((stopTimestamp.QuadPart - startTimestamp.QuadPart) / s_frequency);
}
};

#ifdef _DEBUG
#define FORCEINLINE_NONDEBUG
#else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public static partial class PlatformDetection
public static bool IsNotMonoRuntime => !IsMonoRuntime;
public static bool IsMonoInterpreter => GetIsRunningOnMonoInterpreter();
public static bool IsMonoAOT => Environment.GetEnvironmentVariable("MONO_AOT_MODE") == "aot";
public static bool IsNotMonoAOT => Environment.GetEnvironmentVariable("MONO_AOT_MODE") != "aot";
public static bool IsFreeBSD => RuntimeInformation.IsOSPlatform(OSPlatform.Create("FREEBSD"));
public static bool IsNetBSD => RuntimeInformation.IsOSPlatform(OSPlatform.Create("NETBSD"));
public static bool IsAndroid => RuntimeInformation.IsOSPlatform(OSPlatform.Create("ANDROID"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Intrinsics\Vector64_1.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Intrinsics\Vector64DebugView_1.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Intrinsics\X86\Enums.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\JitInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Loader\AssemblyLoadContext.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Loader\LibraryNameVariation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\MemoryFailPoint.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ internal sealed partial class RuntimeEventSource : EventSource
private PollingCounter? _assemblyCounter;
private PollingCounter? _ilBytesJittedCounter;
private PollingCounter? _methodsJittedCounter;
private IncrementingPollingCounter? _jitTimeCounter;

public static void Initialize()
{
Expand Down Expand Up @@ -83,8 +84,9 @@ 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" };
_ilBytesJittedCounter ??= new PollingCounter("il-bytes-jitted", this, () => System.Runtime.CompilerServices.RuntimeHelpers.GetILBytesJitted()) { DisplayName = "IL Bytes Jitted", DisplayUnits = "B" };
_methodsJittedCounter ??= new PollingCounter("methods-jitted-count", this, () => System.Runtime.CompilerServices.RuntimeHelpers.GetMethodsJittedCount()) { DisplayName = "Number of Methods Jitted" };
_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" };
_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) };
}

}
Expand Down
23 changes: 23 additions & 0 deletions src/libraries/System.Private.CoreLib/src/System/Runtime/JitInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Runtime
{
/// <summary>
/// A static class for getting information about the Just In Time compiler.
/// </summary>
public static partial class JitInfo
{
/// <summary>
/// Get the amount of time the JIT Compiler has spent compiling methods. If <paramref name="currentThread"/> is true,
/// then this value is scoped to the current thread, otherwise, this is a global value.
/// </summary>
/// <param name="currentThread">Whether the returned value should be specific to the current thread. Default: false</param>
/// <returns>The amount of time the JIT Compiler has spent compiling methods.</returns>
public static TimeSpan GetCompilationTime(bool currentThread = false)
{
// TimeSpan.FromTicks() takes 100ns ticks
return TimeSpan.FromTicks(GetCompilationTimeInTicks(currentThread));
}
}
}
6 changes: 6 additions & 0 deletions src/libraries/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12472,6 +12472,12 @@ public static partial class GCSettings
public static System.Runtime.GCLargeObjectHeapCompactionMode LargeObjectHeapCompactionMode { get { throw null; } set { } }
public static System.Runtime.GCLatencyMode LatencyMode { get { throw null; } set { } }
}
public static partial class JitInfo
{
public static long GetCompiledILBytes(bool currentThread=false) { throw null; }
public static long GetCompiledMethodCount(bool currentThread=false) { throw null; }
public static TimeSpan GetCompilationTime(bool currentThread=false) { throw null; }
}
public sealed partial class MemoryFailPoint : System.Runtime.ConstrainedExecution.CriticalFinalizerObject, System.IDisposable
{
public MemoryFailPoint(int sizeInMegabytes) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@
<Compile Include="System\Reflection\TypeTests.Get.CornerCases.cs" />
<Compile Include="System\Reflection\TypeTests.GetMember.cs" />
<Compile Include="System\Runtime\DependentHandleTests.cs" />
<Compile Include="System\Runtime\JitInfoTests.cs" />
<Compile Include="System\Runtime\MemoryFailPointTests.cs" />
<Compile Include="System\Runtime\NgenServicingAttributesTests.cs" />
<Compile Include="System\Runtime\CompilerServices\AttributesTests.cs" />
Expand Down
Loading

0 comments on commit 21a7632

Please sign in to comment.