From d3b34154ad302af2a202a8332d2afcadf3576e7d Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Sun, 20 Dec 2020 17:12:43 +0100 Subject: [PATCH] Added some statistics to coroutines It took me half a year, but closes #4 --- Coroutine/ActiveCoroutine.cs | 36 ++++++++++++++++++++++++--- Coroutine/CoroutineHandler.cs | 22 +++++++++------- Coroutine/CoroutineHandlerInstance.cs | 26 ++++++++++++++----- Test/Example.cs | 3 ++- Test/Test.csproj | 2 +- 5 files changed, 69 insertions(+), 20 deletions(-) diff --git a/Coroutine/ActiveCoroutine.cs b/Coroutine/ActiveCoroutine.cs index 88dcecb..354f1cf 100644 --- a/Coroutine/ActiveCoroutine.cs +++ b/Coroutine/ActiveCoroutine.cs @@ -1,14 +1,16 @@ using System; using System.Collections.Generic; +using System.Diagnostics; namespace Coroutine { /// /// A reference to a currently running coroutine. - /// This is returned by . + /// This is returned by . /// public class ActiveCoroutine { private readonly IEnumerator enumerator; + private readonly Stopwatch stopwatch; private Wait current; /// @@ -21,13 +23,35 @@ namespace Coroutine { /// public bool WasCanceled { get; private set; } /// + /// The total amount of time that took. + /// This is the amount of time that this active coroutine took for the entirety of its "steps", or yield statements. + /// + public TimeSpan TotalMoveNextTime { get; private set; } + /// + /// The total amount of times that was invoked. + /// This is the amount of "steps" in your coroutine, or the amount of yield statements. + /// + public int MoveNextCount { get; private set; } + /// + /// The average amount of time that took. + /// This is the average amount of time that each "step", or each yield statement, of this coroutine took to execute. + /// + public TimeSpan AverageMoveNextTime => new TimeSpan(this.TotalMoveNextTime.Ticks / this.MoveNextCount); + /// /// An event that gets fired when this active coroutine finishes or gets cancelled. /// When this event is called, is always true. /// public event FinishCallback OnFinished; + /// + /// The name of this coroutine. + /// When not specified on startup of this coroutine, the name defaults to an empty string. + /// + public readonly string Name; - internal ActiveCoroutine(IEnumerator enumerator) { + internal ActiveCoroutine(IEnumerator enumerator, string name, Stopwatch stopwatch) { this.enumerator = enumerator; + this.stopwatch = stopwatch; + this.Name = name; } /// @@ -60,7 +84,13 @@ namespace Coroutine { } internal bool MoveNext() { - if (!this.enumerator.MoveNext()) { + this.stopwatch.Restart(); + var result = this.enumerator.MoveNext(); + this.stopwatch.Stop(); + this.TotalMoveNextTime += this.stopwatch.Elapsed; + this.MoveNextCount++; + + if (!result) { this.IsFinished = true; this.OnFinished?.Invoke(this); return false; diff --git a/Coroutine/CoroutineHandler.cs b/Coroutine/CoroutineHandler.cs index 4e5fa8c..cd3238b 100644 --- a/Coroutine/CoroutineHandler.cs +++ b/Coroutine/CoroutineHandler.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; namespace Coroutine { /// @@ -11,19 +10,24 @@ namespace Coroutine { private static readonly CoroutineHandlerInstance Instance = new CoroutineHandlerInstance(); - /// - public static ActiveCoroutine Start(IEnumerable coroutine) { - return Instance.Start(coroutine); + /// + public static int TickingCount => Instance.TickingCount; + /// + public static int EventCount => Instance.EventCount; + + /// + public static ActiveCoroutine Start(IEnumerable coroutine, string name = "") { + return Instance.Start(coroutine, name); } - /// - public static ActiveCoroutine Start(IEnumerator coroutine) { - return Instance.Start(coroutine); + /// + public static ActiveCoroutine Start(IEnumerator coroutine, string name = "") { + return Instance.Start(coroutine, name); } /// - public static void InvokeLater(Wait wait, Action action) { - Instance.InvokeLater(wait, action); + public static ActiveCoroutine InvokeLater(Wait wait, Action action) { + return Instance.InvokeLater(wait, action); } /// diff --git a/Coroutine/CoroutineHandlerInstance.cs b/Coroutine/CoroutineHandlerInstance.cs index c5e3256..35fc62f 100644 --- a/Coroutine/CoroutineHandlerInstance.cs +++ b/Coroutine/CoroutineHandlerInstance.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; namespace Coroutine { @@ -11,24 +12,36 @@ namespace Coroutine { private readonly List tickingCoroutines = new List(); private readonly List eventCoroutines = new List(); + private readonly Stopwatch stopwatch = new Stopwatch(); + + /// + /// The amount of instances that are currently waiting for a tick (waiting for time to pass) + /// + public int TickingCount => this.tickingCoroutines.Count; + /// + /// The amount of instances that are currently waiting for an + /// + public int EventCount => this.eventCoroutines.Count; /// /// Starts the given coroutine, returning a object for management. /// Note that this calls to get the enumerator. /// /// The coroutine to start + /// The name that this coroutine should have. Defaults to an empty string. /// An active coroutine object representing this coroutine - public ActiveCoroutine Start(IEnumerable coroutine) { - return this.Start(coroutine.GetEnumerator()); + public ActiveCoroutine Start(IEnumerable coroutine, string name = "") { + return this.Start(coroutine.GetEnumerator(), name); } /// /// Starts the given coroutine, returning a object for management. /// /// The coroutine to start + /// The name that this coroutine should have. Defaults to an empty string. /// An active coroutine object representing this coroutine - public ActiveCoroutine Start(IEnumerator coroutine) { - var inst = new ActiveCoroutine(coroutine); + public ActiveCoroutine Start(IEnumerator coroutine, string name = "") { + var inst = new ActiveCoroutine(coroutine, name, this.stopwatch); if (inst.MoveNext()) { if (inst.IsWaitingForEvent()) { this.eventCoroutines.Add(inst); @@ -45,8 +58,9 @@ namespace Coroutine { /// /// The wait to wait for /// The action to execute after waiting - public void InvokeLater(Wait wait, Action action) { - this.Start(InvokeLaterImpl(wait, action)); + /// An active coroutine object representing this coroutine + public ActiveCoroutine InvokeLater(Wait wait, Action action) { + return this.Start(InvokeLaterImpl(wait, action)); } /// diff --git a/Test/Example.cs b/Test/Example.cs index 62df103..4b29b9a 100644 --- a/Test/Example.cs +++ b/Test/Example.cs @@ -9,7 +9,7 @@ namespace Test { private static readonly Event TestEvent = new Event(); public static void Main() { - var seconds = CoroutineHandler.Start(WaitSeconds()); + var seconds = CoroutineHandler.Start(WaitSeconds(), "Awesome Waiting Coroutine"); CoroutineHandler.Start(PrintEvery10Seconds(seconds)); CoroutineHandler.Start(EmptyCoroutine()); @@ -50,6 +50,7 @@ namespace Test { Console.WriteLine("The time is " + DateTime.Now); if (first.IsFinished) { Console.WriteLine("By the way, the first coroutine has finished!"); + Console.WriteLine($"{first.Name} data: {first.MoveNextCount} moves, {first.TotalMoveNextTime} total time, {first.AverageMoveNextTime} average"); Environment.Exit(0); } } diff --git a/Test/Test.csproj b/Test/Test.csproj index ed472fc..aaf5e03 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -9,7 +9,7 @@ Properties Test Test - v4.7.2 + v4.6.2 512