This is the eleventh part of the Custom memory allocation series. For your convenience you can find other parts in the table of contents in Part 1 — Allocating object on a stack

I presented some results suggesting that UnsafeList is faster than the array or List< T> in .NET. Today it’s time to run some more serious benchmark to verify if it is so.

I am running this on Runtime=.NET Framework 4.6.1 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.2671.0 and BenchmarkDotNet=v0.10.14, OS=Windows 10.0.15063.1155 (1703/CreatorsUpdate/Redstone2) Intel Core i5-6300U CPU 2.40GHz (Skylake), 1 CPU, 4 logical and 2 physical cores Frequency=2437502 Hz, Resolution=410.2561 ns, Timer=TSC, as reported by BenchmarkDotNet. The benchmark code is below:

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>();
        }
    }
}

And here are the results:

// ***** BenchmarkRunner: Start   *****
// Found benchmarks:
//   Insertion.ArrayInsertion: Job-JWVBYN(Runtime=Clr, IsBaseline=True)
//   Insertion.ListInsertion: Job-JWVBYN(Runtime=Clr, IsBaseline=True)
//   Insertion.UnsafeInsertion: Job-JWVBYN(Runtime=Clr, IsBaseline=True)

// Validating benchmarks:
// ***** Building 3 benchmark(s) in Parallel: Start   *****
// ***** Done, took 00:00:03 (3.06 sec)   *****
// **************************
// Benchmark: Insertion.ArrayInsertion: Job-JWVBYN(Runtime=Clr, IsBaseline=True)
// *** Execute ***
// Launch: 1 / 1
// Execute: C:\Users\adafurma\Desktop\msp_windowsinternals\UnsafeList_bench\bin\Release\d805cc7b-c85b-4054-ace6-aee8f9b905ee.exe
// BeforeAnythingElse

// Benchmark Process Environment Information:
// Runtime=.NET Framework 4.6.1 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.2671.0
// GC=Concurrent Workstation
// Job: Job-JWVBYN(Runtime=Clr, IsBaseline=True)

Pilot  1: 16 op, 7154233309.35 ns, 447.1396 ms/op

IdleWarmup  1: 16 op, 4923.07 ns, 307.6921 ns/op
IdleWarmup  2: 16 op, 820.51 ns, 51.2820 ns/op
IdleWarmup  3: 16 op, 820.51 ns, 51.2820 ns/op
IdleWarmup  4: 16 op, 820.51 ns, 51.2820 ns/op
IdleWarmup  5: 16 op, 820.51 ns, 51.2820 ns/op
IdleWarmup  6: 16 op, 820.51 ns, 51.2820 ns/op

IdleTarget  1: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  2: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  3: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  4: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  5: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  6: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  7: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  8: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  9: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget 10: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget 11: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget 12: 16 op, 1230.77 ns, 76.9230 ns/op
IdleTarget 13: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget 14: 16 op, 410.26 ns, 25.6410 ns/op
IdleTarget 15: 16 op, 820.51 ns, 51.2820 ns/op

MainWarmup  1: 16 op, 7348565457.59 ns, 459.2853 ms/op
MainWarmup  2: 16 op, 6721045972.48 ns, 420.0654 ms/op
MainWarmup  3: 16 op, 6574619015.70 ns, 410.9137 ms/op
MainWarmup  4: 16 op, 6977985248.83 ns, 436.1241 ms/op
MainWarmup  5: 16 op, 6743144005.63 ns, 421.4465 ms/op
MainWarmup  6: 16 op, 7115597853.87 ns, 444.7249 ms/op
MainWarmup  7: 16 op, 6551240573.34 ns, 409.4525 ms/op

// BeforeMainRun
MainTarget  1: 16 op, 6568242405.54 ns, 410.5152 ms/op
MainTarget  2: 16 op, 7025800594.21 ns, 439.1125 ms/op
MainTarget  3: 16 op, 6979129042.77 ns, 436.1956 ms/op
MainTarget  4: 16 op, 6957845367.92 ns, 434.8653 ms/op
MainTarget  5: 16 op, 6462374184.72 ns, 403.8984 ms/op
MainTarget  6: 16 op, 6577030911.15 ns, 411.0644 ms/op
MainTarget  7: 16 op, 6869308414.93 ns, 429.3318 ms/op
MainTarget  8: 16 op, 7016557524.88 ns, 438.5348 ms/op
MainTarget  9: 16 op, 6861911087.66 ns, 428.8694 ms/op
MainTarget 10: 16 op, 6520966136.64 ns, 407.5604 ms/op
MainTarget 11: 16 op, 7403562745.79 ns, 462.7227 ms/op
MainTarget 12: 16 op, 7025309927.95 ns, 439.0819 ms/op
MainTarget 13: 16 op, 7056687132.97 ns, 441.0429 ms/op
MainTarget 14: 16 op, 7018985420.32 ns, 438.6866 ms/op
MainTarget 15: 16 op, 6581938394.31 ns, 411.3711 ms/op
MainTarget 16: 16 op, 6536139457.53 ns, 408.5087 ms/op
MainTarget 17: 16 op, 7338629876.00 ns, 458.6644 ms/op
MainTarget 18: 16 op, 7956029574.54 ns, 497.2518 ms/op
MainTarget 19: 16 op, 7415085608.13 ns, 463.4429 ms/op
MainTarget 20: 16 op, 7052814725.90 ns, 440.8009 ms/op
MainTarget 21: 16 op, 6651503875.69 ns, 415.7190 ms/op
MainTarget 22: 16 op, 7024414338.94 ns, 439.0259 ms/op
MainTarget 23: 16 op, 6871126669.84 ns, 429.4454 ms/op
MainTarget 24: 16 op, 6580886497.73 ns, 411.3054 ms/op
MainTarget 25: 16 op, 6582526291.26 ns, 411.4079 ms/op
MainTarget 26: 16 op, 7074069272.56 ns, 442.1293 ms/op
MainTarget 27: 16 op, 7400710235.31 ns, 462.5444 ms/op
MainTarget 28: 16 op, 6493476518.17 ns, 405.8423 ms/op
MainTarget 29: 16 op, 7176358829.65 ns, 448.5224 ms/op
MainTarget 30: 16 op, 6491634878.66 ns, 405.7272 ms/op
MainTarget 31: 16 op, 7062434410.31 ns, 441.4022 ms/op
MainTarget 32: 16 op, 6694712865.88 ns, 418.4196 ms/op
MainTarget 33: 16 op, 6929649288.49 ns, 433.1031 ms/op
MainTarget 34: 16 op, 7027410439.05 ns, 439.2132 ms/op
MainTarget 35: 16 op, 7053880160.92 ns, 440.8675 ms/op
MainTarget 36: 16 op, 7336032544.79 ns, 458.5020 ms/op
MainTarget 37: 16 op, 7431532774.13 ns, 464.4708 ms/op
MainTarget 38: 16 op, 7113560932.46 ns, 444.5976 ms/op
MainTarget 39: 16 op, 6931749389.33 ns, 433.2343 ms/op
MainTarget 40: 16 op, 6524895569.32 ns, 407.8060 ms/op
MainTarget 41: 16 op, 6802759546.45 ns, 425.1725 ms/op
MainTarget 42: 16 op, 6874988000.01 ns, 429.6868 ms/op
MainTarget 43: 16 op, 6883799890.22 ns, 430.2375 ms/op
MainTarget 44: 16 op, 6945833890.60 ns, 434.1146 ms/op
MainTarget 45: 16 op, 7085936750.00 ns, 442.8710 ms/op
MainTarget 46: 16 op, 6507693121.89 ns, 406.7308 ms/op
MainTarget 47: 16 op, 6989439598.41 ns, 436.8400 ms/op
MainTarget 48: 16 op, 7018757317.94 ns, 438.6723 ms/op
MainTarget 49: 16 op, 6781371666.57 ns, 423.8357 ms/op
MainTarget 50: 16 op, 7040904171.57 ns, 440.0565 ms/op

// AfterMainRun
Result  1: 16 op, 6568241585.03 ns, 410.5151 ms/op
Result  2: 16 op, 7025799773.70 ns, 439.1125 ms/op
Result  3: 16 op, 6979128222.25 ns, 436.1955 ms/op
Result  4: 16 op, 6957844547.41 ns, 434.8653 ms/op
Result  5: 16 op, 6462373364.21 ns, 403.8983 ms/op
Result  6: 16 op, 6577030090.64 ns, 411.0644 ms/op
Result  7: 16 op, 6869307594.41 ns, 429.3317 ms/op
Result  8: 16 op, 7016556704.36 ns, 438.5348 ms/op
Result  9: 16 op, 6861910267.15 ns, 428.8694 ms/op
Result 10: 16 op, 6520965316.13 ns, 407.5603 ms/op
Result 11: 16 op, 7403561925.28 ns, 462.7226 ms/op
Result 12: 16 op, 7025309107.44 ns, 439.0818 ms/op
Result 13: 16 op, 7056686312.46 ns, 441.0429 ms/op
Result 14: 16 op, 7018984599.81 ns, 438.6865 ms/op
Result 15: 16 op, 6581937573.79 ns, 411.3711 ms/op
Result 16: 16 op, 6536138637.01 ns, 408.5087 ms/op
Result 17: 16 op, 7338629055.48 ns, 458.6643 ms/op
Result 18: 16 op, 7415084787.62 ns, 463.4428 ms/op
Result 19: 16 op, 7052813905.38 ns, 440.8009 ms/op
Result 20: 16 op, 6651503055.18 ns, 415.7189 ms/op
Result 21: 16 op, 7024413518.43 ns, 439.0258 ms/op
Result 22: 16 op, 6871125849.33 ns, 429.4454 ms/op
Result 23: 16 op, 6580885677.22 ns, 411.3054 ms/op
Result 24: 16 op, 6582525470.75 ns, 411.4078 ms/op
Result 25: 16 op, 7074068452.05 ns, 442.1293 ms/op
Result 26: 16 op, 7400709414.80 ns, 462.5443 ms/op
Result 27: 16 op, 6493475697.66 ns, 405.8422 ms/op
Result 28: 16 op, 7176358009.14 ns, 448.5224 ms/op
Result 29: 16 op, 6491634058.15 ns, 405.7271 ms/op
Result 30: 16 op, 7062433589.80 ns, 441.4021 ms/op
Result 31: 16 op, 6694712045.36 ns, 418.4195 ms/op
Result 32: 16 op, 6929648467.98 ns, 433.1030 ms/op
Result 33: 16 op, 7027409618.54 ns, 439.2131 ms/op
Result 34: 16 op, 7053879340.41 ns, 440.8675 ms/op
Result 35: 16 op, 7336031724.28 ns, 458.5020 ms/op
Result 36: 16 op, 7431531953.61 ns, 464.4707 ms/op
Result 37: 16 op, 7113560111.95 ns, 444.5975 ms/op
Result 38: 16 op, 6931748568.82 ns, 433.2343 ms/op
Result 39: 16 op, 6524894748.80 ns, 407.8059 ms/op
Result 40: 16 op, 6802758725.94 ns, 425.1724 ms/op
Result 41: 16 op, 6874987179.50 ns, 429.6867 ms/op
Result 42: 16 op, 6883799069.70 ns, 430.2374 ms/op
Result 43: 16 op, 6945833070.09 ns, 434.1146 ms/op
Result 44: 16 op, 7085935929.49 ns, 442.8710 ms/op
Result 45: 16 op, 6507692301.38 ns, 406.7308 ms/op
Result 46: 16 op, 6989438777.90 ns, 436.8399 ms/op
Result 47: 16 op, 7018756497.43 ns, 438.6723 ms/op
Result 48: 16 op, 6781370846.05 ns, 423.8357 ms/op
Result 49: 16 op, 7040903351.05 ns, 440.0565 ms/op
GC:  0 0 0 0 0

// AfterAll

Mean = 431.9545 ms, StdErr = 2.4464 ms (0.57%); N = 49, StdDev = 17.1251 ms
Min = 403.8983 ms, Q1 = 413.5634 ms, Median = 434.8653 ms, Q3 = 440.9552 ms, Max = 464.4707 ms
IQR = 27.3918 ms, LowerFence = 372.4757 ms, UpperFence = 482.0429 ms
ConfidenceInterval = [423.3796 ms; 440.5294 ms] (CI 99.9%), Margin = 8.5749 ms (1.99% of Mean)
Skewness = 0.03, Kurtosis = 2.15, MValue = 2.92

// **************************
// Benchmark: Insertion.ListInsertion: Job-JWVBYN(Runtime=Clr, IsBaseline=True)
// *** Execute ***
// Launch: 1 / 1
// Execute: C:\Users\adafurma\Desktop\msp_windowsinternals\UnsafeList_bench\bin\Release\ea9fd2e7-c387-4ac9-a241-2c646415e1f9.exe
// BeforeAnythingElse

// Benchmark Process Environment Information:
// Runtime=.NET Framework 4.6.1 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.2671.0
// GC=Concurrent Workstation
// Job: Job-JWVBYN(Runtime=Clr, IsBaseline=True)

Pilot  1: 16 op, 7325801578.83 ns, 457.8626 ms/op

IdleWarmup  1: 16 op, 4923.07 ns, 307.6921 ns/op
IdleWarmup  2: 16 op, 820.51 ns, 51.2820 ns/op
IdleWarmup  3: 16 op, 820.51 ns, 51.2820 ns/op
IdleWarmup  4: 16 op, 410.26 ns, 25.6410 ns/op
IdleWarmup  5: 16 op, 820.51 ns, 51.2820 ns/op
IdleWarmup  6: 16 op, 1230.77 ns, 76.9230 ns/op
IdleWarmup  7: 16 op, 820.51 ns, 51.2820 ns/op

IdleTarget  1: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  2: 16 op, 410.26 ns, 25.6410 ns/op
IdleTarget  3: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  4: 16 op, 410.26 ns, 25.6410 ns/op
IdleTarget  5: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  6: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  7: 16 op, 1230.77 ns, 76.9230 ns/op
IdleTarget  8: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  9: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget 10: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget 11: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget 12: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget 13: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget 14: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget 15: 16 op, 820.51 ns, 51.2820 ns/op

MainWarmup  1: 16 op, 6761338041.98 ns, 422.5836 ms/op
MainWarmup  2: 16 op, 6632286660.69 ns, 414.5179 ms/op
MainWarmup  3: 16 op, 6703430397.19 ns, 418.9644 ms/op
MainWarmup  4: 16 op, 6916518222.34 ns, 432.2824 ms/op
MainWarmup  5: 16 op, 6656070436.04 ns, 416.0044 ms/op
MainWarmup  6: 16 op, 7126314563.02 ns, 445.3947 ms/op
MainWarmup  7: 16 op, 6678495443.29 ns, 417.4060 ms/op

// BeforeMainRun
MainTarget  1: 16 op, 7399429005.60 ns, 462.4643 ms/op
MainTarget  2: 16 op, 6901733824.22 ns, 431.3584 ms/op
MainTarget  3: 16 op, 6917735452.11 ns, 432.3585 ms/op
MainTarget  4: 16 op, 7076888962.55 ns, 442.3056 ms/op
MainTarget  5: 16 op, 6564660459.77 ns, 410.2913 ms/op
MainTarget  6: 16 op, 6586053262.73 ns, 411.6283 ms/op
MainTarget  7: 16 op, 7234502371.69 ns, 452.1564 ms/op
MainTarget  8: 16 op, 6908187972.77 ns, 431.7617 ms/op
MainTarget  9: 16 op, 6648146750.24 ns, 415.5092 ms/op
MainTarget 10: 16 op, 6808872361.95 ns, 425.5545 ms/op
MainTarget 11: 16 op, 6646745315.49 ns, 415.4216 ms/op
MainTarget 12: 16 op, 6832064137.79 ns, 427.0040 ms/op
MainTarget 13: 16 op, 6618488928.42 ns, 413.6556 ms/op
MainTarget 14: 16 op, 6833884443.99 ns, 427.1178 ms/op
MainTarget 15: 16 op, 6873002770.87 ns, 429.5627 ms/op
MainTarget 16: 16 op, 7127737741.34 ns, 445.4836 ms/op
MainTarget 17: 16 op, 7133032506.23 ns, 445.8145 ms/op
MainTarget 18: 16 op, 7504547278.32 ns, 469.0342 ms/op
MainTarget 19: 16 op, 7143976907.51 ns, 446.4986 ms/op
MainTarget 20: 16 op, 6727426685.19 ns, 420.4642 ms/op
MainTarget 21: 16 op, 6647545725.09 ns, 415.4716 ms/op
MainTarget 22: 16 op, 7070121788.62 ns, 441.8826 ms/op
MainTarget 23: 16 op, 7204433883.54 ns, 450.2771 ms/op
MainTarget 24: 16 op, 6961947518.40 ns, 435.1217 ms/op
MainTarget 25: 16 op, 6876601537.15 ns, 429.7876 ms/op
MainTarget 26: 16 op, 6796513807.99 ns, 424.7821 ms/op
MainTarget 27: 16 op, 7037623764.00 ns, 439.8515 ms/op
MainTarget 28: 16 op, 6720519203.68 ns, 420.0325 ms/op
MainTarget 29: 16 op, 6992796723.86 ns, 437.0498 ms/op
MainTarget 30: 16 op, 6845292844.89 ns, 427.8308 ms/op
MainTarget 31: 16 op, 6802711136.24 ns, 425.1694 ms/op
MainTarget 32: 16 op, 7084377776.92 ns, 442.7736 ms/op
MainTarget 33: 16 op, 7076028655.57 ns, 442.2518 ms/op
MainTarget 34: 16 op, 6895445829.38 ns, 430.9654 ms/op

// AfterMainRun
Result  1: 16 op, 7399428212.43 ns, 462.4643 ms/op
Result  2: 16 op, 6901733031.06 ns, 431.3583 ms/op
Result  3: 16 op, 6917734658.95 ns, 432.3584 ms/op
Result  4: 16 op, 7076888169.39 ns, 442.3055 ms/op
Result  5: 16 op, 6564659666.60 ns, 410.2912 ms/op
Result  6: 16 op, 6586052469.56 ns, 411.6283 ms/op
Result  7: 16 op, 7234501578.53 ns, 452.1563 ms/op
Result  8: 16 op, 6908187179.61 ns, 431.7617 ms/op
Result  9: 16 op, 6648145957.08 ns, 415.5091 ms/op
Result 10: 16 op, 6808871568.79 ns, 425.5545 ms/op
Result 11: 16 op, 6646744522.33 ns, 415.4215 ms/op
Result 12: 16 op, 6832063344.63 ns, 427.0040 ms/op
Result 13: 16 op, 6618488135.26 ns, 413.6555 ms/op
Result 14: 16 op, 6833883650.83 ns, 427.1177 ms/op
Result 15: 16 op, 6873001977.71 ns, 429.5626 ms/op
Result 16: 16 op, 7127736948.18 ns, 445.4836 ms/op
Result 17: 16 op, 7133031713.07 ns, 445.8145 ms/op
Result 18: 16 op, 7143976114.34 ns, 446.4985 ms/op
Result 19: 16 op, 6727425892.03 ns, 420.4641 ms/op
Result 20: 16 op, 6647544931.93 ns, 415.4716 ms/op
Result 21: 16 op, 7070120995.46 ns, 441.8826 ms/op
Result 22: 16 op, 7204433090.38 ns, 450.2771 ms/op
Result 23: 16 op, 6961946725.24 ns, 435.1217 ms/op
Result 24: 16 op, 6876600743.99 ns, 429.7875 ms/op
Result 25: 16 op, 6796513014.83 ns, 424.7821 ms/op
Result 26: 16 op, 7037622970.84 ns, 439.8514 ms/op
Result 27: 16 op, 6720518410.51 ns, 420.0324 ms/op
Result 28: 16 op, 6992795930.70 ns, 437.0497 ms/op
Result 29: 16 op, 6845292051.73 ns, 427.8308 ms/op
Result 30: 16 op, 6802710343.08 ns, 425.1694 ms/op
Result 31: 16 op, 7084376983.76 ns, 442.7736 ms/op
Result 32: 16 op, 7076027862.40 ns, 442.2517 ms/op
Result 33: 16 op, 6895445036.22 ns, 430.9653 ms/op
GC:  0 0 0 0 0

// AfterAll

Mean = 431.8078 ms, StdErr = 2.2424 ms (0.52%); N = 33, StdDev = 12.8817 ms
Min = 410.2912 ms, Q1 = 422.6231 ms, Median = 430.9653 ms, Q3 = 442.2786 ms, Max = 462.4643 ms
IQR = 19.6555 ms, LowerFence = 393.1398 ms, UpperFence = 471.7619 ms
ConfidenceInterval = [423.6862 ms; 439.9294 ms] (CI 99.9%), Margin = 8.1216 ms (1.88% of Mean)
Skewness = 0.22, Kurtosis = 2.3, MValue = 2

// **************************
// Benchmark: Insertion.UnsafeInsertion: Job-JWVBYN(Runtime=Clr, IsBaseline=True)
// *** Execute ***
// Launch: 1 / 1
// Execute: C:\Users\adafurma\Desktop\msp_windowsinternals\UnsafeList_bench\bin\Release\e5bd0317-c5b3-4eb6-b295-ba981cf5385f.exe
// BeforeAnythingElse

// Benchmark Process Environment Information:
// Runtime=.NET Framework 4.6.1 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.2671.0
// GC=Concurrent Workstation
// Job: Job-JWVBYN(Runtime=Clr, IsBaseline=True)

Pilot  1: 16 op, 3139367270.26 ns, 196.2105 ms/op

IdleWarmup  1: 16 op, 22153.83 ns, 1.3846 us/op
IdleWarmup  2: 16 op, 820.51 ns, 51.2820 ns/op
IdleWarmup  3: 16 op, 410.26 ns, 25.6410 ns/op
IdleWarmup  4: 16 op, 820.51 ns, 51.2820 ns/op
IdleWarmup  5: 16 op, 410.26 ns, 25.6410 ns/op
IdleWarmup  6: 16 op, 820.51 ns, 51.2820 ns/op
IdleWarmup  7: 16 op, 820.51 ns, 51.2820 ns/op

IdleTarget  1: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  2: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  3: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  4: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  5: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  6: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  7: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  8: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget  9: 16 op, 410.26 ns, 25.6410 ns/op
IdleTarget 10: 16 op, 410.26 ns, 25.6410 ns/op
IdleTarget 11: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget 12: 16 op, 410.26 ns, 25.6410 ns/op
IdleTarget 13: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget 14: 16 op, 820.51 ns, 51.2820 ns/op
IdleTarget 15: 16 op, 820.51 ns, 51.2820 ns/op

MainWarmup  1: 16 op, 3229808221.70 ns, 201.8630 ms/op
MainWarmup  2: 16 op, 3250355897.14 ns, 203.1472 ms/op
MainWarmup  3: 16 op, 3269364702.06 ns, 204.3353 ms/op
MainWarmup  4: 16 op, 3161877610.77 ns, 197.6174 ms/op
MainWarmup  5: 16 op, 3118733851.30 ns, 194.9209 ms/op
MainWarmup  6: 16 op, 3091931822.00 ns, 193.2457 ms/op
MainWarmup  7: 16 op, 3145536701.10 ns, 196.5960 ms/op
MainWarmup  8: 16 op, 3076411834.74 ns, 192.2757 ms/op

// BeforeMainRun
MainTarget  1: 16 op, 3144651778.75 ns, 196.5407 ms/op
MainTarget  2: 16 op, 3114337136.95 ns, 194.6461 ms/op
MainTarget  3: 16 op, 3148537314.02 ns, 196.7836 ms/op
MainTarget  4: 16 op, 3149704082.29 ns, 196.8565 ms/op
MainTarget  5: 16 op, 3173224063.00 ns, 198.3265 ms/op
MainTarget  6: 16 op, 3106977553.25 ns, 194.1861 ms/op
MainTarget  7: 16 op, 3171334833.78 ns, 198.2084 ms/op
MainTarget  8: 16 op, 3454962498.49 ns, 215.9352 ms/op
MainTarget  9: 16 op, 3117861236.63 ns, 194.8663 ms/op
MainTarget 10: 16 op, 3136003580.72 ns, 196.0002 ms/op
MainTarget 11: 16 op, 3194968045.15 ns, 199.6855 ms/op
MainTarget 12: 16 op, 3150785107.05 ns, 196.9241 ms/op
MainTarget 13: 16 op, 3104535709.10 ns, 194.0335 ms/op
MainTarget 14: 16 op, 3113840316.85 ns, 194.6150 ms/op
MainTarget 15: 16 op, 3145571162.61 ns, 196.5982 ms/op

// AfterMainRun
Result  1: 16 op, 3144651040.29 ns, 196.5407 ms/op
Result  2: 16 op, 3114336398.49 ns, 194.6460 ms/op
Result  3: 16 op, 3148536575.56 ns, 196.7835 ms/op
Result  4: 16 op, 3149703343.83 ns, 196.8565 ms/op
Result  5: 16 op, 3173223324.53 ns, 198.3265 ms/op
Result  6: 16 op, 3106976814.79 ns, 194.1861 ms/op
Result  7: 16 op, 3171334095.32 ns, 198.2084 ms/op
Result  8: 16 op, 3117860498.17 ns, 194.8663 ms/op
Result  9: 16 op, 3136002842.25 ns, 196.0002 ms/op
Result 10: 16 op, 3194967306.69 ns, 199.6855 ms/op
Result 11: 16 op, 3150784368.59 ns, 196.9240 ms/op
Result 12: 16 op, 3104534970.64 ns, 194.0334 ms/op
Result 13: 16 op, 3113839578.39 ns, 194.6150 ms/op
Result 14: 16 op, 3145570424.15 ns, 196.5982 ms/op
GC:  0 0 0 0 0

// AfterAll

Mean = 196.3050 ms, StdErr = 0.4546 ms (0.23%); N = 14, StdDev = 1.7010 ms
Min = 194.0334 ms, Q1 = 194.6460 ms, Median = 196.5694 ms, Q3 = 196.9240 ms, Max = 199.6855 ms
IQR = 2.2780 ms, LowerFence = 191.2290 ms, UpperFence = 200.3410 ms
ConfidenceInterval = [194.3861 ms; 198.2239 ms] (CI 99.9%), Margin = 1.9189 ms (0.98% of Mean)
Skewness = 0.3, Kurtosis = 1.94, MValue = 2

// ***** BenchmarkRunner: Finish  *****

// * Export *
  BenchmarkDotNet.Artifacts\results\Insertion-report.csv
  BenchmarkDotNet.Artifacts\results\Insertion-report-github.md
  BenchmarkDotNet.Artifacts\results\Insertion-report.html
  BenchmarkDotNet.Artifacts\results\Insertion-measurements.csv
  BuildPlots.R
RPlotExporter couldn't find Rscript.exe in your PATH and no R_HOME environment variable is defined

// * Detailed results *
Insertion.ArrayInsertion: Job-JWVBYN(Runtime=Clr, IsBaseline=True)
Runtime = .NET Framework 4.6.1 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.2671.0; GC = Concurrent Workstation
Mean = 431.9545 ms, StdErr = 2.4464 ms (0.57%); N = 49, StdDev = 17.1251 ms
Min = 403.8983 ms, Q1 = 413.5634 ms, Median = 434.8653 ms, Q3 = 440.9552 ms, Max = 464.4707 ms
IQR = 27.3918 ms, LowerFence = 372.4757 ms, UpperFence = 482.0429 ms
ConfidenceInterval = [423.3796 ms; 440.5294 ms] (CI 99.9%), Margin = 8.5749 ms (1.99% of Mean)
Skewness = 0.03, Kurtosis = 2.15, MValue = 2.92
-------------------- Histogram --------------------
[403.558 ms ; 412.899 ms) | @@@@@@@@@@@@
[412.899 ms ; 422.766 ms) | @@
[422.766 ms ; 432.702 ms) | @@@@@@@
[432.702 ms ; 449.779 ms) | @@@@@@@@@@@@@@@@@@@@@@
[449.779 ms ; 466.101 ms) | @@@@@@
---------------------------------------------------

Insertion.ListInsertion: Job-JWVBYN(Runtime=Clr, IsBaseline=True)
Runtime = .NET Framework 4.6.1 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.2671.0; GC = Concurrent Workstation
Mean = 431.8078 ms, StdErr = 2.2424 ms (0.52%); N = 33, StdDev = 12.8817 ms
Min = 410.2912 ms, Q1 = 422.6231 ms, Median = 430.9653 ms, Q3 = 442.2786 ms, Max = 462.4643 ms
IQR = 19.6555 ms, LowerFence = 393.1398 ms, UpperFence = 471.7619 ms
ConfidenceInterval = [423.6862 ms; 439.9294 ms] (CI 99.9%), Margin = 8.1216 ms (1.88% of Mean)
Skewness = 0.22, Kurtosis = 2.3, MValue = 2
-------------------- Histogram --------------------
[408.771 ms ; 423.989 ms) | @@@@@@@@
[423.989 ms ; 438.743 ms) | @@@@@@@@@@@@@@
[438.743 ms ; 455.729 ms) | @@@@@@@@@@
[455.729 ms ; 465.978 ms) | @
---------------------------------------------------

