Plug-n-play thread-safe C# utility class for determining which database calls are slowing down your application.
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq;
namespace Hillsdale.API.TicketSystem
{
public static class Ticker
{
private static ConcurrentDictionary<Guid, Stopwatch> _timers = new ConcurrentDictionary<Guid, Stopwatch>();
private static ConcurrentDictionary<string, ConcurrentStack<long>> _results = new ConcurrentDictionary<string, ConcurrentStack<long>>();
private static ConcurrentDictionary<Guid, string> _guidMap = new ConcurrentDictionary<Guid, string>();
public static Guid StartTimer(string name)
{
var g = Guid.NewGuid();
_timers.TryAdd(g, Stopwatch.StartNew());
_guidMap.TryAdd(g, name);
return g;
}
public static void Stop(Guid guid, bool printImmediately = false)
{
if (_timers.TryRemove(guid, out Stopwatch sw))
{
sw.Stop();
var elapsedTime = sw.ElapsedMilliseconds;
_guidMap.TryRemove(guid, out string name);
if (printImmediately)
Console.WriteLine("Ticker[" + name + "]: " + elapsedTime);
if (_results.TryGetValue(name, out ConcurrentStack<long> stack))
{
stack.Push(elapsedTime);
}
else
{
var cs = new ConcurrentStack<long>();
cs.Push(elapsedTime);
_results.TryAdd(name, cs);
}
}
else
{
Console.WriteLine("error removing timer");
}
}
public static void PrintStats()
{
var array = _results.AsEnumerable().ToArray();
var keyPadding = array.Max(x => x.Key.Length);
var valuePadding = array.Max(x => x.Value.ToArray().Max()).ToString().Length;
var countPadding = array.Max(x => x.Value.Count).ToString().Length;
var totalTimeTracked = array.Sum(x => x.Value.ToArray().Sum());
Console.WriteLine("===================================");
foreach (var item in array)
{
var sum = item.Value.ToArray().Sum();
var avg = sum / item.Value.Count;
var max = item.Value.ToArray().Max();
var percentOfTotalTracked = (100 * sum) / totalTimeTracked;
Console.WriteLine(
item.Key.PadLeft(keyPadding)
+ ": Count = " + item.Value.Count.ToString().PadLeft(countPadding)
+ " AVG = " + avg.ToString().PadLeft(valuePadding)
+ " MAX = " + max.ToString().PadLeft(valuePadding)
+ " " + new string('█', (int)percentOfTotalTracked)
);
}
Console.WriteLine("===================================");
}
public static void Tacker(string name, Action a)
{
Guid g = StartTimer(name);
a();
Stop(g);
}
public static T Tacker<T>(string name, Func<T> f)
{
Guid g = StartTimer(name);
T result = f();
Stop(g);
return result;
}
}
}
Examples:
public int ExecuteNonQueryProxy(string commandText, CommandType commandType, List<SqlParameter> commandParameters)
=> Ticker.Tacker(commandText, () => ExecuteNonQuery(commandText, commandType, commandParameters));
Leave a Reply