@@ -166,12 +166,9 @@ public Measurement RunIteration(IterationData data)
166166 if ( EngineEventSource . Log . IsEnabled ( ) )
167167 EngineEventSource . Log . IterationStart ( data . IterationMode , data . IterationStage , totalOperations ) ;
168168
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 ) ;
175172
176173 if ( EngineEventSource . Log . IsEnabled ( ) )
177174 EngineEventSource . Log . IterationStop ( data . IterationMode , data . IterationStage , totalOperations ) ;
@@ -190,9 +187,29 @@ public Measurement RunIteration(IterationData data)
190187 if ( measurement . IterationStage == IterationStage . Jitting )
191188 jittingMeasurements . Add ( measurement ) ;
192189
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 ) ;
193201 Consume ( stackMemory ) ;
202+ return clockSpan ;
203+ }
194204
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 ( ) ;
196213 }
197214
198215 private ( GcStats , ThreadingStats , double ) GetExtraStats ( IterationData data )
@@ -224,9 +241,6 @@ public Measurement RunIteration(IterationData data)
224241 return ( gcStats , threadingStats , exceptionsStats . ExceptionsCount / ( double ) totalOperationsCount ) ;
225242 }
226243
227- [ MethodImpl ( MethodImplOptions . NoInlining ) ]
228- private void Consume ( in Span < byte > _ ) { }
229-
230244 private void RandomizeManagedHeapMemory ( )
231245 {
232246 // invoke global cleanup before global setup
0 commit comments