Cleanup of no longer needed classes. ParallelSynchronizationContext/-Pool renamed to IndexOfSynchronizationContext/-Pool.
This commit is contained in:
1 parent
9ece531129
commit
24c2491df0
9 files changed
+80
-255
No files matched your search
@@ -1,10 +1,11 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
using MoreLinq;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Recyclable.Collections.Benchmarks.POC
|
||||
{
|
||||
public enum WhenParallelSearchBenchmarkType
|
||||
public enum WhenParallelSearchBenchmarkType
|
||||
{
|
||||
IndexOfSequentially,
|
||||
IndexOfParallel,
|
||||
@@ -13,6 +14,62 @@ namespace Recyclable.Collections.Benchmarks.POC
|
||||
[MemoryDiagnoser]
|
||||
public class WhenParallelSearchBenchmarks : PocBenchmarkBase<WhenParallelSearchBenchmarkType>
|
||||
{
|
||||
#region ItemRange V2
|
||||
|
||||
private sealed class ItemRangeV2
|
||||
{
|
||||
public int BlockIndex;
|
||||
public long ItemsToSearchCount;
|
||||
internal bool _returned;
|
||||
|
||||
public ItemRangeV2()
|
||||
{
|
||||
}
|
||||
|
||||
public ItemRangeV2(int blockIndex, long itemsToSearchCount)
|
||||
{
|
||||
BlockIndex = blockIndex;
|
||||
ItemsToSearchCount = itemsToSearchCount;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_returned)
|
||||
{
|
||||
_returned = true;
|
||||
ItemRangePoolV2.Shared.Return(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ItemRangePoolV2
|
||||
|
||||
private static class ItemRangePoolV2
|
||||
{
|
||||
private static readonly SpinLock _updateLock = new(false);
|
||||
public static readonly ObjectPool<ItemRangeV2> Shared = new DefaultObjectPool<ItemRangeV2>(new DefaultPooledObjectPolicy<ItemRangeV2>());
|
||||
|
||||
public static ItemRangeV2 Create(int blockIndex, long itemsToSearchCount)
|
||||
{
|
||||
bool lockTaken = false;
|
||||
_updateLock.Enter(ref lockTaken);
|
||||
var itemRange = Shared.Get();
|
||||
if (lockTaken)
|
||||
{
|
||||
_updateLock.Exit(false);
|
||||
}
|
||||
|
||||
itemRange._returned = false;
|
||||
itemRange.BlockIndex = blockIndex;
|
||||
itemRange.ItemsToSearchCount = itemsToSearchCount;
|
||||
return itemRange;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
//[Params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 32)]
|
||||
//public int NumberOfThreads { get; set; } = 3;
|
||||
|
||||
@@ -66,7 +123,7 @@ namespace Recyclable.Collections.Benchmarks.POC
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
|
||||
private static long DoLongIndexOfParallel(RecyclableList<long> list, in long itemToFind, ItemRange searchInfo, ManualResetEventSlim itemFoundSignal)
|
||||
private static long DoLongIndexOfParallel(RecyclableList<long> list, in long itemToFind, ItemRangeV2 searchInfo, ManualResetEventSlim itemFoundSignal)
|
||||
{
|
||||
int index;
|
||||
int blockSize = list.BlockSize;
|
||||
@@ -248,13 +305,13 @@ namespace Recyclable.Collections.Benchmarks.POC
|
||||
}
|
||||
|
||||
protected override Action? GetTestMethod(WhenParallelSearchBenchmarkType benchmarkType) => BenchmarkType switch
|
||||
{
|
||||
WhenParallelSearchBenchmarkType.IndexOfSequentially => IndexOfSequentially,
|
||||
WhenParallelSearchBenchmarkType.IndexOfParallel => IndexOfParallel,
|
||||
_ => throw CreateUnknownBenchmarkTypeException(benchmarkType),
|
||||
};
|
||||
{
|
||||
WhenParallelSearchBenchmarkType.IndexOfSequentially => IndexOfSequentially,
|
||||
WhenParallelSearchBenchmarkType.IndexOfParallel => IndexOfParallel,
|
||||
_ => throw CreateUnknownBenchmarkTypeException(benchmarkType),
|
||||
};
|
||||
|
||||
public override void Cleanup()
|
||||
public override void Cleanup()
|
||||
{
|
||||
_testData = default;
|
||||
base.Cleanup();
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
using Recyclable.Collections.Pools;
|
||||
|
||||
namespace Recyclable.Collections
|
||||
{
|
||||
public sealed class ItemRange
|
||||
{
|
||||
public int BlockIndex;
|
||||
public long ItemsToSearchCount;
|
||||
internal bool _returned;
|
||||
|
||||
public ItemRange()
|
||||
{
|
||||
}
|
||||
|
||||
public ItemRange(int blockIndex, long itemsToSearchCount)
|
||||
{
|
||||
BlockIndex = blockIndex;
|
||||
ItemsToSearchCount = itemsToSearchCount;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_returned)
|
||||
{
|
||||
_returned = true;
|
||||
ItemRangePool.Shared.Return(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using Recyclable.Collections.Parallel;
|
||||
|
||||
namespace Recyclable.Collections
|
||||
{
|
||||
public static class ItemRangesIterator
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.NoInlining)]
|
||||
public static void Iterate<TList, T>(in ParallelSynchronizationContext context, in SearchConfiguration<TList, T> search, Func<ParallelSynchronizationContext, SearchConfiguration<TList, T>, ItemRange, bool> action)
|
||||
{
|
||||
ItemRange itemRange;
|
||||
int blockIndex = search.StartingBlockIndex;
|
||||
long itemsCount = search.ItemsCount;
|
||||
while (itemsCount > search.BlockSize)
|
||||
{
|
||||
itemRange = new(blockIndex, search.BlockSize);
|
||||
if (!action(context, search, itemRange))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
itemsCount -= search.BlockSize;
|
||||
blockIndex++;
|
||||
}
|
||||
|
||||
itemRange = new(blockIndex, itemsCount);
|
||||
_ = action(context, search, itemRange);
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
namespace Recyclable.Collections.Parallel
|
||||
{
|
||||
public sealed class ParallelSynchronizationContext : IDisposable
|
||||
public sealed class IndexOfSynchronizationContext : IDisposable
|
||||
{
|
||||
internal bool _isItemFound;
|
||||
|
||||
@@ -9,12 +9,12 @@ namespace Recyclable.Collections.Parallel
|
||||
public Exception? Exception;
|
||||
internal bool _returned;
|
||||
|
||||
public ParallelSynchronizationContext()
|
||||
public IndexOfSynchronizationContext()
|
||||
{
|
||||
AllDoneSignal = new(0);
|
||||
}
|
||||
|
||||
public ParallelSynchronizationContext(int participantCount)
|
||||
public IndexOfSynchronizationContext(int participantCount)
|
||||
{
|
||||
AllDoneSignal = new(participantCount);
|
||||
}
|
||||
@@ -31,7 +31,7 @@ namespace Recyclable.Collections.Parallel
|
||||
if (!_returned)
|
||||
{
|
||||
_returned = true;
|
||||
ParallelSynchronizationContextPool.Shared.Return(this);
|
||||
IndexOfSynchronizationContextPool.Shared.Return(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
+3
-3
@@ -2,12 +2,12 @@ using Microsoft.Extensions.ObjectPool;
|
||||
|
||||
namespace Recyclable.Collections.Parallel
|
||||
{
|
||||
public static class ParallelSynchronizationContextPool
|
||||
public static class IndexOfSynchronizationContextPool
|
||||
{
|
||||
private static readonly SpinLock _updateLock = new(false);
|
||||
public static readonly ObjectPool<ParallelSynchronizationContext> Shared = new DefaultObjectPool<ParallelSynchronizationContext>(new DefaultPooledObjectPolicy<ParallelSynchronizationContext>());
|
||||
public static readonly ObjectPool<IndexOfSynchronizationContext> Shared = new DefaultObjectPool<IndexOfSynchronizationContext>(new DefaultPooledObjectPolicy<IndexOfSynchronizationContext>());
|
||||
|
||||
public static ParallelSynchronizationContext GetWithOneParticipant()
|
||||
public static IndexOfSynchronizationContext GetWithOneParticipant()
|
||||
{
|
||||
bool lockTaken = false;
|
||||
_updateLock.Enter(ref lockTaken);
|
||||
@@ -1,26 +0,0 @@
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
|
||||
namespace Recyclable.Collections.Pools
|
||||
{
|
||||
public static class ItemRangePool
|
||||
{
|
||||
private static readonly SpinLock _updateLock = new(false);
|
||||
public static readonly ObjectPool<ItemRange> Shared = new DefaultObjectPool<ItemRange>(new DefaultPooledObjectPolicy<ItemRange>());
|
||||
|
||||
public static ItemRange Create(int blockIndex, long itemsToSearchCount)
|
||||
{
|
||||
bool lockTaken = false;
|
||||
_updateLock.Enter(ref lockTaken);
|
||||
var itemRange = Shared.Get();
|
||||
if (lockTaken)
|
||||
{
|
||||
_updateLock.Exit(false);
|
||||
}
|
||||
|
||||
itemRange._returned = false;
|
||||
itemRange.BlockIndex = blockIndex;
|
||||
itemRange.ItemsToSearchCount = itemsToSearchCount;
|
||||
return itemRange;
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -5,12 +5,12 @@ namespace Recyclable.Collections
|
||||
{
|
||||
public partial class RecyclableList<T>
|
||||
{
|
||||
public static class RecyclableListIndexOfHelpers
|
||||
public static class IndexOfHelpers
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.NoOptimization)]
|
||||
private static void ScheduleIndexOfTask(ParallelSynchronizationContext context, RecyclableList<T> list, int blockIndex, T itemToFind)
|
||||
private static void ScheduleIndexOfTask(IndexOfSynchronizationContext context, RecyclableList<T> list, int blockIndex, T itemToFind)
|
||||
{
|
||||
_ = context.AllDoneSignal.AddParticipant();
|
||||
// & WAS SLOWER
|
||||
@@ -123,7 +123,7 @@ namespace Recyclable.Collections
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.NoOptimization)]
|
||||
private static void ScheduleIndexOfTaskSingle(ParallelSynchronizationContext context, RecyclableList<T> list, int blockIndex, T itemToFind)
|
||||
private static void ScheduleIndexOfTaskSingle(IndexOfSynchronizationContext context, RecyclableList<T> list, int blockIndex, T itemToFind)
|
||||
{
|
||||
_ = context.AllDoneSignal.AddParticipant();
|
||||
// & WAS SLOWER
|
||||
@@ -172,7 +172,7 @@ namespace Recyclable.Collections
|
||||
//}
|
||||
|
||||
//using var context = new ParallelSynchronizationContext(1);
|
||||
ParallelSynchronizationContext context = ParallelSynchronizationContextPool.GetWithOneParticipant();
|
||||
IndexOfSynchronizationContext context = IndexOfSynchronizationContextPool.GetWithOneParticipant();
|
||||
// (long)(_longCount * 0.329) => most efficient step, based on benchmarks
|
||||
//Iterate(this, context, item);
|
||||
|
||||
@@ -857,7 +857,7 @@ namespace Recyclable.Collections
|
||||
}
|
||||
else if (_longCount < RecyclableDefaults.MinItemsCountForParallelization)
|
||||
{
|
||||
return (int)RecyclableListIndexOfHelpers.IndexOfSequential(this, item);
|
||||
return (int)IndexOfHelpers.IndexOfSequential(this, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -866,7 +866,7 @@ namespace Recyclable.Collections
|
||||
if (_longCount > _blockSize)
|
||||
{
|
||||
itemIndex = Array.IndexOf(_memoryBlocks[1], item, 0, (int)Math.Min(_blockSize, _longCount - _blockSize));
|
||||
return itemIndex >= 0 ? _blockSize + itemIndex : (int)RecyclableListIndexOfHelpers.IndexOfParallel(this, item);
|
||||
return itemIndex >= 0 ? _blockSize + itemIndex : (int)IndexOfHelpers.IndexOfParallel(this, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -896,7 +896,7 @@ namespace Recyclable.Collections
|
||||
}
|
||||
else if (_longCount < RecyclableDefaults.MinItemsCountForParallelization)
|
||||
{
|
||||
return RecyclableListIndexOfHelpers.IndexOfSequential(this, item);
|
||||
return IndexOfHelpers.IndexOfSequential(this, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -905,7 +905,7 @@ namespace Recyclable.Collections
|
||||
if (_longCount > _blockSize)
|
||||
{
|
||||
itemIndex = Array.IndexOf(_memoryBlocks[1], item, 0, (int)Math.Min(_blockSize, _longCount - _blockSize));
|
||||
return itemIndex >= 0 ? _blockSize + itemIndex : RecyclableListIndexOfHelpers.IndexOfParallel(this, item);
|
||||
return itemIndex >= 0 ? _blockSize + itemIndex : IndexOfHelpers.IndexOfParallel(this, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using Recyclable.Collections;
|
||||
using Recyclable.Collections.Parallel;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Recyclable.CollectionsTests
|
||||
{
|
||||
public class ItemRangesIteratorTests
|
||||
{
|
||||
[Theory]
|
||||
[MemberData(nameof(TestCases))]
|
||||
public void IterateShouldYieldAllItems(int startingBlockIndex, int blockSize, long itemsCount, int step, IEnumerable<(int BlockIndex, long ItemsCount)> expected)
|
||||
{
|
||||
// Prepare
|
||||
var mockList = new RecyclableList<long>();
|
||||
byte blockSizePow2BitShift = (byte)(31 - BitOperations.LeadingZeroCount((uint)blockSize));
|
||||
|
||||
var synchronizationContext = new ParallelSynchronizationContext(1);
|
||||
var search = new SearchConfiguration<RecyclableList<long>, long>()
|
||||
{
|
||||
List = mockList,
|
||||
ItemToFind = 0,
|
||||
BlockSizeMinus1 = blockSize - 1,
|
||||
BlockSizePow2BitShift = blockSizePow2BitShift,
|
||||
ItemsCount = itemsCount,
|
||||
BlockSize = step,
|
||||
};
|
||||
|
||||
var actualItemRanges = new List<(int BlockIndex, long ItemsCount)>();
|
||||
|
||||
// Act
|
||||
ItemRangesIterator.Iterate(synchronizationContext, search, (context, search, itemRange) =>
|
||||
{
|
||||
actualItemRanges.Add((itemRange.BlockIndex, itemRange.ItemsToSearchCount));
|
||||
return true;
|
||||
});
|
||||
|
||||
// Validate
|
||||
_ = actualItemRanges.Should().HaveCount(expected.Count()).And.ContainInConsecutiveOrder(expected);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> TestCases => new[]
|
||||
{
|
||||
new object[]
|
||||
{
|
||||
0, 128, 333, (long)(333 * 0.329), new(int BlockIndex, long ItemsCount)[]
|
||||
{
|
||||
(0, 109),
|
||||
(0, 109),
|
||||
(1, 109),
|
||||
(2, 6)
|
||||
}
|
||||
},
|
||||
|
||||
new object[]
|
||||
{
|
||||
0, 2, 10, 2, new (int BlockIndex, long ItemsCount)[]
|
||||
{
|
||||
(0, 2),
|
||||
(1, 2),
|
||||
(2, 2),
|
||||
(3, 2),
|
||||
(4, 2),
|
||||
}
|
||||
},
|
||||
|
||||
new object[]
|
||||
{
|
||||
0, 2, 10, 3, new (int BlockIndex, long ItemsCount)[]
|
||||
{
|
||||
(0, 3),
|
||||
(1, 3),
|
||||
(3, 3),
|
||||
(4, 1),
|
||||
}
|
||||
},
|
||||
|
||||
new object[]
|
||||
{
|
||||
0, 1, 10, 3, new (int BlockIndex, long ItemsCount)[]
|
||||
{
|
||||
(0, 3),
|
||||
(3, 3),
|
||||
(6, 3),
|
||||
(9, 1),
|
||||
}
|
||||
},
|
||||
|
||||
new object[]
|
||||
{
|
||||
0, 2, 10, 4, new (int BlockIndex, long ItemsCount)[]
|
||||
{
|
||||
(0, 4),
|
||||
(2, 4),
|
||||
(4, 2),
|
||||
}
|
||||
},
|
||||
|
||||
new object[]
|
||||
{
|
||||
0, 1, 10, 2, new (int BlockIndex, long ItemsCount)[]
|
||||
{
|
||||
(0, 2),
|
||||
(2, 2),
|
||||
(4, 2),
|
||||
(6, 2),
|
||||
(8, 2),
|
||||
}
|
||||
},
|
||||
|
||||
new object[]
|
||||
{
|
||||
0, 2, 10, 1, new (int BlockIndex, long ItemsCount)[]
|
||||
{
|
||||
(0, 1),
|
||||
(0, 1),
|
||||
(1, 1),
|
||||
(1, 1),
|
||||
(2, 1),
|
||||
(2, 1),
|
||||
(3, 1),
|
||||
(3, 1),
|
||||
(4, 1),
|
||||
(4, 1),
|
||||
}
|
||||
},
|
||||
|
||||
new object[]
|
||||
{
|
||||
0, 1, 10, 1, new (int BlockIndex, long ItemsCount)[]
|
||||
{
|
||||
(0, 1),
|
||||
(1, 1),
|
||||
(2, 1),
|
||||
(3, 1),
|
||||
(4, 1),
|
||||
(5, 1),
|
||||
(6, 1),
|
||||
(7, 1),
|
||||
(8, 1),
|
||||
(9, 1),
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user