using System; using System.Collections.Generic; using System.Diagnostics; using System.Text; namespace BBIWARG.Utility { /// <summary> /// Stores and prints timing information for different code sections. /// </summary> internal static class Timer { /// <summary> /// dictionary of current runtimes indexed by name of the code section /// </summary> private static Dictionary<String, double> currentTimes = new Dictionary<string, double>(); /// <summary> /// the maximum length for the name of a code section /// </summary> private static int maxNameLength = 1; /// <summary> /// dictionary of maximum runtimes indexed by name of the code section /// </summary> private static Dictionary<String, double> maxTimes = new Dictionary<string, double>(); /// <summary> /// dictionary of minimum runtimes indexed by name of the code section /// </summary> private static Dictionary<String, double> minTimes = new Dictionary<string, double>(); /// <summary> /// dictionary of the number of times the time was measured indexed by name of the code section /// </summary> private static Dictionary<String, int> numTimes = new Dictionary<string, int>(); /// <summary> /// dictionary of stopwatches indexed by name of the code section /// </summary> private static Dictionary<String, Stopwatch> stopwatches = new Dictionary<string, Stopwatch>(); /// <summary> /// dictionary of the sum of runtimes indexed by name of the code section /// </summary> private static Dictionary<String, double> sumTimes = new Dictionary<string, double>(); /// <summary> /// used to prevent running <see cref="start"/>, <see cref="stop"/> and <see cref="outputAll"/> simultaneously from different threads /// </summary> private static Object sync = new object(); /// <summary> /// Prints all collected timing information. /// </summary> public static void outputAll() { lock (sync) { StringBuilder divider = new StringBuilder(); divider.Append("├-"); divider.Append(new String('-', maxNameLength)); divider.Append("-┼-------┼-------┤"); Console.Clear(); Console.WriteLine(String.Format("| {0,-" + maxNameLength + "} | {1,-5} | {2,-5} |", "NAME", "AVG.", "CUR.")); Console.WriteLine(divider.ToString()); foreach (String name in stopwatches.Keys) { double average = sumTimes[name] / Math.Max(numTimes[name], 1); double current = currentTimes[name]; Console.WriteLine(String.Format("| {0,-" + maxNameLength + "} | {1:00.00} | {2:00.00} |", name, average, current)); } } } /// <summary> /// Starts a timer for the given name and initializes the dictionaries when called for the first time with this name. /// </summary> /// <param name="name">name of the code section</param> public static void start(String name) { lock (sync) { if (!stopwatches.ContainsKey(name)) { stopwatches.Add(name, new Stopwatch()); minTimes.Add(name, int.MaxValue); maxTimes.Add(name, 0); sumTimes.Add(name, 0); numTimes.Add(name, 0); currentTimes.Add(name, 0); maxNameLength = Math.Max(maxNameLength, name.Length); } stopwatches[name].Restart(); } } /// <summary> /// Stops the timer for the given name and stores timing information. /// </summary> /// <param name="name">name of the code section</param> public static void stop(String name) { lock (sync) { stopwatches[name].Stop(); double time = Math.Round((double)stopwatches[name].ElapsedTicks / (double)Stopwatch.Frequency * 1000.0, 2); if (time < minTimes[name]) minTimes[name] = time; if (time > maxTimes[name]) maxTimes[name] = time; sumTimes[name] += time; numTimes[name]++; currentTimes[name] = time; } } } }