From c1d8ac65166f26a5018d3bf03a31b619da6c9e21 Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Tue, 22 May 2018 19:08:59 +0200 Subject: [PATCH] do the math right for unroll factor for JIT, #736 --- src/BenchmarkDotNet/Engines/EngineFactory.cs | 11 ++++++----- .../Engine/EngineFactoryTests.cs | 8 ++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/BenchmarkDotNet/Engines/EngineFactory.cs b/src/BenchmarkDotNet/Engines/EngineFactory.cs index 79766243da..e8f5cf5111 100644 --- a/src/BenchmarkDotNet/Engines/EngineFactory.cs +++ b/src/BenchmarkDotNet/Engines/EngineFactory.cs @@ -29,6 +29,7 @@ public IEngine CreateReadyToRun(EngineParameters engineParameters) throw new ArgumentNullException(nameof(engineParameters.TargetJob)); var resolver = new CompositeResolver(BenchmarkRunner.DefaultResolver, EngineResolver.Instance); + var unrollFactor = engineParameters.TargetJob.ResolveValue(RunMode.UnrollFactorCharacteristic, resolver); engineParameters.GlobalSetupAction?.Invoke(); @@ -45,7 +46,7 @@ public IEngine CreateReadyToRun(EngineParameters engineParameters) var singleActionEngine = CreateEngine(engineParameters, resolver, engineParameters.TargetJob, engineParameters.IdleSingleAction, engineParameters.MainSingleAction); var iterationTime = resolver.Resolve(engineParameters.TargetJob, RunMode.IterationTimeCharacteristic); - if (ShouldExecuteOncePerIteration(Jit(singleActionEngine), iterationTime)) + if (ShouldExecuteOncePerIteration(Jit(singleActionEngine, unrollFactor: 1), iterationTime)) { var reconfiguredJob = engineParameters.TargetJob.WithInvocationCount(1).WithUnrollFactor(1); // todo: consider if we should set the warmup count to 1! @@ -56,7 +57,7 @@ public IEngine CreateReadyToRun(EngineParameters engineParameters) // it's either a job with explicit configuration or not-very time consuming benchmark, just create the engine, Jit and return var multiActionEngine = CreateEngine(engineParameters, resolver, engineParameters.TargetJob, engineParameters.IdleMultiAction, engineParameters.MainMultiAction); - DeadCodeEliminationHelper.KeepAliveWithoutBoxing(Jit(multiActionEngine)); + DeadCodeEliminationHelper.KeepAliveWithoutBoxing(Jit(multiActionEngine, unrollFactor)); return multiActionEngine; } @@ -67,11 +68,11 @@ public IEngine CreateReadyToRun(EngineParameters engineParameters) private static bool ShouldExecuteOncePerIteration(Measurement jit, TimeInterval iterationTime) => TimeInterval.FromNanoseconds(jit.GetAverageNanoseconds()) > iterationTime; - private static Measurement Jit(Engine engine) + private static Measurement Jit(Engine engine, int unrollFactor) { - DeadCodeEliminationHelper.KeepAliveWithoutBoxing(engine.RunIteration(new IterationData(IterationMode.IdleJit, index: -1, invokeCount: 1, unrollFactor: 1))); // don't forget to JIT idle + DeadCodeEliminationHelper.KeepAliveWithoutBoxing(engine.RunIteration(new IterationData(IterationMode.IdleJit, index: -1, invokeCount: unrollFactor, unrollFactor: unrollFactor))); // don't forget to JIT idle - return engine.RunIteration(new IterationData(IterationMode.Jit, index: -1, invokeCount: 1, unrollFactor: 1)); + return engine.RunIteration(new IterationData(IterationMode.Jit, index: -1, invokeCount: unrollFactor, unrollFactor: unrollFactor)); } private static Engine CreateEngine(EngineParameters engineParameters, IResolver resolver, Job job, Action idle, Action main) diff --git a/tests/BenchmarkDotNet.Tests/Engine/EngineFactoryTests.cs b/tests/BenchmarkDotNet.Tests/Engine/EngineFactoryTests.cs index 6894726ef0..50399cabfe 100644 --- a/tests/BenchmarkDotNet.Tests/Engine/EngineFactoryTests.cs +++ b/tests/BenchmarkDotNet.Tests/Engine/EngineFactoryTests.cs @@ -39,10 +39,10 @@ public void VeryTimeConsumingBenchmarksAreExecutedOncePerIterationForDefaultSett var engine = new EngineFactory().CreateReadyToRun(engineParameters); Assert.Equal(1, timesGlobalSetupCalled); - Assert.Equal(1, timesIterationSetupCalled); + Assert.Equal(1 + 1, timesIterationSetupCalled); // 1x for Idle, 1x for Target Assert.Equal(1, timesBenchmarkCalled); Assert.Equal(1, timesIdleCalled); - Assert.Equal(1, timesIterationCleanupCalled); + Assert.Equal(1 + 1, timesIterationCleanupCalled); // 1x for Idle, 1x for Target Assert.Equal(0, timesGlobalCleanupCalled); // cleanup is called as part of dispode Assert.Equal(1, engine.TargetJob.Run.InvocationCount); // call the benchmark once per iteration @@ -80,10 +80,10 @@ public void NonVeryTimeConsumingBenchmarksAreExecutedMoreThanOncePerIterationWit var engine = new EngineFactory().CreateReadyToRun(engineParameters); Assert.Equal(1, timesGlobalSetupCalled); - Assert.Equal(2, timesIterationSetupCalled); // once for single and & once for 16 + Assert.Equal((1+1) * (1+1), timesIterationSetupCalled); // (once for single and & once for 16) x (1x for Idle + 1x for Target) Assert.Equal(1 + 16, timesBenchmarkCalled); Assert.Equal(1 + 16, timesIdleCalled); - Assert.Equal(2, timesIterationCleanupCalled); // once for single and & once for 16 + Assert.Equal((1+1) * (1+1), timesIterationCleanupCalled); // (once for single and & once for 16) x (1x for Idle + 1x for Target) Assert.Equal(0, timesGlobalCleanupCalled); Assert.False(engine.TargetJob.Run.HasValue(RunMode.InvocationCountCharacteristic));