RecyclableList.IndexOf parallel performance improvements.

This commit is contained in:
mlemanczyk committed 2023-05-03 12:36:37 +02:00
1 parent 99600d4854
commit 3db10d7602
21 files changed
+4282 -511

No files matched your search

@@ -0,0 +1,117 @@
using Microsoft.Extensions.ObjectPool;
using System.Runtime.CompilerServices;
namespace Recyclable.Collections.Parallel
{
public sealed class BarrierSlimmer : IDisposable
{
private static readonly ObjectPool<BarrierSlimmer> _defaultPool = new DefaultObjectPool<BarrierSlimmer>(new DefaultPooledObjectPolicy<BarrierSlimmer>());
private ObjectPool<BarrierSlimmer>? _assignedPool;
private readonly SpinLock _lock = new(false);
public bool HasParticipants;
public int Participants;
[MethodImpl(MethodImplOptions.NoInlining)]
public void AddParticipant()
{
bool isLocked = false;
_lock.Enter(ref isLocked);
Participants++;
if (Participants == 1)
{
HasParticipants = true;
}
if (isLocked)
{
_lock.Exit(false);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
public void RemoveParticipant()
{
if (!HasParticipants)
{
ThrowNoMoreParticipants();
}
bool isLocked = false;
_lock.Enter(ref isLocked);
Participants--;
if (Participants == 0)
{
HasParticipants = false;
}
if (isLocked)
{
_lock.Exit(false);
}
}
private static void ThrowNoMoreParticipants()
{
throw new InvalidOperationException("There are no more participants. The operation is not allowed");
}
public BarrierSlimmer()
{
_lock = new(false);
}
public BarrierSlimmer(int participants)
{
_lock = new(false);
Participants = participants;
HasParticipants = participants > 0;
}
public static BarrierSlimmer Create(int participants)
{
var result = _defaultPool.Get();
result.Participants = participants;
result.HasParticipants = participants > 0;
return result;
}
public void Dispose()
{
var assignedPool = _assignedPool;
_assignedPool = null;
assignedPool?.Return(this);
GC.SuppressFinalize(this);
}
public void SignalAndWait()
{
RemoveParticipant();
//if (!HasParticipants)
//{
// return;
//}
//if (!HasParticipants)
//{
// return;
//}
//if (!HasParticipants)
//{
// return;
//}
// SpinWait.SpinUntil(() => HasParticipants);
var waitSpinner = new SpinWait();
while (HasParticipants)
{
waitSpinner.SpinOnce(0);
}
}
}
}
@@ -0,0 +1,37 @@
namespace Recyclable.Collections.Parallel
{
public sealed class ManualResetEventSlimmer
{
internal bool _isSet;
public bool IsSet => _isSet;
internal bool _returned;
public ManualResetEventSlimmer()
{
}
public ManualResetEventSlimmer(bool initialState)
{
_isSet = initialState;
}
public void Set()
{
_isSet = true;
}
public void Reset()
{
_isSet = false;
}
public void Dispose()
{
if (!_returned)
{
_returned = true;
ManualResetEventSlimmerPool.Shared.Return(this);
}
}
}
}
@@ -0,0 +1,29 @@
using Microsoft.Extensions.ObjectPool;
namespace Recyclable.Collections.Parallel
{
public static class ManualResetEventSlimmerPool
{
public static readonly SpinLock _updateLock = new(false);
public static readonly ObjectPool<ManualResetEventSlimmer> Shared = new DefaultObjectPool<ManualResetEventSlimmer>(new DefaultPooledObjectPolicy<ManualResetEventSlimmer>());
public static ManualResetEventSlimmer Create(bool initialState)
{
bool lockTaken = false;
_updateLock.Enter(ref lockTaken);
ManualResetEventSlimmer result = Shared.Get();
if (lockTaken)
{
_updateLock.Exit(false);
}
result._returned = false;
if (result._isSet != initialState)
{
result._isSet = initialState;
}
return result;
}
}
}
@@ -0,0 +1,38 @@
namespace Recyclable.Collections.Parallel
{
public sealed class ParallelSynchronizationContext : IDisposable
{
public readonly ManualResetEventSlimmer ItemFoundSignal;
public readonly Barrier AllDoneSignal;
public long FoundItemIndex;
public Exception? Exception;
internal bool _returned;
public ParallelSynchronizationContext()
{
ItemFoundSignal = ManualResetEventSlimmerPool.Create(false);
AllDoneSignal = new(0);
}
public ParallelSynchronizationContext(int participantCount)
{
ItemFoundSignal = ManualResetEventSlimmerPool.Create(false);
AllDoneSignal = new(participantCount);
}
public void Dispose()
{
if (!_returned)
{
_returned = true;
ParallelSynchronizationContextPool.Shared.Return(this);
}
else
{
ItemFoundSignal.Dispose();
AllDoneSignal.Dispose();
GC.SuppressFinalize(this);
}
}
}
}
@@ -0,0 +1,50 @@
using Microsoft.Extensions.ObjectPool;
namespace Recyclable.Collections.Parallel
{
public static class ParallelSynchronizationContextPool
{
private static readonly SpinLock _updateLock = new(false);
public static readonly ObjectPool<ParallelSynchronizationContext> Shared = new DefaultObjectPool<ParallelSynchronizationContext>(new DefaultPooledObjectPolicy<ParallelSynchronizationContext>());
public static ParallelSynchronizationContext GetWithOneParticipant()
{
bool lockTaken = false;
_updateLock.Enter(ref lockTaken);
var context = Shared.Get();
if (lockTaken)
{
_updateLock.Exit(false);
}
if (context.ItemFoundSignal._isSet)
{
context.ItemFoundSignal.Reset();
}
switch (context.AllDoneSignal.ParticipantsRemaining)
{
case > 1:
context.AllDoneSignal.RemoveParticipants(context.AllDoneSignal.ParticipantsRemaining - 1);
break;
case 0:
context.AllDoneSignal.AddParticipant();
break;
}
if (context.Exception != null)
{
context.Exception = null;
}
if (context.FoundItemIndex >= 0)
{
context.FoundItemIndex = -1L;
}
context._returned = false;
return context;
}
}
}