Criteo R&D Blog
Published in

Criteo R&D Blog

Understanding “reversed” callstacks in Visual Studio and Perfview with async/await code


Let’s see the result of profiling in Visual Studio

Understanding async/await implementation

  1. a timer callback is calling <Compute3>d__4.MoveNext() : this corresponds to the end of the Task.Delay inCompute3 method.
  2. <Compute2>d__3.MoveNext() gets called to continue the code after await Compute3
  3. <Compute1>d__.MoveNext() gets called to continue the code after await Compute2
  4. ConsumeCPUAfterCompute2() gets called as expected
  5. ComputeCPU() or ConsumeCPUInCompute3() get called as expected
  1. run all code up to an await call,
  2. change the “execution state” (more on this later)
  3. do some magic to execute that code in another thread (if needed — more on this later)
  4. come back to continue the execution of the code after the await call
  5. and do that up to the next await call again and again
  • Each time you see an async method, the C# compiler is generating a dedicated state machine type with a MoveNext method that is responsible for executing your code synchronously between await calls
  • each time you see an await call, it means that a continuation will be added to the Task wrapping the async method to be executed. That continuation code will call the MoveNext method of the state machine of the calling method to execute the next piece of code up to its next await call.

Stay tuned!



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store