I needed a better way to benchmark code, because, well, rewriting the same benchmarking code every time I need it is just...well...unpleasant. So, here's a class which does just that, it runs an `Action` over a specific number of rounds, and calculates certain stats on it. The nice thing about this is that it **doesn't** store the run times as it calculates the stats. So you can literally supply any value for `rounds` and it *should* work. (Not tested for `rounds` values greater than 10,000,000.) The latest version is [on GitHub](https://github.com/EBrown8534/Framework/blob/master/Evbpc.Framework/Utilities/BenchmarkResult.cs). It's pretty simple. Two `static` methods on a simple class that run the benchmark. The nice thing about this class is it includes a version for `Func<T>` as well, which will also **verify the output** of the function. This means you can benchmark and verify your code at the same time, to make sure that nothing weird happens. /// <summary> /// Represents the result of a benchmarking session. /// </summary> public class BenchmarkResult { /// <summary> /// The total number of rounds ran. /// </summary> public ulong RoundsRun { get; set; } /// <summary> /// The average time for all the rounds. /// </summary> public TimeSpan AverageTime { get; set; } /// <summary> /// The maximum time taken for a single round. /// </summary> public TimeSpan MaxTime { get; set; } /// <summary> /// The minimum time taken for a single round. /// </summary> public TimeSpan MinTime { get; set; } /// <summary> /// The variance (standard deviation) of all the rounds. /// </summary> public TimeSpan Variance { get; set; } /// <summary> /// The number of rounds that passed testing. (Always equivalent to <see cref="RoundsRun"/> for <see cref="Benchmark(ulong, Action)"/>.) /// </summary> public ulong RoundsPassed { get; set; } /// <summary> /// Runs a benchmark of a method. /// </summary> /// <param name="rounds">The number of rounds to run.</param> /// <param name="method">The code to run.</param> /// <returns>A <see cref="BenchmarkResult"/> representing the result of the session.</returns> public static BenchmarkResult Benchmark(ulong rounds, Action method) { var sw = new Stopwatch(); double m2 = 0; double averageTicks = 0; double totalValues = 0; long maxTicks = 0; long minTicks = 0; for (ulong i = 0; i < rounds; i++) { sw.Start(); method.Invoke(); sw.Stop(); if (totalValues == 0) { maxTicks = sw.ElapsedTicks; minTicks = sw.ElapsedTicks; } totalValues++; maxTicks = Math.Max(sw.ElapsedTicks, maxTicks); minTicks = Math.Min(sw.ElapsedTicks, minTicks); // We need to store `delta` here as the `averageTicks` will change on the next calculation, and we need this previous `delta` for the calculation after it. double delta = sw.ElapsedTicks - averageTicks; averageTicks = averageTicks + delta / totalValues; m2 += delta * (sw.ElapsedTicks - averageTicks); sw.Reset(); } double variance = m2 / (totalValues - 1); return new BenchmarkResult { AverageTime = new TimeSpan(Convert.ToInt64(averageTicks)), MaxTime = new TimeSpan(maxTicks), MinTime = new TimeSpan(minTicks), RoundsPassed = rounds, RoundsRun = rounds, Variance = new TimeSpan(Convert.ToInt64(variance)) }; } /// <summary> /// Runs a benchmark of a function and returns the results of the session. /// </summary> /// <typeparam name="T">The type of the output of the function.</typeparam> /// <param name="rounds">The number of rounds to run.</param> /// <param name="method">The code to run.</param> /// <param name="expectedResult">The expected result of the function. This will be compared to the actual result and used for <see cref="BenchmarkResult.RoundsPassed"/>. This uses the default <code>object.Equals(object)</code> method.</param> /// <returns>A <see cref="BenchmarkResult"/> representing the result of the session.</returns> public static BenchmarkResult Benchmark<T>(ulong rounds, Func<T> method, T expectedResult) { var sw = new Stopwatch(); double m2 = 0; double averageTicks = 0; double totalValues = 0; long maxTicks = 0; long minTicks = 0; ulong roundsPassed = 0; for (ulong i = 0; i < rounds; i++) { sw.Start(); var result = method.Invoke(); sw.Stop(); if (expectedResult.Equals(result)) { roundsPassed++; } if (totalValues == 0) { maxTicks = sw.ElapsedTicks; minTicks = sw.ElapsedTicks; } totalValues++; maxTicks = Math.Max(sw.ElapsedTicks, maxTicks); minTicks = Math.Min(sw.ElapsedTicks, minTicks); // We need to store `delta` here as the `averageTicks` will change on the next calculation, and we need this previous `delta` for the calculation after it. double delta = sw.ElapsedTicks - averageTicks; averageTicks = averageTicks + delta / totalValues; m2 += delta * (sw.ElapsedTicks - averageTicks); sw.Reset(); } double variance = m2 / (totalValues - 1); return new BenchmarkResult { AverageTime = new TimeSpan(Convert.ToInt64(averageTicks)), MaxTime = new TimeSpan(maxTicks), MinTime = new TimeSpan(minTicks), RoundsPassed = roundsPassed, RoundsRun = rounds, Variance = new TimeSpan(Convert.ToInt64(variance)) }; } } It's *literally* a one-liner: > var result = BenchmarkResult.Benchmark(10000000, () => Thread.Sleep(0)); result = BenchmarkResult.Benchmark(10000000, () => true, true); That will benchmark the `Thread.Sleep(0)` method 10,000,000 times, and the `return true` method 10,000,000 times while verifying it always returns `true`.