"Profile with async awareness" causes infinite loop

AndreasHAndreasH Posts: 2
edited January 22, 2016 6:12AM in ANTS Performance Profiler 9
Hello!

We have a problem when profiling our application.
It is pretty tricky but I will try my best to explain.

Our application works just fine. Also, profiling the application with "Profile with async awareness" turned off works fine.
When "Profile with async awareness" is turned on, the same async method is repeated over and over again indefinitely.

Simplified it looks like that:
    internal sealed class StandardExecutionJob<TService, TArgs, TResult> : ExecutionJobBase<TResult>
    {
        // ...
        protected async override Task<TResult> ExecutionBody()
        {
            // FINE
            // ## Stack traces from here  ##
            var result = await adapter.ExecuteAsync(service, args);
            // !!!! NEVER HERE!!!!

            return result;
        }
        // ...
    }

    internal abstract class FuncExecutionAdapterBase<TService, TArgs, TResult> : IFuncExecutionAdapter<TService, TArgs, TResult>
    {
        // ...
        /// <inheritdoc />
        public async Task<TResult> ExecuteAsync(TService service, TArgs arguments)
        {
            try
            {
                // FINE
                var result = await ExecutionBody(service, arguments);
                // FINE
                return result;
            }
            catch (UserException e)
            {
                // ...
            }
            catch (RuntimeUserException e)
            {
                // ...
            }
        }
        // ...

        protected abstract Task<TResult> ExecutionBody(TService service, TArgs arguments);
    }
  • StandardExecutionJob.ExecutionBody is called
  • FuncExecutionAdapterBase.ExecuteAsync is called
  • FuncExecutionAdapterBase.ExecuteAsync returns a value
  • Execution never returns to StandardExecutionJob.ExecutionBody
  • Instead StandardExecutionJob.ExecutionBody is invoked anew, again and again and again...

The first invocation of StandardExecutionJob.ExecutionBody has the following stack trace:
Execution.Jobs.StandardExecutionJob`3 [(null)] - at Execution.Jobs.StandardExecutionJob`3.<ExecutionBody>d__0.MoveNext()
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
at Execution.Jobs.StandardExecutionJob`3.ExecutionBody()
at Execution.Jobs.ExecutionJobBase`1.<Execute>d__0.MoveNext()
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
at Execution.Jobs.ExecutionJobBase`1.Execute()
at Execution.Processors.ExecutionJobProcessor.<ProcessExecutionJob>d__5.MoveNext()
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
at Execution.Processors.ExecutionJobProcessor.ProcessExecutionJob(IExecutionJob job)
at Execution.Processors.ExecutionJobProcessor.<.ctor>b__2(IExecutionJob t)
at System.Threading.Tasks.Dataflow.ActionBlock`1.ProcessMessageWithTask(Func`2 action, KeyValuePair`2 messageWithId)
at System.Threading.Tasks.Dataflow.ActionBlock`1.<>c__DisplayClass7.<.ctor>b__1(KeyValuePair`2 messageWithId)
at System.Threading.Tasks.Dataflow.Internal.TargetCore`1.ProcessMessagesLoopCore()
at System.Threading.Tasks.Task.Execute()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
at System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution)
at System.Threading.ThreadPoolWorkQueue.Dispatch()

From the second invocation on (for ever) it looks like:
Execution.Jobs.StandardExecutionJob`3 [(null)] - at Execution.Jobs.StandardExecutionJob`3.<ExecutionBody>d__0.MoveNext()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run()
at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(Action action, Boolean allowInlining, Task& currentTask)
at System.Threading.Tasks.Task.FinishContinuations()
at System.Threading.Tasks.Task`1.TrySetResult(TResult result)
at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetResult(TResult result)
at Execution.Adapters.FuncExecutionAdapterBase`3.<ExecuteAsync>d__0.MoveNext()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run()
at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(Action action, Boolean allowInlining, Task& currentTask)
at System.Threading.Tasks.Task.FinishContinuations()
at System.Threading.Tasks.Task.Finish(Boolean bUserDelegateExecuted)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
at System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution)
at System.Threading.ThreadPoolWorkQueue.Dispatch()

It seems like the task continuation points back to the beginning of the first method instead of resuming it... or something.

Any idea?

Regards,
Andreas

Comments

Sign In or Register to comment.