From cf9d143ca2f27d40a3d1893b6b72600689b3fd12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Lema=C5=84czyk?= Date: Fri, 24 Oct 2025 05:05:21 +0200 Subject: [PATCH] Remove GPU by-divisor snapshot dependency --- ...MersenneNumberDivisorByDivisorGpuTester.cs | 76 ++++++++----------- 1 file changed, 31 insertions(+), 45 deletions(-) diff --git a/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs b/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs index 690bff7..a25cc51 100644 --- a/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs +++ b/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs @@ -113,8 +113,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv resources.Divisors, resources.Exponents, resources.DivisorData, - resources.CycleLengths, - resources.CycleCapacity, out lastProcessed, out coveredRange, out processedCount); @@ -173,8 +171,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv in ulong[] divisors, ulong[] exponents, MontgomeryDivisorData[] divisorData, - ulong[] cycleLengths, - int cycleCapacity, out ulong lastProcessed, out bool coveredRange, out ulong processedCount) @@ -185,8 +181,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv processedCount = 0UL; lastProcessed = 0UL; - cycleCapacity = Math.Max(1, cycleCapacity); - int chunkCapacity = Math.Min(batchCapacity, cycleCapacity); + int chunkCapacity = Math.Max(1, batchCapacity); UInt128 twoP128 = (UInt128)prime << 1; UInt128 allowedMax128 = allowedMax; @@ -207,12 +202,9 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv UInt128 currentDivisor128 = firstDivisor128; bool lastIsSeven = (prime & 3UL) == 3UL; - DivisorCycleCache cycleCache = DivisorCycleCache.Shared; - ArrayPool ulongPool = ThreadStaticPools.UlongPool; ulong[] filteredDivisors = ulongPool.Rent(chunkCapacity); Span filteredStorage = filteredDivisors.AsSpan(); - Span cycleLengthStorage = cycleLengths.AsSpan(); Span divisorDataStorage = divisorData.AsSpan(); Span divisorStorage = divisors.AsSpan(); Span exponentStorage = exponents.AsSpan(); @@ -261,20 +253,25 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv } Span filteredDivisorsSpan = filteredStorage[..filteredCount]; - Span cycleSpan = cycleLengthStorage[..filteredCount]; - cycleCache.GetCycleLengths(filteredDivisorsSpan, cycleSpan); + + Span divisorDataSpan = divisorDataStorage; + Span divisorSpan = divisorStorage; + Span exponentSpan = exponentStorage; int admissibleCount = 0; for (int i = 0; i < filteredCount; i++) { - ulong candidate = filteredDivisorsSpan[i]; - ulong candidateCycle = cycleSpan[i]; - if (candidateCycle != prime) + ulong divisorValue = filteredDivisorsSpan[i]; + MontgomeryDivisorData divisorDataValue = MontgomeryDivisorData.FromModulus(divisorValue); + ulong divisorCycle = ResolveDivisorCycle(divisorValue, prime, divisorDataValue); + if (divisorCycle != prime) { continue; } - filteredDivisorsSpan[admissibleCount] = candidate; + divisorSpan[admissibleCount] = divisorValue; + exponentSpan[admissibleCount] = prime; + divisorDataSpan[admissibleCount] = divisorDataValue; admissibleCount++; } @@ -283,24 +280,16 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv continue; } - Span divisorDataSpan = divisorDataStorage[..admissibleCount]; - Span divisorSpan = divisorStorage[..admissibleCount]; - Span exponentSpan = exponentStorage[..admissibleCount]; + Span activeDivisors = divisorSpan[..admissibleCount]; + Span activeDivisorData = divisorDataSpan[..admissibleCount]; + Span activeExponents = exponentSpan[..admissibleCount]; ArrayView1D divisorView = divisorsBuffer.View.SubView(0, admissibleCount); ArrayView1D exponentView = exponentBuffer.View.SubView(0, admissibleCount); ArrayView1D hitsView = hitsBuffer.View.SubView(0, admissibleCount); ArrayView1D hitIndexView = hitIndexBuffer.View.SubView(0, 1); - for (int i = 0; i < admissibleCount; i++) - { - 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); + divisorView.CopyFromCPU(ref MemoryMarshal.GetReference(activeDivisorData), admissibleCount); + exponentView.CopyFromCPU(ref MemoryMarshal.GetReference(activeExponents), admissibleCount); int sentinel = int.MaxValue; hitIndexView.SubView(0, 1).CopyFromCPU(ref sentinel, 1); @@ -312,7 +301,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv bool hitFound = hitIndex >= 0; composite = hitFound; int lastIndex = admissibleCount - 1; - lastProcessed = hitFound ? divisorSpan[hitIndex] : divisorSpan[lastIndex]; + lastProcessed = hitFound ? activeDivisors[hitIndex] : activeDivisors[lastIndex]; } ulongPool.Return(filteredDivisors, clearArray: false); @@ -321,11 +310,21 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv 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)] private static bool CandidatePassesHeuristics(ulong candidate, bool lastIsSeven) { - // Keep the divisibility filters aligned with the divisor-cycle snapshot so we never - // request missing entries from the cache. + // Mirror the CPU heuristics so the GPU path rejects obvious composites before computing cycles. ulong remainder10 = candidate % 10UL; bool accept10 = lastIsSeven ? (remainder10 == 3UL || remainder10 == 7UL || remainder10 == 9UL) @@ -574,13 +573,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv { internal BatchResources(Accelerator accelerator, int capacity) { - int cycleCapacity = DivisorCycleCache.Shared.PreferredBatchSize; - if (cycleCapacity <= 0) - { - cycleCapacity = 1; - } - - int actualCapacity = Math.Max(capacity, cycleCapacity); + int actualCapacity = Math.Max(1, capacity); DivisorsBuffer = accelerator.Allocate1D(actualCapacity); ExponentBuffer = accelerator.Allocate1D(actualCapacity); @@ -590,9 +583,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv Divisors = ulongPool.Rent(actualCapacity); Exponents = ulongPool.Rent(actualCapacity); DivisorData = ThreadStaticPools.MontgomeryDivisorDataPool.Rent(actualCapacity); - CycleLengths = ulongPool.Rent(cycleCapacity); Capacity = actualCapacity; - CycleCapacity = cycleCapacity; } internal readonly MemoryBuffer1D DivisorsBuffer; @@ -609,12 +600,8 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv internal readonly MontgomeryDivisorData[] DivisorData; - internal readonly ulong[] CycleLengths; - internal readonly int Capacity; - internal readonly int CycleCapacity; - public void Dispose() { DivisorsBuffer.Dispose(); @@ -626,7 +613,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv ulongPool.Return(Divisors, clearArray: false); ulongPool.Return(Exponents, clearArray: false); divisorPool.Return(DivisorData, clearArray: false); - ulongPool.Return(CycleLengths, clearArray: false); } }