Skip to content

Instantly share code, notes, and snippets.

@ociaw
Created October 22, 2019 05:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ociaw/b25241aa89c9428c02576c9587042595 to your computer and use it in GitHub Desktop.
Save ociaw/b25241aa89c9428c02576c9587042595 to your computer and use it in GitHub Desktop.
A crappy struct benchmark
/*
* A quick and dirty micro benchmark on passing a class vs a struct vs a struct by reference
*
* This is not necessarily a good benchmark. The code will likely perform much differently
* under a more realistic scenario.
*
* Summary:
* | Method | N | Mean | Error | StdDev | Rank |
* |------------------------------ |-------- |------------------:|--------------:|--------------:|-----:|
* | BenchmarkMediumClass | 1 | 0.6700 ns | 0.0017 ns | 0.0016 ns | 2 |
* | BenchmarkMediumStruct | 1 | 0.5522 ns | 0.0025 ns | 0.0023 ns | 1 |
* | BenchmarkMediumStructByRef | 1 | 0.5519 ns | 0.0034 ns | 0.0030 ns | 1 |
* | BenchmarkLargeClass | 1 | 1.6638 ns | 0.0036 ns | 0.0032 ns | 3 |
* | BenchmarkLargeStruct | 1 | 1.9873 ns | 0.0034 ns | 0.0030 ns | 5 |
* | BenchmarkLargeStructByRef | 1 | 1.7395 ns | 0.0036 ns | 0.0033 ns | 4 |
* | BenchmarkVeryLargeClass | 1 | 2.3446 ns | 0.0085 ns | 0.0080 ns | 6 |
* | BenchmarkVeryLargeStruct | 1 | 3.2282 ns | 0.0086 ns | 0.0081 ns | 8 |
* | BenchmarkVeryLargeStructByRef | 1 | 2.5289 ns | 0.0061 ns | 0.0057 ns | 7 |
* | BenchmarkMediumClass | 100 | 68.7325 ns | 0.1097 ns | 0.1026 ns | 9 |
* | BenchmarkMediumStruct | 100 | 69.0129 ns | 0.1152 ns | 0.1078 ns | 9 |
* | BenchmarkMediumStructByRef | 100 | 68.9675 ns | 0.1908 ns | 0.1785 ns | 9 |
* | BenchmarkLargeClass | 100 | 117.6015 ns | 0.1037 ns | 0.0970 ns | 10 |
* | BenchmarkLargeStruct | 100 | 168.3852 ns | 0.3010 ns | 0.2815 ns | 13 |
* | BenchmarkLargeStructByRef | 100 | 134.6392 ns | 0.1441 ns | 0.1348 ns | 11 |
* | BenchmarkVeryLargeClass | 100 | 179.4940 ns | 0.1901 ns | 0.1778 ns | 14 |
* | BenchmarkVeryLargeStruct | 100 | 248.8764 ns | 0.6929 ns | 0.6481 ns | 15 |
* | BenchmarkVeryLargeStructByRef | 100 | 147.1239 ns | 0.2157 ns | 0.2018 ns | 12 |
* | BenchmarkMediumClass | 10000 | 6,486.7953 ns | 7.0721 ns | 6.6152 ns | 16 |
* | BenchmarkMediumStruct | 10000 | 6,484.1350 ns | 12.9782 ns | 12.1398 ns | 16 |
* | BenchmarkMediumStructByRef | 10000 | 6,483.1949 ns | 22.7971 ns | 21.3244 ns | 16 |
* | BenchmarkLargeClass | 10000 | 11,183.8714 ns | 12.2654 ns | 11.4731 ns | 17 |
* | BenchmarkLargeStruct | 10000 | 16,766.1190 ns | 32.2947 ns | 30.2085 ns | 20 |
* | BenchmarkLargeStructByRef | 10000 | 12,950.8779 ns | 20.5533 ns | 19.2256 ns | 18 |
* | BenchmarkVeryLargeClass | 10000 | 17,282.3985 ns | 19.3402 ns | 18.0908 ns | 21 |
* | BenchmarkVeryLargeStruct | 10000 | 24,676.5957 ns | 30.6337 ns | 28.6547 ns | 22 |
* | BenchmarkVeryLargeStructByRef | 10000 | 14,191.3848 ns | 23.9293 ns | 22.3835 ns | 19 |
* | BenchmarkMediumClass | 1000000 | 658,091.9713 ns | 781.5372 ns | 692.8124 ns | 23 |
* | BenchmarkMediumStruct | 1000000 | 659,450.6557 ns | 777.0098 ns | 688.7989 ns | 23 |
* | BenchmarkMediumStructByRef | 1000000 | 658,683.6163 ns | 914.4711 ns | 763.6248 ns | 23 |
* | BenchmarkLargeClass | 1000000 | 1,132,105.6250 ns | 643.7651 ns | 602.1782 ns | 24 |
* | BenchmarkLargeStruct | 1000000 | 1,712,619.0104 ns | 2,524.8616 ns | 2,361.7571 ns | 27 |
* | BenchmarkLargeStructByRef | 1000000 | 1,552,783.2682 ns | 3,965.1857 ns | 3,709.0371 ns | 26 |
* | BenchmarkVeryLargeClass | 1000000 | 1,736,865.7506 ns | 1,658.1848 ns | 1,469.9376 ns | 28 |
* | BenchmarkVeryLargeStruct | 1000000 | 2,480,650.8650 ns | 3,665.8116 ns | 3,249.6465 ns | 29 |
* | BenchmarkVeryLargeStructByRef | 1000000 | 1,431,716.5179 ns | 2,365.8831 ns | 2,097.2937 ns | 25 |
*
*/
using System;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
namespace StructBenchmarking
{
public class Program
{
public static void Main()
{
var summary = BenchmarkRunner.Run<Benchmark>();
}
}
[RPlotExporter, RankColumn]
public class Benchmark
{
private MediumClass _mediumClass;
private MediumStruct _mediumStruct;
private LargeClass _largeClass;
private LargeStruct _largeStruct;
private VeryLargeClass _veryLargeClass;
private VeryLargeStruct _veryLargeStruct;
private long[] _data;
[Params(1, 100, 10000, 1000000)]
public int N;
[GlobalSetup]
public void Setup()
{
const Int32 seed = 42;
var rand = new Random(seed);
_data = new long[N];
long a = rand.Next();
long b = rand.Next();
long c = rand.Next();
long d = rand.Next();
long v = rand.Next();
long x = rand.Next();
long y = rand.Next();
long z = rand.Next();
_mediumClass = new MediumClass(v, x);
_mediumStruct = new MediumStruct(v, x);
_largeClass = new LargeClass(v, x, y, z);
_largeStruct = new LargeStruct(v, x, y, z);
_veryLargeClass = new VeryLargeClass(a, b, c, d, v, x, y, z);
_veryLargeStruct = new VeryLargeStruct(a, b, c, d, v, x, y, z);
for (int i = 0; i < N; i++)
{
long r = rand.Next();
_data[i] = r;
}
}
[Benchmark]
public long BenchmarkMediumClass()
{
long sum = 0;
for (int i = 0; i < N; i++)
sum += _data[i] + SumClass(_mediumClass);
return sum;
}
[Benchmark]
public long BenchmarkMediumStruct()
{
long sum = 0;
for (int i = 0; i < N; i++)
sum += _data[i] + SumStruct(_mediumStruct);
return sum;
}
[Benchmark]
public long BenchmarkMediumStructByRef()
{
long sum = 0;
for (int i = 0; i < N; i++)
sum += _data[i] + SumStructByRef(_mediumStruct);
return sum;
}
[Benchmark]
public long BenchmarkLargeClass()
{
long sum = 0;
for (int i = 0; i < N; i++)
sum += _data[i] + SumClass(_largeClass);
return sum;
}
[Benchmark]
public long BenchmarkLargeStruct()
{
long sum = 0;
for (int i = 0; i < N; i++)
sum += _data[i] + SumStruct(_largeStruct);
return sum;
}
[Benchmark]
public long BenchmarkLargeStructByRef()
{
long sum = 0;
for (int i = 0; i < N; i++)
sum += _data[i] + SumStructByRef(_largeStruct);
return sum;
}
[Benchmark]
public long BenchmarkVeryLargeClass()
{
long sum = 0;
for (int i = 0; i < N; i++)
sum += _data[i] + SumClass(_veryLargeClass);
return sum;
}
[Benchmark]
public long BenchmarkVeryLargeStruct()
{
long sum = 0;
for (int i = 0; i < N; i++)
sum += _data[i] + SumStruct(_veryLargeStruct);
return sum;
}
[Benchmark]
public long BenchmarkVeryLargeStructByRef()
{
long sum = 0;
for (int i = 0; i < N; i++)
sum += _data[i] + SumStructByRef(_veryLargeStruct);
return sum;
}
private long SumClass(MediumClass value) => value.V + value.X;
private long SumStruct(MediumStruct value) => value.V + value.X;
private long SumStructByRef(MediumStruct value) => value.V + value.X;
private long SumClass(LargeClass value) => value.V + value.X + value.Y + value.Z;
private long SumStruct(LargeStruct value) => value.V + value.X + value.Y + value.Z;
private long SumStructByRef(in LargeStruct value) => value.V + value.X + value.Y + value.Z;
private long SumClass(VeryLargeClass value) => value.A + value.B + value.C + value.D + value.V + value.X + value.Y + value.Z;
private long SumStruct(VeryLargeStruct value) => value.A + value.B + value.C + value.D + value.V + value.X + value.Y + value.Z;
private long SumStructByRef(in VeryLargeStruct value) => value.A + value.B + value.C + value.D + value.V + value.X + value.Y + value.Z;
}
public sealed class MediumClass
{
public MediumClass(long v, long x)
{
V = v;
X = x;
}
public long V { get; }
public long X { get; }
}
public readonly struct MediumStruct
{
public MediumStruct(long v, long x)
{
V = v;
X = x;
}
public long V { get; }
public long X { get; }
}
public sealed class LargeClass
{
public LargeClass(long v, long x, long y, long z)
{
V = v;
X = x;
Y = y;
Z = z;
}
public long V { get; }
public long X { get; }
public long Y { get; }
public long Z { get; }
}
public readonly struct LargeStruct
{
public LargeStruct(long v, long x, long y, long z)
{
V = v;
X = x;
Y = y;
Z = z;
}
public long V { get; }
public long X { get; }
public long Y { get; }
public long Z { get; }
}
public sealed class VeryLargeClass
{
public VeryLargeClass(long a, long b, long c, long d, long v, long x, long y, long z)
{
A = a;
B = b;
C = c;
D = d;
V = v;
X = x;
Y = y;
Z = z;
}
public long A { get; }
public long B { get; }
public long C { get; }
public long D { get; }
public long V { get; }
public long X { get; }
public long Y { get; }
public long Z { get; }
}
public readonly struct VeryLargeStruct
{
public VeryLargeStruct(long a, long b, long c, long d, long v, long x, long y, long z)
{
A = a;
B = b;
C = c;
D = d;
V = v;
X = x;
Y = y;
Z = z;
}
public long A { get; }
public long B { get; }
public long C { get; }
public long D { get; }
public long V { get; }
public long X { get; }
public long Y { get; }
public long Z { get; }
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.11.5" />
</ItemGroup>
</Project>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment