Cache GPU remainder configs and fold constant modulos

This commit is contained in:
Marek Lemańczyk committed 2025-10-13 22:15:58 +02:00
1 parent 0b43880959
commit c6008a65b4
3 files changed
+32 -13

No files matched your search

@@ -1,6 +1,7 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Numerics; using System.Numerics;
@@ -122,6 +123,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
resources.CycleCandidates, resources.CycleCandidates,
resources.CycleLengths, resources.CycleLengths,
resources.CycleCapacity, resources.CycleCapacity,
resources,
out lastProcessed, out lastProcessed,
out coveredRange, out coveredRange,
out processedCount out processedCount
@@ -186,6 +188,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
ulong[] cycleCandidates, ulong[] cycleCandidates,
ulong[] cycleLengths, ulong[] cycleLengths,
int cycleCapacity, int cycleCapacity,
BatchResources resources,
out ulong lastProcessed, out ulong lastProcessed,
out bool coveredRange, out bool coveredRange,
out ulong processedCount) out ulong processedCount)
@@ -340,10 +343,10 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
gapView.CopyFromCPU(ref MemoryMarshal.GetReference(gapSpan), chunkCount); gapView.CopyFromCPU(ref MemoryMarshal.GetReference(gapSpan), chunkCount);
ComputeRemaindersOnGpu(chunkCount, remainder10, 10, gapView, deltaView, remainder10View, remainderDeltaKernel, remainderScanKernel); ComputeRemaindersOnGpu(chunkCount, remainder10, 10, gapView, deltaView, remainder10View, remainderDeltaKernel, remainderScanKernel, resources.GetRemainderScanConfig);
ComputeRemaindersOnGpu(chunkCount, remainder8, 8, gapView, deltaView, remainder8View, remainderDeltaKernel, remainderScanKernel); ComputeRemaindersOnGpu(chunkCount, remainder8, 8, gapView, deltaView, remainder8View, remainderDeltaKernel, remainderScanKernel, resources.GetRemainderScanConfig);
ComputeRemaindersOnGpu(chunkCount, remainder5, 5, gapView, deltaView, remainder5View, remainderDeltaKernel, remainderScanKernel); ComputeRemaindersOnGpu(chunkCount, remainder5, 5, gapView, deltaView, remainder5View, remainderDeltaKernel, remainderScanKernel, resources.GetRemainderScanConfig);
ComputeRemaindersOnGpu(chunkCount, remainder3, 3, gapView, deltaView, remainder3View, remainderDeltaKernel, remainderScanKernel); ComputeRemaindersOnGpu(chunkCount, remainder3, 3, gapView, deltaView, remainder3View, remainderDeltaKernel, remainderScanKernel, resources.GetRemainderScanConfig);
BuildCandidateMaskOnGpu(chunkCount, remainder10View, remainder8View, remainder5View, remainder3View, lastIsSevenFlag, maskView, maskSpan, candidateMaskKernel); BuildCandidateMaskOnGpu(chunkCount, remainder10View, remainder8View, remainder5View, remainder3View, lastIsSevenFlag, maskView, maskSpan, candidateMaskKernel);
@@ -461,7 +464,8 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
ArrayView1D<byte, Stride1D.Dense> deltaView, ArrayView1D<byte, Stride1D.Dense> deltaView,
ArrayView1D<byte, Stride1D.Dense> remainderView, ArrayView1D<byte, Stride1D.Dense> remainderView,
Action<Index1D, ArrayView<ulong>, ArrayView<byte>, byte> deltaKernel, Action<Index1D, ArrayView<ulong>, ArrayView<byte>, byte> deltaKernel,
Action<KernelConfig, Index1D, ArrayView<byte>, ArrayView<byte>, byte, byte> scanKernel) Action<KernelConfig, Index1D, ArrayView<byte>, ArrayView<byte>, byte, byte> scanKernel,
Func<int, KernelConfig> configProvider)
{ {
// GPU batches always contain at least one divisor gap, so the empty-count guard remains commented // GPU batches always contain at least one divisor gap, so the empty-count guard remains commented
// to eliminate redundant branching. // to eliminate redundant branching.
@@ -471,10 +475,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
// } // }
deltaKernel(count, gapView, deltaView, modulus); deltaKernel(count, gapView, deltaView, modulus);
SharedMemoryConfig sharedMemoryConfig = SharedMemoryConfig.RequestDynamic<int>(count); KernelConfig kernelConfig = configProvider(count);
Index1D gridDim = new Index1D(1);
Index1D groupDim = new Index1D(count);
KernelConfig kernelConfig = new KernelConfig(gridDim, groupDim, sharedMemoryConfig);
scanKernel(kernelConfig, new Index1D(count), deltaView, remainderView, baseRemainder, modulus); scanKernel(kernelConfig, new Index1D(count), deltaView, remainderView, baseRemainder, modulus);
} }
@@ -906,10 +907,24 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
internal readonly Action<KernelConfig, Index1D, ArrayView<byte>, ArrayView<byte>, byte, byte> RemainderScanKernel; internal readonly Action<KernelConfig, Index1D, ArrayView<byte>, ArrayView<byte>, byte, byte> RemainderScanKernel;
internal readonly Action<Index1D, ArrayView<byte>, ArrayView<byte>, ArrayView<byte>, ArrayView<byte>, byte, ArrayView<byte>> CandidateMaskKernel; internal readonly Action<Index1D, ArrayView<byte>, ArrayView<byte>, ArrayView<byte>, ArrayView<byte>, byte, ArrayView<byte>> CandidateMaskKernel;
private readonly Dictionary<int, KernelConfig> _remainderScanConfigs = new();
internal readonly int Capacity; internal readonly int Capacity;
internal readonly int CycleCapacity; internal readonly int CycleCapacity;
internal KernelConfig GetRemainderScanConfig(int count)
{
if (!_remainderScanConfigs.TryGetValue(count, out KernelConfig config))
{
SharedMemoryConfig sharedMemoryConfig = SharedMemoryConfig.RequestDynamic<int>(count);
config = new KernelConfig(new Index1D(1), new Index1D(count), sharedMemoryConfig);
_remainderScanConfigs[count] = config;
}
return config;
}
public void Dispose() public void Dispose()
{ {
DivisorsBuffer.Dispose(); DivisorsBuffer.Dispose();
@@ -1611,7 +1611,7 @@ internal static partial class PrimeOrderGpuHeuristics
private static ulong CalculateByDoublingKernel(ulong prime) private static ulong CalculateByDoublingKernel(ulong prime)
{ {
ulong order = 1UL; ulong order = 1UL;
ulong value = 2UL % prime; ulong value = 2UL; // Candidate primes exceed two, so the modulo would always return two.
while (value != 1UL) while (value != 1UL)
{ {
+7 -3
View File
@@ -530,7 +530,9 @@ public static class ULongExtensions
ulong modulus = divisor.Modulus; ulong modulus = divisor.Modulus;
if (exponent == 0UL) if (exponent == 0UL)
{ {
return keepMontgomery ? divisor.MontgomeryOne : 1UL % modulus; return keepMontgomery
? divisor.MontgomeryOne
: 1UL; // Montgomery moduli stay above one on the scanning path, so the modulo would always yield one.
} }
if (exponent <= Pow2WindowFallbackThreshold) if (exponent <= Pow2WindowFallbackThreshold)
@@ -622,7 +624,9 @@ public static class ULongExtensions
ulong modulus = divisor.Modulus; ulong modulus = divisor.Modulus;
if (exponent == 0UL) if (exponent == 0UL)
{ {
return keepMontgomery ? divisor.MontgomeryOne : 1UL % modulus; return keepMontgomery
? divisor.MontgomeryOne
: 1UL; // Montgomery moduli stay above one on the scanning path, so the modulo would always yield one.
} }
if (exponent <= Pow2WindowFallbackThreshold) if (exponent <= Pow2WindowFallbackThreshold)
@@ -769,7 +773,7 @@ public static class ULongExtensions
return; return;
} }
ulong baseValue = 2UL % modulus; ulong baseValue = 2UL; // Moduli arrive as odd primes greater than two, so the modulo would always return two.
destination[0] = baseValue; destination[0] = baseValue;
if (oddPowerCount == 1) if (oddPowerCount == 1)
{ {