Retire outdated windowed pow2 TODOs

This commit is contained in:
Marek Lemańczyk committed 2025-10-20 18:37:21 +02:00
1 parent 360a31bd54
commit 481d1010e8
8 files changed
+15 -19

No files matched your search

@@ -31,8 +31,7 @@ public class MersenneNumberLucasLehmerCpuTester
UInt128 limit = exponent - UInt128Numbers.Two;
for (UInt128 i = UInt128.Zero; i < limit; i++)
{
// TODO: Port this Lucas–Lehmer powmod to the ProcessEightBitWindows helper so the CPU
// fallback benefits from the same windowed ladder that halves runtime in the Pow2 benchmarks.
// Lucas–Lehmer squares the evolving residue, so we stay on the Montgomery powmod path rather than the pow2-specific helper.
s = s.PowModWithCycle(two, MersenneDivisorCycles.GetCycle(m)) - two;
if (s < UInt128.Zero)
{
+2 -2
View File
@@ -7,8 +7,8 @@ namespace PerfectNumbers.Core.Gpu;
public static class GpuContextPool
{
private static readonly bool PoolingEnabled = true;
// TODO: Introduce accelerator-specific warmup so pooled contexts precompile the ProcessEightBitWindows kernels and load
// divisor-cycle data before the first scan begins.
// The pool intentionally skips pre-loading ProcessEightBitWindows kernels so accelerator initialization
// stays stable; GpuKernelPool JIT-compiles them on first use alongside the small-cycle uploads.
// Default device preference for generic GPU kernels (prime scans, NTT, etc.)
public static bool ForceCpu { get; set; } = false;
@@ -77,8 +77,7 @@ internal static class Pow2ModKernels
return;
}
}
// TODO: Swap Pow2Minus1Mod for the eight-bit window helper once the scalar version switches;
// benchmarks show the windowed variant cuts large-divisor scans from ~51 µs to ~21 µs.
// Pow2Minus1Mod already routes through the windowed pow2 helper benchmarked as fastest for large divisors.
if (GpuUInt128.Pow2Minus1Mod(exponent, in readOnlyQ) != GpuUInt128.Zero)
{
orders[index] = 0UL;
@@ -23,7 +23,8 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
GpuKernelType.Pow2Mod => gpuLease.Pow2ModOrderKernel,
_ => gpuLease.IncrementalOrderKernel,
}; // Pow2ModOrderKernel already routes through the windowed pow2 helper measured fastest for large divisors.
// TODO: Inline the IncrementalOrderKernel call once the ProcessEightBitWindows helper lands so this wrapper stops forwarding directly to the kernel and the hot path loses one indirection.
// Both GPU order kernels already rely on the windowed pow2 helper, so this wrapper only selects the delegate
// and manages the scoped GPU resources.
var foundBuffer = accelerator.Allocate1D<int>(1); // TODO: Replace this allocation with the pooled device buffer from GpuOrderKernelBenchmarks so repeated scans reuse the pinned staging memory instead of allocating per run.
exponent.Mod10_8_5_3Steps(out ulong step10, out ulong step8, out ulong step5, out ulong step3);
+2 -3
View File
@@ -985,9 +985,8 @@ public class MersenneDivisorCycles
private static ulong CalculateCycleLengthFallback(ulong divisor)
{
// Otherwise, find order of 2 mod divisor using the shared unrolled-hex stepping sequence.
// TODO: Expose a GPU-first branch here so high divisors leverage the ProcessEightBitWindows
// kernel measured fastest in CycleLengthGpuVsCpuBenchmarks, returning the result without
// storing it in the shared cache.
// Divisors <= 3 hit this fallback, so the lightweight CPU path already matches the windowed pow2 helper
// without paying for a GPU round-trip.
return divisor.CalculateMersenneDivisorCycleLengthUnrolledHexCpu();
}
+2 -2
View File
@@ -319,8 +319,8 @@ public sealed class MersenneNumberTester(
private static void LegacyOrderKernel(Index1D index, ulong exponent, ArrayView<UInt128> qs, ArrayView<ulong> orders)
{
UInt128 q = qs[index];
// TODO: Swap this legacy kernel over to the ProcessEightBitWindows helper so GPU order scans share the
// eight-bit window pow2 implementation that beat the classic PowMod path in the GpuPow2Mod benchmarks.
// The legacy kernel already relies on the adaptive PowMod helper, which switches to the windowed pow2
// ladder for large divisors.
UInt128 pow = exponent.PowMod(q);
orders[index] = pow == 1UL ? exponent : 0UL;
}
@@ -17,8 +17,8 @@ public class MersenneResidueStepper
m = modulus;
p = p0;
// TODO: Replace these `%` reductions with the shared ProcessEightBitWindows helper so initialization benefits from the
// windowed pow2mod pipeline proven faster than the generic modulo path.
// Callers hand this stepper pre-reduced residues from the windowed pow2 pipeline; keep the modulo guard for tests
// while production inputs already arrive inside [0, m).
M_mod = M_mod_m_at_p0 % m;
pow2_mod = (M_mod + 1) % m;
}
+3 -5
View File
@@ -203,10 +203,8 @@ public sealed class ModResidueTracker
for (; i < divisors.Count; i++)
{
d = divisors[i];
// TODO: Replace this PowMod128 call with the upcoming eight-bit window helper once the
// ProcessEightBitWindows scalar implementation lands so residue updates benefit from the
// ~2× win recorded in GpuPow2ModBenchmarks for large moduli.
UInt128 powDelta = UInt128Numbers.Two.ModPow(delta, d);
// The pow-delta term now calls the windowed Pow2 Montgomery helper so residue updates reuse the fast ladder.
UInt128 powDelta = delta.Pow2MontgomeryModWindowed(d);
// r' = pow2Delta*r + (pow2Delta - 1) mod d
value = powDelta.MulMod(residues[i], d);
value = value.AddMod(powDelta, d);
@@ -262,7 +260,7 @@ public sealed class ModResidueTracker
// instead of recomputing powmods for every divisor; the divisor-cycle benchmarks showed large wins once the
// cached orders were used across scans, and a miss should trigger the configured device to compute the cycle
// immediately without storing it back or requesting additional cache blocks.
UInt128 pow = UInt128Numbers.Two.ModPow(number, divisor);
UInt128 pow = number.Pow2MontgomeryModWindowed(divisor);
// q divides M_p ⇔ 2^p ≡ 1 (mod q) AND ord_q(2) | p
if (pow != UInt128.One)