diff --git a/PerfectNumbers.Core/Gpu/Kernels/Pow2MontgomeryKernels.cs b/PerfectNumbers.Core/Gpu/Kernels/Pow2MontgomeryKernels.cs index 64120f7..d00733a 100644 --- a/PerfectNumbers.Core/Gpu/Kernels/Pow2MontgomeryKernels.cs +++ b/PerfectNumbers.Core/Gpu/Kernels/Pow2MontgomeryKernels.cs @@ -6,13 +6,21 @@ namespace PerfectNumbers.Core.Gpu; internal static class Pow2MontgomeryKernels { - public static void Pow2MontgomeryKernel( + public static void Pow2MontgomeryKernelKeepMontgomery( Index1D index, ArrayView1D exponents, MontgomeryDivisorData divisor, - byte keepMontgomery, ArrayView1D results) { - results[index] = ULongExtensions.Pow2MontgomeryModWindowedGpu(divisor, exponents[index], keepMontgomery != 0); + results[index] = ULongExtensions.Pow2MontgomeryModWindowedGpu(divisor, exponents[index], keepMontgomery: true); + } + + public static void Pow2MontgomeryKernelConvertToStandard( + Index1D index, + ArrayView1D exponents, + MontgomeryDivisorData divisor, + ArrayView1D results) + { + results[index] = ULongExtensions.Pow2MontgomeryModWindowedGpu(divisor, exponents[index], keepMontgomery: false); } } diff --git a/PerfectNumbers.Core/ULongExtensions.Gpu.cs b/PerfectNumbers.Core/ULongExtensions.Gpu.cs index 1ff7b47..3f1f482 100644 --- a/PerfectNumbers.Core/ULongExtensions.Gpu.cs +++ b/PerfectNumbers.Core/ULongExtensions.Gpu.cs @@ -303,7 +303,7 @@ public static partial class ULongExtensions private static class Pow2MontgomeryGpuExecutor { - private static readonly ConcurrentDictionary, MontgomeryDivisorData, byte, ArrayView1D>> KernelCache = new(); + private static readonly ConcurrentDictionary KernelCache = new(); public static ulong Execute(ulong exponent, in MontgomeryDivisorData divisor, bool keepMontgomery) { @@ -319,12 +319,7 @@ public static partial class ULongExtensions // return 0UL; // } - var kernel = KernelCache.GetOrAdd(accelerator, static accel => - { - var loaded = accel.LoadAutoGroupedStreamKernel, MontgomeryDivisorData, byte, ArrayView1D>(Pow2MontgomeryKernels.Pow2MontgomeryKernel); - var launcher = KernelUtil.GetKernel(loaded); - return launcher.CreateLauncherDelegate, MontgomeryDivisorData, byte, ArrayView1D>>(); - }); + var kernelGroup = KernelCache.GetOrAdd(accelerator, static accel => Pow2MontgomeryKernelGroup.Create(accel)); var exponentBuffer = accelerator.Allocate1D(1); var resultBuffer = accelerator.Allocate1D(1); @@ -333,10 +328,9 @@ public static partial class ULongExtensions // We don't need to worry about any left-overs here. // resultBuffer.MemSetToZero(); - // TODO: Have 2 kernels for both cases to have branch-less solution. - byte keepFlag = keepMontgomery ? (byte)1 : (byte)0; + var kernel = keepMontgomery ? kernelGroup.KeepMontgomery : kernelGroup.ConvertToStandard; AcceleratorStream stream = lease.Stream; - kernel(stream, 1, exponentBuffer.View, divisor, keepFlag, resultBuffer.View); + kernel(stream, 1, exponentBuffer.View, divisor, resultBuffer.View); stream.Synchronize(); resultBuffer.View.CopyToCPU(ref result, 1); @@ -357,5 +351,33 @@ public static partial class ULongExtensions // Intentionally avoid exception handling here; any accelerator failure should crash the scanner. return result; } + private sealed class Pow2MontgomeryKernelGroup + { + internal Pow2MontgomeryKernelGroup( + Action, MontgomeryDivisorData, ArrayView1D> keepMontgomery, + Action, MontgomeryDivisorData, ArrayView1D> convertToStandard) + { + KeepMontgomery = keepMontgomery; + ConvertToStandard = convertToStandard; + } + + internal Action, MontgomeryDivisorData, ArrayView1D> KeepMontgomery { get; } + + internal Action, MontgomeryDivisorData, ArrayView1D> ConvertToStandard { get; } + + internal static Pow2MontgomeryKernelGroup Create(Accelerator accelerator) + { + var keepKernel = accelerator.LoadAutoGroupedStreamKernel, MontgomeryDivisorData, ArrayView1D>(Pow2MontgomeryKernels.Pow2MontgomeryKernelKeepMontgomery); + var keepLauncher = KernelUtil.GetKernel(keepKernel); + var keepDelegate = keepLauncher.CreateLauncherDelegate, MontgomeryDivisorData, ArrayView1D>>(); + + var convertKernel = accelerator.LoadAutoGroupedStreamKernel, MontgomeryDivisorData, ArrayView1D>(Pow2MontgomeryKernels.Pow2MontgomeryKernelConvertToStandard); + var convertLauncher = KernelUtil.GetKernel(convertKernel); + var convertDelegate = convertLauncher.CreateLauncherDelegate, MontgomeryDivisorData, ArrayView1D>>(); + + return new Pow2MontgomeryKernelGroup(keepDelegate, convertDelegate); + } + } + } }