using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using static System.Console;
using STT=System.Threading.Tasks;
using CMN=System.Runtime.CompilerServices.CallerMemberNameAttribute;
using CFP=System.Runtime.CompilerServices.CallerFilePathAttribute;
using CLN=System.Runtime.CompilerServices.CallerLineNumberAttribute;
using DN=System.Diagnostics.CodeAnalysis.DisallowNullAttribute;
using DPV=System.Runtime.InteropServices.DefaultParameterValueAttribute;
using dt=System.DateTime;
using static Utilities.DebugMethods;
public async static Task Main()
Console.WriteLine($"Bugs in main method ({dt.UtcNow})\n");
var t=p.GetString("Bugs Bunny");
Console.WriteLine(">awaited t=" + await t);
WL( "ContinueWith: " + await t.ContinueWith (async antecedent=>{return await Task<str>.FromResult(antecedent + " " + v);}) );
WL( "ContinueWith: " + await t.ContinueWith ( antecedent=>{return Task<str>.FromResult(antecedent + " " + v + v);}) );
Console.WriteLine("\nafter call\n");
foreach(var k in ManagedTaskBroker.Logs)
Console.WriteLine($"KEY: {k.Key.ToString()} \nVALUE: {k.Value.ToString()}\n");
public async ManagedTask<string> GetString(string s)
var temp=new ManagedTask<string>(async ()=> { return "Daffy TOO";} );
WL($"GetString (await temp: {await temp})" );
var t=ManagedTask<string>.Run( ()=> { WL("INSIDE");return "Hello " + s; });
WL("Typeof T: " + t.GetType().FullName);
public readonly record struct CallerKey(str Name, int Line, str Path);
public class CalledSummaryValue
public CalledSummaryValue(dt start, dt end, string returnType, bool isPrimitiveReturnType, bool isSlow, CallerKey callerKey, [DPV(DetailMode.Verbose)]DetailMode detailMode, [Optional]bool isValueTask, [Optional]CalledSummaryValue oldValue)
if(callerKey!=null) { Name=callerKey.Name; Path=callerKey.Path; Line=callerKey.Line; }
if(detailMode==DetailMode.Verbose)
Entries=oldValue?.Entries??new();
Entries.Add(new CalledEntryValue(Timed:new TimedEventsInformation(start,end), ReturnType:returnType, IsPrimitiveReturnType:isPrimitiveReturnType, IsSlow:isSlow, IsValueTask:isValueTask));
TotalDuration+=e.Duration;
if(e.IsSlow) SlowTasks++; else FastTasks++;
if(isSlow) SlowTasks++; else FastTasks++;
TotalDuration+=end-start;
public readonly int Line;
public readonly str Name, Path;
public TimeSpan TotalDuration {get;private set;}=TimeSpan.Zero;
public TimeSpan AverageDuration {get=>TimeSpan.FromTicks(TotalDuration.Ticks/TotalTasks);}
public dt LastUpdate {get;private set;}=dt.UtcNow;
public int FastTasks {get;private set;}=0;
public int SlowTasks {get;private set;}=0;
public int TotalTasks {get=>FastTasks+SlowTasks;}
public decimal PercentSlow {get=>TotalTasks==0 || SlowTasks==0 ? 0m : Convert.ToDecimal(SlowTasks)/Convert.ToDecimal(TotalTasks) * 100m;}
public readonly List<CalledEntryValue> Entries;
public override string ToString()
$@"# Tasks: {TotalTasks}, FastTasks: {FastTasks}, SlowTasks: {SlowTasks}, % Slow: {PercentSlow}%
LastUpdate: {LastUpdate}, ∑ Duration: {TotalDuration.Ticks} ticks, µ Duration: {AverageDuration.Ticks}";
if(Entries==null || Entries.Count==0) r+="\n\tEntries Count: 0 (In Summary Mode)";
else r+=$"\n\tEntries Count: {Entries.Count}" ;
Entries?.ForEach(e=>r+=e.ToString());
public readonly record struct CalledEntryValue (TimedEventsInformation Timed, str ReturnType, bool IsPrimitiveReturnType, bool IsSlow, [Optional]bool IsValueTask)
public dt Start {get=>Timed.Start;}
public dt End {get=>Timed.End;}
public TimeSpan Duration {get=>Timed.End-Timed.Start;}
public override string ToString()
---> Start: {Start}, End: {End}, Duration: {Duration.Ticks}
ReturnType: {ReturnType}, IsPrimitiveRT: {IsPrimitiveReturnType}, IsSlow: {IsSlow}, IsValueTask: {IsValueTask}";
public class Manager : ConcurrentDictionary<CallerKey, CalledSummaryValue>
public Manager(DetailMode detailMode=DetailMode.Verbose)=>this.DetailMode=detailMode;
public DetailMode DetailMode {get;set;}
public void IncrementSlowPath(CallerKey callerKey, dt start, dt end, string returnType, bool isPrimitiveReturnType, [Optional]bool isValueTask)
if(!validateKey(callerKey)) return;
key=>new CalledSummaryValue(start, end, returnType, isPrimitiveReturnType, true, callerKey, DetailMode),
(key, oldValue)=>new CalledSummaryValue(start, end, returnType, isPrimitiveReturnType, true, callerKey, DetailMode, isValueTask, oldValue)
public void IncrementFastPath(CallerKey callerKey, dt start, dt end, string returnType, bool isPrimitiveReturnType, [Optional]bool isValueTask)
if(!validateKey(callerKey)) return;
key=>new CalledSummaryValue(start, end, returnType, isPrimitiveReturnType, false, callerKey, DetailMode),
(key, oldValue)=>new CalledSummaryValue(start, end, returnType, isPrimitiveReturnType, false, callerKey, DetailMode, isValueTask, oldValue)
private bool validateKey(CallerKey callerKey)
=> (String.IsNullOrWhiteSpace(callerKey.Name) && String.IsNullOrWhiteSpace(callerKey.Path) && callerKey.Line==0 ? false : true);
this.Keys.OrderBy(k=>k.Line).ToList().ForEach(l=>r+=l.ToString());
public readonly record struct TimedEventsInformation ([DN]dt Start, [DN]dt End)
public TimeSpan Duration {get=>End-Start;}
public enum DetailMode { Summary, Verbose }
public class ManagedTaskBroker
public static Telemetry.Manager Logs=new(Telemetry.DetailMode.Verbose);
public static Configuration Config=new( new SwitchToValueTaskTrigger() );
public class Configuration
public Configuration(params IConfigurationTrigger [] triggers) => this.triggers.AddRange(triggers);
public readonly List<IConfigurationTrigger> triggers=new();
public class SwitchToValueTaskTrigger : IConfigurationTrigger
static bool triggerActivated=false;
int minRunsBeforeEvaluation =10;
decimal thresholdForValueSwitch =.8m;
int telemetryFrequency =1;
public void Fire<T>(CallerKey callerKey, ManagedTask<T> task)
if(!ManagedTaskBroker.Logs.ContainsKey(callerKey))
WL("!!!callerKey not found");return;
var val=ManagedTaskBroker.Logs[callerKey];
if(ManagedTaskBroker.Logs[callerKey].TotalTasks>1)
WL($"PercentSlow: {val.PercentSlow}");
if(ManagedTaskBroker.Logs[callerKey].PercentSlow>49 || triggerActivated)
public interface IConfigurationTrigger
public void Fire<T>(CallerKey callerKey, ManagedTask<T> task);
public partial class ManagedTask
public static Task Delay(int milliseconds)
return Task.Delay(milliseconds);
[AsyncMethodBuilder(typeof(ManagedTaskBuilder<>))]
public partial class ManagedTask<T> : IAwaitable<T>
public bool configureAwait {get;set;}=false;
public TaskContinuationOptions continuationOptions {get;set;}=TaskContinuationOptions.DenyChildAttach | TaskContinuationOptions.ExecuteSynchronously;
public TaskCreationOptions creationOptions {get;set;}=TaskCreationOptions.DenyChildAttach;
private CallerKey _callerKey;
private Lazy<IAwaiter<T>> _taskAwaiter, _valueTaskAwaiter;
private bool _isTaskStarted;
internal bool _isValueTask;
private Func<T>? _function;
private Func<Task<T>>? _asyncFunction;
internal ValueTask<T> _valueTask;
private Exception _exception;
private dt _startDateTime=dt.UtcNow;
public ManagedTask([DN]Func<T> function, bool configureAwait=false, [CMN]str callerName="", [CLN] int callerLineNumber=0, [CFP] str callerFilePath="")
_callerKey=new(Name:callerName, Line:callerLineNumber, Path:callerFilePath);
ManagedTaskBroker.Config.triggers.ForEach(t=>t.Fire<T>(_callerKey,this));
( this.configureAwait, _function, _task, _valueTask)=
( configureAwait, function, _isValueTask ? new TaskCompletionSource<T>().Task : Task<T>.Run(function), _isValueTask ? new ValueTask<T>(function()) : default );
WL($"_isValueTask: {_isValueTask}");
WL($"ManagedTask<T>.ctor (function: {function is null}, {_task.Status})");
public ManagedTask(Expression<Func<T>> expression, bool configureAwait=false, [CMN]str callerName="", [CLN] int callerLineNumber=0, [CFP] str callerFilePath="")
_callerKey=new(Name:callerName, Line:callerLineNumber, Path:callerFilePath);
ManagedTaskBroker.Config.triggers.ForEach(t=>t.Fire<T>(_callerKey,this));
( this.configureAwait, _function, _task, _valueTask)=
( configureAwait, expression.Compile(), _isValueTask ? new TaskCompletionSource<T>().Task : Task<T>.Run(_function), _isValueTask ? new ValueTask<T>(_function()) : default );
WL($"_isValueTask: {_isValueTask}");
WL($"ManagedTask<T>.ctor (expression: {expression is null}, {_task.Status})");
public ManagedTask([DN]Func<Task<T>> asyncFunction, bool configureAwait=false, [CMN]str callerName="", [CLN] int callerLineNumber=0, [CFP] str callerFilePath="")
_callerKey=new(Name:callerName, Line:callerLineNumber, Path:callerFilePath);
ManagedTaskBroker.Config.triggers.ForEach(t=>t.Fire<T>(_callerKey,this));
( this.configureAwait, _asyncFunction, _task, _valueTask) =
( configureAwait, asyncFunction, _isValueTask ? new TaskCompletionSource<T>().Task : asyncFunction(), _isValueTask ? new ValueTask<T>(asyncFunction()) : default );
WL($"ManagedTask<T>.ctor (Func<Task<T>>: {asyncFunction is null}), {_task is null}, {_task.Status}");
public ManagedTask([DN]Task<T> task, bool configureAwait=false, bool autoStartTask=false, [CMN]str callerName="", [CLN] int callerLineNumber=0, [CFP] str callerFilePath="")
_callerKey=new(Name:callerName, Line:callerLineNumber, Path:callerFilePath);
( _callerKey, this.configureAwait, _task ) =
( new (Name:callerName,Line:callerLineNumber,Path:callerFilePath), configureAwait, task );
WL($"ManagedTask<T>.ctor (task: {task is null})");
if(autoStartTask) Start();
public ManagedTask([DN]ValueTask<T> valueTask, bool configureAwait=false, [CMN]str callerName="", [CLN] int callerLineNumber=0, [CFP] str callerFilePath="")
_callerKey=new(Name:callerName, Line:callerLineNumber, Path:callerFilePath);
( _callerKey, this.configureAwait, _isValueTask, _valueTask ) =
( new (Name:callerName,Line:callerLineNumber,Path:callerFilePath), configureAwait, true, valueTask );
WL($"ManagedTask<T>.ctor (valueTask)");
public ManagedTask([DN]ValueTask<T> valueTask)
( _isValueTask, _valueTask ) =
WL($"ManagedTask<T>.ctor (valueTask)");
internal ManagedTask([DN]TaskCompletionSource<T> tcs)
WL($"ManagedTask<T>.ctor (tcs: {tcs is null})");
internal ManagedTask([DN]T fromResult)
( _isValueTask, _valueTask ) =
( true, ValueTask.FromResult<T>(fromResult) );
WL($"ManagedTask<T>.ctor (fromResult: {fromResult is null})");
internal ManagedTask(Exception fromException)
( _isValueTask, _exception, _valueTask ) =
( true, fromException, ValueTask.FromException<T>(fromException) );
WL($"ManagedTask<T>.ctor (fromException: {fromException is null}");
WL("ManagedTask.init start");
_taskAwaiter=new Lazy<IAwaiter<T>>( ()=>new ManagedTaskAwaiter<T>(_task!, _callerKey, _startDateTime) );
_valueTaskAwaiter=new Lazy<IAwaiter<T>>( ()=>new ManagedTaskAwaiter<T>(_valueTask!, _callerKey, _startDateTime) );
_task?.ConfigureAwait(configureAwait);
_valueTask.ConfigureAwait(configureAwait);
WL("ManagedTask.init end");
WL($"ManagedTask.Start {_task!.Status}");
if(_isTaskStarted) return;
if(_task.Status==TaskStatus.Created) _task.Start();
_startDateTime=dt.UtcNow;
public bool IsCompleted =>!_isValueTask ? _task!.IsCompleted : _valueTask.IsCompleted;
public Task<T> AsTask() => _isValueTask ? _task??=_valueTask.AsTask() : _task!;
public IAwaiter<T> GetAwaiter()
WL($"ManagedTask<T>.GetAwaiter");
return _isValueTask ? _valueTaskAwaiter.Value : _taskAwaiter.Value;
if(!IsCompleted) AwaitThis();
return _result??=!_isValueTask ? _task!.Result : _valueTask.Result ;
async void AwaitThis() => await this;
public ManagedTask<T> ContinueWith(Func<T, T> function)
=>new ManagedTask<T>( function:()=>function(Result) );
public ManagedTask<OUT> ContinueWith<OUT>(Func<T, OUT> function)
=>new ManagedTask<OUT>( function:()=>function(Result) );
public ManagedTask<T> ContinueWith(Func<T, Task<T>> asyncfunction)
=>new ManagedTask<T>( ()=>asyncfunction(Result) );
public ManagedTask<OUT> ContinueWith<OUT>(Func<T, Task<OUT>> asyncfunction)
=>new ManagedTask<OUT>( ()=>asyncfunction(Result) );
public partial class ManagedTask<T>
public static IAwaitable<T> Run(Func<Task<T>> asyncFunction, bool configureAwait=false, [CMN]str callerName="", [CLN] int callerLineNumber=0, [CFP] str callerFilePath="")
WL("ManagedTask.Run<Task<T>>");
var iA=new ManagedTask<T>(asyncFunction:asyncFunction, configureAwait:configureAwait, callerName:callerName, callerLineNumber:callerLineNumber, callerFilePath:callerFilePath);
public static IAwaitable<T> Run(Func<T> function, bool configureAwait=false, [CMN]str callerName="", [CLN] int callerLineNumber=0, [CFP] str callerFilePath="")
WL("ManagedTask.Run<T>");
var iA=new ManagedTask<T>(function:function, configureAwait:configureAwait, callerName:callerName, callerLineNumber:callerLineNumber, callerFilePath:callerFilePath);
public static IAwaitable<T> FromException([DN]Exception fromException)
WL($"ManagedTask<T>.FromException");
var returned=new ManagedTask<T>(fromException:fromException);
public static IAwaitable<T> FromResult([DN]T fromResult)
WL($"ManagedTask<T>.FromResult");
var returned=new ManagedTask<T>( fromResult:fromResult );
public static implicit operator ManagedTask<T>(Task<T> task)
WL($"Implicit from Task to ManagedTask");
public static explicit operator ManagedTask<T>([DN]T result)
WL($"Explicit from Result<T> to ManagedTask");
return new ManagedTask<T>( fromResult:result );
public static implicit operator Task<T>([DN]ManagedTask<T> managedTask)
WL($"Implicit from ManagedTask to Task");
return managedTask._task??new TaskCompletionSource<T>().Task;
public static explicit operator ValueTask<T>([DN]ManagedTask<T> managedTask)
WL("Explicit from ManagedTask to ValueTask");
return managedTask._valueTask;
public struct ManagedTaskAwaiter<T> : IAwaiter<T>, ICriticalNotifyCompletion
private readonly Task<T>? _task {get;init;}
private readonly ValueTask<T> _valueTask {get;init;}
private bool _gotResult, _isCompleted, _isValueTask;
private int _lastHashCode;
private readonly CallerKey _callerKey;
private dt _startDateTime;
public ManagedTaskAwaiter([DN]Task<T>? t, CallerKey callerKey, dt startDateTime) => (_callerKey, _task, _isValueTask, _startDateTime)=(callerKey, t!, false, startDateTime);
public ManagedTaskAwaiter([DN]ValueTask<T> t, CallerKey callerKey, dt startDateTime)
=> (_callerKey, _valueTask, _isValueTask, _startDateTime) = (callerKey, t, true, startDateTime);
if(!_isCompleted) _isCompleted=_isValueTask ? _valueTask.GetAwaiter().IsCompleted : _task!.GetAwaiter().IsCompleted;
WL($"Awaiter.IsCompleted={_isCompleted} (_valueTask:{_valueTask==null},_task={_task is null}, LastHashCode={_lastHashCode})");
int compareHashCode=_isValueTask ? _valueTask.GetHashCode() : _task!.GetHashCode();
if(compareHashCode!=_lastHashCode)
ManagedTaskBroker.Logs.IncrementSlowPath(_callerKey, _startDateTime, now, typeof(T).FullName!, typeof(T).IsPrimitive, _isValueTask);
ManagedTaskBroker.Logs.IncrementFastPath(_callerKey, _startDateTime, now, typeof(T).FullName!, typeof(T).IsPrimitive, _isValueTask);
_lastHashCode=compareHashCode;
WL($"Awaiter.GetResult");
if(!_gotResult) (_gotResult, _result)=( true, _isValueTask ? _valueTask.GetAwaiter().GetResult() :_task!.GetAwaiter().GetResult() );
public void OnCompleted(Action continuation)
WL($"Awaiter.OnCompleted({continuation==null})");
public void UnsafeOnCompleted(Action continuation)
WL($"Awaiter.UnsafeOnCompleted({continuation==null})");
public struct ManagedTaskBuilder<T>
private AsyncTaskMethodBuilder<T> builder=new AsyncTaskMethodBuilder<T>();
private Exception? _exception;
public ManagedTaskBuilder()
public static ManagedTaskBuilder<T> Create() => new ManagedTaskBuilder<T>();
public readonly void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine => stateMachine.MoveNext();
public ManagedTask<T> Task
_lock.Enter(ref lockTaken);
if (_exception is not null)
return new ManagedTask<T>(fromException:_exception);
return new ManagedTask<T>(fromResult:_result!);
return new ManagedTask<T>( task:(new TaskCompletionSource<T>(TaskCreationOptions.RunContinuationsAsynchronously).Task) );
if (lockTaken) _lock.Exit();
public void SetResult(T result)
WL($"Builder.SetResult(Result={result})");
_lock.Enter(ref lockTaken);
if (lockTaken) _lock.Exit();
public void SetException(Exception exception)
_lock.Enter(ref lockTaken);
if (lockTaken) _lock.Exit();
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
WL("Builder.AwaitOnCompleted");
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine
WL($"Builder.AwaitUnsafeOnCompleted (awaiter={awaiter==null}, stateMachine={stateMachine==null})");
stateMachine!.MoveNext();
public readonly void SetStateMachine(IAsyncStateMachine stateMachine) {this.builder.SetStateMachine(stateMachine);}
public interface IAwaitable
public IAwaiter GetAwaiter();
public interface IAwaitable<T>
public IAwaiter<T> GetAwaiter();
public interface IAwaiter : ICriticalNotifyCompletion
public bool IsCompleted { get; }
public interface IAwaiter<T> : ICriticalNotifyCompletion
public bool IsCompleted { get; }
public static class DebugMethods
public static bool debug=true;
public static void DoNothing() {}
public static void L() { if(debug) Console.Write("\n"); }
public static void W<T>(T s) { if(debug) Console.Write(s); }
public static void WL<T>(T s) { if(debug) Console.WriteLine(s); }