GPU logic updated to use prime % divisor result precomputed on CPU instead of re-calculating it on GPU side. Cycle lease removed.

This commit is contained in:
Marek Lemańczyk committed 2025-09-25 05:28:23 +02:00
1 parent a171e57353
commit 49fcd93747
2 files changed
+31 -95

No files matched your search

+9 -55
View File
@@ -12,60 +12,15 @@ namespace PerfectNumbers.Core;
public sealed class DivisorCycleCache
{
internal sealed class CycleBlock
public sealed class CycleBlock(int index, ulong start, ulong[] cycles)
{
internal CycleBlock(int index, ulong start, ulong[] cycles)
{
Index = index;
Start = start;
Cycles = cycles;
End = start + (ulong)cycles.Length - 1UL;
}
internal int Index { get; }
internal ulong Start { get; }
internal ulong End { get; }
internal ulong[] Cycles { get; }
internal readonly int Index = index;
internal readonly ulong Start = start;
internal readonly ulong End = start + (ulong)cycles.Length - 1UL;
internal readonly ulong[] Cycles = cycles;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ulong GetCycle(ulong divisor)
{
if (divisor < Start || divisor > End)
{
return 0UL;
}
return Cycles[(int)(divisor - Start)];
}
}
public struct Lease : IDisposable
{
private CycleBlock? _block;
internal Lease(CycleBlock block)
{
_block = block;
}
public readonly bool IsValid => _block is not null;
public readonly ulong Start => _block?.Start ?? 0UL;
public readonly ulong End => _block?.End ?? 0UL;
public readonly ulong[]? Values => _block?.Cycles;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly ulong GetCycle(ulong divisor) => _block?.GetCycle(divisor) ?? 0UL;
public void Dispose()
{
_block = null;
}
public ulong GetCycle(ulong divisor) => Cycles[(int)(divisor - Start)];
}
private const int CycleGenerationBatchSize = 262_144;
@@ -115,15 +70,14 @@ public sealed class DivisorCycleCache
}
}
public Lease Acquire(ulong divisor)
public CycleBlock Acquire(ulong divisor)
{
if (divisor <= _baseBlock.End)
{
return new Lease(_baseBlock);
return _baseBlock;
}
CycleBlock block = AcquireDynamicBlock(divisor);
return new Lease(block);
return AcquireDynamicBlock(divisor);
}
private CycleBlock AcquireDynamicBlock(ulong divisor)
@@ -25,14 +25,14 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
public readonly ulong MontgomeryTwo = montgomeryTwo;
}
private readonly ConcurrentDictionary<Accelerator, Action<Index1D, ulong, byte, ArrayView<MontgomeryDivisorData>, ArrayView<byte>>> _kernelCache = new();
private readonly ConcurrentDictionary<Accelerator, Action<Index1D, ulong, byte, ulong, ArrayView<MontgomeryDivisorData>, ArrayView<byte>>> _kernelCache = new();
private readonly ConcurrentDictionary<Accelerator, Action<Index1D, MontgomeryDivisorData, ArrayView<ulong>, ArrayView<ulong>>> _kernelExponentCache = new();
private readonly ConcurrentDictionary<Accelerator, ConcurrentBag<BatchResources>> _resourcePools = new(AcceleratorReferenceComparer.Instance);
private readonly ConcurrentDictionary<Accelerator, Action<Index1D, ulong, ArrayView<ulong>, ArrayView<byte>>> _cycleKernelCache = new();
private readonly ConcurrentBag<DivisorScanSession> _sessionPool = new();
private Action<Index1D, ulong, byte, ArrayView<MontgomeryDivisorData>, ArrayView<byte>> GetKernel(Accelerator accelerator) =>
_kernelCache.GetOrAdd(accelerator, acc => acc.LoadAutoGroupedStreamKernel<Index1D, ulong, byte, ArrayView<MontgomeryDivisorData>, ArrayView<byte>>(CheckKernel));
private Action<Index1D, ulong, byte, ulong, ArrayView<MontgomeryDivisorData>, ArrayView<byte>> GetKernel(Accelerator accelerator) =>
_kernelCache.GetOrAdd(accelerator, acc => acc.LoadAutoGroupedStreamKernel<Index1D, ulong, byte, ulong, ArrayView<MontgomeryDivisorData>, ArrayView<byte>>(CheckKernel));
private Action<Index1D, MontgomeryDivisorData, ArrayView<ulong>, ArrayView<ulong>> GetKernelByPrimeExponent(Accelerator accelerator) =>
_kernelExponentCache.GetOrAdd(accelerator, acc => acc.LoadAutoGroupedStreamKernel<Index1D, MontgomeryDivisorData, ArrayView<ulong>, ArrayView<ulong>>(ComputePrimeExponentKernel));
private Action<Index1D, ulong, ArrayView<ulong>, ArrayView<byte>> GetCycleKernel(Accelerator accelerator) =>
@@ -138,7 +138,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
ulong allowedMax,
bool useCycles,
Accelerator accelerator,
Action<Index1D, ulong, byte, ArrayView<MontgomeryDivisorData>, ArrayView<byte>> kernel,
Action<Index1D, ulong, byte, ulong, ArrayView<MontgomeryDivisorData>, ArrayView<byte>> kernel,
MemoryBuffer1D<MontgomeryDivisorData, Stride1D.Dense> divisorsBuffer,
MemoryBuffer1D<byte, Stride1D.Dense> hitsBuffer,
ulong[] divisors,
@@ -161,10 +161,9 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
bool composite = false;
bool processedAll = false;
ulong currentDivisor, divisor = 3UL, next, nextDivisor;
ulong currentDivisor = 3UL, cycle = 0UL, next, nextDivisor;
int batchSize, i;
bool reachedEndInBatch;
bool requiresCycleKernelCheck;
Span<MontgomeryDivisorData> divisorDataSpan;
Span<ulong> divisorSpan;
@@ -172,34 +171,31 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
ArrayView1D<MontgomeryDivisorData, Stride1D.Dense> divisorView;
ArrayView1D<byte, Stride1D.Dense> hitsView;
DivisorCycleCache divisorCyclesCache = DivisorCycleCache.Shared;
DivisorCycleCache.CycleBlock? cycleLease = useCycles ? divisorCyclesCache.Acquire(currentDivisor) : null;
while (divisor <= allowedMax)
while (currentDivisor <= allowedMax)
{
batchSize = 0;
reachedEndInBatch = false;
requiresCycleKernelCheck = false;
while (batchSize < batchCapacity && divisor <= allowedMax)
while (batchSize < batchCapacity && currentDivisor <= allowedMax)
{
currentDivisor = divisor;
nextDivisor = currentDivisor + 2UL;
processedCount++;
bool includeDivisor = true;
if (useCycles)
{
DivisorCycleCache.Lease cycleLease = divisorCyclesCache.Acquire(currentDivisor);
ulong cycle = cycleLease.GetCycle(currentDivisor);
if (cycle == 0UL)
if (currentDivisor > cycleLease!.End)
{
requiresCycleKernelCheck = true;
cycleLease = divisorCyclesCache.Acquire(currentDivisor);
}
else if (prime % cycle != 0UL)
cycle = prime % cycleLease.GetCycle(currentDivisor);
if (cycle != 0UL)
{
includeDivisor = false;
}
cycleLease.Dispose();
}
if (includeDivisor)
@@ -210,7 +206,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
lastProcessed = currentDivisor;
next = nextDivisor;
if (next <= divisor)
if (next <= currentDivisor)
{
reachedEndInBatch = true;
break;
@@ -218,12 +214,12 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
if (next > allowedMax)
{
divisor = next;
currentDivisor = next;
reachedEndInBatch = true;
break;
}
divisor = next;
currentDivisor = next;
}
if (batchSize == 0)
@@ -250,8 +246,8 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
}
divisorView.CopyFromCPU(ref MemoryMarshal.GetReference(divisorDataSpan), batchSize);
byte useCycleChecks = useCycles && requiresCycleKernelCheck ? (byte)1 : (byte)0;
kernel(batchSize, prime, useCycleChecks, divisorView, hitsView);
byte useCycleChecks = useCycles ? (byte)1 : (byte)0;
kernel(batchSize, prime, useCycleChecks, cycle, divisorView, hitsView);
accelerator.Synchronize();
hitsView.CopyToCPU(ref MemoryMarshal.GetReference(hitsSpan), batchSize);
@@ -281,7 +277,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
}
}
coveredRange = composite || processedAll || divisor > allowedMax;
coveredRange = composite || processedAll || currentDivisor > allowedMax;
return composite;
}
@@ -316,7 +312,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
return Math.Min((1UL << (int)(prime - 1UL)) - 1UL, divisorLimit);
}
private static void CheckKernel(Index1D index, ulong prime, byte useCycleChecks, ArrayView<MontgomeryDivisorData> divisors, ArrayView<byte> hits)
private static void CheckKernel(Index1D index, ulong prime, byte useCycleChecks, ulong cycle, ArrayView<MontgomeryDivisorData> divisors, ArrayView<byte> hits)
{
MontgomeryDivisorData divisor = divisors[index];
ulong modulus = divisor.Modulus;
@@ -326,26 +322,12 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
return;
}
ulong exponent = prime;
if (useCycleChecks != 0)
{
ulong cycle = MersenneDivisorCycles.CalculateCycleLengthGpu(modulus);
if (cycle == 0UL)
{
hits[index] = 0;
return;
}
ulong remainder = prime % cycle;
if (remainder != 0UL)
{
hits[index] = 0;
return;
prime = cycle;
}
exponent = remainder;
}
hits[index] = exponent.Pow2MontgomeryMod(divisor) == 1UL ? (byte)1 : (byte)0;
hits[index] = prime.Pow2MontgomeryMod(divisor) == 1UL ? (byte)1 : (byte)0;
}
public sealed class DivisorScanSession : IMersenneNumberDivisorByDivisorTester.IDivisorScanSession