1
1
using System ;
2
2
using System . Collections . Generic ;
3
3
using System . Threading ;
4
+ using BenchmarkDotNet . Helpers ;
4
5
using BenchmarkDotNet . Jobs ;
5
6
using BenchmarkDotNet . Portability ;
6
7
using BenchmarkDotNet . Reports ;
@@ -27,27 +28,35 @@ internal sealed class EngineFirstJitStage : EngineJitStage
27
28
// It is not worth spending a long time in jit stage for macro-benchmarks.
28
29
private static readonly TimeInterval MaxTieringTime = TimeInterval . FromSeconds ( 10 ) ;
29
30
31
+ // Jit call counting delay is only for when the app starts up. We don't need to wait for every benchmark if multiple benchmarks are ran in-process.
32
+ private static TimeSpan tieredDelay = JitInfo . TieredDelay ;
33
+
30
34
internal bool didStopEarly = false ;
31
35
internal Measurement lastMeasurement ;
32
36
33
37
private readonly IEnumerator < IterationData > enumerator ;
38
+ private readonly bool evaluateOverhead ;
34
39
35
- internal EngineFirstJitStage ( EngineParameters parameters ) : base ( parameters )
40
+ internal EngineFirstJitStage ( bool evaluateOverhead , EngineParameters parameters ) : base ( parameters )
36
41
{
37
42
enumerator = EnumerateIterations ( ) ;
43
+ this . evaluateOverhead = evaluateOverhead ;
38
44
}
39
45
40
46
internal override List < Measurement > GetMeasurementList ( ) => new ( GetMaxMeasurementCount ( ) ) ;
41
47
42
- private static int GetMaxMeasurementCount ( )
48
+ private int GetMaxMeasurementCount ( )
43
49
{
44
- int tieredCallCountThreshold = JitInfo . TieredCallCountThreshold ;
45
- if ( JitInfo . IsDPGO )
50
+ if ( ! JitInfo . IsTiered )
46
51
{
47
- tieredCallCountThreshold *= 2 ;
52
+ return 1 ;
48
53
}
49
- // +1 for first jit, x2 for overhead + workload
50
- return ( tieredCallCountThreshold + 1 ) * 2 ;
54
+ int count = JitInfo . MaxTierPromotions * JitInfo . TieredCallCountThreshold + 2 ;
55
+ if ( evaluateOverhead )
56
+ {
57
+ count *= 2 ;
58
+ }
59
+ return count ;
51
60
}
52
61
53
62
internal override bool GetShouldRunIteration ( List < Measurement > measurements , out IterationData iterationData )
@@ -73,8 +82,11 @@ internal override bool GetShouldRunIteration(List<Measurement> measurements, out
73
82
private IEnumerator < IterationData > EnumerateIterations ( )
74
83
{
75
84
++ iterationIndex ;
76
- yield return GetDummyIterationData ( dummy1Action ) ;
77
- yield return GetOverheadIterationData ( ) ;
85
+ if ( evaluateOverhead )
86
+ {
87
+ yield return GetDummyIterationData ( dummy1Action ) ;
88
+ yield return GetOverheadIterationData ( ) ;
89
+ }
78
90
yield return GetDummyIterationData ( dummy2Action ) ;
79
91
yield return GetWorkloadIterationData ( ) ;
80
92
yield return GetDummyIterationData ( dummy3Action ) ;
@@ -86,12 +98,14 @@ private IEnumerator<IterationData> EnumerateIterations()
86
98
}
87
99
88
100
// Wait enough time for jit call counting to begin.
89
- MaybeSleep ( JitInfo . TieredDelay ) ;
101
+ SleepHelper . SleepIfPositive ( tieredDelay ) ;
102
+ // Don't make the next jit stage wait if it's ran in the same process.
103
+ tieredDelay = TimeSpan . Zero ;
90
104
91
105
// Attempt to promote methods to tier1, but don't spend too much time in jit stage.
92
106
StartedClock startedClock = parameters . TargetJob . ResolveValue ( InfrastructureMode . ClockCharacteristic , parameters . Resolver ) . Start ( ) ;
93
107
94
- int remainingTiers = JitInfo . IsDPGO ? 2 : 1 ;
108
+ int remainingTiers = JitInfo . MaxTierPromotions ;
95
109
while ( remainingTiers > 0 )
96
110
{
97
111
-- remainingTiers ;
@@ -100,7 +114,10 @@ private IEnumerator<IterationData> EnumerateIterations()
100
114
{
101
115
-- remainingCalls ;
102
116
++ iterationIndex ;
103
- yield return GetOverheadIterationData ( ) ;
117
+ if ( evaluateOverhead )
118
+ {
119
+ yield return GetOverheadIterationData ( ) ;
120
+ }
104
121
yield return GetWorkloadIterationData ( ) ;
105
122
106
123
if ( ( remainingTiers + remainingCalls ) > 0
@@ -111,13 +128,16 @@ private IEnumerator<IterationData> EnumerateIterations()
111
128
}
112
129
}
113
130
114
- MaybeSleep ( JitInfo . BackgroundCompilationDelay ) ;
131
+ SleepHelper . SleepIfPositive ( JitInfo . BackgroundCompilationDelay ) ;
115
132
}
116
133
117
- // Empirical evidence shows that the first call after the method is tiered up takes longer,
134
+ // Empirical evidence shows that the first call after the method is tiered up may take longer,
118
135
// so we run an extra iteration to ensure the next stage gets a stable measurement.
119
136
++ iterationIndex ;
120
- yield return GetOverheadIterationData ( ) ;
137
+ if ( evaluateOverhead )
138
+ {
139
+ yield return GetOverheadIterationData ( ) ;
140
+ }
121
141
yield return GetWorkloadIterationData ( ) ;
122
142
}
123
143
@@ -126,32 +146,22 @@ private IterationData GetOverheadIterationData()
126
146
127
147
private IterationData GetWorkloadIterationData ( )
128
148
=> new ( IterationMode . Workload , IterationStage . Jitting , iterationIndex , 1 , 1 , parameters . IterationSetupAction , parameters . IterationCleanupAction , parameters . WorkloadActionNoUnroll ) ;
129
-
130
- private static void MaybeSleep ( TimeSpan timeSpan )
131
- {
132
- if ( timeSpan > TimeSpan . Zero )
133
- {
134
- Thread . Sleep ( timeSpan ) ;
135
- }
136
- }
137
149
}
138
150
139
- internal sealed class EngineSecondJitStage ( int unrollFactor , EngineParameters parameters ) : EngineJitStage ( parameters )
151
+ internal sealed class EngineSecondJitStage : EngineJitStage
140
152
{
141
- private readonly int unrollFactor = unrollFactor ;
153
+ private readonly int unrollFactor ;
154
+ private readonly bool evaluateOverhead ;
142
155
143
- internal override List < Measurement > GetMeasurementList ( ) => new ( GetMaxCallCount ( ) ) ;
144
-
145
- private static int GetMaxCallCount ( )
156
+ public EngineSecondJitStage ( int unrollFactor , bool evaluateOverhead , EngineParameters parameters ) : base ( parameters )
146
157
{
147
- int tieredCallCountThreshold = JitInfo . TieredCallCountThreshold ;
148
- if ( JitInfo . IsDPGO )
149
- {
150
- tieredCallCountThreshold *= 2 ;
151
- }
152
- return tieredCallCountThreshold + 1 ;
158
+ this . unrollFactor = unrollFactor ;
159
+ this . evaluateOverhead = evaluateOverhead ;
160
+ iterationIndex = evaluateOverhead ? 0 : 2 ;
153
161
}
154
162
163
+ internal override List < Measurement > GetMeasurementList ( ) => new ( evaluateOverhead ? 5 : 3 ) ;
164
+
155
165
// The benchmark method has already been jitted via *NoUnroll, we only need to jit the *Unroll methods here, which aren't tiered.
156
166
internal override bool GetShouldRunIteration ( List < Measurement > measurements , out IterationData iterationData )
157
167
{
0 commit comments