Convert divisor session results to hits on the GPU
This commit is contained in:
1 parent
faab60c2cd
commit
ea01585892
3 files changed
+56
-42
No files matched your search
@@ -197,17 +197,7 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
|
|
||||||
session.CheckDivisor(7UL, divisorData, cycle, exponents, hits);
|
session.CheckDivisor(7UL, divisorData, cycle, exponents, hits);
|
||||||
|
|
||||||
var hostBufferField = typeof(MersenneNumberDivisorByDivisorGpuTester.DivisorScanSession)
|
hits.Should().Equal(new byte[] { 1, 0, 1, 0, 1 });
|
||||||
.GetField("_hostBuffer", BindingFlags.NonPublic | BindingFlags.Instance)!;
|
|
||||||
ulong[] hostBuffer = (ulong[])hostBufferField.GetValue(session)!;
|
|
||||||
Span<ulong> residues = hostBuffer.AsSpan(0, exponents.Length);
|
|
||||||
byte[] computedHits = new byte[exponents.Length];
|
|
||||||
for (int i = 0; i < residues.Length; i++)
|
|
||||||
{
|
|
||||||
computedHits[i] = residues[i] == divisorData.MontgomeryOne ? (byte)1 : (byte)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
computedHits.Should().Equal(new byte[] { 1, 0, 1, 0, 1 });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -229,17 +219,7 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
|
|
||||||
session.CheckDivisor(11UL, divisorData, cycle, exponents, hits);
|
session.CheckDivisor(11UL, divisorData, cycle, exponents, hits);
|
||||||
|
|
||||||
var hostBufferField = typeof(MersenneNumberDivisorByDivisorGpuTester.DivisorScanSession)
|
hits.Should().Equal(new byte[] { 1, 0, 1, 0, 1 });
|
||||||
.GetField("_hostBuffer", BindingFlags.NonPublic | BindingFlags.Instance)!;
|
|
||||||
ulong[] hostBuffer = (ulong[])hostBufferField.GetValue(session)!;
|
|
||||||
Span<ulong> residues = hostBuffer.AsSpan(0, exponents.Length);
|
|
||||||
byte[] computedHits = new byte[exponents.Length];
|
|
||||||
for (int i = 0; i < residues.Length; i++)
|
|
||||||
{
|
|
||||||
computedHits[i] = residues[i] == divisorData.MontgomeryOne ? (byte)1 : (byte)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
computedHits.Should().Equal(new byte[] { 1, 0, 1, 0, 1 });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
@@ -255,6 +255,24 @@ internal static class DivisorByDivisorKernels
|
|||||||
Atomic.Min(ref firstHit[0], candidate);
|
Atomic.Min(ref firstHit[0], candidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ConvertMontgomeryResultsToHitsKernel(
|
||||||
|
Index1D index,
|
||||||
|
ArrayView<ulong> results,
|
||||||
|
ArrayView<byte> hits)
|
||||||
|
{
|
||||||
|
int globalIndex = index;
|
||||||
|
// EvenPerfectBitScanner launches this kernel with an extent matching the result and hit spans,
|
||||||
|
// so the defensive bounds guard stays commented out to keep the conversion branch-free.
|
||||||
|
// int length = (int)results.Length;
|
||||||
|
// if (globalIndex >= length)
|
||||||
|
// {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
ulong montgomeryResult = results[globalIndex];
|
||||||
|
hits[globalIndex] = montgomeryResult == 1UL ? (byte)1 : (byte)0;
|
||||||
|
}
|
||||||
|
|
||||||
public static void ComputeMontgomeryExponentKernel(Index1D index, MontgomeryDivisorData divisor, ArrayView<ulong> exponents, ArrayView<ulong> results)
|
public static void ComputeMontgomeryExponentKernel(Index1D index, MontgomeryDivisorData divisor, ArrayView<ulong> exponents, ArrayView<ulong> results)
|
||||||
{
|
{
|
||||||
ulong modulus = divisor.Modulus;
|
ulong modulus = divisor.Modulus;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
private readonly ConcurrentDictionary<Accelerator, Action<Index1D, ArrayView<byte>, ArrayView<byte>, ArrayView<byte>, ArrayView<byte>, byte, ArrayView<byte>>> _candidateMaskKernelCache = new(AcceleratorReferenceComparer.Instance);
|
private readonly ConcurrentDictionary<Accelerator, Action<Index1D, ArrayView<byte>, ArrayView<byte>, ArrayView<byte>, ArrayView<byte>, byte, ArrayView<byte>>> _candidateMaskKernelCache = new(AcceleratorReferenceComparer.Instance);
|
||||||
private readonly ConcurrentDictionary<Accelerator, Action<KernelConfig, Index1D, ArrayView<byte>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<int>>> _candidateCompactionKernelCache = new(AcceleratorReferenceComparer.Instance);
|
private readonly ConcurrentDictionary<Accelerator, Action<KernelConfig, Index1D, ArrayView<byte>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<int>>> _candidateCompactionKernelCache = new(AcceleratorReferenceComparer.Instance);
|
||||||
private readonly ConcurrentDictionary<Accelerator, Action<Index1D, ArrayView<byte>, ArrayView<int>>> _hitDetectionKernelCache = new(AcceleratorReferenceComparer.Instance);
|
private readonly ConcurrentDictionary<Accelerator, Action<Index1D, ArrayView<byte>, ArrayView<int>>> _hitDetectionKernelCache = new(AcceleratorReferenceComparer.Instance);
|
||||||
|
private readonly ConcurrentDictionary<Accelerator, Action<Index1D, ArrayView<ulong>, ArrayView<byte>>> _hitConversionKernelCache = new(AcceleratorReferenceComparer.Instance);
|
||||||
private readonly ConcurrentDictionary<Accelerator, Action<Index1D, ArrayView<ulong>, ArrayView<ulong>, ArrayView<GpuUInt128>, GpuUInt128, GpuUInt128>> _candidateGenerationKernelCache = new(AcceleratorReferenceComparer.Instance);
|
private readonly ConcurrentDictionary<Accelerator, Action<Index1D, ArrayView<ulong>, ArrayView<ulong>, ArrayView<GpuUInt128>, GpuUInt128, GpuUInt128>> _candidateGenerationKernelCache = new(AcceleratorReferenceComparer.Instance);
|
||||||
private readonly ConcurrentDictionary<Accelerator, ConcurrentBag<BatchResources>> _resourcePools = new(AcceleratorReferenceComparer.Instance);
|
private readonly ConcurrentDictionary<Accelerator, ConcurrentBag<BatchResources>> _resourcePools = new(AcceleratorReferenceComparer.Instance);
|
||||||
private readonly ConcurrentBag<GpuContextPool.GpuContextLease> _acceleratorPool = new();
|
private readonly ConcurrentBag<GpuContextPool.GpuContextLease> _acceleratorPool = new();
|
||||||
@@ -64,6 +65,11 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
accelerator,
|
accelerator,
|
||||||
acc => acc.LoadAutoGroupedStreamKernel<Index1D, ArrayView<byte>, ArrayView<int>>(DivisorByDivisorKernels.PublishFirstHitKernel));
|
acc => acc.LoadAutoGroupedStreamKernel<Index1D, ArrayView<byte>, ArrayView<int>>(DivisorByDivisorKernels.PublishFirstHitKernel));
|
||||||
|
|
||||||
|
private Action<Index1D, ArrayView<ulong>, ArrayView<byte>> GetResultConversionKernel(Accelerator accelerator) =>
|
||||||
|
_hitConversionKernelCache.GetOrAdd(
|
||||||
|
accelerator,
|
||||||
|
acc => acc.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<byte>>(DivisorByDivisorKernels.ConvertMontgomeryResultsToHitsKernel));
|
||||||
|
|
||||||
private Action<Index1D, ArrayView<ulong>, ArrayView<ulong>, ArrayView<GpuUInt128>, GpuUInt128, GpuUInt128> GetCandidateGenerationKernel(Accelerator accelerator) =>
|
private Action<Index1D, ArrayView<ulong>, ArrayView<ulong>, ArrayView<GpuUInt128>, GpuUInt128, GpuUInt128> GetCandidateGenerationKernel(Accelerator accelerator) =>
|
||||||
_candidateGenerationKernelCache.GetOrAdd(
|
_candidateGenerationKernelCache.GetOrAdd(
|
||||||
accelerator,
|
accelerator,
|
||||||
@@ -686,10 +692,12 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
private readonly MersenneNumberDivisorByDivisorGpuTester _owner;
|
private readonly MersenneNumberDivisorByDivisorGpuTester _owner;
|
||||||
private readonly GpuContextPool.GpuContextLease _lease;
|
private readonly GpuContextPool.GpuContextLease _lease;
|
||||||
private readonly Accelerator _accelerator;
|
private readonly Accelerator _accelerator;
|
||||||
private Action<Index1D, MontgomeryDivisorData, ArrayView<ulong>, ArrayView<ulong>> _kernel;
|
private Action<Index1D, MontgomeryDivisorData, ArrayView<ulong>, ArrayView<ulong>> _kernel = null!;
|
||||||
private MemoryBuffer1D<ulong, Stride1D.Dense> _exponentsBuffer;
|
private Action<Index1D, ArrayView<ulong>, ArrayView<byte>> _hitConversionKernel = null!;
|
||||||
private MemoryBuffer1D<ulong, Stride1D.Dense> _resultsBuffer;
|
private MemoryBuffer1D<ulong, Stride1D.Dense> _exponentsBuffer = null!;
|
||||||
private ulong[] _hostBuffer;
|
private MemoryBuffer1D<ulong, Stride1D.Dense> _resultsBuffer = null!;
|
||||||
|
private MemoryBuffer1D<byte, Stride1D.Dense> _hitBuffer = null!;
|
||||||
|
private ulong[] _hostBuffer = null!;
|
||||||
private int _capacity;
|
private int _capacity;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
@@ -709,8 +717,10 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
private void EnsureExecutionResourcesLocked()
|
private void EnsureExecutionResourcesLocked()
|
||||||
{
|
{
|
||||||
_kernel = _owner.GetKernelByPrimeExponent(_accelerator);
|
_kernel = _owner.GetKernelByPrimeExponent(_accelerator);
|
||||||
|
_hitConversionKernel = _owner.GetResultConversionKernel(_accelerator);
|
||||||
_exponentsBuffer = _accelerator.Allocate1D<ulong>(_capacity);
|
_exponentsBuffer = _accelerator.Allocate1D<ulong>(_capacity);
|
||||||
_resultsBuffer = _accelerator.Allocate1D<ulong>(_capacity);
|
_resultsBuffer = _accelerator.Allocate1D<ulong>(_capacity);
|
||||||
|
_hitBuffer = _accelerator.Allocate1D<byte>(_capacity);
|
||||||
_hostBuffer = ThreadStaticPools.UlongPool.Rent(_capacity);
|
_hostBuffer = ThreadStaticPools.UlongPool.Rent(_capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -722,26 +732,33 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
}
|
}
|
||||||
|
|
||||||
int length = primes.Length;
|
int length = primes.Length;
|
||||||
if (length == 0)
|
// EvenPerfectBitScanner always supplies at least one exponent per divisor check, so the previous zero-length guard stays commented out.
|
||||||
{
|
// if (length == 0)
|
||||||
return;
|
// {
|
||||||
}
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
if (divisorData.Modulus <= 1UL || (divisorData.Modulus & 1UL) == 0UL)
|
// The GPU divisor sessions only materialize odd moduli greater than one (q = 2kp + 1),
|
||||||
{
|
// so the defensive modulus guard stays commented out to keep the hot path branch-free.
|
||||||
hits.Clear();
|
// if (divisorData.Modulus <= 1UL || (divisorData.Modulus & 1UL) == 0UL)
|
||||||
return;
|
// {
|
||||||
}
|
// hits.Clear();
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
Monitor.Enter(_lease.ExecutionLock);
|
Monitor.Enter(_lease.ExecutionLock);
|
||||||
|
|
||||||
if (_kernel == null)
|
if (_kernel == null || _hitConversionKernel == null)
|
||||||
{
|
{
|
||||||
EnsureExecutionResourcesLocked();
|
EnsureExecutionResourcesLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var kernel = _kernel!;
|
||||||
|
var hitConversionKernel = _hitConversionKernel!;
|
||||||
|
|
||||||
ArrayView1D<ulong, Stride1D.Dense> exponentsView = _exponentsBuffer.View;
|
ArrayView1D<ulong, Stride1D.Dense> exponentsView = _exponentsBuffer.View;
|
||||||
ArrayView1D<ulong, Stride1D.Dense> resultsView = _resultsBuffer.View;
|
ArrayView1D<ulong, Stride1D.Dense> resultsView = _resultsBuffer.View;
|
||||||
|
ArrayView1D<byte, Stride1D.Dense> hitView = _hitBuffer.View;
|
||||||
Span<ulong> hostSpan = _hostBuffer.AsSpan(0, _capacity);
|
Span<ulong> hostSpan = _hostBuffer.AsSpan(0, _capacity);
|
||||||
|
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
@@ -755,14 +772,13 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
exponentSlice.CopyFromCPU(ref MemoryMarshal.GetReference(hostSpan), batchSize);
|
exponentSlice.CopyFromCPU(ref MemoryMarshal.GetReference(hostSpan), batchSize);
|
||||||
|
|
||||||
ArrayView1D<ulong, Stride1D.Dense> resultSlice = resultsView.SubView(0, batchSize);
|
ArrayView1D<ulong, Stride1D.Dense> resultSlice = resultsView.SubView(0, batchSize);
|
||||||
_kernel(batchSize, divisorData, exponentSlice, resultSlice);
|
kernel(batchSize, divisorData, exponentSlice, resultSlice);
|
||||||
resultSlice.CopyToCPU(ref MemoryMarshal.GetReference(hostSpan), batchSize);
|
|
||||||
|
ArrayView1D<byte, Stride1D.Dense> hitSliceView = hitView.SubView(0, batchSize);
|
||||||
|
hitConversionKernel(batchSize, resultSlice, hitSliceView);
|
||||||
|
|
||||||
Span<byte> hitSlice = hits.Slice(offset, batchSize);
|
Span<byte> hitSlice = hits.Slice(offset, batchSize);
|
||||||
for (int i = 0; i < batchSize; i++)
|
hitSliceView.CopyToCPU(ref MemoryMarshal.GetReference(hitSlice), batchSize);
|
||||||
{
|
|
||||||
hitSlice[i] = hostSpan[i] == 1UL ? (byte)1 : (byte)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += batchSize;
|
offset += batchSize;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user