Streamline GPU remainder batching tables
This commit is contained in:
1 parent
483584b5d4
commit
9e06a21718
3 files changed
+49
-65
No files matched your search
@@ -419,15 +419,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
byte[] stepBuffer = ArrayPool<byte>.Shared.Rent(RemainderTableSize);
|
byte[] stepBuffer = ArrayPool<byte>.Shared.Rent(RemainderTableSize);
|
||||||
Span<byte> remainderSpan = remainderBuffer.AsSpan(0, RemainderTableSize);
|
Span<byte> remainderSpan = remainderBuffer.AsSpan(0, RemainderTableSize);
|
||||||
Span<byte> stepSpan = stepBuffer.AsSpan(0, RemainderTableSize);
|
Span<byte> stepSpan = stepBuffer.AsSpan(0, RemainderTableSize);
|
||||||
Span<byte> modulusSpan = stackalloc byte[RemainderTableSize]
|
// The remainder and step tables follow the fixed modulus order: 10, 8, 5, 3, 7, 11.
|
||||||
{
|
|
||||||
10,
|
|
||||||
8,
|
|
||||||
5,
|
|
||||||
3,
|
|
||||||
7,
|
|
||||||
11,
|
|
||||||
};
|
|
||||||
|
|
||||||
ulong startDivisor64 = divisor128.Low;
|
ulong startDivisor64 = divisor128.Low;
|
||||||
remainderSpan[0] = (byte)(startDivisor64 % 10UL);
|
remainderSpan[0] = (byte)(startDivisor64 % 10UL);
|
||||||
@@ -446,7 +438,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
|
|
||||||
bool lastIsSeven = (prime & 3UL) == 3UL;
|
bool lastIsSeven = (prime & 3UL) == 3UL;
|
||||||
|
|
||||||
MersenneNumberDivisorRemainderGpuStepper remainderStepper = new(stepSpan, modulusSpan);
|
MersenneNumberDivisorRemainderGpuStepper remainderStepper = new(stepSpan);
|
||||||
MersenneNumberDivisorMontgomeryGpuBuilder? montgomeryBuilder = _montgomeryDevice == ByDivisorMontgomeryDevice.Gpu
|
MersenneNumberDivisorMontgomeryGpuBuilder? montgomeryBuilder = _montgomeryDevice == ByDivisorMontgomeryDevice.Gpu
|
||||||
? new MersenneNumberDivisorMontgomeryGpuBuilder(batchCapacity)
|
? new MersenneNumberDivisorMontgomeryGpuBuilder(batchCapacity)
|
||||||
: null;
|
: null;
|
||||||
@@ -481,18 +473,8 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
currentDivisor,
|
currentDivisor,
|
||||||
step,
|
step,
|
||||||
limit64,
|
limit64,
|
||||||
remainderSpan[0],
|
remainderSpan,
|
||||||
remainderSpan[1],
|
stepSpan,
|
||||||
remainderSpan[2],
|
|
||||||
remainderSpan[3],
|
|
||||||
remainderSpan[4],
|
|
||||||
remainderSpan[5],
|
|
||||||
stepSpan[0],
|
|
||||||
stepSpan[1],
|
|
||||||
stepSpan[2],
|
|
||||||
stepSpan[3],
|
|
||||||
stepSpan[4],
|
|
||||||
stepSpan[5],
|
|
||||||
lastIsSeven,
|
lastIsSeven,
|
||||||
candidateSpan,
|
candidateSpan,
|
||||||
maskSpan);
|
maskSpan);
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ namespace PerfectNumbers.Core.Gpu;
|
|||||||
|
|
||||||
internal sealed class MersenneNumberDivisorCandidateGpuEvaluator : IDisposable
|
internal sealed class MersenneNumberDivisorCandidateGpuEvaluator : IDisposable
|
||||||
{
|
{
|
||||||
|
private const int RemainderCount = 6;
|
||||||
|
|
||||||
private readonly GpuContextPool.GpuContextLease _lease;
|
private readonly GpuContextPool.GpuContextLease _lease;
|
||||||
private readonly Accelerator _accelerator;
|
private readonly Accelerator _accelerator;
|
||||||
private readonly Action<Index1D, CandidateFilterArgs, ArrayView<ulong>, ArrayView<byte>> _kernel;
|
private readonly Action<Index1D, CandidateFilterArgs, ArrayView<ulong>, ArrayView<byte>> _kernel;
|
||||||
@@ -49,18 +51,8 @@ internal sealed class MersenneNumberDivisorCandidateGpuEvaluator : IDisposable
|
|||||||
ulong startDivisor,
|
ulong startDivisor,
|
||||||
ulong step,
|
ulong step,
|
||||||
ulong limit,
|
ulong limit,
|
||||||
byte remainder10,
|
ReadOnlySpan<byte> remainders,
|
||||||
byte remainder8,
|
ReadOnlySpan<byte> steps,
|
||||||
byte remainder5,
|
|
||||||
byte remainder3,
|
|
||||||
byte remainder7,
|
|
||||||
byte remainder11,
|
|
||||||
byte step10,
|
|
||||||
byte step8,
|
|
||||||
byte step5,
|
|
||||||
byte step3,
|
|
||||||
byte step7,
|
|
||||||
byte step11,
|
|
||||||
bool lastIsSeven,
|
bool lastIsSeven,
|
||||||
Span<ulong> candidates,
|
Span<ulong> candidates,
|
||||||
Span<byte> mask)
|
Span<byte> mask)
|
||||||
@@ -70,6 +62,11 @@ internal sealed class MersenneNumberDivisorCandidateGpuEvaluator : IDisposable
|
|||||||
throw new ObjectDisposedException(nameof(MersenneNumberDivisorCandidateGpuEvaluator));
|
throw new ObjectDisposedException(nameof(MersenneNumberDivisorCandidateGpuEvaluator));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (remainders.Length != RemainderCount || steps.Length != RemainderCount)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Remainder and step tables must contain exactly six entries.");
|
||||||
|
}
|
||||||
|
|
||||||
int count = candidates.Length;
|
int count = candidates.Length;
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
{
|
{
|
||||||
@@ -88,18 +85,18 @@ internal sealed class MersenneNumberDivisorCandidateGpuEvaluator : IDisposable
|
|||||||
startDivisor,
|
startDivisor,
|
||||||
step,
|
step,
|
||||||
limit,
|
limit,
|
||||||
remainder10,
|
remainders[0],
|
||||||
remainder8,
|
remainders[1],
|
||||||
remainder5,
|
remainders[2],
|
||||||
remainder3,
|
remainders[3],
|
||||||
remainder7,
|
remainders[4],
|
||||||
remainder11,
|
remainders[5],
|
||||||
step10,
|
steps[0],
|
||||||
step8,
|
steps[1],
|
||||||
step5,
|
steps[2],
|
||||||
step3,
|
steps[3],
|
||||||
step7,
|
steps[4],
|
||||||
step11,
|
steps[5],
|
||||||
lastIsSeven ? (byte)1 : (byte)0);
|
lastIsSeven ? (byte)1 : (byte)0);
|
||||||
|
|
||||||
_kernel(count, args, candidateView, maskView);
|
_kernel(count, args, candidateView, maskView);
|
||||||
|
|||||||
@@ -8,50 +8,44 @@ namespace PerfectNumbers.Core.Gpu;
|
|||||||
|
|
||||||
internal sealed class MersenneNumberDivisorRemainderGpuStepper : IDisposable
|
internal sealed class MersenneNumberDivisorRemainderGpuStepper : IDisposable
|
||||||
{
|
{
|
||||||
|
private const int RemainderCount = 6;
|
||||||
|
|
||||||
private readonly GpuContextPool.GpuContextLease _lease;
|
private readonly GpuContextPool.GpuContextLease _lease;
|
||||||
private readonly Accelerator _accelerator;
|
private readonly Accelerator _accelerator;
|
||||||
private readonly Action<Index1D, int, ArrayView<byte>, ArrayView<byte>, ArrayView<byte>, ArrayView<byte>> _kernel;
|
private readonly Action<Index1D, int, ArrayView<byte>, ArrayView<byte>, ArrayView<byte>> _kernel;
|
||||||
private MemoryBuffer1D<byte, Stride1D.Dense> _remainderBuffer;
|
private MemoryBuffer1D<byte, Stride1D.Dense> _remainderBuffer;
|
||||||
private MemoryBuffer1D<byte, Stride1D.Dense> _stepBuffer;
|
private MemoryBuffer1D<byte, Stride1D.Dense> _stepBuffer;
|
||||||
private MemoryBuffer1D<byte, Stride1D.Dense> _modulusBuffer;
|
|
||||||
private MemoryBuffer1D<byte, Stride1D.Dense> _resultBuffer;
|
private MemoryBuffer1D<byte, Stride1D.Dense> _resultBuffer;
|
||||||
private byte[] _hostRemainders;
|
private byte[] _hostRemainders;
|
||||||
private byte[] _hostSteps;
|
private byte[] _hostSteps;
|
||||||
private byte[] _hostModuli;
|
|
||||||
private readonly int _length;
|
private readonly int _length;
|
||||||
private int _capacity;
|
private int _capacity;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
internal MersenneNumberDivisorRemainderGpuStepper(ReadOnlySpan<byte> steps, ReadOnlySpan<byte> moduli)
|
internal MersenneNumberDivisorRemainderGpuStepper(ReadOnlySpan<byte> steps)
|
||||||
{
|
{
|
||||||
if (steps.Length != moduli.Length)
|
if (steps.Length != RemainderCount)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Steps and moduli must have the same length.");
|
throw new ArgumentException("Step table must contain exactly six entries.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_lease = GpuContextPool.RentPreferred(preferCpu: false);
|
_lease = GpuContextPool.RentPreferred(preferCpu: false);
|
||||||
_accelerator = _lease.Accelerator;
|
_accelerator = _lease.Accelerator;
|
||||||
_kernel = _accelerator.LoadAutoGroupedStreamKernel<Index1D, int, ArrayView<byte>, ArrayView<byte>, ArrayView<byte>, ArrayView<byte>>(AdvanceRemaindersKernel);
|
_kernel = _accelerator.LoadAutoGroupedStreamKernel<Index1D, int, ArrayView<byte>, ArrayView<byte>, ArrayView<byte>>(AdvanceRemaindersKernel);
|
||||||
|
|
||||||
_length = steps.Length;
|
_length = steps.Length;
|
||||||
_capacity = Math.Max(1, _length);
|
_capacity = Math.Max(1, _length);
|
||||||
_remainderBuffer = _accelerator.Allocate1D<byte>(_capacity);
|
_remainderBuffer = _accelerator.Allocate1D<byte>(_capacity);
|
||||||
_stepBuffer = _accelerator.Allocate1D<byte>(_capacity);
|
_stepBuffer = _accelerator.Allocate1D<byte>(_capacity);
|
||||||
_modulusBuffer = _accelerator.Allocate1D<byte>(_capacity);
|
|
||||||
_resultBuffer = _accelerator.Allocate1D<byte>(_capacity);
|
_resultBuffer = _accelerator.Allocate1D<byte>(_capacity);
|
||||||
|
|
||||||
_hostRemainders = ArrayPool<byte>.Shared.Rent(_capacity);
|
_hostRemainders = ArrayPool<byte>.Shared.Rent(_capacity);
|
||||||
_hostSteps = ArrayPool<byte>.Shared.Rent(_capacity);
|
_hostSteps = ArrayPool<byte>.Shared.Rent(_capacity);
|
||||||
_hostModuli = ArrayPool<byte>.Shared.Rent(_capacity);
|
|
||||||
|
|
||||||
steps.CopyTo(_hostSteps.AsSpan(0, _length));
|
steps.CopyTo(_hostSteps.AsSpan(0, _length));
|
||||||
moduli.CopyTo(_hostModuli.AsSpan(0, _length));
|
|
||||||
|
|
||||||
ArrayView1D<byte, Stride1D.Dense> stepView = _stepBuffer.View.SubView(0, _length);
|
ArrayView1D<byte, Stride1D.Dense> stepView = _stepBuffer.View.SubView(0, _length);
|
||||||
stepView.CopyFromCPU(ref MemoryMarshal.GetReference(_hostSteps.AsSpan(0, _length)), _length);
|
stepView.CopyFromCPU(ref MemoryMarshal.GetReference(_hostSteps.AsSpan(0, _length)), _length);
|
||||||
|
|
||||||
ArrayView1D<byte, Stride1D.Dense> modulusView = _modulusBuffer.View.SubView(0, _length);
|
|
||||||
modulusView.CopyFromCPU(ref MemoryMarshal.GetReference(_hostModuli.AsSpan(0, _length)), _length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
@@ -64,11 +58,9 @@ internal sealed class MersenneNumberDivisorRemainderGpuStepper : IDisposable
|
|||||||
_disposed = true;
|
_disposed = true;
|
||||||
_remainderBuffer.Dispose();
|
_remainderBuffer.Dispose();
|
||||||
_stepBuffer.Dispose();
|
_stepBuffer.Dispose();
|
||||||
_modulusBuffer.Dispose();
|
|
||||||
_resultBuffer.Dispose();
|
_resultBuffer.Dispose();
|
||||||
ArrayPool<byte>.Shared.Return(_hostRemainders, clearArray: false);
|
ArrayPool<byte>.Shared.Return(_hostRemainders, clearArray: false);
|
||||||
ArrayPool<byte>.Shared.Return(_hostSteps, clearArray: false);
|
ArrayPool<byte>.Shared.Return(_hostSteps, clearArray: false);
|
||||||
ArrayPool<byte>.Shared.Return(_hostModuli, clearArray: false);
|
|
||||||
_lease.Dispose();
|
_lease.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,16 +88,15 @@ internal sealed class MersenneNumberDivisorRemainderGpuStepper : IDisposable
|
|||||||
remainderView.CopyFromCPU(ref MemoryMarshal.GetReference(hostRemainderSpan), _length);
|
remainderView.CopyFromCPU(ref MemoryMarshal.GetReference(hostRemainderSpan), _length);
|
||||||
|
|
||||||
ArrayView1D<byte, Stride1D.Dense> stepView = _stepBuffer.View.SubView(0, _length);
|
ArrayView1D<byte, Stride1D.Dense> stepView = _stepBuffer.View.SubView(0, _length);
|
||||||
ArrayView1D<byte, Stride1D.Dense> modulusView = _modulusBuffer.View.SubView(0, _length);
|
|
||||||
ArrayView1D<byte, Stride1D.Dense> resultView = _resultBuffer.View.SubView(0, _length);
|
ArrayView1D<byte, Stride1D.Dense> resultView = _resultBuffer.View.SubView(0, _length);
|
||||||
|
|
||||||
_kernel(_length, advanceCount, remainderView, stepView, modulusView, resultView);
|
_kernel(_length, advanceCount, remainderView, stepView, resultView);
|
||||||
|
|
||||||
resultView.CopyToCPU(ref MemoryMarshal.GetReference(hostRemainderSpan), _length);
|
resultView.CopyToCPU(ref MemoryMarshal.GetReference(hostRemainderSpan), _length);
|
||||||
hostRemainderSpan.CopyTo(remainders);
|
hostRemainderSpan.CopyTo(remainders);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AdvanceRemaindersKernel(Index1D index, int advanceCount, ArrayView<byte> remainders, ArrayView<byte> steps, ArrayView<byte> moduli, ArrayView<byte> results)
|
private static void AdvanceRemaindersKernel(Index1D index, int advanceCount, ArrayView<byte> remainders, ArrayView<byte> steps, ArrayView<byte> results)
|
||||||
{
|
{
|
||||||
int idx = index;
|
int idx = index;
|
||||||
if (idx >= remainders.Length)
|
if (idx >= remainders.Length)
|
||||||
@@ -113,7 +104,7 @@ internal sealed class MersenneNumberDivisorRemainderGpuStepper : IDisposable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int modulus = moduli[idx];
|
int modulus = GetModulus(idx);
|
||||||
if (modulus == 0)
|
if (modulus == 0)
|
||||||
{
|
{
|
||||||
results[idx] = remainders[idx];
|
results[idx] = remainders[idx];
|
||||||
@@ -132,4 +123,18 @@ internal sealed class MersenneNumberDivisorRemainderGpuStepper : IDisposable
|
|||||||
|
|
||||||
results[idx] = (byte)adjusted;
|
results[idx] = (byte)adjusted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int GetModulus(int index)
|
||||||
|
{
|
||||||
|
return index switch
|
||||||
|
{
|
||||||
|
0 => 10,
|
||||||
|
1 => 8,
|
||||||
|
2 => 5,
|
||||||
|
3 => 3,
|
||||||
|
4 => 7,
|
||||||
|
5 => 11,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user