Skip to content

Instantly share code, notes, and snippets.

@afish

afish/Program.cs Secret

Created July 10, 2018 03:33
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 afish/b79afe5f350534c19bc1ffeaa6435082 to your computer and use it in GitHub Desktop.
Save afish/b79afe5f350534c19bc1ffeaa6435082 to your computer and use it in GitHub Desktop.
UnsafeList benchmark
using System;
using System.Collections.Generic;
using System.Collections;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes.Columns;
using BenchmarkDotNet.Attributes.Exporters;
using BenchmarkDotNet.Attributes.Jobs;
using BenchmarkDotNet.Running;
using UnsafeListSpace;
using UnsafeList_bench;
namespace UnsafeListSpace
{
public class UnsafeList<T> : IEnumerable where T : class
{
private readonly int _elementSize;
private T _target;
private int[] _storage;
private int _currentIndex = -1;
private readonly T[] _elements;
public UnsafeList(int size, int elementSize)
{
_elementSize = elementSize + 1;
_storage = new int[size * _elementSize];
_elements = new T[size];
_target = default(T);
}
public void Add(T item)
{
_currentIndex++;
unsafe
{
TypedReference reference = __makeref(item);
int* itemAddress = (int*)(*(int*)*(int*)&reference - 4);
for (int i = 1; i < _elementSize; ++i)
{
_storage[_currentIndex * _elementSize + i] = *itemAddress;
itemAddress = itemAddress + 1;
}
reference = __makeref(_storage);
_storage[_currentIndex * _elementSize] = *(int*)*(int*)&reference + _currentIndex * _elementSize * 4 + 16;
_elements[_currentIndex] = GetInternal(_currentIndex);
}
}
private T GetInternal(int index)
{
unsafe
{
TypedReference reference = __makeref(_target);
*(int*)*(int*)&reference = _storage[index * _elementSize];
T result = __refvalue(reference, T);
return result;
}
}
public T Get(int index)
{
return _elements[index];
}
public IEnumerator<T> GetEnumerator()
{
return new CustomEnumerator<T>(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private class CustomEnumerator<T> : IEnumerator<T> where T : class
{
private readonly UnsafeList<T> _list;
private int _index;
private T _current;
private int size;
public CustomEnumerator(UnsafeList<T> list)
{
_list = list;
_index = -1;
size = _list._currentIndex;
}
public void Dispose()
{
}
public bool MoveNext()
{
_index++;
if (_index <= size)
{
_current = _list.Get(_index);
return true;
}
return false;
}
public void Reset()
{
_index = -1;
}
public T Current
{
get { return _current; }
}
object IEnumerator.Current
{
get { return _current; }
}
}
}
}
namespace UnsafeList_bench
{
public static class Settings
{
public static int elementsCount = 2 * 1000 * 1000;
}
public class Poco
{
public int Field1;
public int Field2;
public int Field3;
public int Field4;
public int Field5;
public int Field6;
public int Field7;
public int Field8;
public int Field9;
public int Field10;
public int Field11;
public int Field12;
public int Field13;
public int Field14;
public int Field15;
public int Field16;
public static Poco CreatePoco(int i)
{
return new Poco
{
Field1 = i,
Field2 = i - 1,
Field3 = i - 2,
Field4 = i - 3,
Field5 = i - 4,
Field6 = i - 5,
Field7 = i - 6,
Field8 = i - 7,
Field9 = i - 7,
Field10 = i - 6,
Field11 = i - 5,
Field12 = i - 4,
Field13 = i - 3,
Field14 = i - 2,
Field15 = i - 1,
Field16 = i
};
}
}
[ClrJob(isBaseline: true)]
[RPlotExporter, RankColumn]
public class Insertion
{
Poco[] array;
List<Poco> list;
UnsafeList<Poco> unsafeList;
[Benchmark]
public void ArrayInsertion()
{
array = new Poco[Settings.elementsCount];
for (int i = 0; i < Settings.elementsCount; ++i)
{
var poco = Poco.CreatePoco(i);
array[i] = poco;
}
}
[Benchmark]
public void ListInsertion()
{
list = new List<Poco>(Settings.elementsCount);
for (int i = 0; i < Settings.elementsCount; ++i)
{
var poco = Poco.CreatePoco(i);
list.Add(poco);
}
}
[Benchmark]
public void UnsafeInsertion()
{
unsafeList = new UnsafeList<Poco>(Settings.elementsCount, 18);
for (int i = 0; i < Settings.elementsCount; ++i)
{
var poco = Poco.CreatePoco(i);
unsafeList.Add(poco);
}
}
}
}
namespace UnsafeListBench
{
public class Program
{
public static void Main(string[] args)
{
var insertion = BenchmarkRunner.Run<Insertion>();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment