@@ -166,12 +166,9 @@ public Measurement RunIteration(IterationData data)
166
166
if ( EngineEventSource . Log . IsEnabled ( ) )
167
167
EngineEventSource . Log . IterationStart ( data . IterationMode , data . IterationStage , totalOperations ) ;
168
168
169
- Span < byte > stackMemory = randomizeMemory ? stackalloc byte [ random . Next ( 32 ) ] : Span < byte > . Empty ;
170
-
171
- // Measure
172
- var clock = Clock . Start ( ) ;
173
- action ( invokeCount / unrollFactor ) ;
174
- var clockSpan = clock . GetElapsed ( ) ;
169
+ var clockSpan = randomizeMemory
170
+ ? MeasureWithRandomMemory ( action , invokeCount / unrollFactor )
171
+ : Measure ( action , invokeCount / unrollFactor ) ;
175
172
176
173
if ( EngineEventSource . Log . IsEnabled ( ) )
177
174
EngineEventSource . Log . IterationStop ( data . IterationMode , data . IterationStage , totalOperations ) ;
@@ -190,9 +187,29 @@ public Measurement RunIteration(IterationData data)
190
187
if ( measurement . IterationStage == IterationStage . Jitting )
191
188
jittingMeasurements . Add ( measurement ) ;
192
189
190
+ return measurement ;
191
+ }
192
+
193
+ // This is in a separate method, because stackalloc can affect code alignment,
194
+ // resulting in unexpected measurements on some AMD cpus,
195
+ // even if the stackalloc branch isn't executed. (#2366)
196
+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
197
+ private unsafe ClockSpan MeasureWithRandomMemory ( Action < long > action , long invokeCount )
198
+ {
199
+ byte * stackMemory = stackalloc byte [ random . Next ( 32 ) ] ;
200
+ var clockSpan = Measure ( action , invokeCount ) ;
193
201
Consume ( stackMemory ) ;
202
+ return clockSpan ;
203
+ }
194
204
195
- return measurement ;
205
+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
206
+ private unsafe void Consume ( byte * _ ) { }
207
+
208
+ private ClockSpan Measure ( Action < long > action , long invokeCount )
209
+ {
210
+ var clock = Clock . Start ( ) ;
211
+ action ( invokeCount ) ;
212
+ return clock . GetElapsed ( ) ;
196
213
}
197
214
198
215
private ( GcStats , ThreadingStats , double ) GetExtraStats ( IterationData data )
@@ -224,9 +241,6 @@ public Measurement RunIteration(IterationData data)
224
241
return ( gcStats , threadingStats , exceptionsStats . ExceptionsCount / ( double ) totalOperationsCount ) ;
225
242
}
226
243
227
- [ MethodImpl ( MethodImplOptions . NoInlining ) ]
228
- private void Consume ( in Span < byte > _ ) { }
229
-
230
244
private void RandomizeManagedHeapMemory ( )
231
245
{
232
246
// invoke global cleanup before global setup
0 commit comments