Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ internal ref struct Info
{
public object? Context;
public object? CurrentContinuation;
public bool CurrentContinuationCompleted;
public ref nint ContinuationTable;
public uint ContinuationIndex;
}
Expand All @@ -163,6 +164,7 @@ internal static void InitInfo(ref Info info)
{
info.Context = null;
info.CurrentContinuation = null;
info.CurrentContinuationCompleted = false;
ContinuationWrapper.InitInfo(ref info);
}

Expand Down Expand Up @@ -1015,7 +1017,7 @@ public static void Append(AsyncStateMachineDispatcher dispatcher, AsyncThreadCon
{
if (IsEnabled.ResumeStateMachineAsyncCallstackEvent(context.ActiveEventKeywords) && dispatcher.ContinuationChainChanged)
{
AsyncCallstack.EmitEvent(dispatcher, context, dispatcher.LastContinuation?.ContinuationForDiagnostics, currentTimestamp, AsyncEventID.AppendStateMachineAsyncCallstack, DispatcherIds.GetDispatcherId(dispatcher));
AsyncCallstack.EmitEvent(dispatcher, context, dispatcher.NextContinuationForDiagnostics, currentTimestamp, AsyncEventID.AppendStateMachineAsyncCallstack, DispatcherIds.GetDispatcherId(dispatcher));
}
}

Expand Down Expand Up @@ -1607,17 +1609,7 @@ public static void EmitEvent(ref AsyncStateMachineDispatcherInfo info, AsyncThre

EmitAsyncCallstack(context, currentTimestamp, currentTimestamp - context.LastEventTimestamp, AsyncEventID.ResumeStateMachineAsyncCallstack, 0, dispatcherId, ref state);

IAsyncStateMachineBox? last = IsTruncated(in state) ? null : ResolveAsyncStateMachineBox(state.LastContinuation);
if (last != null)
{
Debug.Assert(last is Task);
info.Dispatcher.LastContinuation = Unsafe.As<Task>(last);
}
else
{
info.Dispatcher.LastContinuation = null;
}

info.Dispatcher.LastContinuation = IsTruncated(in state) ? null : ResolveAsyncStateMachineBox(state.LastContinuation);
info.Dispatcher.ReachedLastContinuation = false;
}

Expand All @@ -1635,16 +1627,7 @@ public static void EmitEvent(AsyncStateMachineDispatcher dispatcher, AsyncThread

EmitAsyncCallstack(context, currentTimestamp, currentTimestamp - context.LastEventTimestamp, eventID, 0, dispatcherId, ref state);

box = IsTruncated(in state) ? null : ResolveAsyncStateMachineBox(state.LastContinuation);
if (box != null)
{
Debug.Assert(box is Task);
dispatcher.LastContinuation = Unsafe.As<Task>(box);
}
else
{
dispatcher.LastContinuation = null;
}
dispatcher.LastContinuation = IsTruncated(in state) ? null : ResolveAsyncStateMachineBox(state.LastContinuation);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,17 @@ internal static unsafe AsyncStateMachineDispatcher CreateDispatcher(IAsyncStateM
return dispatcher;
}

internal static unsafe void UnwindAsyncFrame()
internal static unsafe void UnwindAsyncFrame(AsyncInstrumentation.Flags flags)
{
AsyncStateMachineDispatcherInfo* info = t_current;
if (info != null)
{
AsyncProfiler.AsyncMethodException.UnwindFrames(ref *info, 1);
info->AsyncProfilerInfo.CurrentContinuationCompleted = true;

if (AsyncInstrumentation.IsEnabled.UnwindAsyncException(flags))
{
AsyncProfiler.AsyncMethodException.UnwindFrames(ref *info, 1);
}
}
}

Expand All @@ -113,6 +118,7 @@ internal static unsafe void ResumeAsyncMethod(IAsyncStateMachineBox box, AsyncIn
}

info->AsyncProfilerInfo.CurrentContinuation = box;
info->AsyncProfilerInfo.CurrentContinuationCompleted = false;

AsyncProfiler.SyncPoint.Check(ref info->AsyncProfilerInfo);

Expand Down Expand Up @@ -142,12 +148,17 @@ private static unsafe void ResumeAsyncMethod(AsyncStateMachineDispatcher activeD
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe void CompleteAsyncMethod()
internal static unsafe void CompleteAsyncMethod(AsyncInstrumentation.Flags flags)
{
AsyncStateMachineDispatcherInfo* info = t_current;
if (info != null)
{
AsyncProfiler.CompleteAsyncMethod.Complete(ref *info);
info->AsyncProfilerInfo.CurrentContinuationCompleted = true;

if (AsyncInstrumentation.IsEnabled.CompleteAsyncMethod(flags))
{
AsyncProfiler.CompleteAsyncMethod.Complete(ref *info);
}
}
}
}
Expand All @@ -157,11 +168,25 @@ internal sealed class AsyncStateMachineDispatcher : Task<VoidTaskResult>, IAsync
private IAsyncStateMachineBox? _inner;
private Action? _moveNextAction;

internal Task? LastContinuation;
internal IAsyncStateMachineBox? LastContinuation;

internal bool ReachedLastContinuation;

internal bool ContinuationChainChanged => LastContinuation?.ContinuationForDiagnostics != null;
internal object? NextContinuationForDiagnostics
{
get
{
IAsyncStateMachineBox? last = LastContinuation;
if (last is Task task)
{
return task.ContinuationForDiagnostics;
}

return last is not null && last.GetDiagnosticData(out _, out _, out object? next) ? next : null;
}
}

internal bool ContinuationChainChanged => NextContinuationForDiagnostics != null;

internal AsyncStateMachineDispatcher(IAsyncStateMachineBox inner) : base()
{
Expand Down Expand Up @@ -245,21 +270,14 @@ private void InstrumentedMoveNext(ref AsyncStateMachineDispatcherInfo info, IAsy
}
finally
{
if (info.AsyncProfilerInfo.CurrentContinuation is Task curContinuation)
bool isCompleted = info.AsyncProfilerInfo.CurrentContinuationCompleted;
if (AsyncInstrumentation.IsEnabled.CompleteAsyncContext(flags) && isCompleted)
{
bool isCompleted = curContinuation.IsCompleted;
if (AsyncInstrumentation.IsEnabled.CompleteAsyncContext(flags) && isCompleted)
{
AsyncProfiler.CompleteAsyncContext.Complete(this, ref info.AsyncProfilerInfo);
}
else if (AsyncInstrumentation.IsEnabled.SuspendAsyncContext(flags) && !isCompleted)
{
AsyncProfiler.SuspendAsyncContext.Suspend(this, ref info.AsyncProfilerInfo);
}
AsyncProfiler.CompleteAsyncContext.Complete(this, ref info.AsyncProfilerInfo);
}
else if (AsyncInstrumentation.IsEnabled.CompleteAsyncContext(flags))
else if (AsyncInstrumentation.IsEnabled.SuspendAsyncContext(flags) && !isCompleted)
{
AsyncProfiler.CompleteAsyncContext.Complete(this, ref info.AsyncProfilerInfo);
AsyncProfiler.SuspendAsyncContext.Suspend(this, ref info.AsyncProfilerInfo);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,6 @@ bool IAsyncStateMachineBox.GetDiagnosticData(out ulong methodId, out int state,
nextContinuation = null;
return false;
}

}

/// <summary>Gets the <see cref="Task{TResult}"/> for this builder.</summary>
Expand Down Expand Up @@ -510,10 +509,7 @@ internal static void SetExistingTaskResult(Task<TResult> task, TResult? result)

if (AsyncStateMachineDispatcherInfo.AsyncProfilerInstrumentCheckPoint)
{
if (AsyncInstrumentation.IsEnabled.CompleteAsyncMethod(AsyncInstrumentation.ActiveFlags))
{
AsyncStateMachineDispatcherInfo.CompleteAsyncMethod();
}
AsyncStateMachineDispatcherInfo.CompleteAsyncMethod(AsyncInstrumentation.ActiveFlags);
}

if (TplEventSource.Log.IsEnabled())
Expand Down Expand Up @@ -548,10 +544,7 @@ internal static void SetException(Exception exception, ref Task<TResult>? taskFi

if (AsyncStateMachineDispatcherInfo.AsyncProfilerInstrumentCheckPoint)
{
if (AsyncInstrumentation.IsEnabled.UnwindAsyncException(AsyncInstrumentation.ActiveFlags))
{
AsyncStateMachineDispatcherInfo.UnwindAsyncFrame();
}
AsyncStateMachineDispatcherInfo.UnwindAsyncFrame(AsyncInstrumentation.ActiveFlags);
}

// If the exception represents cancellation, cancel the task. Otherwise, fault the task.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox b
}
else if (obj != null)
{
if (AsyncStateMachineDispatcherInfo.AsyncProfilerInstrumentCheckPoint)
if (AsyncStateMachineDispatcherInfo.AsyncProfilerInstrumentCheckPoint && obj is not IAsyncStateMachineBox)
{
box = AsyncStateMachineDispatcherInfo.CreateDispatcher(box);
}
Expand Down Expand Up @@ -212,7 +212,7 @@ void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox b
}
else if (obj != null)
{
if (AsyncStateMachineDispatcherInfo.AsyncProfilerInstrumentCheckPoint)
if (AsyncStateMachineDispatcherInfo.AsyncProfilerInstrumentCheckPoint && obj is not IAsyncStateMachineBox)
{
box = AsyncStateMachineDispatcherInfo.CreateDispatcher(box);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,13 +245,27 @@ internal abstract class StateMachineBox : IValueTaskSource<TResult>, IValueTaskS

/// <summary>Completes the box with a result.</summary>
/// <param name="result">The result.</param>
public void SetResult(TResult result) =>
public void SetResult(TResult result)
{
if (AsyncStateMachineDispatcherInfo.AsyncProfilerInstrumentCheckPoint)
{
AsyncStateMachineDispatcherInfo.CompleteAsyncMethod(AsyncInstrumentation.ActiveFlags);
}

_valueTaskSource.SetResult(result);
}

/// <summary>Completes the box with an error.</summary>
/// <param name="error">The exception.</param>
public void SetException(Exception error) =>
public void SetException(Exception error)
{
if (AsyncStateMachineDispatcherInfo.AsyncProfilerInstrumentCheckPoint)
{
AsyncStateMachineDispatcherInfo.UnwindAsyncFrame(AsyncInstrumentation.ActiveFlags);
}

_valueTaskSource.SetException(error);
}

/// <summary>Gets the status of the box.</summary>
public ValueTaskSourceStatus GetStatus(short token) => _valueTaskSource.GetStatus(token);
Expand Down Expand Up @@ -401,6 +415,11 @@ private static void ExecutionContextCallback(object? s)
/// <summary>Calls MoveNext on <see cref="StateMachine"/></summary>
public void MoveNext()
{
if (AsyncStateMachineDispatcherInfo.AsyncProfilerInstrumentCheckPoint)
{
AsyncStateMachineDispatcherInfo.ResumeAsyncMethod(this, AsyncInstrumentation.ActiveFlags);
}

ExecutionContext? context = Context;

if (context == ExecutionContext.DefaultFlowSuppressed)
Expand Down Expand Up @@ -440,17 +459,33 @@ void IValueTaskSource.GetResult(short token)
}
}

/// <summary>Gets the state machine as a boxed object. This should only be used for debugging purposes.</summary>
/// <summary>Gets the state machine as a boxed object. This should only be used for debugging purposes.</summary>
IAsyncStateMachine IAsyncStateMachineBox.GetStateMachineObject() => StateMachine!; // likely boxes, only use for debugging

bool IAsyncStateMachineBox.GetDiagnosticData(out ulong methodId, out int state, out object? nextContinuation)
{
// TODO-AsyncProfiler: Implement when pooling async builders are fully supported in AsyncProfiler.
if (AsyncStateMachineDispatcherInfo.InstrumentCheckPoint)
{
methodId = AsyncStateMachineDiagnostics<TStateMachine>.MethodId;
state = AsyncStateMachineDiagnostics<TStateMachine>.GetState(ref StateMachine);
nextContinuation = ContinuationForDiagnostics;
return true;
}

methodId = 0;
state = -1;
nextContinuation = null;
return false;
}

private object? ContinuationForDiagnostics
{
get
{
object? continuation = _valueTaskSource.ContinuationForDiagnostics;
return ReferenceEquals(continuation, this) ? null : continuation;
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox b
}
else if (obj != null)
{
if (AsyncStateMachineDispatcherInfo.AsyncProfilerInstrumentCheckPoint)
if (AsyncStateMachineDispatcherInfo.AsyncProfilerInstrumentCheckPoint && obj is not IAsyncStateMachineBox)
{
box = AsyncStateMachineDispatcherInfo.CreateDispatcher(box);
}
Expand Down Expand Up @@ -181,7 +181,7 @@ void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox b
}
else if (obj != null)
{
if (AsyncStateMachineDispatcherInfo.AsyncProfilerInstrumentCheckPoint)
if (AsyncStateMachineDispatcherInfo.AsyncProfilerInstrumentCheckPoint && obj is not IAsyncStateMachineBox)
{
box = AsyncStateMachineDispatcherInfo.CreateDispatcher(box);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ public void SetException(Exception error)
/// <summary>Gets whether the operation has completed.</summary>
internal bool IsCompleted => ReferenceEquals(Volatile.Read(ref _continuation), ManualResetValueTaskSourceCoreShared.s_sentinel);

/// <summary>Gets the continuation object for diagnostic purposes only.</summary>
internal object? ContinuationForDiagnostics => _continuationState;
Comment thread
lateralusX marked this conversation as resolved.

/// <summary>Gets the status of the operation.</summary>
/// <param name="token">Opaque value that was provided to the <see cref="ValueTask"/>'s constructor.</param>
public ValueTaskSourceStatus GetStatus(short token)
Expand Down
Loading
Loading