Skip to content

Commit c55939d

Browse files
committed
Only do an extra WorkloadAction measurement if totalOperations > 1.
1 parent 8a521cf commit c55939d

File tree

2 files changed

+36
-22
lines changed

2 files changed

+36
-22
lines changed

src/BenchmarkDotNet/Engines/Engine.cs

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public class Engine : IEngine
1919

2020
[PublicAPI] public IHost Host { get; }
2121
[PublicAPI] public Action<long> WorkloadAction { get; }
22-
[PublicAPI] public Action WorkloadActionSingleInvoke { get; }
22+
[PublicAPI] public Action<long> WorkloadActionNoUnroll { get; }
2323
[PublicAPI] public Action Dummy1Action { get; }
2424
[PublicAPI] public Action Dummy2Action { get; }
2525
[PublicAPI] public Action Dummy3Action { get; }
@@ -54,13 +54,13 @@ public class Engine : IEngine
5454
internal Engine(
5555
IHost host,
5656
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,
5858
Action globalSetupAction, Action globalCleanupAction, Action iterationSetupAction, Action iterationCleanupAction, long operationsPerInvoke,
5959
bool includeExtraStats, bool includeSurvivedMemory, string benchmarkName)
6060
{
6161
Host = host;
6262
OverheadAction = overheadAction;
63-
WorkloadActionSingleInvoke = workloadActionSingleInvoke;
63+
WorkloadActionNoUnroll = workloadActionNoUnroll;
6464
Dummy1Action = dummy1Action;
6565
Dummy2Action = dummy2Action;
6666
Dummy3Action = dummy3Action;
@@ -96,7 +96,7 @@ internal Engine(
9696
// Measure bytes to allow GC monitor to make its allocations.
9797
GetTotalBytes();
9898
// Run the clock once to allow it to make its allocations.
99-
MeasureAction(() => { });
99+
MeasureAction(_ => { }, 0);
100100
GetTotalBytes();
101101
}
102102
}
@@ -197,32 +197,46 @@ public Measurement RunIteration(IterationData data)
197197
bool isOverhead = data.IterationMode == IterationMode.Overhead;
198198
var action = isOverhead ? OverheadAction : WorkloadAction;
199199

200-
double nanoseconds = 0;
201200
if (!isOverhead)
202201
{
203202
IterationSetupAction();
203+
}
204+
205+
GcCollect();
206+
207+
if (EngineEventSource.Log.IsEnabled())
208+
EngineEventSource.Log.IterationStart(data.IterationMode, data.IterationStage, totalOperations);
204209

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)
206217
{
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.
209227
++totalOperations;
210228
long beforeBytes = GetTotalBytes();
211-
nanoseconds = MeasureAction(WorkloadActionSingleInvoke);
229+
nanoseconds = MeasureAction(WorkloadActionNoUnroll, 1);
212230
long afterBytes = GetTotalBytes();
213231
survivedBytes = afterBytes - beforeBytes;
232+
nanoseconds += MeasureAction(action, invokeCount / unrollFactor);
214233
}
215234
}
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+
}
226240

227241
if (EngineEventSource.Log.IsEnabled())
228242
EngineEventSource.Log.IterationStop(data.IterationMode, data.IterationStage, totalOperations);
@@ -241,10 +255,10 @@ public Measurement RunIteration(IterationData data)
241255

242256
// This is necessary for the CORE runtime to clean up the memory from the clock.
243257
[MethodImpl(MethodImplOptions.NoInlining)]
244-
private double MeasureAction(Action action)
258+
private double MeasureAction(Action<long> action, long arg)
245259
{
246260
var clock = Clock.Start();
247-
action();
261+
action(arg);
248262
return clock.GetElapsed().GetNanoseconds();
249263
}
250264

src/BenchmarkDotNet/Engines/EngineFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ private static Engine CreateEngine(EngineParameters engineParameters, Job job, A
112112
engineParameters.Dummy3Action,
113113
idle,
114114
main,
115-
() => engineParameters.WorkloadActionNoUnroll(1),
115+
engineParameters.WorkloadActionNoUnroll,
116116
job,
117117
engineParameters.GlobalSetupAction,
118118
engineParameters.GlobalCleanupAction,

0 commit comments

Comments
 (0)