using System.Collections.Generic;
using System.Diagnostics;
public static void Main()
Console.WriteLine("Enter benchmarks");
.AddCase(() => { ConsoleColor.Black.HasFlag(ConsoleColor.Black); }, "HasFlag")
.AddCase(() => { ConsoleColor.Black.ToString(); }, "ToString")
.DumpResults(Console.Out);
public class BenchmarkRunner
public uint Iterations = 10000;
public bool CollectBetweenCases = true;
public bool CollectBetweenRepeat = true;
public bool Warmup = true;
public uint WarmupCycles = 3;
public SortMode Sort = SortMode.Memory;
List<Case> _casesList = new List<Case>();
public BenchmarkRunner AddCase(Action action, string name = "")
_casesList.Add(new Case()
{Action = action, Name = string.IsNullOrWhiteSpace(name) ? action.Method.Name : name, Memory = new long[Repeat], Time = new TimeSpan[Repeat], });
public BenchmarkRunner DoTest()
_cases = _casesList.ToArray();
int casesCount = _cases.Length;
for (int i = 0; i < WarmupCycles; i++)
for (int c = 0; c < casesCount; c++)
Stopwatch stopwatch = new Stopwatch();
for (int c = 0; c < casesCount; c++)
var currentCase = _cases[c];
for (int r = 0; r < Repeat; r++)
long startMemory = GC.GetTotalMemory(CollectBetweenRepeat);
for (int i = 0; i < Iterations; i++)
long endMemory = GC.GetTotalMemory(false);
currentCase.Memory[r] = endMemory - startMemory;
currentCase.Time[r] = stopwatch.Elapsed;
public void DumpResults(TextWriter writer)
IEnumerable<Case> cases = _casesList;
if (Sort == SortMode.Memory) {
cases = _casesList.OrderBy(c => c.Memory.Max());
} else if (Sort == SortMode.Time) {
cases = _casesList.OrderBy(c => c.Time.Max(t => t.Ticks));
foreach (var currentCase in cases)
writer.Write(currentCase.Name);
for (int index = 0; index < currentCase.Memory.Length; index++)
long currentCaseMemory = currentCase.Memory[index];
TimeSpan currentCaseTime = currentCase.Time[index];
writer.Write(HumanReadableTimeSpan(currentCaseTime));
writer.Write(HumanReadableBytes(currentCaseMemory));
writer.WriteLine(" ------ ");
static string HumanReadableTimeSpan(TimeSpan timeSpan)
StringBuilder sb = new StringBuilder();
Action<long, StringBuilder, int, bool> addActionToSB = (val, displayunit, zeroplaces, skipZero) =>
if (val > 0 || !skipZero)
sb.AppendFormat(" {0:DZ}X".Replace("X", displayunit.ToString()).Replace("Z", zeroplaces.ToString()), val);
addActionToSB((long)timeSpan.Seconds, new StringBuilder("s"), 1, true);
addActionToSB((long)timeSpan.Milliseconds, new StringBuilder("ms"), 3, false);
addActionToSB((long)Convert.ToUInt64((int)((timeSpan.TotalMilliseconds - (int)timeSpan.TotalMilliseconds) * 1000)), new StringBuilder("µs"), 3, false);
addActionToSB((long)Convert.ToUInt64((((decimal)(timeSpan.Ticks * 100) % 1000))), new StringBuilder("ns"), 3, false);
return sb.ToString().TrimStart();
static string HumanReadableBytes(long byteCount)
string[] suf = {"B", "KB", "MB", "GB", "TB", "PB", "EB"};
long bytes = Math.Abs(byteCount);
int place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024)));
double num = Math.Round(bytes / Math.Pow(1024, place), 1);
return (Math.Sign(byteCount) * num).ToString() + suf[place];