Multi-Platform Package Manager for Stable Diffusion
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

129 lines
3.3 KiB

using System.Diagnostics;
using System.Reactive.Disposables;
using System.Runtime.CompilerServices;
using System.Text;
namespace StabilityMatrix.Core.Helper;
public class CodeTimer : IDisposable
{
private static readonly Stack<CodeTimer> RunningTimers = new();
private readonly string name;
private readonly Stopwatch stopwatch;
private bool isDisposed;
private CodeTimer? ParentTimer { get; }
private List<CodeTimer> SubTimers { get; } = new();
public CodeTimer(string postFix = "", [CallerMemberName] string callerName = "")
{
name = $"{callerName}" + (string.IsNullOrEmpty(postFix) ? "" : $" ({postFix})");
stopwatch = Stopwatch.StartNew();
// Set parent as the top of the stack
if (RunningTimers.TryPeek(out var timer))
{
ParentTimer = timer;
timer.SubTimers.Add(this);
}
// Add ourselves to the stack
RunningTimers.Push(this);
}
/// <summary>
/// Starts a new timer and returns it if DEBUG is defined, otherwise returns an empty IDisposable
/// </summary>
/// <param name="postFix"></param>
/// <param name="callerName"></param>
/// <returns></returns>
public static IDisposable StartDebug(
string postFix = "",
[CallerMemberName] string callerName = ""
)
{
#if DEBUG
return new CodeTimer(postFix, callerName);
#else
return Disposable.Empty;
#endif
}
/// <summary>
/// Formats a TimeSpan into a string. Chooses the most appropriate unit of time.
/// </summary>
public static string FormatTime(TimeSpan duration)
{
if (duration.TotalSeconds < 1)
{
return $"{duration.TotalMilliseconds:0.00}ms";
}
if (duration.TotalMinutes < 1)
{
return $"{duration.TotalSeconds:0.00}s";
}
if (duration.TotalHours < 1)
{
return $"{duration.TotalMinutes:0.00}m";
}
return $"{duration.TotalHours:0.00}h";
}
private static void OutputDebug(string message)
{
Debug.WriteLine(message);
}
/// <summary>
/// Get results for this timer and all sub timers recursively
/// </summary>
private string GetResult()
{
var builder = new StringBuilder();
builder.AppendLine($"{name}: took {FormatTime(stopwatch.Elapsed)}");
foreach (var timer in SubTimers)
{
// For each sub timer layer, add a `|-` prefix
builder.AppendLine($"|- {timer.GetResult()}");
}
return builder.ToString();
}
public void Dispose()
{
if (isDisposed)
return;
stopwatch.Stop();
// Remove ourselves from the stack
if (RunningTimers.TryPop(out var timer))
{
if (timer != this)
{
throw new InvalidOperationException("Timer stack is corrupted");
}
}
else
{
throw new InvalidOperationException("Timer stack is empty");
}
// If we're a root timer, output all results
if (ParentTimer is null)
{
OutputDebug(GetResult());
SubTimers.Clear();
}
isDisposed = true;
GC.SuppressFinalize(this);
}
}