Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Add JIT time metric
* add per thread privately
* add test for counter
* add test for priuvate metric (currently failing due to linker I think)
  • Loading branch information
John Salem committed Jun 5, 2021
commit 264a74f3438bda1eb655d2a3668b0ce8ea1a6224
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
<type fullname="Internal.Runtime.InteropServices.InMemoryAssemblyLoader">
<method name="LoadInMemoryAssembly" />
</type>

<type fullname="System.Runtime.CompilerServices.RuntimeHelpers">
<method name="GetNanosecondsInJitForThread" />
</type>
</assembly>

<!-- The private Event methods are accessed by private reflection in the base EventSource class. -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,12 @@ private static unsafe void DispatchTailCalls(

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern int GetMethodsJittedCount();

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

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern long GetNanosecondsInJitForThread();
}
// Helper class to assist with unsafe pinning of arbitrary objects.
// It's used by VM code.
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,8 @@ FCFuncStart(gRuntimeHelpers)
FCFuncElement("GetTailCallInfo", TailCallHelp::GetTailCallInfo)
FCFuncElement("GetILBytesJitted", GetJittedBytes)
FCFuncElement("GetMethodsJittedCount", GetJittedMethodsCount)
FCFuncElement("GetNanosecondsInJit", GetNanosecondsInJit)
FCFuncElement("GetNanosecondsInJitForThread", GetNanosecondsInJitForThread)
FCFuncEnd()

FCFuncStart(gMngdFixedArrayMarshalerFuncs)
Expand Down
37 changes: 37 additions & 0 deletions src/coreclr/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ GARY_IMPL(VMHELPDEF, hlpDynamicFuncTable, DYNAMIC_CORINFO_HELP_COUNT);

uint64_t g_cbILJitted = 0;
uint32_t g_cMethodsJitted = 0;
thread_local int64_t g_cNanosecondsInJitForThread = 0;
int64_t g_cNanosecondsInJit = 0;

#ifndef CROSSGEN_COMPILE
FCIMPL0(INT64, GetJittedBytes)
Expand All @@ -121,6 +123,22 @@ FCIMPL0(INT32, GetJittedMethodsCount)
return g_cMethodsJitted;
}
FCIMPLEND

FCIMPL0(INT64, GetNanosecondsInJit)
{
FCALL_CONTRACT;

return g_cNanosecondsInJit;
}
FCIMPLEND

FCIMPL0(INT64, GetNanosecondsInJitForThread)
{
FCALL_CONTRACT;

return g_cNanosecondsInJitForThread;
}
FCIMPLEND
#endif

/*********************************************************************/
Expand Down Expand Up @@ -13015,9 +13033,21 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config,
MethodDesc* ftn = nativeCodeVersion.GetMethodDesc();

PCODE ret = NULL;
int64_t jitStartTimestamp = 0;
int64_t jitEndTimestamp = 0;
int64_t jitTimeNs = 0;
static int64_t qpcFrequency = 1;
LARGE_INTEGER qpcValue;

COOPERATIVE_TRANSITION_BEGIN();

if (qpcFrequency == 1)
if (QueryPerformanceFrequency (&qpcValue))
qpcFrequency = static_cast<int64_t>(qpcValue.QuadPart) / 1000000000 /* ns per s */;

if (QueryPerformanceCounter (&qpcValue))
jitStartTimestamp = static_cast<int64_t>(qpcValue.QuadPart);

#ifdef FEATURE_PREJIT

if (g_pConfig->RequireZaps() == EEConfig::REQUIRE_ZAPS_ALL &&
Expand Down Expand Up @@ -13379,6 +13409,13 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config,
printf(".");
#endif // _DEBUG

if (QueryPerformanceCounter (&qpcValue))
jitEndTimestamp = static_cast<int64_t>(qpcValue.QuadPart);

jitTimeNs = jitEndTimestamp - jitStartTimestamp;
jitTimeNs /= qpcFrequency;
FastInterlockExchangeAddLong((LONG64*)&g_cNanosecondsInJit, jitTimeNs);
FastInterlockExchangeAddLong((LONG64*)&g_cNanosecondsInJitForThread, jitTimeNs);
FastInterlockExchangeAddLong((LONG64*)&g_cbILJitted, methodInfo.ILCodeSize);
FastInterlockIncrement((LONG*)&g_cMethodsJitted);

Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/vm/jitinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -1157,6 +1157,8 @@ bool __stdcall TrackAllocationsEnabled();

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

#endif // JITINTERFACE_H

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 @@ -85,6 +86,7 @@ protected override void OnEventCommand(EventCommandEventArgs command)
_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" };
_jitTimeCounter ??= new IncrementingPollingCounter("nanoseconds-in-jit", this, () => System.Runtime.CompilerServices.RuntimeHelpers.GetNanosecondsInJit()) { DisplayName = "Nanoseconds spent in JIT", DisplayUnits = "ns", DisplayRateTimeScale = new TimeSpan(0, 0, 1) };
}

}
Expand Down
71 changes: 71 additions & 0 deletions src/tests/tracing/eventcounter/perthreadjittime.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;

namespace PerTHreadJitTime
{
public class MyClass
{
public int MyMethod(int n)
{
int ret = 0;
for (int i = 0; i < n; i++)
ret += i;
return ret;
}
}

public class MyOtherClass
{
public int MyOtherMethod(int n)
{
int ret = 1;
for (int i = 0; i < n; i++)
ret *= i;
return ret;
}
}

public class Program
{
public static int Main(string[] args)
{
long threadOneJitTime = 0;
long threadTwoJitTime = 0;

MethodInfo getNanosecondsInJitForThread = typeof(RuntimeHelpers).GetMethod("GetNanosecondsInJitForThread", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy);
if (getNanosecondsInJitForThread is null)
{
foreach (var m in typeof(RuntimeHelpers).GetMembers(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy))
Console.WriteLine($"\t{m}");
}

Thread[] threads = new Thread[2];
threads[0] = new Thread(() => {
var mc = new MyClass();
int n = mc.MyMethod(100);
threadOneJitTime = (long)getNanosecondsInJitForThread.Invoke(null, null);
});
threads[1] = new Thread(() => {
var moc = new MyOtherClass();
int n = moc.MyOtherMethod(10);
threadTwoJitTime = (long)getNanosecondsInJitForThread.Invoke(null, null);
});

foreach (Thread t in threads)
t.Start();

foreach (Thread t in threads)
t.Join();

Console.WriteLine($"Thread One JIT Time: {threadOneJitTime}");
Console.WriteLine($"Thread Two JIT Time: {threadTwoJitTime}");

return (threadOneJitTime > 0 && threadTwoJitTime > 0) ? 100 : -1;
}
}
}
17 changes: 17 additions & 0 deletions src/tests/tracing/eventcounter/perthreadjittime.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<CLRTestKind>BuildAndRun</CLRTestKind>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CLRTestPriority>0</CLRTestPriority>
<GCStressIncompatible>true</GCStressIncompatible>
<!-- This test is timing sensitive and JIT timing affects the results of the test -->
<JitOptimizationSensitive>true</JitOptimizationSensitive>
<!-- This test has a secondary thread with an infinite loop -->
<UnloadabilityIncompatible>true</UnloadabilityIncompatible>
</PropertyGroup>
<ItemGroup>
<Compile Include="perthreadjittime.cs" />
<ProjectReference Include="../common/common.csproj" />
</ItemGroup>
</Project>
3 changes: 2 additions & 1 deletion src/tests/tracing/eventcounter/runtimecounters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ public RuntimeCounterListener()
{ "poh-size", false },
{ "assembly-count", false },
{ "il-bytes-jitted", false },
{ "methods-jitted-count", false }
{ "methods-jitted-count", false },
{ "nanoseconds-in-jit", false }
};
}
private Dictionary<string, bool> observedRuntimeCounters;
Expand Down