Retire outdated windowed pow2 TODOs
This commit is contained in:
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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in new issue
Block a user