Skip to content

Instantly share code, notes, and snippets.

@HellBrick
Last active July 10, 2016 11:08
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 HellBrick/195c3c0f097f16bab6b4b5c6b659b654 to your computer and use it in GitHub Desktop.
Save HellBrick/195c3c0f097f16bab6b4b5c6b659b654 to your computer and use it in GitHub Desktop.
Enumerator benchmark
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnostics.Windows;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
namespace EnumeratorBoxingTest
{
internal class Program
{
private static void Main( string[] args )
{
var config
= ManualConfig
.Create( DefaultConfig.Instance )
.With( Job.RyuJitX64 )
.With( new MemoryDiagnoser() );
BenchmarkRunner.Run<EnumeratorBenchmark>( config );
}
}
public class EnumeratorBenchmark
{
private static readonly int[] _array = Enumerable.Range( 0, 50 ).ToArray();
[Benchmark]
public void StructEnumerator()
{
var collection = new CollectionWithStructEnumerator<int>( _array );
foreach ( var item in collection )
{
}
}
[Benchmark]
public void BoxedStructEnumerator()
{
var collection = new CollectionWithStructEnumerator<int>( _array ) as IEnumerable<int>;
foreach ( var item in collection )
{
}
}
[Benchmark]
public void ManuallyBoxedStructEnumerator()
{
var collection = new CollectionWithManuallyBoxedEnumerator<int>( _array );
foreach ( var item in collection )
{
}
}
[Benchmark]
public void NaiveClassEnumerator()
{
var collection = new CollectionWithNaiveClassEnumerator<int>( _array );
foreach ( var item in collection )
{
}
}
[Benchmark]
public void ManualClassEnumerator()
{
var collection = new CollectionWithManualClassEnumerator<int>( _array );
foreach ( var item in collection )
{
}
}
private class CollectionWithNaiveClassEnumerator<T> : IEnumerable<T>
{
private readonly T[] _items;
public CollectionWithNaiveClassEnumerator( T[] items )
{
_items = items;
}
public IEnumerator<T> GetEnumerator()
{
for ( int i = 0; i < _items.Length; i++ )
yield return _items[ i ];
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
private class CollectionWithManualClassEnumerator<T> : IEnumerable<T>
{
private readonly T[] _items;
public CollectionWithManualClassEnumerator( T[] items )
{
_items = items;
}
public IEnumerator<T> GetEnumerator() => new Enumerator( _items );
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public class Enumerator : IEnumerator<T>
{
private int _index;
private readonly T[] _items;
public Enumerator( T[] items )
{
_items = items;
_index = -1;
Current = default( T );
}
public T Current { get; private set; }
object IEnumerator.Current => Current;
public bool MoveNext()
{
_index++;
if ( _index >= _items.Length )
return false;
Current = _items[ _index ];
return true;
}
public void Dispose() { }
public void Reset() { }
}
}
private class CollectionWithStructEnumerator<T> : IEnumerable<T>
{
private readonly T[] _items;
public CollectionWithStructEnumerator( T[] items )
{
_items = items;
}
public StructEnumeratorImpementation<T> GetEnumerator() => new StructEnumeratorImpementation<T>( _items );
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
private class CollectionWithManuallyBoxedEnumerator<T> : IEnumerable<T>
{
private readonly T[] _items;
public CollectionWithManuallyBoxedEnumerator( T[] items )
{
_items = items;
}
public IEnumerator<T> GetEnumerator() => new BoxedEnumerator<T, StructEnumeratorImpementation<T>>( new StructEnumeratorImpementation<T>( _items ) );
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
private class BoxedEnumerator<TItem, TEnumerator> : IEnumerator<TItem> where TEnumerator : struct, IEnumerator<TItem>
{
private TEnumerator _structEnumerator;
public BoxedEnumerator( TEnumerator structEnumerator )
{
_structEnumerator = structEnumerator;
}
public TItem Current => _structEnumerator.Current;
object IEnumerator.Current => Current;
public void Dispose() => _structEnumerator.Dispose();
public bool MoveNext() => _structEnumerator.MoveNext();
public void Reset() => _structEnumerator.Reset();
}
private struct StructEnumeratorImpementation<T> : IEnumerator<T>
{
private int _index;
private readonly T[] _items;
public StructEnumeratorImpementation( T[] items )
{
_items = items;
_index = -1;
Current = default( T );
}
public T Current { get; private set; }
object IEnumerator.Current => Current;
public bool MoveNext()
{
_index++;
if ( _index >= _items.Length )
return false;
Current = _items[ _index ];
return true;
}
public void Dispose() { }
public void Reset() { }
}
}
}
@HellBrick
Copy link
Author

HellBrick commented Jul 10, 2016

Host Process Environment Information:
BenchmarkDotNet=v0.9.8.0
OS=Microsoft Windows NT 6.2.9200.0
Processor=Intel(R) Core(TM) i5-2500 CPU 3.30GHz, ProcessorCount=4
Frequency=3239552 ticks, Resolution=308.6847 ns, Timer=TSC
CLR=MS.NET 4.0.30319.42000, Arch=32-bit RELEASE
GC=Concurrent Workstation
JitModules=clrjit-v4.6.1584.0

Type=EnumeratorBenchmark  Mode=Throughput  Platform=X64
Jit=RyuJit  GarbageCollection=Concurrent Workstation

                        Method |      Median |    StdDev |  Gen 0 | Gen 1 | Gen 2 | Bytes Allocated/Op |
------------------------------ |------------ |---------- |------- |------ |------ |------------------- |
              StructEnumerator |  59.4483 ns | 0.8035 ns |  70.89 |     - |     - |               9,11 |
         BoxedStructEnumerator | 435.4701 ns | 3.9348 ns | 169.00 |     - |     - |              22,77 |
 ManuallyBoxedStructEnumerator | 342.6922 ns | 2.4756 ns | 171.69 |     - |     - |              22,97 |
          NaiveClassEnumerator | 316.4042 ns | 2.2237 ns | 193.47 |     - |     - |              25,40 |
         ManualClassEnumerator | 294.7561 ns | 0.7229 ns | 177.56 |     - |     - |              23,76 |

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment