7
7
using BenchmarkDotNet . Jobs ;
8
8
using BenchmarkDotNet . Running ;
9
9
using JetBrains . Annotations ;
10
+ using Perfolizer . Horology ;
10
11
using Xunit ;
11
12
12
13
namespace BenchmarkDotNet . Tests . Engine
@@ -33,6 +34,14 @@ private void VeryTimeConsumingSingle(long _)
33
34
Thread . Sleep ( IterationTime ) ;
34
35
}
35
36
37
+ private void TimeConsumingOnlyForTheFirstCall ( long _ )
38
+ {
39
+ if ( timesBenchmarkCalled ++ == 0 )
40
+ {
41
+ Thread . Sleep ( IterationTime ) ;
42
+ }
43
+ }
44
+
36
45
private void InstantNoUnroll ( long invocationCount ) => timesBenchmarkCalled += ( int ) invocationCount ;
37
46
private void InstantUnroll ( long _ ) => timesBenchmarkCalled += 16 ;
38
47
@@ -78,10 +87,10 @@ public void ForDefaultSettingsVeryTimeConsumingBenchmarksAreExecutedOncePerItera
78
87
var engine = new EngineFactory ( ) . CreateReadyToRun ( engineParameters ) ;
79
88
80
89
Assert . Equal ( 1 , timesGlobalSetupCalled ) ;
81
- Assert . Equal ( 1 , timesIterationSetupCalled ) ; // 1x for Target
82
- Assert . Equal ( 1 , timesBenchmarkCalled ) ;
83
- Assert . Equal ( 1 , timesOverheadCalled ) ;
84
- Assert . Equal ( 1 , timesIterationCleanupCalled ) ; // 1x for Target
90
+ Assert . Equal ( 2 , timesIterationSetupCalled ) ; // 2x for Target
91
+ Assert . Equal ( 2 , timesBenchmarkCalled ) ;
92
+ Assert . Equal ( 2 , timesOverheadCalled ) ;
93
+ Assert . Equal ( 2 , timesIterationCleanupCalled ) ; // 2x for Target
85
94
Assert . Equal ( 0 , timesGlobalCleanupCalled ) ; // cleanup is called as part of dispose
86
95
87
96
Assert . Equal ( 1 , engine . TargetJob . Run . InvocationCount ) ; // call the benchmark once per iteration
@@ -95,6 +104,39 @@ public void ForDefaultSettingsVeryTimeConsumingBenchmarksAreExecutedOncePerItera
95
104
Assert . Equal ( 1 , timesGlobalCleanupCalled ) ;
96
105
}
97
106
107
+ [ Theory ]
108
+ [ InlineData ( 120 ) ] // 120 ms as in the bug report
109
+ [ InlineData ( 250 ) ] // 250 ms as configured in dotnet/performance repo
110
+ [ InlineData ( EngineResolver . DefaultIterationTime ) ] // 500 ms - the default BDN setting
111
+ public void BenchmarksThatRunLongerThanIterationTimeOnlyDuringFirstInvocationAreNotInvokedOncePerIteration ( int iterationTime )
112
+ {
113
+ var engineParameters = CreateEngineParameters (
114
+ mainNoUnroll : TimeConsumingOnlyForTheFirstCall ,
115
+ mainUnroll : InstantUnroll ,
116
+ job : Job . Default . WithIterationTime ( TimeInterval . FromMilliseconds ( iterationTime ) ) ) ;
117
+
118
+ var engine = new EngineFactory ( ) . CreateReadyToRun ( engineParameters ) ;
119
+
120
+ Assert . Equal ( 1 , timesGlobalSetupCalled ) ;
121
+ // the factory should call the benchmark:
122
+ // 1st time with unroll factor to JIT the code
123
+ // one more to check that the Jitting has not dominated the reported time
124
+ // and one more time to JIT the 16 unroll factor case as it turned out that Jitting has dominated the time
125
+ Assert . Equal ( 1 + 1 + 1 , timesIterationSetupCalled ) ;
126
+ Assert . Equal ( 1 + 1 + 16 , timesBenchmarkCalled ) ;
127
+ Assert . Equal ( 1 + 1 + 16 , timesOverheadCalled ) ;
128
+ Assert . Equal ( 1 + 1 + 1 , timesIterationCleanupCalled ) ; // 2x for Target
129
+ Assert . Equal ( 0 , timesGlobalCleanupCalled ) ; // cleanup is called as part of dispose
130
+
131
+ Assert . False ( engine . TargetJob . Run . HasValue ( RunMode . InvocationCountCharacteristic ) ) ; // we need pilot stage
132
+
133
+ Assert . False ( engine . TargetJob . Run . HasValue ( AccuracyMode . EvaluateOverheadCharacteristic ) ) ;
134
+
135
+ engine . Dispose ( ) ; // cleanup is called as part of dispose
136
+
137
+ Assert . Equal ( 1 , timesGlobalCleanupCalled ) ;
138
+ }
139
+
98
140
[ Fact ]
99
141
public void ForJobsWithExplicitUnrollFactorTheGlobalSetupIsCalledAndMultiActionCodeGetsJitted ( )
100
142
=> AssertGlobalSetupWasCalledAndMultiActionGotJitted ( Job . Default . WithUnrollFactor ( 16 ) ) ;
0 commit comments