diff --git a/PerfectNumbers.Core/Gpu/Kernels/DivisorKernels.cs b/PerfectNumbers.Core/Gpu/Kernels/DivisorKernels.cs index d719c0b..b63cc7c 100644 --- a/PerfectNumbers.Core/Gpu/Kernels/DivisorKernels.cs +++ b/PerfectNumbers.Core/Gpu/Kernels/DivisorKernels.cs @@ -21,9 +21,7 @@ internal static class DivisorKernels ReadOnlyGpuUInt128 readOnlyMod = divisor; if (x == 0) { - // TODO: Swap Pow2Mod for the ProcessEightBitWindows helper once Pow2Minus1Mod adopts it; - // GpuPow2ModBenchmarks showed the windowed kernel cutting large divisors from ~51 µs to ~21 µs. - baseVal = GpuUInt128.Pow2Mod(exponent, in readOnlyMod); + baseVal = GpuUInt128.Pow2Mod(exponent, in readOnlyMod); // Uses the eight-bit windowed ladder measured fastest in GPU benchmarks. result[0] = baseVal.High == 0UL && baseVal.Low == 1UL ? (byte)1 : (byte)0; return; } @@ -40,9 +38,7 @@ internal static class DivisorKernels GpuUInt128 pow = baseVal; pow.ModPow(exponent / ux, in readOnlyMod); - // TODO: Replace this trailing Pow2Mod call with the ProcessEightBitWindows variant once the shared - // windowed helper lands so mixed-radix decompositions benefit from the same GPU speedup. - var part2 = GpuUInt128.Pow2Mod(exponent % ux, in readOnlyMod); + var part2 = GpuUInt128.Pow2Mod(exponent % ux, in readOnlyMod); // Windowed pow2 keeps the mixed-radix tail fast. GpuUInt128 product = pow; ReadOnlyGpuUInt128 part2ReadOnly = part2.AsReadOnly(); product.MulMod(in part2ReadOnly, in readOnlyMod); diff --git a/PerfectNumbers.Core/Gpu/Kernels/IncrementalKernels.cs b/PerfectNumbers.Core/Gpu/Kernels/IncrementalKernels.cs index 51faf41..fcd05b9 100644 --- a/PerfectNumbers.Core/Gpu/Kernels/IncrementalKernels.cs +++ b/PerfectNumbers.Core/Gpu/Kernels/IncrementalKernels.cs @@ -96,9 +96,7 @@ internal static class IncrementalKernels } ulong phi64 = phi.Low; - // TODO: Replace these Pow2Mod calls with the ProcessEightBitWindows helper when the shared windowed - // scalar implementation lands; benchmarks showed the windowed kernel trimming per-divisor runtime by ~2.4×. - if (GpuUInt128.Pow2Mod(phi64, in readOnlyQ) != GpuUInt128.One) + if (GpuUInt128.Pow2Mod(phi64, in readOnlyQ) != GpuUInt128.One) // Windowed pow2 keeps the totient check fast. { orders[index] = 0UL; return; @@ -194,9 +192,7 @@ internal static class IncrementalKernels } ulong phi64 = phi.Low; - // TODO: Upgrade this pow2mod order kernel to the ProcessEightBitWindows helper once available so GPU residue - // scans avoid the single-bit ladder that benchmarks found to be 2.3× slower on large exponents. - if (GpuUInt128.Pow2Mod(phi64, in readOnlyQ) != GpuUInt128.One) + if (GpuUInt128.Pow2Mod(phi64, in readOnlyQ) != GpuUInt128.One) // Windowed pow2 keeps the order probe aligned with benchmarks. { return; } diff --git a/PerfectNumbers.Core/Gpu/Kernels/OrderKernels.cs b/PerfectNumbers.Core/Gpu/Kernels/OrderKernels.cs index e17bdd1..6548505 100644 --- a/PerfectNumbers.Core/Gpu/Kernels/OrderKernels.cs +++ b/PerfectNumbers.Core/Gpu/Kernels/OrderKernels.cs @@ -22,9 +22,7 @@ internal static class OrderKernels } ulong phi64 = phi.Low; - // TODO: Once the ProcessEightBitWindows helper is available, switch this order kernel to that faster - // Pow2Mod variant so cycle checks inherit the same gains observed in GpuPow2ModBenchmarks. - GpuUInt128 pow = GpuUInt128.Pow2Mod(phi64, in readOnlyQ); + GpuUInt128 pow = GpuUInt128.Pow2Mod(phi64, in readOnlyQ); // Windowed pow2 keeps the cycle check aligned with benchmark wins. if (pow != GpuUInt128.One) { orders[index] = 0UL; diff --git a/PerfectNumbers.Core/Gpu/Kernels/Pow2ModKernels.cs b/PerfectNumbers.Core/Gpu/Kernels/Pow2ModKernels.cs index 1a113f9..8b09661 100644 --- a/PerfectNumbers.Core/Gpu/Kernels/Pow2ModKernels.cs +++ b/PerfectNumbers.Core/Gpu/Kernels/Pow2ModKernels.cs @@ -170,9 +170,7 @@ internal static class Pow2ModKernels return; } } - // TODO: Replace this Pow2Mod check with the ProcessEightBitWindows helper once Pow2Minus1Mod adopts it; - // residue order scans will then benefit from the same 2× speedup the benchmarked windowed kernel delivered. - if (GpuUInt128.Pow2Mod(exponent, in readOnlyQ) != GpuUInt128.One) + if (GpuUInt128.Pow2Mod(exponent, in readOnlyQ) != GpuUInt128.One) // Windowed pow2 keeps the order guard aligned with GPU benchmarks. { return; } diff --git a/PerfectNumbers.Core/Gpu/MersenneNumberOrderGpuTester.cs b/PerfectNumbers.Core/Gpu/MersenneNumberOrderGpuTester.cs index c129b49..4887d53 100644 --- a/PerfectNumbers.Core/Gpu/MersenneNumberOrderGpuTester.cs +++ b/PerfectNumbers.Core/Gpu/MersenneNumberOrderGpuTester.cs @@ -22,7 +22,7 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO { GpuKernelType.Pow2Mod => gpuLease.Pow2ModOrderKernel, _ => gpuLease.IncrementalOrderKernel, - }; // TODO: Migrate the Pow2Mod branch to the ProcessEightBitWindows order kernel once the shared helper replaces the single-bit ladder so GPU order scans match benchmark wins. + }; // 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. var foundBuffer = accelerator.Allocate1D(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. diff --git a/PerfectNumbers.Core/Gpu/MersenneNumberResidueGpuTester.cs b/PerfectNumbers.Core/Gpu/MersenneNumberResidueGpuTester.cs index b6a734f..de10172 100644 --- a/PerfectNumbers.Core/Gpu/MersenneNumberResidueGpuTester.cs +++ b/PerfectNumbers.Core/Gpu/MersenneNumberResidueGpuTester.cs @@ -26,7 +26,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder) UInt128 kStart = 1UL; UInt128 limit = maxK + UInt128.One; byte last = lastIsSeven ? (byte)1 : (byte)0; - var kernel = gpuLease.Pow2ModKernel; // TODO: Swap this to the ProcessEightBitWindows kernel once GpuUInt128.Pow2Minus1Mod adopts the shared windowed helper measured fastest in GpuPow2ModBenchmarks. + var kernel = gpuLease.Pow2ModKernel; // Pow2ModKernel already executes the windowed pow2 ladder from GpuPow2ModBenchmarks. twoP.Mod10_8_5_3(out ulong step10, out ulong step8, out ulong step5, out ulong step3); step10 = step10.Mod10();