Remove GPU by-divisor snapshot dependency

This commit is contained in:
Marek Lemańczyk committed 2025-10-24 05:05:21 +02:00
1 parent 8637ee8875
commit cf9d143ca2
1 file changed
+31 -45
@@ -113,8 +113,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
resources.Divisors, resources.Divisors,
resources.Exponents, resources.Exponents,
resources.DivisorData, resources.DivisorData,
resources.CycleLengths,
resources.CycleCapacity,
out lastProcessed, out lastProcessed,
out coveredRange, out coveredRange,
out processedCount); out processedCount);
@@ -173,8 +171,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
in ulong[] divisors, in ulong[] divisors,
ulong[] exponents, ulong[] exponents,
MontgomeryDivisorData[] divisorData, MontgomeryDivisorData[] divisorData,
ulong[] cycleLengths,
int cycleCapacity,
out ulong lastProcessed, out ulong lastProcessed,
out bool coveredRange, out bool coveredRange,
out ulong processedCount) out ulong processedCount)
@@ -185,8 +181,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
processedCount = 0UL; processedCount = 0UL;
lastProcessed = 0UL; lastProcessed = 0UL;
cycleCapacity = Math.Max(1, cycleCapacity); int chunkCapacity = Math.Max(1, batchCapacity);
int chunkCapacity = Math.Min(batchCapacity, cycleCapacity);
UInt128 twoP128 = (UInt128)prime << 1; UInt128 twoP128 = (UInt128)prime << 1;
UInt128 allowedMax128 = allowedMax; UInt128 allowedMax128 = allowedMax;
@@ -207,12 +202,9 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
UInt128 currentDivisor128 = firstDivisor128; UInt128 currentDivisor128 = firstDivisor128;
bool lastIsSeven = (prime & 3UL) == 3UL; bool lastIsSeven = (prime & 3UL) == 3UL;
DivisorCycleCache cycleCache = DivisorCycleCache.Shared;
ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool; ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool;
ulong[] filteredDivisors = ulongPool.Rent(chunkCapacity); ulong[] filteredDivisors = ulongPool.Rent(chunkCapacity);
Span<ulong> filteredStorage = filteredDivisors.AsSpan(); Span<ulong> filteredStorage = filteredDivisors.AsSpan();
Span<ulong> cycleLengthStorage = cycleLengths.AsSpan();
Span<MontgomeryDivisorData> divisorDataStorage = divisorData.AsSpan(); Span<MontgomeryDivisorData> divisorDataStorage = divisorData.AsSpan();
Span<ulong> divisorStorage = divisors.AsSpan(); Span<ulong> divisorStorage = divisors.AsSpan();
Span<ulong> exponentStorage = exponents.AsSpan(); Span<ulong> exponentStorage = exponents.AsSpan();
@@ -261,20 +253,25 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
} }
Span<ulong> filteredDivisorsSpan = filteredStorage[..filteredCount]; Span<ulong> filteredDivisorsSpan = filteredStorage[..filteredCount];
Span<ulong> cycleSpan = cycleLengthStorage[..filteredCount];
cycleCache.GetCycleLengths(filteredDivisorsSpan, cycleSpan); Span<MontgomeryDivisorData> divisorDataSpan = divisorDataStorage;
Span<ulong> divisorSpan = divisorStorage;
Span<ulong> exponentSpan = exponentStorage;
int admissibleCount = 0; int admissibleCount = 0;
for (int i = 0; i < filteredCount; i++) for (int i = 0; i < filteredCount; i++)
{ {
ulong candidate = filteredDivisorsSpan[i]; ulong divisorValue = filteredDivisorsSpan[i];
ulong candidateCycle = cycleSpan[i]; MontgomeryDivisorData divisorDataValue = MontgomeryDivisorData.FromModulus(divisorValue);
if (candidateCycle != prime) ulong divisorCycle = ResolveDivisorCycle(divisorValue, prime, divisorDataValue);
if (divisorCycle != prime)
{ {
continue; continue;
} }
filteredDivisorsSpan[admissibleCount] = candidate; divisorSpan[admissibleCount] = divisorValue;
exponentSpan[admissibleCount] = prime;
divisorDataSpan[admissibleCount] = divisorDataValue;
admissibleCount++; admissibleCount++;
} }
@@ -283,24 +280,16 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
continue; continue;
} }
Span<MontgomeryDivisorData> divisorDataSpan = divisorDataStorage[..admissibleCount]; Span<ulong> activeDivisors = divisorSpan[..admissibleCount];
Span<ulong> divisorSpan = divisorStorage[..admissibleCount]; Span<MontgomeryDivisorData> activeDivisorData = divisorDataSpan[..admissibleCount];
Span<ulong> exponentSpan = exponentStorage[..admissibleCount]; Span<ulong> activeExponents = exponentSpan[..admissibleCount];
ArrayView1D<MontgomeryDivisorData, Stride1D.Dense> divisorView = divisorsBuffer.View.SubView(0, admissibleCount); ArrayView1D<MontgomeryDivisorData, Stride1D.Dense> divisorView = divisorsBuffer.View.SubView(0, admissibleCount);
ArrayView1D<ulong, Stride1D.Dense> exponentView = exponentBuffer.View.SubView(0, admissibleCount); ArrayView1D<ulong, Stride1D.Dense> exponentView = exponentBuffer.View.SubView(0, admissibleCount);
ArrayView1D<byte, Stride1D.Dense> hitsView = hitsBuffer.View.SubView(0, admissibleCount); ArrayView1D<byte, Stride1D.Dense> hitsView = hitsBuffer.View.SubView(0, admissibleCount);
ArrayView1D<int, Stride1D.Dense> hitIndexView = hitIndexBuffer.View.SubView(0, 1); ArrayView1D<int, Stride1D.Dense> hitIndexView = hitIndexBuffer.View.SubView(0, 1);
for (int i = 0; i < admissibleCount; i++) divisorView.CopyFromCPU(ref MemoryMarshal.GetReference(activeDivisorData), admissibleCount);
{ exponentView.CopyFromCPU(ref MemoryMarshal.GetReference(activeExponents), admissibleCount);
ulong divisorValue = filteredDivisorsSpan[i];
divisorSpan[i] = divisorValue;
exponentSpan[i] = prime;
divisorDataSpan[i] = MontgomeryDivisorData.FromModulus(divisorValue);
}
divisorView.CopyFromCPU(ref MemoryMarshal.GetReference(divisorDataSpan), admissibleCount);
exponentView.CopyFromCPU(ref MemoryMarshal.GetReference(exponentSpan), admissibleCount);
int sentinel = int.MaxValue; int sentinel = int.MaxValue;
hitIndexView.SubView(0, 1).CopyFromCPU(ref sentinel, 1); hitIndexView.SubView(0, 1).CopyFromCPU(ref sentinel, 1);
@@ -312,7 +301,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
bool hitFound = hitIndex >= 0; bool hitFound = hitIndex >= 0;
composite = hitFound; composite = hitFound;
int lastIndex = admissibleCount - 1; int lastIndex = admissibleCount - 1;
lastProcessed = hitFound ? divisorSpan[hitIndex] : divisorSpan[lastIndex]; lastProcessed = hitFound ? activeDivisors[hitIndex] : activeDivisors[lastIndex];
} }
ulongPool.Return(filteredDivisors, clearArray: false); ulongPool.Return(filteredDivisors, clearArray: false);
@@ -321,11 +310,21 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
return composite; return composite;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong ResolveDivisorCycle(ulong divisor, ulong prime, in MontgomeryDivisorData divisorData)
{
if (!MersenneDivisorCycles.TryCalculateCycleLengthForExponent(divisor, prime, divisorData, out ulong computedCycle, out bool primeOrderFailed) || computedCycle == 0UL)
{
return MersenneDivisorCycles.CalculateCycleLength(divisor, divisorData, skipPrimeOrderHeuristic: primeOrderFailed);
}
return computedCycle;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool CandidatePassesHeuristics(ulong candidate, bool lastIsSeven) private static bool CandidatePassesHeuristics(ulong candidate, bool lastIsSeven)
{ {
// Keep the divisibility filters aligned with the divisor-cycle snapshot so we never // Mirror the CPU heuristics so the GPU path rejects obvious composites before computing cycles.
// request missing entries from the cache.
ulong remainder10 = candidate % 10UL; ulong remainder10 = candidate % 10UL;
bool accept10 = lastIsSeven bool accept10 = lastIsSeven
? (remainder10 == 3UL || remainder10 == 7UL || remainder10 == 9UL) ? (remainder10 == 3UL || remainder10 == 7UL || remainder10 == 9UL)
@@ -574,13 +573,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
{ {
internal BatchResources(Accelerator accelerator, int capacity) internal BatchResources(Accelerator accelerator, int capacity)
{ {
int cycleCapacity = DivisorCycleCache.Shared.PreferredBatchSize; int actualCapacity = Math.Max(1, capacity);
if (cycleCapacity <= 0)
{
cycleCapacity = 1;
}
int actualCapacity = Math.Max(capacity, cycleCapacity);
DivisorsBuffer = accelerator.Allocate1D<MontgomeryDivisorData>(actualCapacity); DivisorsBuffer = accelerator.Allocate1D<MontgomeryDivisorData>(actualCapacity);
ExponentBuffer = accelerator.Allocate1D<ulong>(actualCapacity); ExponentBuffer = accelerator.Allocate1D<ulong>(actualCapacity);
@@ -590,9 +583,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
Divisors = ulongPool.Rent(actualCapacity); Divisors = ulongPool.Rent(actualCapacity);
Exponents = ulongPool.Rent(actualCapacity); Exponents = ulongPool.Rent(actualCapacity);
DivisorData = ThreadStaticPools.MontgomeryDivisorDataPool.Rent(actualCapacity); DivisorData = ThreadStaticPools.MontgomeryDivisorDataPool.Rent(actualCapacity);
CycleLengths = ulongPool.Rent(cycleCapacity);
Capacity = actualCapacity; Capacity = actualCapacity;
CycleCapacity = cycleCapacity;
} }
internal readonly MemoryBuffer1D<MontgomeryDivisorData, Stride1D.Dense> DivisorsBuffer; internal readonly MemoryBuffer1D<MontgomeryDivisorData, Stride1D.Dense> DivisorsBuffer;
@@ -609,12 +600,8 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
internal readonly MontgomeryDivisorData[] DivisorData; internal readonly MontgomeryDivisorData[] DivisorData;
internal readonly ulong[] CycleLengths;
internal readonly int Capacity; internal readonly int Capacity;
internal readonly int CycleCapacity;
public void Dispose() public void Dispose()
{ {
DivisorsBuffer.Dispose(); DivisorsBuffer.Dispose();
@@ -626,7 +613,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
ulongPool.Return(Divisors, clearArray: false); ulongPool.Return(Divisors, clearArray: false);
ulongPool.Return(Exponents, clearArray: false); ulongPool.Return(Exponents, clearArray: false);
divisorPool.Return(DivisorData, clearArray: false); divisorPool.Return(DivisorData, clearArray: false);
ulongPool.Return(CycleLengths, clearArray: false);
} }
} }