-
-
Save AndreyAkinshin/6bb05400d327ed98370ea4c42a221170 to your computer and use it in GitHub Desktop.
DotNextSpb2017
This file contains 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.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