Skip to content

Instantly share code, notes, and snippets.

@adamsitnik
Created December 4, 2018 21:48
Show Gist options
  • Select an option

  • Save adamsitnik/ef9c3915ef5bcb7de65e1670939dc5af to your computer and use it in GitHub Desktop.

Select an option

Save adamsitnik/ef9c3915ef5bcb7de65e1670939dc5af to your computer and use it in GitHub Desktop.
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