11using System ;
22using System . Collections . Generic ;
33using System . Linq ;
4+ using BenchmarkDotNet . Analysers ;
45using BenchmarkDotNet . Attributes ;
56using BenchmarkDotNet . Configs ;
67using BenchmarkDotNet . Diagnosers ;
1011using BenchmarkDotNet . Reports ;
1112using BenchmarkDotNet . Tests . XUnit ;
1213using BenchmarkDotNet . Toolchains . InProcess . Emit ;
14+ using Perfolizer . Horology ;
1315using Xunit ;
1416using Xunit . Abstractions ;
1517
@@ -20,6 +22,8 @@ public class ExpectedBenchmarkResultsTests : BenchmarkTestExecutor
2022 // NativeAot takes a long time to build, so not including it in these tests.
2123 // We also don't test InProcessNoEmitToolchain because it is known to be less accurate than code-gen toolchains.
2224
25+ private static readonly TimeInterval FallbackCpuResolutionValue = TimeInterval . FromNanoseconds ( 0.2d ) ;
26+
2327 public ExpectedBenchmarkResultsTests ( ITestOutputHelper output ) : base ( output ) { }
2428
2529 private static IEnumerable < Type > EmptyBenchmarkTypes ( ) =>
@@ -104,21 +108,25 @@ private void AssertZeroResults(Type benchmarkType, IConfig config)
104108 . AddDiagnoser ( new MemoryDiagnoser ( new MemoryDiagnoserConfig ( false ) ) )
105109 ) ;
106110
107- var cpuGhz = RuntimeInformation . GetCpuInfo ( ) . MaxFrequency . Value . ToGHz ( ) ;
111+ var cpuResolution = RuntimeInformation . GetCpuInfo ( ) . MaxFrequency ? . ToResolution ( ) ?? FallbackCpuResolutionValue ;
112+ var cpuGhz = cpuResolution . ToFrequency ( ) . ToGHz ( ) ;
108113
109114 foreach ( var report in summary . Reports )
110115 {
111- Assert . True ( cpuGhz * report . ResultStatistics . Mean < 1 , $ "Actual time was greater than 1 clock cycle.") ;
112-
113- var overheadTime = report . AllMeasurements
116+ var workloadTimes = report . AllMeasurements
114117 . Where ( m => m . IsOverhead ( ) && m . IterationStage == Engines . IterationStage . Actual )
115118 . Select ( m => m . GetAverageTime ( ) . Nanoseconds )
116- . Average ( ) ;
117-
118- var workloadTime = report . AllMeasurements
119- . Where ( m => m . IsWorkload ( ) && m . IterationStage == Engines . IterationStage . Actual )
119+ . ToArray ( ) ;
120+ var overheadTimes = report . AllMeasurements
121+ . Where ( m => m . IsOverhead ( ) && m . IterationStage == Engines . IterationStage . Actual )
120122 . Select ( m => m . GetAverageTime ( ) . Nanoseconds )
121- . Average ( ) ;
123+ . ToArray ( ) ;
124+
125+ bool isZero = ZeroMeasurementHelper . CheckZeroMeasurementTwoSamples ( workloadTimes , overheadTimes ) ;
126+ Assert . True ( isZero , $ "Actual time was not 0.") ;
127+
128+ var workloadTime = workloadTimes . Average ( ) ;
129+ var overheadTime = overheadTimes . Average ( ) ;
122130
123131 // Allow for 1 cpu cycle variance
124132 Assert . True ( overheadTime * cpuGhz < workloadTime * cpuGhz + 1 , "Overhead took more time than workload." ) ;
@@ -165,21 +173,25 @@ private void AssertLargeStructResults(IConfig config)
165173 . AddDiagnoser ( new MemoryDiagnoser ( new MemoryDiagnoserConfig ( false ) ) )
166174 ) ;
167175
168- var cpuGhz = RuntimeInformation . GetCpuInfo ( ) . MaxFrequency . Value . ToGHz ( ) ;
176+ var cpuResolution = RuntimeInformation . GetCpuInfo ( ) . MaxFrequency ? . ToResolution ( ) ?? FallbackCpuResolutionValue ;
177+ var cpuGhz = cpuResolution . ToFrequency ( ) . ToGHz ( ) ;
169178
170179 foreach ( var report in summary . Reports )
171180 {
172- Assert . True ( cpuGhz * report . ResultStatistics . Mean >= 1 , $ "Actual time was less than 1 clock cycle.") ;
173-
174- var overheadTime = report . AllMeasurements
181+ var workloadTimes = report . AllMeasurements
175182 . Where ( m => m . IsOverhead ( ) && m . IterationStage == Engines . IterationStage . Actual )
176183 . Select ( m => m . GetAverageTime ( ) . Nanoseconds )
177- . Average ( ) ;
178-
179- var workloadTime = report . AllMeasurements
180- . Where ( m => m . IsWorkload ( ) && m . IterationStage == Engines . IterationStage . Actual )
184+ . ToArray ( ) ;
185+ var overheadTimes = report . AllMeasurements
186+ . Where ( m => m . IsOverhead ( ) && m . IterationStage == Engines . IterationStage . Actual )
181187 . Select ( m => m . GetAverageTime ( ) . Nanoseconds )
182- . Average ( ) ;
188+ . ToArray ( ) ;
189+
190+ bool isZero = ZeroMeasurementHelper . CheckZeroMeasurementTwoSamples ( workloadTimes , overheadTimes ) ;
191+ Assert . False ( isZero , $ "Actual time was 0.") ;
192+
193+ var workloadTime = workloadTimes . Average ( ) ;
194+ var overheadTime = overheadTimes . Average ( ) ;
183195
184196 // Allow for 1 cpu cycle variance
185197 Assert . True ( overheadTime * cpuGhz < workloadTime * cpuGhz + 1 , "Overhead took more time than workload." ) ;
0 commit comments