9
9
using BenchmarkDotNet . ConsoleArguments . ListBenchmarks ;
10
10
using BenchmarkDotNet . Environments ;
11
11
using BenchmarkDotNet . Extensions ;
12
+ using BenchmarkDotNet . Jobs ;
12
13
using BenchmarkDotNet . Loggers ;
14
+ using BenchmarkDotNet . Parameters ;
13
15
using BenchmarkDotNet . Reports ;
14
16
using JetBrains . Annotations ;
17
+ using Perfolizer . Mathematics . OutlierDetection ;
15
18
16
19
namespace BenchmarkDotNet . Running
17
20
{
@@ -109,6 +112,11 @@ internal IEnumerable<Summary> RunWithDirtyAssemblyResolveHelper(string[] args, I
109
112
? allAvailableTypesWithRunnableBenchmarks
110
113
: userInteraction . AskUser ( allAvailableTypesWithRunnableBenchmarks , logger ) ;
111
114
115
+ if ( effectiveConfig . Options . HasFlag ( ConfigOptions . ApplesToApples ) )
116
+ {
117
+ return ApplesToApples ( effectiveConfig , benchmarksToFilter , logger , options ) ;
118
+ }
119
+
112
120
var filteredBenchmarks = TypeFilter . Filter ( effectiveConfig , benchmarksToFilter ) ;
113
121
114
122
if ( filteredBenchmarks . IsEmpty ( ) )
@@ -131,5 +139,74 @@ private static void PrintList(ILogger nonNullLogger, IConfig effectiveConfig, IR
131
139
132
140
printer . Print ( testNames , nonNullLogger ) ;
133
141
}
142
+
143
+ private IEnumerable < Summary > ApplesToApples ( ManualConfig effectiveConfig , IReadOnlyList < Type > benchmarksToFilter , ILogger logger , CommandLineOptions options )
144
+ {
145
+ var jobs = effectiveConfig . GetJobs ( ) . ToArray ( ) ;
146
+ if ( jobs . Length <= 1 )
147
+ {
148
+ logger . WriteError ( "To use apples-to-apples comparison you must specify at least two Job objects." ) ;
149
+ return Array . Empty < Summary > ( ) ;
150
+ }
151
+ var baselineJob = jobs . SingleOrDefault ( job => job . Meta . Baseline ) ;
152
+ if ( baselineJob == default )
153
+ {
154
+ logger . WriteError ( "To use apples-to-apples comparison you must specify exactly ONE baseline Job object." ) ;
155
+ return Array . Empty < Summary > ( ) ;
156
+ }
157
+ else if ( jobs . Any ( job => ! job . Run . HasValue ( RunMode . IterationCountCharacteristic ) ) )
158
+ {
159
+ logger . WriteError ( "To use apples-to-apples comparison you must specify the number of iterations in explicit way." ) ;
160
+ return Array . Empty < Summary > ( ) ;
161
+ }
162
+
163
+ Job invocationCountJob = baselineJob
164
+ . WithWarmupCount ( 1 )
165
+ . WithIterationCount ( 1 )
166
+ . WithEvaluateOverhead ( false ) ;
167
+
168
+ ManualConfig invocationCountConfig = ManualConfig . Create ( effectiveConfig ) ;
169
+ invocationCountConfig . RemoveAllJobs ( ) ;
170
+ invocationCountConfig . RemoveAllDiagnosers ( ) ;
171
+ invocationCountConfig . AddJob ( invocationCountJob ) ;
172
+
173
+ var invocationCountBenchmarks = TypeFilter . Filter ( invocationCountConfig , benchmarksToFilter ) ;
174
+ if ( invocationCountBenchmarks . IsEmpty ( ) )
175
+ {
176
+ userInteraction . PrintWrongFilterInfo ( benchmarksToFilter , logger , options . Filters . ToArray ( ) ) ;
177
+ return Array . Empty < Summary > ( ) ;
178
+ }
179
+
180
+ logger . WriteLineHeader ( "Each benchmark is going to be executed just once to get invocation counts." ) ;
181
+ Summary [ ] invocationCountSummaries = BenchmarkRunnerClean . Run ( invocationCountBenchmarks ) ;
182
+
183
+ Dictionary < ( Descriptor Descriptor , ParameterInstances Parameters ) , Measurement > dictionary = invocationCountSummaries
184
+ . SelectMany ( summary => summary . Reports )
185
+ . ToDictionary (
186
+ report => ( report . BenchmarkCase . Descriptor , report . BenchmarkCase . Parameters ) ,
187
+ report => report . AllMeasurements . Single ( measurement => measurement . IsWorkload ( ) && measurement . IterationStage == Engines . IterationStage . Actual ) ) ;
188
+
189
+ int iterationCount = baselineJob . Run . IterationCount ;
190
+ BenchmarkRunInfo [ ] benchmarksWithoutInvocationCount = TypeFilter . Filter ( effectiveConfig , benchmarksToFilter ) ;
191
+ BenchmarkRunInfo [ ] benchmarksWithInvocationCount = benchmarksWithoutInvocationCount
192
+ . Select ( benchmarkInfo => new BenchmarkRunInfo (
193
+ benchmarkInfo . BenchmarksCases . Select ( benchmark =>
194
+ new BenchmarkCase (
195
+ benchmark . Descriptor ,
196
+ benchmark . Job
197
+ . WithIterationCount ( iterationCount )
198
+ . WithEvaluateOverhead ( false )
199
+ . WithWarmupCount ( 1 )
200
+ . WithOutlierMode ( OutlierMode . DontRemove )
201
+ . WithInvocationCount ( dictionary [ ( benchmark . Descriptor , benchmark . Parameters ) ] . Operations )
202
+ . WithUnrollFactor ( dictionary [ ( benchmark . Descriptor , benchmark . Parameters ) ] . Operations % 16 == 0 ? 16 : 1 ) ,
203
+ benchmark . Parameters ,
204
+ benchmark . Config ) ) . ToArray ( ) ,
205
+ benchmarkInfo . Type , benchmarkInfo . Config ) )
206
+ . ToArray ( ) ;
207
+
208
+ logger . WriteLineHeader ( "Actual benchmarking is going to happen now!" ) ;
209
+ return BenchmarkRunnerClean . Run ( benchmarksWithInvocationCount ) ;
210
+ }
134
211
}
135
212
}
0 commit comments