Skip to content

Instantly share code, notes, and snippets.

@AndreyAkinshin
Created May 15, 2017 15:56
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save AndreyAkinshin/6bb05400d327ed98370ea4c42a221170 to your computer and use it in GitHub Desktop.
Save AndreyAkinshin/6bb05400d327ed98370ea4c42a221170 to your computer and use it in GitHub Desktop.
DotNextSpb2017
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