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
Prev Previous commit
Next Next commit
PR feedback + adding ref source
* normalize ticks to 100ns in native code
  * add NormalizedTimer class
* added source ref
* change ret value to long
  • Loading branch information
John Salem committed Jul 2, 2021
commit 064fd0cb950aacc61a522553ec5cac6829ea7ec1
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ public static partial class JitInfo
/// <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 int GetCompiledMethodCount(bool currentThread = false);
public static extern long GetCompiledMethodCount(bool currentThread = false);

// Normalized to 100ns ticks on vm side
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern long GetCompilationTimeInTicks(bool currentThread = false);
}
Expand Down
14 changes: 5 additions & 9 deletions src/coreclr/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13042,13 +13042,11 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config,
MethodDesc* ftn = nativeCodeVersion.GetMethodDesc();

PCODE ret = NULL;
LARGE_INTEGER jitStartTimestamp;
LARGE_INTEGER jitEndTimestamp;
int64_t jitTimeQPCTicks = 0;
NormalizedTimer timer;

COOPERATIVE_TRANSITION_BEGIN();

QueryPerformanceCounter(&jitStartTimestamp);
timer.Start();

#ifdef FEATURE_PREJIT

Expand Down Expand Up @@ -13411,12 +13409,10 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config,
printf(".");
#endif // _DEBUG

QueryPerformanceCounter(&jitEndTimestamp);
timer.Stop();

jitTimeQPCTicks = static_cast<int64_t>(jitEndTimestamp.QuadPart - jitStartTimestamp.QuadPart);

FastInterlockExchangeAddLong((LONG64*)&g_cQPCTicksInJit, jitTimeQPCTicks);
g_cQPCTicksInJitForThread += jitTimeQPCTicks;
FastInterlockExchangeAddLong((LONG64*)&g_cQPCTicksInJit, timer.Elapsed100nsTicks());
g_cQPCTicksInJitForThread += timer.Elapsed100nsTicks();

FastInterlockExchangeAddLong((LONG64*)&g_cbILJitted, methodInfo.ILCodeSize);
g_cbILJittedForThread += methodInfo.ILCodeSize;
Expand Down
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<int64_t> NormalizedTimer::s_frequency = -1;

#endif // !DACCESS_COMPILE
80 changes: 80 additions & 0 deletions src/coreclr/vm/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,86 @@ 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:
LARGE_INTEGER startTimestamp = { .QuadPart = 0 };
LARGE_INTEGER stopTimestamp = { .QuadPart = 0 };
int64_t cachedElapsed100nsTicks = 0;
bool shouldRecalculate = true;
bool isRunning = false;
static const int64_t NormalizedTicksPerSecond = 10000000 /* 100ns ticks per second (1e7) */;
static Volatile<int64_t> s_frequency;

inline
void Lap()
{
startTimestamp = stopTimestamp;
stopTimestamp.QuadPart = 0;
isRunning = true;
shouldRecalculate = true;
}
public:
// ======================================================================================
// Start the timer
inline
void Start()
{
QueryPerformanceCounter(&startTimestamp);
stopTimestamp.QuadPart = 0;
isRunning = true;
shouldRecalculate = true;
}

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

isRunning = false;
shouldRecalculate = true;
}

// ======================================================================================
// 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(bool shouldContinue = false)
{
if (s_frequency == -1)
{
int64_t frequency;
LARGE_INTEGER qpfValue;
QueryPerformanceFrequency(&qpfValue);
frequency = static_cast<int64_t>(qpfValue.QuadPart);
frequency /= NormalizedTicksPerSecond;
InterlockedExchange64(&s_frequency, frequency);
}

if (shouldRecalculate)
{
if (isRunning)
Stop();

cachedElapsed100nsTicks = static_cast<int64_t>(stopTimestamp.QuadPart - startTimestamp.QuadPart) / s_frequency;

if (shouldContinue)
Lap();
}

return cachedElapsed100nsTicks;
}
};

#ifdef _DEBUG
#define FORCEINLINE_NONDEBUG
#else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ namespace System.Diagnostics
{
public partial class Stopwatch
{
internal static long QueryPerformanceFrequency()
private static long QueryPerformanceFrequency()
{
const long SecondsToNanoSeconds = 1000000000;
return SecondsToNanoSeconds;
}

internal static long QueryPerformanceCounter()
private static long QueryPerformanceCounter()
{
return (long)Interop.Sys.GetTimestamp();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace System.Diagnostics
{
public partial class Stopwatch
{
internal static unsafe long QueryPerformanceFrequency()
private static unsafe long QueryPerformanceFrequency()
{
long resolution;

Expand All @@ -16,7 +16,7 @@ internal static unsafe long QueryPerformanceFrequency()
return resolution;
}

internal static unsafe long QueryPerformanceCounter()
private static unsafe long QueryPerformanceCounter()
{
long timestamp;

Expand Down
19 changes: 5 additions & 14 deletions src/libraries/System.Private.CoreLib/src/System/Runtime/JitInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,11 @@

namespace System.Runtime
{
/// <summary>
/// A static class for getting information about the Just In Time compiler.
/// </summary>
public static partial class JitInfo
{
private const long TicksPerMillisecond = 10000;
private const long TicksPerSecond = TicksPerMillisecond * 1000;

// "Frequency" stores the frequency of the high-resolution performance counter,
// if one exists. Otherwise it will store TicksPerSecond.
// The frequency cannot change while the system is running,
// so we only need to initialize it once.
public static readonly long Frequency = System.Diagnostics.Stopwatch.QueryPerformanceFrequency();

// pre calculating the tick frequency for quickly converting from QPC ticks to DateTime ticks
private static readonly double s_tickFrequency = (double)TicksPerSecond / Frequency;

/// <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.
Expand All @@ -25,8 +16,8 @@ public static partial class JitInfo
/// <returns>The amount of time the JIT Compiler has spent compiling methods.</returns>
public static TimeSpan GetCompilationTime(bool currentThread = false)
{
// See System.Diagnostics.Stopwatch.GetElapsedDateTimeTicks()
return TimeSpan.FromTicks((long)(GetCompilationTimeInTicks(currentThread) * s_tickFrequency));
// 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 @@ -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
21 changes: 21 additions & 0 deletions src/libraries/System.Runtime/tests/System/Runtime/JitInfoTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Xunit;

namespace System.Runtime.Tests
{
// NOTE: DependentHandle is already heavily tested indirectly through ConditionalWeakTable<,>.
// This class contains some specific tests for APIs that are only relevant when used directly.
public class JitInfoTests
{
// TODO(josalem): disable test on iOS/Android/browser
[Fact]
public void JitInfoIsPopulated()
{
Assert.True(System.Runtime.JitInfo.GetCompilationTime() > TimeSpan.Zero);
Assert.True(System.Runtime.JitInfo.GetCompiledILBytes() > 0);
Assert.True(System.Runtime.JitInfo.GetCompiledMethodCount() > 0);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ public static long GetCompiledILBytes(bool currentThread = false)
/// </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>
public static int GetCompiledMethodCount(bool currentThread = false)
public static long GetCompiledMethodCount(bool currentThread = false)
{
return currentThread ? 0 : (int)EventPipeInternal.GetRuntimeCounterValue(EventPipeInternal.RuntimeCounters.JIT_METHODS_JITTED);
return currentThread ? 0 : (long)EventPipeInternal.GetRuntimeCounterValue(EventPipeInternal.RuntimeCounters.JIT_METHODS_JITTED);
}

// normalized to 100ns ticks on vm side
public static long GetCompilationTimeInTicks(bool currentThread = false)
{
return currentThread ? 0 : (long)EventPipeInternal.GetRuntimeCounterValue(EventPipeInternal.RuntimeCounters.JIT_TICKS_IN_JIT);
Expand Down
4 changes: 2 additions & 2 deletions src/mono/mono/metadata/icall-eventpipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ get_il_bytes_jitted (void)

static
inline
gint32
gint64
get_methods_jitted (void)
{
gint64 methods_compiled = 0;
Expand All @@ -285,7 +285,7 @@ get_methods_jitted (void)

if (mono_get_runtime_callbacks ()->get_jit_stats)
mono_get_runtime_callbacks ()->get_jit_stats (&methods_compiled, &cil_code_size_bytes, &native_code_size_bytes, &jit_time);
return (gint32)methods_compiled;
return methods_compiled;
}

static
Expand Down
65 changes: 0 additions & 65 deletions src/tests/tracing/eventcounter/perthreadjittime.cs

This file was deleted.

17 changes: 0 additions & 17 deletions src/tests/tracing/eventcounter/perthreadjittime.csproj

This file was deleted.