ArrayPool<T> replaced with ThreadStaticPools
This commit is contained in:
1 parent
c004e140db
commit
9537addf38
12 files changed
+102
-54
No files matched your search
@@ -95,7 +95,7 @@ public sealed class DivisorCycleCache
|
|||||||
int[]? rentedMissing = null;
|
int[]? rentedMissing = null;
|
||||||
Span<int> missingBuffer = length <= StackBufferThreshold
|
Span<int> missingBuffer = length <= StackBufferThreshold
|
||||||
? stackalloc int[length]
|
? stackalloc int[length]
|
||||||
: new Span<int>(rentedMissing = ArrayPool<int>.Shared.Rent(length), 0, length);
|
: new Span<int>(rentedMissing = ThreadStaticPools.IntPool.Rent(length), 0, length);
|
||||||
|
|
||||||
int missingCount = 0;
|
int missingCount = 0;
|
||||||
|
|
||||||
@@ -139,7 +139,7 @@ public sealed class DivisorCycleCache
|
|||||||
|
|
||||||
if (rentedMissing is not null)
|
if (rentedMissing is not null)
|
||||||
{
|
{
|
||||||
ArrayPool<int>.Shared.Return(rentedMissing, clearArray: false);
|
ThreadStaticPools.IntPool.Return(rentedMissing, clearArray: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,12 +198,12 @@ public sealed class DivisorCycleCache
|
|||||||
ulong[]? rentedDivisors = null;
|
ulong[]? rentedDivisors = null;
|
||||||
Span<ulong> workDivisors = count <= StackBufferThreshold
|
Span<ulong> workDivisors = count <= StackBufferThreshold
|
||||||
? stackalloc ulong[count]
|
? stackalloc ulong[count]
|
||||||
: new Span<ulong>(rentedDivisors = ArrayPool<ulong>.Shared.Rent(count), 0, count);
|
: new Span<ulong>(rentedDivisors = ThreadStaticPools.UlongPool.Rent(count), 0, count);
|
||||||
|
|
||||||
ulong[]? rentedResults = null;
|
ulong[]? rentedResults = null;
|
||||||
Span<ulong> workResults = count <= StackBufferThreshold
|
Span<ulong> workResults = count <= StackBufferThreshold
|
||||||
? stackalloc ulong[count]
|
? stackalloc ulong[count]
|
||||||
: new Span<ulong>(rentedResults = ArrayPool<ulong>.Shared.Rent(count), 0, count);
|
: new Span<ulong>(rentedResults = ThreadStaticPools.UlongPool.Rent(count), 0, count);
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
@@ -219,8 +219,8 @@ public sealed class DivisorCycleCache
|
|||||||
|
|
||||||
if (rentedDivisors is not null)
|
if (rentedDivisors is not null)
|
||||||
{
|
{
|
||||||
ArrayPool<ulong>.Shared.Return(rentedDivisors, clearArray: false);
|
ThreadStaticPools.UlongPool.Return(rentedDivisors, clearArray: false);
|
||||||
ArrayPool<ulong>.Shared.Return(rentedResults!, clearArray: false);
|
ThreadStaticPools.UlongPool.Return(rentedResults!, clearArray: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,22 +242,22 @@ public sealed class DivisorCycleCache
|
|||||||
ulong[]? rentedPow = null;
|
ulong[]? rentedPow = null;
|
||||||
Span<ulong> powSpan = length <= StackBufferThreshold
|
Span<ulong> powSpan = length <= StackBufferThreshold
|
||||||
? stackalloc ulong[length]
|
? stackalloc ulong[length]
|
||||||
: new Span<ulong>(rentedPow = ArrayPool<ulong>.Shared.Rent(length), 0, length);
|
: new Span<ulong>(rentedPow = ThreadStaticPools.UlongPool.Rent(length), 0, length);
|
||||||
|
|
||||||
ulong[]? rentedOrder = null;
|
ulong[]? rentedOrder = null;
|
||||||
Span<ulong> orderSpan = length <= StackBufferThreshold
|
Span<ulong> orderSpan = length <= StackBufferThreshold
|
||||||
? stackalloc ulong[length]
|
? stackalloc ulong[length]
|
||||||
: new Span<ulong>(rentedOrder = ArrayPool<ulong>.Shared.Rent(length), 0, length);
|
: new Span<ulong>(rentedOrder = ThreadStaticPools.UlongPool.Rent(length), 0, length);
|
||||||
|
|
||||||
ulong[]? rentedResult = null;
|
ulong[]? rentedResult = null;
|
||||||
Span<ulong> resultSpan = length <= StackBufferThreshold
|
Span<ulong> resultSpan = length <= StackBufferThreshold
|
||||||
? stackalloc ulong[length]
|
? stackalloc ulong[length]
|
||||||
: new Span<ulong>(rentedResult = ArrayPool<ulong>.Shared.Rent(length), 0, length);
|
: new Span<ulong>(rentedResult = ThreadStaticPools.UlongPool.Rent(length), 0, length);
|
||||||
|
|
||||||
byte[]? rentedStatus = null;
|
byte[]? rentedStatus = null;
|
||||||
Span<byte> statusSpan = length <= StackBufferThreshold
|
Span<byte> statusSpan = length <= StackBufferThreshold
|
||||||
? stackalloc byte[length]
|
? stackalloc byte[length]
|
||||||
: new Span<byte>(rentedStatus = ArrayPool<byte>.Shared.Rent(length), 0, length);
|
: new Span<byte>(rentedStatus = ThreadStaticPools.BytePool.Rent(length), 0, length);
|
||||||
|
|
||||||
ref ulong divisorRef = ref MemoryMarshal.GetReference(divisors);
|
ref ulong divisorRef = ref MemoryMarshal.GetReference(divisors);
|
||||||
divisorBuffer.View.CopyFromCPU(stream, ref divisorRef, length);
|
divisorBuffer.View.CopyFromCPU(stream, ref divisorRef, length);
|
||||||
@@ -306,10 +306,10 @@ public sealed class DivisorCycleCache
|
|||||||
resultSpan.CopyTo(destination);
|
resultSpan.CopyTo(destination);
|
||||||
if (rentedPow is not null)
|
if (rentedPow is not null)
|
||||||
{
|
{
|
||||||
ArrayPool<ulong>.Shared.Return(rentedPow, clearArray: false);
|
ThreadStaticPools.UlongPool.Return(rentedPow, clearArray: false);
|
||||||
ArrayPool<ulong>.Shared.Return(rentedOrder!, clearArray: false);
|
ThreadStaticPools.UlongPool.Return(rentedOrder!, clearArray: false);
|
||||||
ArrayPool<ulong>.Shared.Return(rentedResult!, clearArray: false);
|
ThreadStaticPools.UlongPool.Return(rentedResult!, clearArray: false);
|
||||||
ArrayPool<byte>.Shared.Return(rentedStatus!, clearArray: false);
|
ThreadStaticPools.BytePool.Return(rentedStatus!, clearArray: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
gpuLease.Dispose();
|
gpuLease.Dispose();
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ public class MersenneNumberIncrementalGpuTester(GpuKernelType kernelType, bool u
|
|||||||
var orderBuffer = accelerator.Allocate1D<ulong>(batchSize);
|
var orderBuffer = accelerator.Allocate1D<ulong>(batchSize);
|
||||||
// Avoid giant stack allocations that can trigger StackOverflow when batchSize is large.
|
// Avoid giant stack allocations that can trigger StackOverflow when batchSize is large.
|
||||||
// Rent a reusable array from the shared pool instead.
|
// Rent a reusable array from the shared pool instead.
|
||||||
ulong[] orderArray = ArrayPool<ulong>.Shared.Rent(batchSize);
|
ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool;
|
||||||
|
ulong[] orderArray = ulongPool.Rent(batchSize);
|
||||||
UInt128 remaining;
|
UInt128 remaining;
|
||||||
int currentSize;
|
int currentSize;
|
||||||
int i;
|
int i;
|
||||||
@@ -120,7 +121,7 @@ public class MersenneNumberIncrementalGpuTester(GpuKernelType kernelType, bool u
|
|||||||
kStart += (UInt128)currentSize;
|
kStart += (UInt128)currentSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayPool<ulong>.Shared.Return(orderArray);
|
ulongPool.Return(orderArray);
|
||||||
orderBuffer.Dispose();
|
orderBuffer.Dispose();
|
||||||
gpuLease.Dispose();
|
gpuLease.Dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,11 +138,13 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
var kernel = GetBatchKernel(accelerator);
|
var kernel = GetBatchKernel(accelerator);
|
||||||
|
|
||||||
var expBuffer = accelerator.Allocate1D<ulong>(count);
|
var expBuffer = accelerator.Allocate1D<ulong>(count);
|
||||||
ulong[] expArray = ArrayPool<ulong>.Shared.Rent(count);
|
ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool;
|
||||||
|
ulong[] expArray = ulongPool.Rent(count);
|
||||||
exponents.CopyTo(expArray);
|
exponents.CopyTo(expArray);
|
||||||
expBuffer.View.CopyFromCPU(stream, ref expArray[0], count);
|
expBuffer.View.CopyFromCPU(stream, ref expArray[0], count);
|
||||||
|
|
||||||
GpuUInt128[] modulusArray = ArrayPool<GpuUInt128>.Shared.Rent(count);
|
ArrayPool<GpuUInt128> gpuUInt128Pool = ThreadStaticPools.GpuUInt128Pool;
|
||||||
|
GpuUInt128[] modulusArray = gpuUInt128Pool.Rent(count);
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
// TODO: Replace this per-exponent shift with a small shared table (one entry per supported exponent < 128)
|
// TODO: Replace this per-exponent shift with a small shared table (one entry per supported exponent < 128)
|
||||||
@@ -161,8 +163,8 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
stateBuffer.Dispose();
|
stateBuffer.Dispose();
|
||||||
modBuffer.Dispose();
|
modBuffer.Dispose();
|
||||||
expBuffer.Dispose();
|
expBuffer.Dispose();
|
||||||
ArrayPool<GpuUInt128>.Shared.Return(modulusArray);
|
gpuUInt128Pool.Return(modulusArray);
|
||||||
ArrayPool<ulong>.Shared.Return(expArray);
|
ulongPool.Return(expArray);
|
||||||
stream.Dispose();
|
stream.Dispose();
|
||||||
gpu.Dispose();
|
gpu.Dispose();
|
||||||
}
|
}
|
||||||
@@ -175,13 +177,14 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
throw new ArgumentException("Result span too small", nameof(results));
|
throw new ArgumentException("Result span too small", nameof(results));
|
||||||
}
|
}
|
||||||
|
|
||||||
GpuUInt128[] buffer = ArrayPool<GpuUInt128>.Shared.Rent(count);
|
ArrayPool<GpuUInt128> gpuUInt128Pool = ThreadStaticPools.GpuUInt128Pool;
|
||||||
|
GpuUInt128[] buffer = gpuUInt128Pool.Rent(count);
|
||||||
ComputeResidues(exponents, buffer.AsSpan(0, count));
|
ComputeResidues(exponents, buffer.AsSpan(0, count));
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
results[i] = buffer[i].IsZero;
|
results[i] = buffer[i].IsZero;
|
||||||
}
|
}
|
||||||
ArrayPool<GpuUInt128>.Shared.Return(buffer);
|
gpuUInt128Pool.Return(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsMersennePrimeNtt(ulong exponent, GpuUInt128 nttMod, GpuUInt128 primitiveRoot, bool runOnGpu)
|
private bool IsMersennePrimeNtt(ulong exponent, GpuUInt128 nttMod, GpuUInt128 primitiveRoot, bool runOnGpu)
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
|||||||
{
|
{
|
||||||
Capacity = Math.Max(1, capacity);
|
Capacity = Math.Max(1, capacity);
|
||||||
OrderBuffer = accelerator.Allocate1D<ulong>(Capacity);
|
OrderBuffer = accelerator.Allocate1D<ulong>(Capacity);
|
||||||
OrderArray = ArrayPool<ulong>.Shared.Rent(Capacity);
|
OrderArray = ThreadStaticPools.UlongPool.Rent(Capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal MemoryBuffer1D<ulong, Stride1D.Dense> OrderBuffer { get; }
|
internal MemoryBuffer1D<ulong, Stride1D.Dense> OrderBuffer { get; }
|
||||||
@@ -184,7 +184,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
|||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
OrderBuffer.Dispose();
|
OrderBuffer.Dispose();
|
||||||
ArrayPool<ulong>.Shared.Return(OrderArray, clearArray: false);
|
ThreadStaticPools.UlongPool.Return(OrderArray, clearArray: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ public static class NttGpuMath
|
|||||||
// Precompute stage twiddle factors (forward and inverse) and upload to GPU.
|
// Precompute stage twiddle factors (forward and inverse) and upload to GPU.
|
||||||
Bits = (int)Math.Log2(length);
|
Bits = (int)Math.Log2(length);
|
||||||
int twiddleCount = length - 1;
|
int twiddleCount = length - 1;
|
||||||
var pool = ArrayPool<GpuUInt128>.Shared;
|
var pool = ThreadStaticPools.GpuUInt128Pool;
|
||||||
var forward = pool.Rent(twiddleCount);
|
var forward = pool.Rent(twiddleCount);
|
||||||
var inverse = pool.Rent(twiddleCount);
|
var inverse = pool.Rent(twiddleCount);
|
||||||
StageOffsets = new int[Bits];
|
StageOffsets = new int[Bits];
|
||||||
@@ -507,7 +507,7 @@ public static class NttGpuMath
|
|||||||
var gpu = GpuContextPool.Rent();
|
var gpu = GpuContextPool.Rent();
|
||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
var kernel = GetBitReverseKernel(accelerator);
|
var kernel = GetBitReverseKernel(accelerator);
|
||||||
var pool = ArrayPool<GpuUInt128>.Shared;
|
var pool = ThreadStaticPools.GpuUInt128Pool;
|
||||||
var array = pool.Rent(n);
|
var array = pool.Rent(n);
|
||||||
values.CopyTo(array);
|
values.CopyTo(array);
|
||||||
var buffer = accelerator.Allocate1D<GpuUInt128>(n);
|
var buffer = accelerator.Allocate1D<GpuUInt128>(n);
|
||||||
@@ -572,7 +572,7 @@ public static class NttGpuMath
|
|||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
var stream = accelerator.CreateStream();
|
var stream = accelerator.CreateStream();
|
||||||
var kernel = GetForwardKernel(accelerator);
|
var kernel = GetForwardKernel(accelerator);
|
||||||
var pool = ArrayPool<GpuUInt128>.Shared;
|
var pool = ThreadStaticPools.GpuUInt128Pool;
|
||||||
var inputArray = pool.Rent(n);
|
var inputArray = pool.Rent(n);
|
||||||
var outputArray = pool.Rent(n);
|
var outputArray = pool.Rent(n);
|
||||||
values.CopyTo(inputArray);
|
values.CopyTo(inputArray);
|
||||||
@@ -671,7 +671,7 @@ public static class NttGpuMath
|
|||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
var stream = accelerator.CreateStream();
|
var stream = accelerator.CreateStream();
|
||||||
var kernel = GetInverseKernel(accelerator);
|
var kernel = GetInverseKernel(accelerator);
|
||||||
var pool = ArrayPool<GpuUInt128>.Shared;
|
var pool = ThreadStaticPools.GpuUInt128Pool;
|
||||||
var inputArray = pool.Rent(n);
|
var inputArray = pool.Rent(n);
|
||||||
var outputArray = pool.Rent(n);
|
var outputArray = pool.Rent(n);
|
||||||
values.CopyTo(inputArray);
|
values.CopyTo(inputArray);
|
||||||
@@ -857,7 +857,7 @@ public static class NttGpuMath
|
|||||||
n <<= 1;
|
n <<= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var pool = ArrayPool<GpuUInt128>.Shared;
|
var pool = ThreadStaticPools.GpuUInt128Pool;
|
||||||
var aBuffer = pool.Rent(n);
|
var aBuffer = pool.Rent(n);
|
||||||
var bBuffer = pool.Rent(n);
|
var bBuffer = pool.Rent(n);
|
||||||
var a = aBuffer.AsSpan(0, n);
|
var a = aBuffer.AsSpan(0, n);
|
||||||
@@ -894,7 +894,7 @@ public static class NttGpuMath
|
|||||||
n <<= 1;
|
n <<= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var pool = ArrayPool<GpuUInt128>.Shared;
|
var pool = ThreadStaticPools.GpuUInt128Pool;
|
||||||
var aBuffer = pool.Rent(n);
|
var aBuffer = pool.Rent(n);
|
||||||
var bBuffer = pool.Rent(n);
|
var bBuffer = pool.Rent(n);
|
||||||
var a = aBuffer.AsSpan(0, n);
|
var a = aBuffer.AsSpan(0, n);
|
||||||
@@ -943,7 +943,7 @@ public static class NttGpuMath
|
|||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
var stream = accelerator.CreateStream();
|
var stream = accelerator.CreateStream();
|
||||||
var kernel = GetMulKernel(accelerator);
|
var kernel = GetMulKernel(accelerator);
|
||||||
var pool = ArrayPool<GpuUInt128>.Shared;
|
var pool = ThreadStaticPools.GpuUInt128Pool;
|
||||||
var leftArray = pool.Rent(left.Length);
|
var leftArray = pool.Rent(left.Length);
|
||||||
var rightArray = pool.Rent(right.Length);
|
var rightArray = pool.Rent(right.Length);
|
||||||
left.CopyTo(leftArray);
|
left.CopyTo(leftArray);
|
||||||
|
|||||||
@@ -582,6 +582,7 @@ internal static partial class PrimeOrderGpuHeuristics
|
|||||||
GpuUInt128[]? rentedExponents = null;
|
GpuUInt128[]? rentedExponents = null;
|
||||||
GpuUInt128[]? rentedResults = null;
|
GpuUInt128[]? rentedResults = null;
|
||||||
var lease = GpuKernelPool.GetKernel();
|
var lease = GpuKernelPool.GetKernel();
|
||||||
|
ArrayPool<GpuUInt128> gpuUInt128Pool = ThreadStaticPools.GpuUInt128Pool;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -596,7 +597,7 @@ internal static partial class PrimeOrderGpuHeuristics
|
|||||||
|
|
||||||
Span<GpuUInt128> exponentSpan = length <= WideStackThreshold
|
Span<GpuUInt128> exponentSpan = length <= WideStackThreshold
|
||||||
? stackalloc GpuUInt128[length]
|
? stackalloc GpuUInt128[length]
|
||||||
: new Span<GpuUInt128>(rentedExponents = ArrayPool<GpuUInt128>.Shared.Rent(length), 0, length);
|
: new Span<GpuUInt128>(rentedExponents = gpuUInt128Pool.Rent(length), 0, length);
|
||||||
|
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < length; i++)
|
||||||
{
|
{
|
||||||
@@ -613,7 +614,7 @@ internal static partial class PrimeOrderGpuHeuristics
|
|||||||
|
|
||||||
Span<GpuUInt128> resultSpan = length <= WideStackThreshold
|
Span<GpuUInt128> resultSpan = length <= WideStackThreshold
|
||||||
? stackalloc GpuUInt128[length]
|
? stackalloc GpuUInt128[length]
|
||||||
: new Span<GpuUInt128>(rentedResults = ArrayPool<GpuUInt128>.Shared.Rent(length), 0, length);
|
: new Span<GpuUInt128>(rentedResults = gpuUInt128Pool.Rent(length), 0, length);
|
||||||
|
|
||||||
remainderBuffer.View.CopyToCPU(stream, ref MemoryMarshal.GetReference(resultSpan), length);
|
remainderBuffer.View.CopyToCPU(stream, ref MemoryMarshal.GetReference(resultSpan), length);
|
||||||
stream.Synchronize();
|
stream.Synchronize();
|
||||||
@@ -636,12 +637,8 @@ internal static partial class PrimeOrderGpuHeuristics
|
|||||||
{
|
{
|
||||||
if (rentedExponents is not null)
|
if (rentedExponents is not null)
|
||||||
{
|
{
|
||||||
ArrayPool<GpuUInt128>.Shared.Return(rentedExponents, clearArray: false);
|
gpuUInt128Pool.Return(rentedExponents, clearArray: false);
|
||||||
}
|
gpuUInt128Pool.Return(rentedResults!, clearArray: false);
|
||||||
|
|
||||||
if (rentedResults is not null)
|
|
||||||
{
|
|
||||||
ArrayPool<GpuUInt128>.Shared.Return(rentedResults, clearArray: false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lease.Dispose();
|
lease.Dispose();
|
||||||
|
|||||||
@@ -797,7 +797,7 @@ public class MersenneDivisorCycles
|
|||||||
ulong start = 3UL;
|
ulong start = 3UL;
|
||||||
var locker = new object();
|
var locker = new object();
|
||||||
|
|
||||||
var pool = ArrayPool<ulong>.Shared;
|
var pool = ThreadStaticPools.UlongPool;
|
||||||
ulong batchSizeUL = (ulong)batchSize, d, end;
|
ulong batchSizeUL = (ulong)batchSize, d, end;
|
||||||
int count = (int)Math.Min(batchSizeUL, maxDivisor), i, idx;
|
int count = (int)Math.Min(batchSizeUL, maxDivisor), i, idx;
|
||||||
ulong[] divisors, outCycles, validDivisors;
|
ulong[] divisors, outCycles, validDivisors;
|
||||||
|
|||||||
@@ -101,7 +101,8 @@ public sealed class MersenneNumberTester(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt128[] qsBuffer = ArrayPool<UInt128>.Shared.Rent((int)limit);
|
ArrayPool<UInt128> uInt128Pool = ThreadStaticPools.UInt128Pool;
|
||||||
|
UInt128[] qsBuffer = uInt128Pool.Rent((int)limit);
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
UInt128 k2 = 1UL;
|
UInt128 k2 = 1UL;
|
||||||
UInt128 q2;
|
UInt128 q2;
|
||||||
@@ -140,7 +141,7 @@ public sealed class MersenneNumberTester(
|
|||||||
|
|
||||||
if (idx == 0)
|
if (idx == 0)
|
||||||
{
|
{
|
||||||
ArrayPool<UInt128>.Shared.Return(qsBuffer);
|
ThreadStaticPools.UInt128Pool.Return(qsBuffer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,20 +157,21 @@ public sealed class MersenneNumberTester(
|
|||||||
int batchSize = GpuConstants.ScanBatchSize;
|
int batchSize = GpuConstants.ScanBatchSize;
|
||||||
ulong divMul = (ulong)((((UInt128)1 << 64) - 1UL) / exponent) + 1UL;
|
ulong divMul = (ulong)((((UInt128)1 << 64) - 1UL) / exponent) + 1UL;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
var gpuUInt128Pool = ThreadStaticPools.GpuUInt128Pool;
|
||||||
while (offset < idx)
|
while (offset < idx)
|
||||||
{
|
{
|
||||||
int count = Math.Min(batchSize, idx - offset);
|
int count = Math.Min(batchSize, idx - offset);
|
||||||
var qBuffer = accelerator.Allocate1D<PerfectNumbers.Core.Gpu.GpuUInt128>(count);
|
var qBuffer = accelerator.Allocate1D<GpuUInt128>(count);
|
||||||
var orderBuffer = accelerator.Allocate1D<ulong>(count);
|
var orderBuffer = accelerator.Allocate1D<ulong>(count);
|
||||||
// Convert to device-friendly GpuUInt128 on the fly
|
// Convert to device-friendly GpuUInt128 on the fly
|
||||||
var tmp = System.Buffers.ArrayPool<PerfectNumbers.Core.Gpu.GpuUInt128>.Shared.Rent(count);
|
var tmp = gpuUInt128Pool.Rent(count);
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
tmp[i] = (PerfectNumbers.Core.Gpu.GpuUInt128)qs[offset + i];
|
tmp[i] = (GpuUInt128)qs[offset + i];
|
||||||
}
|
}
|
||||||
// Copy only the populated elements to the device buffer to avoid overrun on pooled arrays.
|
// Copy only the populated elements to the device buffer to avoid overrun on pooled arrays.
|
||||||
qBuffer.View.CopyFromCPU(stream, ref tmp[0], count);
|
qBuffer.View.CopyFromCPU(stream, ref tmp[0], count);
|
||||||
System.Buffers.ArrayPool<PerfectNumbers.Core.Gpu.GpuUInt128>.Shared.Return(tmp);
|
gpuUInt128Pool.Return(tmp);
|
||||||
orderKernel(stream, count, exponent, divMul, qBuffer.View, orderBuffer.View);
|
orderKernel(stream, count, exponent, divMul, qBuffer.View, orderBuffer.View);
|
||||||
stream.Synchronize();
|
stream.Synchronize();
|
||||||
|
|
||||||
@@ -195,7 +197,7 @@ public sealed class MersenneNumberTester(
|
|||||||
}
|
}
|
||||||
|
|
||||||
gpuLease.Dispose();
|
gpuLease.Dispose();
|
||||||
ArrayPool<UInt128>.Shared.Return(qs);
|
uInt128Pool.Return(qs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsMersennePrime(ulong exponent)
|
public bool IsMersennePrime(ulong exponent)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Runtime.CompilerServices;
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using UInt128 = System.UInt128;
|
using UInt128 = System.UInt128;
|
||||||
using ILGPU;
|
using ILGPU;
|
||||||
|
using System.Buffers;
|
||||||
|
|
||||||
namespace PerfectNumbers.Core;
|
namespace PerfectNumbers.Core;
|
||||||
|
|
||||||
@@ -75,6 +76,7 @@ public static class MersennePrimeFactorTester
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static UInt128 OrderOf2ModPrime(UInt128 q, CancellationToken ct)
|
private static UInt128 OrderOf2ModPrime(UInt128 q, CancellationToken ct)
|
||||||
{
|
{
|
||||||
|
|
||||||
lock (_orderCache)
|
lock (_orderCache)
|
||||||
{
|
{
|
||||||
// TODO: Replace this lock with the lock-free order cache once the divisor-cycle snapshot exposes
|
// TODO: Replace this lock with the lock-free order cache once the divisor-cycle snapshot exposes
|
||||||
@@ -86,6 +88,8 @@ public static class MersennePrimeFactorTester
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArrayPool<UInt128> uInt128Pool = ThreadStaticPools.UInt128Pool;
|
||||||
|
|
||||||
UInt128 phi = q - 1;
|
UInt128 phi = q - 1;
|
||||||
UInt128[] factors = phi <= ulong.MaxValue
|
UInt128[] factors = phi <= ulong.MaxValue
|
||||||
? Array.ConvertAll(Factor64((ulong)phi, ct), x => (UInt128)x)
|
? Array.ConvertAll(Factor64((ulong)phi, ct), x => (UInt128)x)
|
||||||
@@ -101,6 +105,7 @@ public static class MersennePrimeFactorTester
|
|||||||
prime = factors[i];
|
prime = factors[i];
|
||||||
if (ct.IsCancellationRequested)
|
if (ct.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
|
uInt128Pool.Return(factors);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,6 +115,7 @@ public static class MersennePrimeFactorTester
|
|||||||
{
|
{
|
||||||
if (ct.IsCancellationRequested)
|
if (ct.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
|
uInt128Pool.Return(factors);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,6 +129,8 @@ public static class MersennePrimeFactorTester
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uInt128Pool.Return(factors);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Integrate divisor-cycle data here so repeated order refinement uses cached cycle
|
// TODO: Integrate divisor-cycle data here so repeated order refinement uses cached cycle
|
||||||
@@ -136,6 +144,7 @@ public static class MersennePrimeFactorTester
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uInt128Pool.Return(factors);
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,9 +336,7 @@ public static class MersennePrimeFactorTester
|
|||||||
queue.Enqueue(m / d);
|
queue.Enqueue(m / d);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = new UInt128[dict.Count]; // TODO: Rent this array from ArrayPool<UInt128> so
|
var result = ThreadStaticPools.UInt128Pool.Rent(dict.Count);
|
||||||
// wide-factorization batches stop allocating fresh
|
|
||||||
// buffers per candidate.
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
foreach (var key in dict.Keys)
|
foreach (var key in dict.Keys)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -50,12 +50,12 @@ namespace PerfectNumbers.Core
|
|||||||
FactorEntry[]? source = Factors;
|
FactorEntry[]? source = Factors;
|
||||||
if (source is null || Count == 0)
|
if (source is null || Count == 0)
|
||||||
{
|
{
|
||||||
FactorEntry[] local = ArrayPool<FactorEntry>.Shared.Rent(1);
|
FactorEntry[] local = ThreadStaticPools.FactorEntryPool.Rent(1);
|
||||||
local[0] = new FactorEntry(prime, 1, true);
|
local[0] = new FactorEntry(prime, 1, true);
|
||||||
return Rent(local, 1UL, true, 1, false);
|
return Rent(local, 1UL, true, 1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
FactorEntry[] extended = ArrayPool<FactorEntry>.Shared.Rent(Count + 1);
|
FactorEntry[] extended = ThreadStaticPools.FactorEntryPool.Rent(Count + 1);
|
||||||
Array.Copy(source, 0, extended, 0, Count);
|
Array.Copy(source, 0, extended, 0, Count);
|
||||||
extended[Count] = new FactorEntry(prime, 1, true);
|
extended[Count] = new FactorEntry(prime, 1, true);
|
||||||
Span<FactorEntry> span = extended.AsSpan(0, Count + 1);
|
Span<FactorEntry> span = extended.AsSpan(0, Count + 1);
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ public sealed class PrimeCache
|
|||||||
index = ~index;
|
index = ~index;
|
||||||
}
|
}
|
||||||
|
|
||||||
EInteger[] primesArray = ArrayPool<EInteger>.Shared.Rent(_primes.Count);
|
ArrayPool<EInteger> eIntegerPool = ThreadStaticPools.EIntegerPool;
|
||||||
|
EInteger[] primesArray = eIntegerPool.Rent(_primes.Count);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Span<EInteger> primes = new(primesArray);
|
Span<EInteger> primes = new(primesArray);
|
||||||
@@ -64,7 +65,7 @@ public sealed class PrimeCache
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
ArrayPool<EInteger>.Shared.Return(primesArray);
|
eIntegerPool.Return(primesArray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,24 @@ using System.Collections.Generic;
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using PerfectNumbers.Core.Cpu;
|
using PerfectNumbers.Core.Cpu;
|
||||||
using PerfectNumbers.Core.Gpu;
|
using PerfectNumbers.Core.Gpu;
|
||||||
|
using PeterO.Numbers;
|
||||||
|
|
||||||
namespace PerfectNumbers.Core
|
namespace PerfectNumbers.Core
|
||||||
{
|
{
|
||||||
public readonly struct ThreadStaticPools
|
public readonly struct ThreadStaticPools
|
||||||
{
|
{
|
||||||
|
[ThreadStatic]
|
||||||
|
private static ArrayPool<EInteger>? _eintegerPool;
|
||||||
|
|
||||||
|
public static ArrayPool<EInteger> EIntegerPool
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _eintegerPool ??= ArrayPool<EInteger>.Create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[ThreadStatic]
|
[ThreadStatic]
|
||||||
private static ArrayPool<FactorEntry>? _factorEntryPool;
|
private static ArrayPool<FactorEntry>? _factorEntryPool;
|
||||||
|
|
||||||
@@ -32,6 +45,18 @@ namespace PerfectNumbers.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ThreadStatic]
|
||||||
|
private static ArrayPool<GpuUInt128>? _gpuUInt128Pool;
|
||||||
|
|
||||||
|
public static ArrayPool<GpuUInt128> GpuUInt128Pool
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _gpuUInt128Pool ??= ArrayPool<GpuUInt128>.Create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[ThreadStatic]
|
[ThreadStatic]
|
||||||
private static MersenneCpuDivisorScanSession? _mersenneCpuDivisorSession;
|
private static MersenneCpuDivisorScanSession? _mersenneCpuDivisorSession;
|
||||||
|
|
||||||
@@ -55,6 +80,18 @@ namespace PerfectNumbers.Core
|
|||||||
_mersenneCpuDivisorSession = session;
|
_mersenneCpuDivisorSession = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ThreadStatic]
|
||||||
|
private static ArrayPool<UInt128>? _uint128Pool;
|
||||||
|
|
||||||
|
public static ArrayPool<UInt128> UInt128Pool
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _uint128Pool ??= ArrayPool<UInt128>.Create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[ThreadStatic]
|
[ThreadStatic]
|
||||||
private static ArrayPool<ulong>? _ulongPool;
|
private static ArrayPool<ulong>? _ulongPool;
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user