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

Implement JitInfo API #55046

Merged
merged 22 commits into from
Jul 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
josalem marked this conversation as resolved.
Show resolved Hide resolved
{
/// <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 @@ -1157,8 +1157,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 @@ -26,6 +26,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 @@ -857,6 +857,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));
josalem marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
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 @@ -9623,6 +9623,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 @@ -216,6 +216,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