using System; | |
using System.Collections.Generic; | |
using System.Runtime; | |
using System.Runtime.CompilerServices; | |
using System.Runtime.InteropServices; | |
using BenchmarkDotNet.Attributes; | |
using BenchmarkDotNet.Attributes.Columns; | |
using BenchmarkDotNet.Attributes.Exporters; | |
using BenchmarkDotNet.Attributes.Jobs; | |
using BenchmarkDotNet.Configs; | |
using BenchmarkDotNet.Horology; | |
using BenchmarkDotNet.Jobs; | |
using BenchmarkDotNet.Running; | |
// BenchmarkDotNet v0.10.6 | |
namespace DotNextSpb2017 | |
{ | |
[LegacyJitX86Job, MinColumn, MaxColumn, RPlotExporter] | |
public class CacheSize | |
{ | |
private const int N = 16 * 1024 * 1024; | |
private byte[] data; | |
[Params(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 6144, 8192, 16384, 32768)] | |
//[Params(2048, 4096, 6144)] | |
public int SizeKb; | |
[Setup] | |
public void Setup() => data = new byte[SizeKb * 1024]; | |
[Benchmark] | |
public void Calc() | |
{ | |
var mask = data.Length - 1; | |
for (int i = 0; i < N; i++) | |
data[(i * 64) & mask]++; | |
} | |
} | |
[LegacyJitX86Job] | |
public unsafe class CacheBankConflict | |
{ | |
private readonly int[] data = new int[2 * 1024 * 1024]; | |
[Params(15, 16, 17)] | |
public int Delta; | |
[Benchmark] | |
public bool Calc() | |
{ | |
fixed (int* dataPtr = data) | |
{ | |
int* ptr = dataPtr; | |
int d = Delta; | |
bool res = false; | |
for (int i = 0; i < 1024 * 1024; i++) | |
{ | |
res |= (ptr[0] < ptr[d]); | |
ptr++; | |
} | |
return res; | |
} | |
} | |
} | |
[LegacyJitX86Job] | |
public class CacheAssociativity | |
{ | |
private int[,] a; | |
[Params(511, 512, 513)] | |
public int N; | |
[Setup] | |
public void Setup() => a = new int[N, N]; | |
[Benchmark] | |
public int Max() | |
{ | |
var max = 0; | |
for (int i = 0; i < N; i++) | |
max = Math.Max(max, a[i, 0]); | |
return max; | |
} | |
} | |
[Config(typeof(Config))] | |
public class Aliasing4K | |
{ | |
public class Config : ManualConfig | |
{ | |
public Config() => Add(Job.LegacyJitX86.WithWarmupCount(10).WithLaunchCount(3).WithTargetCount(100) | |
.WithMinIterationTime(2 * TimeInterval.Second)); | |
} | |
private readonly byte[] data = new byte[32 * 1024 * 1024]; | |
private readonly int baseOffset; | |
public Aliasing4K() | |
{ | |
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); | |
IntPtr addrOfPinnedObject = handle.AddrOfPinnedObject(); | |
long address = addrOfPinnedObject.ToInt64(); | |
const int align = 4 * 1024; | |
baseOffset = ((int) (align - (address % (align)))); | |
} | |
[Params(0, 1)] | |
public int SrcOffset; | |
[Params(-65, -64, -63, -34, -33, -32, -31, -3, -2, -1, 0, 1, 2, 30, 31, 32, 33, 34, 63, 64, 65, 66)] | |
public int StrideOffset; | |
[Benchmark] | |
[MethodImpl(MethodImplOptions.NoInlining)] | |
public void ArrayCopy() => Array.Copy( | |
sourceArray: data, | |
sourceIndex: baseOffset + SrcOffset, | |
destinationArray: data, | |
destinationIndex: baseOffset + SrcOffset + (24 * 1024 + StrideOffset), | |
length: 16 * 1024); | |
} | |
[LegacyJitX86Job, RyuJitX64Job, MonoJob] | |
public class Alignment | |
{ | |
public struct Struct3 | |
{ | |
public byte X1, X2, X3; | |
} | |
public struct Struct8 | |
{ | |
public byte X1, X2, X3, X4, X5, X6, X7, X8; | |
} | |
private Struct3[] struct3 = new Struct3[256]; | |
private Struct8[] struct8 = new Struct8[256]; | |
[Benchmark] | |
public int S3() | |
{ | |
int res = 0; | |
for (int i = 0; i < struct3.Length; i++) | |
{ | |
var s = struct3[i]; | |
res += s.X1 + s.X2; | |
} | |
return res; | |
} | |
[Benchmark] | |
public int S8() | |
{ | |
int res = 0; | |
for (int i = 0; i < struct8.Length; i++) | |
{ | |
var s = struct8[i]; | |
res += s.X1 + s.X2; | |
} | |
return res; | |
} | |
} | |
[LegacyJitX86Job] | |
public class Prefetching | |
{ | |
private int[] data = new int[32 * 1024 * 1024]; | |
private int[] next = new int[32 * 1024 * 1024]; | |
private int n = 2000; | |
public Prefetching() | |
{ | |
var random = new Random(42); | |
for (int i = 0; i < data.Length; i++) | |
data[i] = random.Next(); | |
for (int i = 0; i < next.Length; i++) | |
next[i] = random.Next(data.Length); | |
} | |
// CPU-bound method | |
[MethodImpl(MethodImplOptions.NoInlining)] | |
private static int IsNice(int x) | |
{ | |
if (x % 13 == 0 | x % 17 == 0 | x % 19 == 0 | x % 43 == 0 | x % 71 == 0 | | |
x % 101 == 0 | x % 233 == 0 | x % 383 == 0 | x % 479 == 0 | x % 541 == 0) | |
return 1; | |
return 0; | |
} | |
[Benchmark(Baseline = true)] | |
public int Simple() | |
{ | |
var res = 0; | |
var index = 0; | |
for (int i = 0; i < n; i++) | |
{ | |
index = next[index]; | |
var x = data[index]; | |
res += IsNice(x); | |
} | |
return res; | |
} | |
[Benchmark] | |
public int Prefetch() | |
{ | |
var res = 0; | |
var index = next[0]; | |
var y = data[index]; | |
for (int i = 0; i < n; i++) | |
{ | |
var x = y; | |
index = next[index]; | |
y = data[index]; | |
res += IsNice(x); | |
} | |
return res; | |
} | |
} | |
[Config(typeof(Config))] | |
public class Loh | |
{ | |
private class Config : ManualConfig | |
{ | |
public Config() | |
{ | |
Add(Job.RyuJitX64.WithInvocationCount(1).WithUnrollFactor(1).WithWarmupCount(5).WithTargetCount(10)); | |
Add(Job.Mono.WithInvocationCount(1).WithUnrollFactor(1).WithWarmupCount(5).WithTargetCount(10)); | |
} | |
} | |
public class ChunkedArray<T> | |
{ | |
private readonly List<T[]> arrays; | |
public ChunkedArray(int n, int chunkSize) | |
{ | |
var elementSize = GetElementSize(); | |
arrays = new List<T[]>(); | |
while (n > 0) | |
{ | |
var size = Math.Min(n, chunkSize / elementSize); | |
arrays.Add(new T[size]); | |
n -= size; | |
} | |
} | |
private static int GetElementSize() | |
{ | |
if (typeof(T) == typeof(byte)) | |
return 1; | |
if (typeof(T) == typeof(object)) | |
return IntPtr.Size; | |
if (typeof(T) == typeof(long)) | |
return 8; | |
throw new ArgumentOutOfRangeException(); | |
} | |
} | |
public class Node<T> | |
{ | |
public ChunkedArray<T> Array { get; } | |
public Node<T> Next { get; } | |
public int X; | |
public Node(ChunkedArray<T> array, Node<T> next) | |
{ | |
Array = array; | |
Next = next; | |
} | |
~Node() => X++; | |
} | |
[Params(80000, 1000000000)] | |
public int ChunkSize; | |
public const int N = 1024 * 300; | |
public void Allocate<T>() | |
{ | |
var node = new Node<T>(new ChunkedArray<T>(N, ChunkSize), null); | |
for (int i = 0; i < 1000; i++) | |
node = new Node<T>(new ChunkedArray<T>(N, ChunkSize), (i % 50 == 0) ? null : node); | |
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; | |
GC.Collect(); | |
GC.WaitForPendingFinalizers(); | |
} | |
[Benchmark] | |
public void AllocateByte() => Allocate<byte>(); | |
[Benchmark] | |
public void AllocateObject() => Allocate<object>(); | |
[Benchmark] | |
public void AllocateLong() => Allocate<long>(); | |
} | |
internal class Program | |
{ | |
public static void Main(string[] args) | |
{ | |
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment