Skip to content

Commit

Permalink
Add benchmarks
Browse files Browse the repository at this point in the history
  • Loading branch information
ocoanet committed Jan 8, 2020
1 parent 31a00fd commit 15a187a
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 208 deletions.
140 changes: 96 additions & 44 deletions src/Disruptor.Benchmarks/BatchEventProcessorBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -1,78 +1,130 @@
using System;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
using Disruptor.Internal;

namespace Disruptor.Benchmarks
{
public class BatchEventProcessorBenchmarks
{
private readonly Sequence _sequence = new Sequence();
private readonly RingBuffer<TestEvent> _ringBuffer;
private readonly TestEventHandler _eventHandler;
private readonly ISequenceBarrier _sequenceBarrier;
private readonly IRunner _runner;

public BatchEventProcessorBenchmarks()
{
_ringBuffer = new RingBuffer<TestEvent>(() => new TestEvent(), new SingleProducerSequencer(4096, new SpinWaitWaitStrategy()));
_eventHandler = new TestEventHandler();
_sequenceBarrier = _ringBuffer.NewBarrier();
var ringBuffer = new RingBuffer<XEvent>(() => new XEvent(), new SingleProducerSequencer(4096, new SpinWaitWaitStrategy()));
var eventHandler = new XEventHandler();
var sequenceBarrier = ringBuffer.NewBarrier();

_ringBuffer.PublishEvent().Dispose();
}
ringBuffer.PublishEvent().Dispose();

var dataProviderProxy = StructProxy.CreateProxyInstance<IDataProvider<XEvent>>(ringBuffer);
var sequenceBarrierProxy = StructProxy.CreateProxyInstance(sequenceBarrier);
var eventHandlerProxy = StructProxy.CreateProxyInstance<IEventHandler<XEvent>>(eventHandler);
var batchStartAwareProxy = new NoopBatchStartAware();

public volatile int Running;
var runnerType = typeof(Runner<,,,,>).MakeGenericType(typeof(XEvent), dataProviderProxy.GetType(), sequenceBarrierProxy.GetType(), eventHandlerProxy.GetType(), batchStartAwareProxy.GetType());
_runner = (IRunner)Activator.CreateInstance(runnerType, dataProviderProxy, sequenceBarrierProxy, eventHandlerProxy, batchStartAwareProxy);
}

[Benchmark]
public long ProcessEvent()
{
var nextSequence = 0L;
try
{
var availableSequence = _sequenceBarrier.WaitFor(nextSequence);
return _runner.ProcessEvent();
}

while (nextSequence <= availableSequence)
{
var evt = _ringBuffer[nextSequence];
_eventHandler.OnEvent(evt, nextSequence, nextSequence == availableSequence);
nextSequence++;
}
public class XEvent
{
public long Data { get; set; }
}

_sequence.SetValue(availableSequence);
}
catch (TimeoutException)
{
NotifyTimeout(_sequence.Value);
}
catch (AlertException)
{
if (Running != 2)
{
return nextSequence;
}
}
catch (Exception)
public class XEventHandler : IEventHandler<XEvent>
{
public long Sum;

public void OnEvent(XEvent data, long sequence, bool endOfBatch)
{
_sequence.SetValue(nextSequence);
nextSequence++;
Sum += data.Data;
}

return nextSequence;
}

[MethodImpl(MethodImplOptions.NoInlining)]
private void NotifyTimeout(long sequenceValue)
private struct NoopBatchStartAware : IBatchStartAware
{
public void OnBatchStart(long batchSize)
{
}
}

public class TestEvent
public interface IRunner
{
public long Data { get; set; }
long ProcessEvent();
}

public class TestEventHandler : IEventHandler<TestEvent>
public class Runner<T, TDataProvider, TSequenceBarrier, TEventHandler, TBatchStartAware> : IRunner
where T : class
where TDataProvider : IDataProvider<T>
where TSequenceBarrier : ISequenceBarrier
where TEventHandler : IEventHandler<T>
where TBatchStartAware : IBatchStartAware
{
public void OnEvent(TestEvent data, long sequence, bool endOfBatch)
private readonly Sequence _sequence = new Sequence();
private IExceptionHandler<T> _exceptionHandler = new FatalExceptionHandler();

private TDataProvider _dataProvider;
private TSequenceBarrier _sequenceBarrier;
private TEventHandler _eventHandler;
private TBatchStartAware _batchStartAware;

public volatile int Running;

public Runner(TDataProvider dataProvider, TSequenceBarrier sequenceBarrier, TEventHandler eventHandler, TBatchStartAware batchStartAware)
{
_dataProvider = dataProvider;
_sequenceBarrier = sequenceBarrier;
_eventHandler = eventHandler;
_batchStartAware = batchStartAware;
}

public long ProcessEvent()
{
T evt = null;
var nextSequence = _sequence.Value + 1L;

try
{
var availableSequence = _sequenceBarrier.WaitFor(nextSequence);

_batchStartAware.OnBatchStart(availableSequence - nextSequence + 1);

while (nextSequence <= availableSequence)
{
evt = _dataProvider[nextSequence];
_eventHandler.OnEvent(evt, nextSequence, nextSequence == availableSequence);
nextSequence++;
}

//_sequence.SetValue(availableSequence);
}
catch (TimeoutException)
{
NotifyTimeout(_sequence.Value);
}
catch (AlertException)
{
}
catch (Exception ex)
{
_exceptionHandler.HandleEventException(ex, nextSequence, evt);
_sequence.SetValue(nextSequence);
nextSequence++;
}

return nextSequence;
}

[MethodImpl(MethodImplOptions.NoInlining)]
private void NotifyTimeout(long sequence)
{
Console.WriteLine(sequence);
}
}
}
Expand Down
146 changes: 7 additions & 139 deletions src/Disruptor.Benchmarks/ObjectArrayBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -1,165 +1,33 @@
using System;
using System.Reflection.Emit;
using System.Linq;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
using InlineIL;
using static InlineIL.IL.Emit;

namespace Disruptor.Benchmarks
{
public class ObjectArrayBenchmarks
{
private static readonly int _offsetToArrayData = ElemOffset(new object[1]);
private readonly object[] _array;
private readonly Event[] _array;

public ObjectArrayBenchmarks()
{
_array = new object[1024];
for (int i = 0; i < _array.Length; i++)
{
_array[i] = new Event { Value = i };
}

var item = _array[42];

if (!ReferenceEquals(ReadILImpl<Event>(42), item))
throw new InvalidOperationException();

if (!ReferenceEquals(ReadILImpl2<Event>(42), item))
throw new InvalidOperationException();
_array = Enumerable.Range(0, 1024)
.Select(i => new Event { Value = i })
.ToArray();
}

public int Index = 371;

[Benchmark(Baseline = true)]
[MethodImpl(MethodImplOptions.NoInlining)]
public int ReadOne()
{
return ReadImpl<Event>(Index).Value;
}

//[Benchmark(OperationsPerInvoke = 1024)]
[MethodImpl(MethodImplOptions.NoInlining)]
public int ReadMany()
{
var sum = 0;
for (int i = 0; i < 1024; i++)
{
sum += ReadImpl<Event>(i).Value;
}

return sum;
}

[MethodImpl(MethodImplOptions.NoInlining)]
public Event ReadImplPublic(int index)
{
return ReadImpl<Event>(index);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private T ReadImpl<T>(int index)
{
return (T)_array[index];
}

[Benchmark]
[MethodImpl(MethodImplOptions.NoInlining)]
public int ReadOneUnsafe()
{
return ReadUnsafeImpl<Event>(Index).Value;
}

//[Benchmark(OperationsPerInvoke = 1024)]
[MethodImpl(MethodImplOptions.NoInlining)]
public int ReadManyUnsafe()
{
var sum = 0;
for (int i = 0; i < 1024; i++)
{
sum += ReadUnsafeImpl<Event>(i).Value;
}

return sum;
}

[MethodImpl(MethodImplOptions.NoInlining)]
public Event ReadUnsafeImplPublic(int index)
{
return ReadUnsafeImpl<Event>(index);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private T ReadUnsafeImpl<T>(int index)
{
ref var firstItem = ref Unsafe.As<object, T>(ref _array[0]);
return Unsafe.Add(ref firstItem, index);
return _array[Index].Value;
}

[Benchmark]
[MethodImpl(MethodImplOptions.NoInlining)]
public int ReadOneIL()
{
return ReadILImpl<Event>(Index).Value;
}

[Benchmark]
[MethodImpl(MethodImplOptions.NoInlining)]
public int ReadOneIL2()
{
return ReadILImpl2<Event>(Index).Value;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T ReadILImpl<T>(int index)
{
IL.DeclareLocals(
false,
typeof(byte).MakeByRefType()
);

Ldarg_0();
Ldfld(new FieldRef(typeof(ObjectArrayBenchmarks), nameof(_array)));
Stloc_0();
Ldloc_0();

Ldarg(nameof(index));
Sizeof(typeof(object));
Mul();

Ldsfld(new FieldRef(typeof(ObjectArrayBenchmarks), nameof(_offsetToArrayData)));
Add();

Add();

Ldobj(typeof(T));

return IL.Return<T>();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T ReadILImpl2<T>(int index)
{
Ldarg_0();
Ldfld(new FieldRef(typeof(ObjectArrayBenchmarks), nameof(_array)));

Ldarg(nameof(index));
Readonly(); // Trigger this codepath in the JIT: https://github.com/dotnet/coreclr/blob/bc28740cd5f0533655f347fc315f6a28836a7efe/src/jit/importer.cpp#L11141-L11147
Ldelema(typeof(T));
Ldind_Ref();

return IL.Return<T>();
}

private static int ElemOffset<T>(T[] arr)
{
Ldarg(nameof(arr));
Ldc_I4_0();
Ldelema(typeof(T));
Ldarg(nameof(arr));
Sub();

return IL.Return<int>();
return Util.Read<Event>(_array, Index).Value;
}

public class Event
Expand Down
17 changes: 1 addition & 16 deletions src/Disruptor.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public static void Main()

BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run();

//Console.ReadLine();
Console.ReadLine();
}

private static void RunMultiProducerSequencerBenchmarks()
Expand Down Expand Up @@ -72,20 +72,5 @@ private static void RunInt32ArrayBenchmarks()
bench.Read();
bench.ReadFixed();
}

private static void RunObjectArrayBenchmarks()
{
var bench = new ObjectArrayBenchmarks();

bench.ReadImplPublic(371);
bench.ReadUnsafeImplPublic(371);

Console.WriteLine("YYY");
Console.ReadLine();
Console.WriteLine("ZZZ");

bench.ReadImplPublic(371);
bench.ReadUnsafeImplPublic(371);
}
}
}
Loading

0 comments on commit 15a187a

Please sign in to comment.