Skip to content

Commit 1251e63

Browse files
committed
Added an extra invocation to the end of jit stage.
1 parent 778a1a7 commit 1251e63

File tree

1 file changed

+11
-5
lines changed

1 file changed

+11
-5
lines changed

src/BenchmarkDotNet/Engines/EngineJitStage.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ protected IterationData GetDummyIterationData(Action<long> dummyAction)
1818
=> new(IterationMode.Dummy, IterationStage.Jitting, iterationIndex, 1, 1, () => { }, () => { }, dummyAction);
1919
}
2020

21+
// We do our best to encourage the jit to fully promote methods to tier1, but tiered jit relies on heuristics,
22+
// and we purposefully don't spend too much time in this stage, so we can't guarantee it.
23+
// This should succeed for 99%+ of microbenchmarks. For any sufficiently short benchmarks where this fails,
24+
// the following stages (Pilot and Warmup) will likely take it the rest of the way. Long-running benchmarks may never fully reach tier1.
2125
internal sealed class EngineFirstJitStage : EngineJitStage
2226
{
2327
// It is not worth spending a long time in jit stage for macro-benchmarks.
@@ -66,10 +70,6 @@ internal override bool GetShouldRunIteration(List<Measurement> measurements, out
6670
return false;
6771
}
6872

69-
// We do our best to encourage the jit to fully promote methods to tier1, but tiered jit relies on heuristics,
70-
// and we purposefully don't spend too much time in this stage, so we can't guarantee it.
71-
// This should succeed for 99%+ of microbenchmarks. For any sufficiently short benchmarks where this fails,
72-
// the following stages (Pilot and Warmup) will likely take it the rest of the way. Long-running benchmarks may never fully reach tier1.
7373
private IEnumerator<IterationData> EnumerateIterations()
7474
{
7575
++iterationIndex;
@@ -113,6 +113,12 @@ private IEnumerator<IterationData> EnumerateIterations()
113113

114114
MaybeSleep(JitInfo.BackgroundCompilationDelay);
115115
}
116+
117+
// Empirical evidence shows that the first call after the method is tiered up takes longer,
118+
// so we run an extra iteration to ensure the next stage gets a stable measurement.
119+
++iterationIndex;
120+
yield return GetOverheadIterationData();
121+
yield return GetWorkloadIterationData();
116122
}
117123

118124
private IterationData GetOverheadIterationData()
@@ -121,7 +127,7 @@ private IterationData GetOverheadIterationData()
121127
private IterationData GetWorkloadIterationData()
122128
=> new(IterationMode.Workload, IterationStage.Jitting, iterationIndex, 1, 1, parameters.IterationSetupAction, parameters.IterationCleanupAction, parameters.WorkloadActionNoUnroll);
123129

124-
private void MaybeSleep(TimeSpan timeSpan)
130+
private static void MaybeSleep(TimeSpan timeSpan)
125131
{
126132
if (timeSpan > TimeSpan.Zero)
127133
{

0 commit comments

Comments
 (0)