Created
December 4, 2018 21:48
-
-
Save adamsitnik/ef9c3915ef5bcb7de65e1670939dc5af to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Diagnostics; | |
| using System.Runtime.CompilerServices; | |
| using System.Threading; | |
| using BenchmarkDotNet.Attributes; | |
| namespace BenchmarkDotNet.Samples | |
| { | |
| public class MathNano | |
| { | |
| [Benchmark] | |
| [Arguments(-1.0)] | |
| public double AbsDoubleBenchmark(double value) => Math.Abs(value); | |
| } | |
| public class StepByStep | |
| { | |
| private double _doubleHolder; | |
| public double AbsDoubleBenchmark(double value) => Math.Abs(value); | |
| public double Empty(double value) => value; | |
| public double SimpleLoop_Hardcoded(long operations) | |
| { | |
| double result = 0; | |
| const double hardcoded = -1.0; | |
| for (int iteration = 0; iteration < 20; iteration++) | |
| { | |
| var actual = Stopwatch.StartNew(); | |
| for (long innerIteration = 0; innerIteration < operations; innerIteration++) | |
| result = AbsDoubleBenchmark(hardcoded); | |
| actual.Stop(); | |
| double total = actual.Elapsed.TotalMilliseconds; | |
| double perOperation = total / operations; | |
| double nanosecondPerOperation = perOperation * 1_000_000.0; | |
| Console.WriteLine($"SimpleLoop_Hardcoded {nanosecondPerOperation} ns/op"); | |
| } | |
| Console.WriteLine(); Console.WriteLine(); Console.WriteLine(); | |
| return result; | |
| } | |
| public double SimpleLoop_Overhead_Hardcoded(long operations) | |
| { | |
| double result = 0; | |
| const double hardcoded = -1.0; | |
| for (int iteration = 0; iteration < 20; iteration++) | |
| { | |
| var actual = Stopwatch.StartNew(); | |
| for (long innerIteration = 0; innerIteration < operations; innerIteration++) | |
| result = AbsDoubleBenchmark(hardcoded); | |
| actual.Stop(); | |
| var overhead = Stopwatch.StartNew(); | |
| for (long innerIteration = 0; innerIteration < operations; innerIteration++) | |
| result = Empty(hardcoded); | |
| overhead.Stop(); | |
| double diff = actual.Elapsed.TotalMilliseconds - overhead.Elapsed.TotalMilliseconds; | |
| double perOperation = diff / operations; | |
| double nanosecondPerOperation = perOperation * 1_000_000.0; | |
| Console.WriteLine($"SimpleLoop_Overhead_Hardcoded {nanosecondPerOperation} ns/op"); | |
| } | |
| Console.WriteLine(); Console.WriteLine(); Console.WriteLine(); | |
| return result; | |
| } | |
| public double SimpleLoop_Overhead_Passed(long operations, double value) | |
| { | |
| double result = 0; | |
| for (int iteration = 0; iteration < 20; iteration++) | |
| { | |
| var actual = Stopwatch.StartNew(); | |
| for (long innerIteration = 0; innerIteration < operations; innerIteration++) | |
| result = AbsDoubleBenchmark(value); | |
| actual.Stop(); | |
| var overhead = Stopwatch.StartNew(); | |
| for (long innerIteration = 0; innerIteration < operations; innerIteration++) | |
| result = Empty(value); | |
| overhead.Stop(); | |
| double diff = actual.Elapsed.TotalMilliseconds - overhead.Elapsed.TotalMilliseconds; | |
| double perOperation = diff / operations; | |
| double nanosecondPerOperation = perOperation * 1_000_000.0; | |
| Console.WriteLine($"SimpleLoop_Overhead_Passed {nanosecondPerOperation} ns/op"); | |
| } | |
| Console.WriteLine(); Console.WriteLine(); Console.WriteLine(); | |
| return result; | |
| } | |
| [MethodImpl(MethodImplOptions.NoInlining)] | |
| public double AbsDoubleBenchmarkNoInline(double value) => Math.Abs(value); | |
| [MethodImpl(MethodImplOptions.NoInlining)] | |
| public double EmptyNoInline(double value) => value; | |
| public double SimpleLoop_Overhead_Passed_NoInline(long operations, double value) | |
| { | |
| double result = 0; | |
| for (int iteration = 0; iteration < 20; iteration++) | |
| { | |
| var actual = Stopwatch.StartNew(); | |
| for (long innerIteration = 0; innerIteration < operations; innerIteration++) | |
| result = AbsDoubleBenchmarkNoInline(value); | |
| actual.Stop(); | |
| var overhead = Stopwatch.StartNew(); | |
| for (long innerIteration = 0; innerIteration < operations; innerIteration++) | |
| result = EmptyNoInline(value); | |
| overhead.Stop(); | |
| double diff = actual.Elapsed.TotalMilliseconds - overhead.Elapsed.TotalMilliseconds; | |
| double perOperation = diff / operations; | |
| double nanosecondPerOperation = perOperation * 1_000_000.0; | |
| Console.WriteLine($"SimpleLoop_Overhead_Passed_NoInline {nanosecondPerOperation} ns/op"); | |
| } | |
| Console.WriteLine(); Console.WriteLine(); Console.WriteLine(); | |
| return result; | |
| } | |
| public void SimpleLoop_Overhead_Passed_NoInline_Volatile(long operations, double value) | |
| { | |
| for (int iteration = 0; iteration < 20; iteration++) | |
| { | |
| var actual = Stopwatch.StartNew(); | |
| for (long innerIteration = 0; innerIteration < operations; innerIteration++) | |
| Volatile.Write(ref _doubleHolder, AbsDoubleBenchmarkNoInline(value)); | |
| actual.Stop(); | |
| var overhead = Stopwatch.StartNew(); | |
| for (long innerIteration = 0; innerIteration < operations; innerIteration++) | |
| Volatile.Write(ref _doubleHolder, EmptyNoInline(value)); | |
| overhead.Stop(); | |
| double diff = actual.Elapsed.TotalMilliseconds - overhead.Elapsed.TotalMilliseconds; | |
| double perOperation = diff / operations; | |
| double nanosecondPerOperation = perOperation * 1_000_000.0; | |
| Console.WriteLine($"SimpleLoop_Overhead_Passed_NoInline_Volatile {nanosecondPerOperation} ns/op"); | |
| } | |
| Console.WriteLine(); Console.WriteLine(); Console.WriteLine(); | |
| } | |
| public void SimpleLoop_Overhead_Passed_NoInline_Volatile_Unroll(long operations, double value) | |
| { | |
| for (int iteration = 0; iteration < 20; iteration++) | |
| { | |
| var actual = Stopwatch.StartNew(); | |
| for (long innerIteration = 0; innerIteration < operations / 16; innerIteration++) | |
| { | |
| Volatile.Write(ref _doubleHolder, AbsDoubleBenchmarkNoInline(value)); Volatile.Write(ref _doubleHolder, AbsDoubleBenchmarkNoInline(value)); | |
| Volatile.Write(ref _doubleHolder, AbsDoubleBenchmarkNoInline(value)); Volatile.Write(ref _doubleHolder, AbsDoubleBenchmarkNoInline(value)); | |
| Volatile.Write(ref _doubleHolder, AbsDoubleBenchmarkNoInline(value)); Volatile.Write(ref _doubleHolder, AbsDoubleBenchmarkNoInline(value)); | |
| Volatile.Write(ref _doubleHolder, AbsDoubleBenchmarkNoInline(value)); Volatile.Write(ref _doubleHolder, AbsDoubleBenchmarkNoInline(value)); | |
| Volatile.Write(ref _doubleHolder, AbsDoubleBenchmarkNoInline(value)); Volatile.Write(ref _doubleHolder, AbsDoubleBenchmarkNoInline(value)); | |
| Volatile.Write(ref _doubleHolder, AbsDoubleBenchmarkNoInline(value)); Volatile.Write(ref _doubleHolder, AbsDoubleBenchmarkNoInline(value)); | |
| Volatile.Write(ref _doubleHolder, AbsDoubleBenchmarkNoInline(value)); Volatile.Write(ref _doubleHolder, AbsDoubleBenchmarkNoInline(value)); | |
| Volatile.Write(ref _doubleHolder, AbsDoubleBenchmarkNoInline(value)); Volatile.Write(ref _doubleHolder, AbsDoubleBenchmarkNoInline(value)); | |
| } | |
| actual.Stop(); | |
| var overhead = Stopwatch.StartNew(); | |
| for (long innerIteration = 0; innerIteration < operations / 16; innerIteration++) | |
| { | |
| Volatile.Write(ref _doubleHolder, EmptyNoInline(value)); Volatile.Write(ref _doubleHolder, EmptyNoInline(value)); | |
| Volatile.Write(ref _doubleHolder, EmptyNoInline(value)); Volatile.Write(ref _doubleHolder, EmptyNoInline(value)); | |
| Volatile.Write(ref _doubleHolder, EmptyNoInline(value)); Volatile.Write(ref _doubleHolder, EmptyNoInline(value)); | |
| Volatile.Write(ref _doubleHolder, EmptyNoInline(value)); Volatile.Write(ref _doubleHolder, EmptyNoInline(value)); | |
| Volatile.Write(ref _doubleHolder, EmptyNoInline(value)); Volatile.Write(ref _doubleHolder, EmptyNoInline(value)); | |
| Volatile.Write(ref _doubleHolder, EmptyNoInline(value)); Volatile.Write(ref _doubleHolder, EmptyNoInline(value)); | |
| Volatile.Write(ref _doubleHolder, EmptyNoInline(value)); Volatile.Write(ref _doubleHolder, EmptyNoInline(value)); | |
| Volatile.Write(ref _doubleHolder, EmptyNoInline(value)); Volatile.Write(ref _doubleHolder, EmptyNoInline(value)); | |
| } | |
| overhead.Stop(); | |
| double diff = actual.Elapsed.TotalMilliseconds - overhead.Elapsed.TotalMilliseconds; | |
| double perOperation = diff / operations; | |
| double nanosecondPerOperation = perOperation * 1_000_000.0; | |
| Console.WriteLine($"SimpleLoop_Overhead_Passed_NoInline_Volatile_Unroll {nanosecondPerOperation} ns/op"); | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment