@@ -19,7 +19,7 @@ public class Engine : IEngine
19
19
20
20
[ PublicAPI ] public IHost Host { get ; }
21
21
[ PublicAPI ] public Action < long > WorkloadAction { get ; }
22
- [ PublicAPI ] public Action WorkloadActionSingleInvoke { get ; }
22
+ [ PublicAPI ] public Action < long > WorkloadActionNoUnroll { get ; }
23
23
[ PublicAPI ] public Action Dummy1Action { get ; }
24
24
[ PublicAPI ] public Action Dummy2Action { get ; }
25
25
[ PublicAPI ] public Action Dummy3Action { get ; }
@@ -54,13 +54,13 @@ public class Engine : IEngine
54
54
internal Engine (
55
55
IHost host ,
56
56
IResolver resolver ,
57
- Action dummy1Action , Action dummy2Action , Action dummy3Action , Action < long > overheadAction , Action < long > workloadAction , Action workloadActionSingleInvoke , Job targetJob ,
57
+ Action dummy1Action , Action dummy2Action , Action dummy3Action , Action < long > overheadAction , Action < long > workloadAction , Action < long > workloadActionNoUnroll , Job targetJob ,
58
58
Action globalSetupAction , Action globalCleanupAction , Action iterationSetupAction , Action iterationCleanupAction , long operationsPerInvoke ,
59
59
bool includeExtraStats , bool includeSurvivedMemory , string benchmarkName )
60
60
{
61
61
Host = host ;
62
62
OverheadAction = overheadAction ;
63
- WorkloadActionSingleInvoke = workloadActionSingleInvoke ;
63
+ WorkloadActionNoUnroll = workloadActionNoUnroll ;
64
64
Dummy1Action = dummy1Action ;
65
65
Dummy2Action = dummy2Action ;
66
66
Dummy3Action = dummy3Action ;
@@ -96,7 +96,7 @@ internal Engine(
96
96
// Measure bytes to allow GC monitor to make its allocations.
97
97
GetTotalBytes ( ) ;
98
98
// Run the clock once to allow it to make its allocations.
99
- MeasureAction ( ( ) => { } ) ;
99
+ MeasureAction ( _ => { } , 0 ) ;
100
100
GetTotalBytes ( ) ;
101
101
}
102
102
}
@@ -197,32 +197,46 @@ public Measurement RunIteration(IterationData data)
197
197
bool isOverhead = data . IterationMode == IterationMode . Overhead ;
198
198
var action = isOverhead ? OverheadAction : WorkloadAction ;
199
199
200
- double nanoseconds = 0 ;
201
200
if ( ! isOverhead )
202
201
{
203
202
IterationSetupAction ( ) ;
203
+ }
204
+
205
+ GcCollect ( ) ;
206
+
207
+ if ( EngineEventSource . Log . IsEnabled ( ) )
208
+ EngineEventSource . Log . IterationStart ( data . IterationMode , data . IterationStage , totalOperations ) ;
204
209
205
- if ( includeSurvivedMemory && ! survivedBytesMeasured )
210
+ bool needsSurvivedMeasurement = includeSurvivedMemory && ! isOverhead && ! survivedBytesMeasured ;
211
+ double nanoseconds ;
212
+ if ( needsSurvivedMeasurement )
213
+ {
214
+ // Measure survived bytes for only the first invocation.
215
+ survivedBytesMeasured = true ;
216
+ if ( totalOperations == 1 )
206
217
{
207
- // Measure survived bytes for only the first invocation.
208
- survivedBytesMeasured = true ;
218
+ // Measure normal invocation for both survived memory and time.
219
+ long beforeBytes = GetTotalBytes ( ) ;
220
+ nanoseconds = MeasureAction ( action , invokeCount / unrollFactor ) ;
221
+ long afterBytes = GetTotalBytes ( ) ;
222
+ survivedBytes = afterBytes - beforeBytes ;
223
+ }
224
+ else
225
+ {
226
+ // Measure a single invocation for survived memory, plus normal invocations for time.
209
227
++ totalOperations ;
210
228
long beforeBytes = GetTotalBytes ( ) ;
211
- nanoseconds = MeasureAction ( WorkloadActionSingleInvoke ) ;
229
+ nanoseconds = MeasureAction ( WorkloadActionNoUnroll , 1 ) ;
212
230
long afterBytes = GetTotalBytes ( ) ;
213
231
survivedBytes = afterBytes - beforeBytes ;
232
+ nanoseconds += MeasureAction ( action , invokeCount / unrollFactor ) ;
214
233
}
215
234
}
216
-
217
- GcCollect ( ) ;
218
-
219
- if ( EngineEventSource . Log . IsEnabled ( ) )
220
- EngineEventSource . Log . IterationStart ( data . IterationMode , data . IterationStage , totalOperations ) ;
221
-
222
- // Measure
223
- var clock = Clock . Start ( ) ;
224
- action ( invokeCount / unrollFactor ) ;
225
- nanoseconds += clock . GetElapsed ( ) . GetNanoseconds ( ) ;
235
+ else
236
+ {
237
+ // Measure time normally.
238
+ nanoseconds = MeasureAction ( action , invokeCount / unrollFactor ) ;
239
+ }
226
240
227
241
if ( EngineEventSource . Log . IsEnabled ( ) )
228
242
EngineEventSource . Log . IterationStop ( data . IterationMode , data . IterationStage , totalOperations ) ;
@@ -241,10 +255,10 @@ public Measurement RunIteration(IterationData data)
241
255
242
256
// This is necessary for the CORE runtime to clean up the memory from the clock.
243
257
[ MethodImpl ( MethodImplOptions . NoInlining ) ]
244
- private double MeasureAction ( Action action )
258
+ private double MeasureAction ( Action < long > action , long arg )
245
259
{
246
260
var clock = Clock . Start ( ) ;
247
- action ( ) ;
261
+ action ( arg ) ;
248
262
return clock . GetElapsed ( ) . GetNanoseconds ( ) ;
249
263
}
250
264
0 commit comments