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.Buffers;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Numerics;
@@ -122,6 +123,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
resources.CycleCandidates,
resources.CycleLengths,
resources.CycleCapacity,
resources,
out lastProcessed,
out coveredRange,
out processedCount
@@ -186,6 +188,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
ulong[] cycleCandidates,
ulong[] cycleLengths,
int cycleCapacity,
BatchResources resources,
out ulong lastProcessed,
out bool coveredRange,
out ulong processedCount)
@@ -340,10 +343,10 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
gapView.CopyFromCPU(ref MemoryMarshal.GetReference(gapSpan), chunkCount);
ComputeRemaindersOnGpu(chunkCount, remainder10, 10, gapView, deltaView, remainder10View, remainderDeltaKernel, remainderScanKernel);
ComputeRemaindersOnGpu(chunkCount, remainder8, 8, gapView, deltaView, remainder8View, remainderDeltaKernel, remainderScanKernel);
ComputeRemaindersOnGpu(chunkCount, remainder5, 5, gapView, deltaView, remainder5View, remainderDeltaKernel, remainderScanKernel);
ComputeRemaindersOnGpu(chunkCount, remainder3, 3, gapView, deltaView, remainder3View, remainderDeltaKernel, remainderScanKernel);
ComputeRemaindersOnGpu(chunkCount, remainder10, 10, gapView, deltaView, remainder10View, remainderDeltaKernel, remainderScanKernel, resources.GetRemainderScanConfig);
ComputeRemaindersOnGpu(chunkCount, remainder8, 8, gapView, deltaView, remainder8View, remainderDeltaKernel, remainderScanKernel, resources.GetRemainderScanConfig);
ComputeRemaindersOnGpu(chunkCount, remainder5, 5, gapView, deltaView, remainder5View, remainderDeltaKernel, remainderScanKernel, resources.GetRemainderScanConfig);
ComputeRemaindersOnGpu(chunkCount, remainder3, 3, gapView, deltaView, remainder3View, remainderDeltaKernel, remainderScanKernel, resources.GetRemainderScanConfig);
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> remainderView,
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
// to eliminate redundant branching.
@@ -471,10 +475,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
// }
deltaKernel(count, gapView, deltaView, modulus);
SharedMemoryConfig sharedMemoryConfig = SharedMemoryConfig.RequestDynamic<int>(count);
Index1D gridDim = new Index1D(1);
Index1D groupDim = new Index1D(count);
KernelConfig kernelConfig = new KernelConfig(gridDim, groupDim, sharedMemoryConfig);
KernelConfig kernelConfig = configProvider(count);
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<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 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()
{
DivisorsBuffer.Dispose();
@@ -1611,7 +1611,7 @@ internal static partial class PrimeOrderGpuHeuristics
private static ulong CalculateByDoublingKernel(ulong prime)
{
ulong order = 1UL;
ulong value = 2UL % prime;
ulong value = 2UL; // Candidate primes exceed two, so the modulo would always return two.
while (value != 1UL)
{
+7 -3
View File
@@ -530,7 +530,9 @@ public static class ULongExtensions
ulong modulus = divisor.Modulus;
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)
@@ -622,7 +624,9 @@ public static class ULongExtensions
ulong modulus = divisor.Modulus;
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)
@@ -769,7 +773,7 @@ public static class ULongExtensions
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;
if (oddPowerCount == 1)
{