Insertion.UnsafeInsertion: Job-JWVBYN(Runtime=Clr, IsBaseline=True)
Runtime = .NET Framework 4.6.1 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.2671.0; GC = Concurrent Workstation
Mean = 196.3050 ms, StdErr = 0.4546 ms (0.23%); N = 14, StdDev = 1.7010 ms
Min = 194.0334 ms, Q1 = 194.6460 ms, Median = 196.5694 ms, Q3 = 196.9240 ms, Max = 199.6855 ms
IQR = 2.2780 ms, LowerFence = 191.2290 ms, UpperFence = 200.3410 ms
ConfidenceInterval = [194.3861 ms; 198.2239 ms] (CI 99.9%), Margin = 1.9189 ms (0.98% of Mean)
Skewness = 0.3, Kurtosis = 1.94, MValue = 2
-------------------- Histogram --------------------
[193.416 ms ; 200.303 ms) | @@@@@@@@@@@@@@
---------------------------------------------------

Total time: 00:13:48 (828.75 sec)

// * Summary *

BenchmarkDotNet=v0.10.14, OS=Windows 10.0.15063.1155 (1703/CreatorsUpdate/Redstone2)
Intel Core i5-6300U CPU 2.40GHz (Skylake), 1 CPU, 4 logical and 2 physical cores
Frequency=2437502 Hz, Resolution=410.2561 ns, Timer=TSC
  [Host]     : .NET Framework 4.6.1 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.2671.0
  Job-JWVBYN : .NET Framework 4.6.1 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.2671.0

Runtime=Clr  IsBaseline=True

          Method |     Mean |    Error |    StdDev | Scaled | Rank |
---------------- |---------:|---------:|----------:|-------:|-----:|
  ArrayInsertion | 432.0 ms | 8.575 ms | 17.125 ms |   1.00 |    1 |
                 |          |          |           |        |      |
   ListInsertion | 431.8 ms | 8.122 ms | 12.882 ms |   1.00 |    1 |
                 |          |          |           |        |      |
 UnsafeInsertion | 196.3 ms | 1.919 ms |  1.701 ms |   1.00 |    1 |

// * Warnings *
MultimodalDistribution
  Insertion.ArrayInsertion: Runtime=Clr, IsBaseline=True -> It seems that the distribution can have several modes (mValue = 2.92307692307692)

// * Hints *
Outliers
  Insertion.ArrayInsertion: Runtime=Clr, IsBaseline=True  -> 1 outlier  was  removed
  Insertion.ListInsertion: Runtime=Clr, IsBaseline=True   -> 1 outlier  was  removed
  Insertion.UnsafeInsertion: Runtime=Clr, IsBaseline=True -> 1 outlier  was  removed

// * Legends *
  Mean   : Arithmetic mean of all measurements
  Error  : Half of 99.9% confidence interval
  StdDev : Standard deviation of all measurements
  Scaled : Mean(CurrentBenchmark) / Mean(BaselineBenchmark)
  Rank   : Relative position of current benchmark mean among all benchmarks (Arabic style)
  1 ms   : 1 Millisecond (0.001 sec)

// ***** BenchmarkRunner: End *****
// * Artifacts cleanup *

The most important part is here:

          Method |     Mean |    Error |    StdDev | Scaled | Rank |
---------------- |---------:|---------:|----------:|-------:|-----:|
  ArrayInsertion | 432.0 ms | 8.575 ms | 17.125 ms |   1.00 |    1 |
                 |          |          |           |        |      |
   ListInsertion | 431.8 ms | 8.122 ms | 12.882 ms |   1.00 |    1 |
                 |          |          |           |        |      |
 UnsafeInsertion | 196.3 ms | 1.919 ms |  1.701 ms |   1.00 |    1 |

I used 2 million elements for insertion and as we can see, UnsafeList is over two times faster.