C# Benchmark

Use Stopwatch to benchmark a method, computing the average number of nanoseconds.

Benchmark. If we have a solid knowledge of how fast code executes, we can develop more efficient programs. This opens new possibilities.StopwatchConvert Nanoseconds

Benchmarking, notes. With benchmarking, we can make smarter decisions. Most of the programs we use every day have been benchmarked many times.

Example. First we see some benchmark loops. This program is what I use for my experiments. Change "_max" depending on the code of each iteration. Start smaller and push the limit up.For
Max: Adjust _max higher or lower based on how slow your iterations are. This could be automated, but is not that important.
Version 1: Each benchmark should have a description in the code, and on the description about the code.
Version 2: This version of the code should be slightly different (but hopefully have the same approximate effect).
Result: Always run in Release mode, never in Visual Studio—click the .exe yourself. Change the order of the tests.
C# program that benchmarks Console application, 2 loops using System; using System.Diagnostics; class Program { const int _max = 1000000; static void Main() { var s1 = Stopwatch.StartNew(); // Version 1: describe version 1 here. for (int i = 0; i < _max; i++) { } s1.Stop(); var s2 = Stopwatch.StartNew(); // Version 2: describe version 2 here. for (int i = 0; i < _max; i++) { } s2.Stop(); Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); } } Output ??? ns Version 1 description ??? ns Version 2 description

Benchmark, 3 loops. Suppose you are feeling ambitious and want to benchmark 3 different versions of code at once. This might be too much, but can be useful at times.
Version 1: In this inner loop, place the code for version 1. It is important to consider whether garbage collection occurs.
Version 2: Another part of the benchmark should be placed here. It is acceptable to increment a counter that is shared between the loops.
Version 3: Another version is placed here. Occasionally, warming up the JIT and calling methods before the benchmark helps.
Result: Having benchmarks carefully labeled, so they can be understood at a glance, is important.
C# program that benchmarks 3 loops using System; using System.Diagnostics; class Program { static void Main() { const int m = 1000000; Stopwatch s1 = Stopwatch.StartNew(); // Version 1: description here. for (int i = 0; i < m; i++) { } s1.Stop(); Stopwatch s2 = Stopwatch.StartNew(); // Version 2: description here. for (int i = 0; i < m; i++) { } s2.Stop(); Stopwatch s3 = Stopwatch.StartNew(); // Version 3: description here. for (int i = 0; i < m; i++) { } s3.Stop(); Console.WriteLine(s1.ElapsedMilliseconds); Console.WriteLine(s2.ElapsedMilliseconds); Console.WriteLine(s3.ElapsedMilliseconds); } } Output ??? Version 1 description ??? Version 2 description ??? Version 3 description

Some problems. The benchmarking code has some problems. The second block sometimes takes less time to execute due to unknown causes.
Tip: Repeat and swap two loops if you are doubtful. The first program shown converts the results to nanoseconds.
Nanoseconds: It is usually best to report results in nanoseconds or microseconds with the number of iterations used to divide the result.

An example optimization. The Dictionary collection in the base class library is a huge optimization. But developers sometimes write code that results in twice as many lookups.TryGetValue

More complex benchmark. For an example of a more complex benchmark, check the Tuple page. It performs several tests on Tuples to determine how fast tuples are.Tuple

Summary. Benchmarking encourages careful thinking about your code. It saves nanoseconds from your software. It also improves the depth of your understanding.

© 2007-2020 Sam Allen. Send bug reports to info@dotnetperls.com.