// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Text; using Microsoft.Extensions.Logging; namespace UnrealBuildTool { /// /// Scoped timer, start is in the constructor, end in Dispose. Best used with using(ScopedTimer Timer = new ScopedTimer()). Suports nesting. /// public class ScopedTimer : IDisposable { DateTime StartTime; string Name; ILogger Logger; LogLevel Level; bool bIncreaseIndent; static int Indent = 0; static object IndentLock = new object(); /// /// Constructor /// /// Name of the block being measured /// Logger for output /// Verbosity for output messages /// Whether gobal indent should be increased or not; set to false when running a scope in parallel. Message will still be printed indented relative to parent scope. public ScopedTimer(string Name, ILogger Logger, LogLevel InLevel = LogLevel.Debug, bool bIncreaseIndent = true) { this.Name = Name; this.Logger = Logger; if (bIncreaseIndent) { lock (IndentLock) { Indent++; } } Level = InLevel; StartTime = DateTime.UtcNow; this.bIncreaseIndent = bIncreaseIndent; } /// /// Prints out the timing message /// public void Dispose() { double TotalSeconds = (DateTime.UtcNow - StartTime).TotalSeconds; int LogIndent = Indent; if (bIncreaseIndent) { lock (IndentLock) { LogIndent = --Indent; } } StringBuilder IndentText = new StringBuilder(LogIndent * 2); IndentText.Append(' ', LogIndent * 2); Logger.Log(Level, "{Indent}{Name} took {TimeSeconds:0.000}s", IndentText.ToString(), Name, TotalSeconds); } } }