diff --git a/PerfectNumbers.Core/DivisorCycleCache.cs b/PerfectNumbers.Core/DivisorCycleCache.cs index 0947ad4..4145a8d 100644 --- a/PerfectNumbers.Core/DivisorCycleCache.cs +++ b/PerfectNumbers.Core/DivisorCycleCache.cs @@ -260,11 +260,14 @@ public sealed class DivisorCycleCache } Accelerator accelerator = _accelerator; - divisorBuffer = accelerator.Allocate1D(requiredCapacity); - powBuffer = accelerator.Allocate1D(requiredCapacity); - orderBuffer = accelerator.Allocate1D(requiredCapacity); - resultBuffer = accelerator.Allocate1D(requiredCapacity); - statusBuffer = accelerator.Allocate1D(requiredCapacity); + lock(accelerator) + { + divisorBuffer = accelerator.Allocate1D(requiredCapacity); + powBuffer = accelerator.Allocate1D(requiredCapacity); + orderBuffer = accelerator.Allocate1D(requiredCapacity); + resultBuffer = accelerator.Allocate1D(requiredCapacity); + statusBuffer = accelerator.Allocate1D(requiredCapacity); + } } private void ComputeCyclesGpuCore(ReadOnlySpan divisors, Span destination) diff --git a/PerfectNumbers.Core/Gpu/Accelerators/PrimeOrderCalculatorAccelerator.cs b/PerfectNumbers.Core/Gpu/Accelerators/PrimeOrderCalculatorAccelerator.cs index c7b933d..d743378 100644 --- a/PerfectNumbers.Core/Gpu/Accelerators/PrimeOrderCalculatorAccelerator.cs +++ b/PerfectNumbers.Core/Gpu/Accelerators/PrimeOrderCalculatorAccelerator.cs @@ -117,7 +117,11 @@ public sealed class PrimeOrderCalculatorAccelerator public readonly Kernel CheckFactorsKernel; public readonly Kernel ConvertToStandardKernel; + + public readonly Action, MontgomeryDivisorData, ArrayView1D> ConvertToStandardKernelLauncher; + public readonly Kernel HeuristicCombinedTrialDivisionKernel; + public readonly Action, ulong, ulong, HeuristicCombinedGpuViews> HeuristicCombinedTrialDivisionKernelLauncher; public readonly Kernel KeepMontgomeryKernel; public readonly Kernel PollardRhoKernel; public readonly Kernel Pow2ModWideKernel; @@ -133,29 +137,41 @@ public sealed class PrimeOrderCalculatorAccelerator MemoryBuffer1D, Stride1D.Dense> pow2ModEntriesToTestOnDevice = Pow2ModEntriesToTestOnDevice; if (pow2ModEntriesToTestOnDevice.Length < factorsCount) { - pow2ModEntriesToTestOnDevice.Dispose(); - Pow2ModEntriesToTestOnDevice = accelerator.Allocate1D>(factorsCount); + lock (accelerator) + { + pow2ModEntriesToTestOnDevice.Dispose(); + Pow2ModEntriesToTestOnDevice = accelerator.Allocate1D>(factorsCount); + } } MemoryBuffer1D input = Input; if (input.Length < primeTesterCapacity) { - input.Dispose(); - Input = accelerator.Allocate1D(primeTesterCapacity); + lock (accelerator) + { + input.Dispose(); + Input = accelerator.Allocate1D(primeTesterCapacity); + } } MemoryBuffer1D outputByte = OutputByte; if (outputByte.Length < primeTesterCapacity) { - outputByte.Dispose(); - OutputByte = accelerator.Allocate1D(primeTesterCapacity); + lock (accelerator) + { + outputByte.Dispose(); + OutputByte = accelerator.Allocate1D(primeTesterCapacity); + } } MemoryBuffer1D outputInt = OutputInt; if (outputInt.Length < primeTesterCapacity) { - outputInt.Dispose(); - OutputInt = accelerator.Allocate1D(primeTesterCapacity); + lock (accelerator) + { + outputInt.Dispose(); + OutputInt = accelerator.Allocate1D(primeTesterCapacity); + } } } @@ -166,15 +182,21 @@ public sealed class PrimeOrderCalculatorAccelerator MemoryBuffer1D outputUlong = OutputUlong; if (outputUlong.Length < newSize) { - outputUlong.Dispose(); - OutputUlong = accelerator.Allocate1D(newSize); + lock (accelerator) + { + outputUlong.Dispose(); + OutputUlong = accelerator.Allocate1D(newSize); + } } MemoryBuffer1D outputInt = OutputInt; if (outputInt.Length < newSize) { - outputInt.Dispose(); - OutputInt = accelerator.Allocate1D(newSize); + lock (accelerator) + { + outputInt.Dispose(); + OutputInt = accelerator.Allocate1D(newSize); + } } } @@ -184,15 +206,21 @@ public sealed class PrimeOrderCalculatorAccelerator MemoryBuffer1D input = Input; if (input.Length < newSize) { - input.Dispose(); - Input = accelerator.Allocate1D(newSize); + lock (accelerator) + { + input.Dispose(); + Input = accelerator.Allocate1D(newSize); + } } MemoryBuffer1D outputUlong = OutputUlong; if (outputUlong.Length < newSize) { - outputUlong.Dispose(); - OutputUlong = accelerator.Allocate1D(newSize); + lock (accelerator) + { + outputUlong.Dispose(); + OutputUlong = accelerator.Allocate1D(newSize); + } } } @@ -201,57 +229,65 @@ public sealed class PrimeOrderCalculatorAccelerator var accelerator = _accelerators[acceleratorIndex]; Accelerator = accelerator; AcceleratorIndex = acceleratorIndex; - Input = accelerator.Allocate1D(Math.Max(specialMaxFactorCapacity, primeTesterCapacity)); - OutputByte = Accelerator.Allocate1D(primeTesterCapacity); - OutputInt = Accelerator.Allocate1D(Math.Max(primeTesterCapacity, smallPrimeFactorSlotCount)); - OutputUlong = accelerator.Allocate1D(Math.Max(specialMaxFactorCapacity, smallPrimeFactorSlotCount)); - Pow2ModEntriesToTestOnDevice = accelerator.Allocate1D>(factorsCount); - SmallPrimeFactorCountSlot = accelerator.Allocate1D(1); - SpecialMaxResult = accelerator.Allocate1D(1); - - LastDigitGpuTables lastDigitSharedTables = LastDigitGpuTables.GetStaticTables(acceleratorIndex); - - DevicePrimesLastOne = lastDigitSharedTables.DevicePrimesLastOne.View; - DevicePrimesLastSeven = lastDigitSharedTables.DevicePrimesLastSeven.View; - DevicePrimesLastThree = lastDigitSharedTables.DevicePrimesLastThree.View; - DevicePrimesLastNine = lastDigitSharedTables.DevicePrimesLastNine.View; - DevicePrimesPow2LastOne = lastDigitSharedTables.DevicePrimesPow2LastOne.View; - DevicePrimesPow2LastSeven = lastDigitSharedTables.DevicePrimesPow2LastSeven.View; - DevicePrimesPow2LastThree = lastDigitSharedTables.DevicePrimesPow2LastThree.View; - DevicePrimesPow2LastNine = lastDigitSharedTables.DevicePrimesPow2LastNine.View; - - DivisorTables = HeuristicCombinedGpuTables - .GetStaticTables(acceleratorIndex) - .CreateViews(); - - var smallPrimeFactorTables = SmallPrimeFactorGpuTables.GetStaticTables(acceleratorIndex); - - if (smallPrimeFactorTables.HasValue) + lock (accelerator) { - SmallPrimeFactorGpuTables tables = smallPrimeFactorTables.Value; - SmallPrimeFactorPrimes = tables.Primes.View; - SmallPrimeFactorSquares = tables.Squares.View; + Input = accelerator.Allocate1D(Math.Max(specialMaxFactorCapacity, primeTesterCapacity)); + OutputByte = Accelerator.Allocate1D(primeTesterCapacity); + OutputInt = Accelerator.Allocate1D(Math.Max(primeTesterCapacity, smallPrimeFactorSlotCount)); + OutputUlong = accelerator.Allocate1D(Math.Max(specialMaxFactorCapacity, smallPrimeFactorSlotCount)); + Pow2ModEntriesToTestOnDevice = accelerator.Allocate1D>(factorsCount); + SmallPrimeFactorCountSlot = accelerator.Allocate1D(1); + SpecialMaxResult = accelerator.Allocate1D(1); + + LastDigitGpuTables lastDigitSharedTables = LastDigitGpuTables.GetStaticTables(acceleratorIndex); + DevicePrimesLastOne = lastDigitSharedTables.DevicePrimesLastOne.View; + DevicePrimesLastSeven = lastDigitSharedTables.DevicePrimesLastSeven.View; + DevicePrimesLastThree = lastDigitSharedTables.DevicePrimesLastThree.View; + DevicePrimesLastNine = lastDigitSharedTables.DevicePrimesLastNine.View; + DevicePrimesPow2LastOne = lastDigitSharedTables.DevicePrimesPow2LastOne.View; + DevicePrimesPow2LastSeven = lastDigitSharedTables.DevicePrimesPow2LastSeven.View; + DevicePrimesPow2LastThree = lastDigitSharedTables.DevicePrimesPow2LastThree.View; + DevicePrimesPow2LastNine = lastDigitSharedTables.DevicePrimesPow2LastNine.View; + + DivisorTables = HeuristicCombinedGpuTables + .GetStaticTables(acceleratorIndex) + .CreateViews(); + + var smallPrimeFactorTables = SmallPrimeFactorGpuTables.GetStaticTables(acceleratorIndex); + + if (smallPrimeFactorTables.HasValue) + { + SmallPrimeFactorGpuTables tables = smallPrimeFactorTables.Value; + SmallPrimeFactorPrimes = tables.Primes.View; + SmallPrimeFactorSquares = tables.Squares.View; + } + + CheckFactorsKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D>(PrimeOrderGpuHeuristics.CheckFactorsKernel)); + + Kernel convertToStandardKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel, MontgomeryDivisorData, ArrayView1D>(Pow2MontgomeryKernels.Pow2MontgomeryKernelConvertToStandard)); + + ConvertToStandardKernel = convertToStandardKernel; + ConvertToStandardKernelLauncher = convertToStandardKernel.CreateLauncherDelegate, MontgomeryDivisorData, ArrayView1D>>(); + + var heuristicCombinedTrialDivisionKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel, ulong, ulong, HeuristicCombinedGpuViews>(PrimeTesterKernels.HeuristicTrialCombinedDivisionKernel)); + + HeuristicCombinedTrialDivisionKernel = heuristicCombinedTrialDivisionKernel; + HeuristicCombinedTrialDivisionKernelLauncher = heuristicCombinedTrialDivisionKernel.CreateLauncherDelegate, ulong, ulong, HeuristicCombinedGpuViews>>(); + + KeepMontgomeryKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel, MontgomeryDivisorData, ArrayView1D>(Pow2MontgomeryKernels.Pow2MontgomeryKernelKeepMontgomery)); + + PollardRhoKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel, ArrayView1D, ArrayView1D>(Pow2MontgomeryKernels.TryPollardRhoKernel)); + + Pow2ModWideKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel, GpuUInt128, ArrayView1D>(PrimeOrderGpuHeuristics.Pow2ModKernelWide)); + + SharesFactorKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel, ArrayView>(PrimeTesterKernels.SharesFactorKernel)); + + SmallPrimeFactorKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel, ArrayView1D, int, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D>(SmallPrimeFactorKernels.SmallPrimeFactorKernelScan)); + + SmallPrimeSieveKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView>(PrimeTesterKernels.SmallPrimeSieveKernel)); + + SpecialMaxKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel, int, MontgomeryDivisorData, ArrayView1D, ArrayView1D>(PrimeOrderGpuHeuristics.EvaluateSpecialMaxCandidatesKernel)); } - - CheckFactorsKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D>(PrimeOrderGpuHeuristics.CheckFactorsKernel)); - - ConvertToStandardKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel, MontgomeryDivisorData, ArrayView1D>(Pow2MontgomeryKernels.Pow2MontgomeryKernelConvertToStandard)); - - HeuristicCombinedTrialDivisionKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel, ulong, ulong, HeuristicCombinedGpuViews>(PrimeTesterKernels.HeuristicTrialCombinedDivisionKernel)); - - KeepMontgomeryKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel, MontgomeryDivisorData, ArrayView1D>(Pow2MontgomeryKernels.Pow2MontgomeryKernelKeepMontgomery)); - - PollardRhoKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel, ArrayView1D, ArrayView1D>(Pow2MontgomeryKernels.TryPollardRhoKernel)); - - Pow2ModWideKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel, GpuUInt128, ArrayView1D>(PrimeOrderGpuHeuristics.Pow2ModKernelWide)); - - SharesFactorKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel, ArrayView>(PrimeTesterKernels.SharesFactorKernel)); - - SmallPrimeFactorKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel, ArrayView1D, int, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D>(SmallPrimeFactorKernels.SmallPrimeFactorKernelScan)); - - SmallPrimeSieveKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView>(PrimeTesterKernels.SmallPrimeSieveKernel)); - - SpecialMaxKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel, int, MontgomeryDivisorData, ArrayView1D, ArrayView1D>(PrimeOrderGpuHeuristics.EvaluateSpecialMaxCandidatesKernel)); } public void Dispose() diff --git a/PerfectNumbers.Core/Gpu/GpuKernelPool.cs b/PerfectNumbers.Core/Gpu/GpuKernelPool.cs index 5a97c63..4632216 100644 --- a/PerfectNumbers.Core/Gpu/GpuKernelPool.cs +++ b/PerfectNumbers.Core/Gpu/GpuKernelPool.cs @@ -26,7 +26,7 @@ public class GpuKernelPool internal static KernelContainer GetOrAddKernels(int acceleratorIndex, AcceleratorStream stream, KernelType kernelType) { var pool = _pool ??= []; - if (pool[acceleratorIndex] is not {} kernels) + if (pool[acceleratorIndex] is not { } kernels) { kernels = new(); } @@ -151,7 +151,7 @@ public class GpuKernelPool var host = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot(); MemoryBuffer1D? device; - // lock (accelerator) + lock (accelerator) { device = accelerator.Allocate1D(host.Length); } @@ -195,13 +195,13 @@ public class GpuKernelPool MemoryBuffer1D? deviceLastOnePow2; MemoryBuffer1D? deviceLastSevenPow2; - // lock (accelerator) - // { - deviceLastOne = accelerator.Allocate1D(hostLastOne.Length); - deviceLastSeven = accelerator.Allocate1D(hostLastSeven.Length); - deviceLastOnePow2 = accelerator.Allocate1D(hostLastOnePow2.Length); - deviceLastSevenPow2 = accelerator.Allocate1D(hostLastSevenPow2.Length); - // } + lock (accelerator) + { + deviceLastOne = accelerator.Allocate1D(hostLastOne.Length); + deviceLastSeven = accelerator.Allocate1D(hostLastSeven.Length); + deviceLastOnePow2 = accelerator.Allocate1D(hostLastOnePow2.Length); + deviceLastSevenPow2 = accelerator.Allocate1D(hostLastSevenPow2.Length); + } deviceLastOne.View.CopyFromCPU(stream, hostLastOne); deviceLastSeven.View.CopyFromCPU(stream, hostLastSeven); diff --git a/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs b/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs index 07fb8bd..fb01ae8 100644 --- a/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs +++ b/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs @@ -540,7 +540,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv if (_divisorBuffer == null) { - // lock(accelerator) + lock(accelerator) { _divisorBuffer = accelerator.Allocate1D(1); _offsetBuffer = accelerator.Allocate1D(1); @@ -570,7 +570,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv { int desiredCapacity = requiredCapacity > _capacity ? requiredCapacity : _capacity; _capacity = desiredCapacity; - // lock (accelerator) + lock (accelerator) { _exponentsBuffer = accelerator.Allocate1D(desiredCapacity); _hitBuffer = accelerator.Allocate1D(desiredCapacity); @@ -798,7 +798,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv private void AllocateDeviceBuffers(Accelerator accelerator, int capacity) { - // lock (accelerator) + lock (accelerator) { _divisorDataBuffer = accelerator.Allocate1D(capacity); _offsetBuffer = accelerator.Allocate1D(capacity); diff --git a/PerfectNumbers.Core/Gpu/Pow2MontgomeryGpuCalculator.cs b/PerfectNumbers.Core/Gpu/Pow2MontgomeryGpuCalculator.cs index 9ecc739..1348cc1 100644 --- a/PerfectNumbers.Core/Gpu/Pow2MontgomeryGpuCalculator.cs +++ b/PerfectNumbers.Core/Gpu/Pow2MontgomeryGpuCalculator.cs @@ -55,8 +55,10 @@ public static class Pow2MontgomeryGpuCalculator // We don't need to worry about any left-overs here. // resultBuffer.MemSetToZero(stream); - var kernel = gpu.ConvertToStandardKernel; - kernel.Launch(stream, 1, 1, exponentBuffer.View, divisor, resultBuffer.View); + var kernelLauncher = gpu.ConvertToStandardKernelLauncher!; + + kernelLauncher(stream, 1, exponentBuffer.View, divisor, resultBuffer.View); + resultBuffer.View.CopyToCPU(stream, ref result, 1); stream.Synchronize(); @@ -73,7 +75,6 @@ public static class Pow2MontgomeryGpuCalculator ulong result = 0UL; MemoryBuffer1D exponentBuffer = gpu.Input; MemoryBuffer1D resultBuffer = gpu.OutputUlong; - var kernel = gpu.ConvertToStandardKernel; int acceleratorIndex = gpu.AcceleratorIndex; AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex); @@ -81,8 +82,11 @@ public static class Pow2MontgomeryGpuCalculator // We don't need to worry about any left-overs here. // resultBuffer.MemSetToZero(stream); - var kernelLauncher = kernel.CreateLauncherDelegate, MontgomeryDivisorData, ArrayView1D>>(); - kernelLauncher(stream, 1,exponentBuffer.View, divisor, resultBuffer.View); + + var accelerator = gpu.Accelerator; + var kernelLauncher = gpu.ConvertToStandardKernelLauncher; + kernelLauncher(stream, 1, exponentBuffer.View, divisor, resultBuffer.View); + resultBuffer.View.CopyToCPU(stream, ref result, 1); stream.Synchronize(); diff --git a/PerfectNumbers.Core/Gpu/PrimeOrderGpuHeuristics.cs b/PerfectNumbers.Core/Gpu/PrimeOrderGpuHeuristics.cs index f6cc2c4..22285b7 100644 --- a/PerfectNumbers.Core/Gpu/PrimeOrderGpuHeuristics.cs +++ b/PerfectNumbers.Core/Gpu/PrimeOrderGpuHeuristics.cs @@ -190,14 +190,14 @@ internal static partial class PrimeOrderGpuHeuristics // fullyFactoredBuffer.MemSetToZero(stream); var partialFactorKernel = GetPartialFactorKernel(acceleratorIndex); + var kernelLauncher = partialFactorKernel.CreateLauncherDelegate, ArrayView1D, int, int, ulong, uint, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D>>(); - partialFactorKernel.Launch( + kernelLauncher( stream, 1, - 1, smallPrimesView, smallSquaresView, - smallPrimesView.Length, + (int)smallPrimesView.Length, primeTargets.Length, value, limit, @@ -354,7 +354,7 @@ internal static partial class PrimeOrderGpuHeuristics MemoryBuffer1D? resultBuffer; MemoryBuffer1D? statusBuffer; - // lock(accelerator) + lock(accelerator) { phiFactorBuffer = accelerator.Allocate1D(GpuSmallPrimeFactorSlots); phiExponentBuffer = accelerator.Allocate1D(GpuSmallPrimeFactorSlots); @@ -398,16 +398,17 @@ internal static partial class PrimeOrderGpuHeuristics statusBuffer.View); var orderKernel = GetOrderKernel(acceleratorIndex); - orderKernel.Launch( + var kernelLauncher = orderKernel.CreateLauncherDelegate, ArrayView1D, int, OrderKernelBuffers>>(); + + kernelLauncher( stream, 1, - 1, prime, kernelConfig, divisorData, smallPrimesView, smallSquaresView, - smallPrimesView.Length, + (int)smallPrimesView.Length, buffers); @@ -517,7 +518,7 @@ internal static partial class PrimeOrderGpuHeuristics // with out preallocated buffers. Share the pool with Pow2ModWide kernel. MemoryBuffer1D? exponentBuffer; MemoryBuffer1D? remainderBuffer; - // lock(accelerator) + lock(accelerator) { exponentBuffer = accelerator.Allocate1D(exponents.Length); remainderBuffer = accelerator.Allocate1D(exponents.Length); @@ -529,9 +530,11 @@ internal static partial class PrimeOrderGpuHeuristics // remainderBuffer.MemSetToZero(stream); var pow2ModKernel = GetPow2ModKernel(acceleratorIndex); + var kernelLauncher = pow2ModKernel.CreateLauncherDelegate, MontgomeryDivisorData, ArrayView1D>>(); + try { - pow2ModKernel.Launch(stream, 1, exponents.Length, exponentBuffer.View, divisorData, remainderBuffer.View); + kernelLauncher(stream, exponents.Length, exponentBuffer.View, divisorData, remainderBuffer.View); remainderBuffer.View.CopyToCPU(stream, ref MemoryMarshal.GetReference(results), exponents.Length); stream.Synchronize(); @@ -590,13 +593,20 @@ internal static partial class PrimeOrderGpuHeuristics int acceleratorIndex = gpu.AcceleratorIndex; Accelerator accelerator = gpu.Accelerator; - MemoryBuffer1D exponentBuffer = accelerator.Allocate1D(length); - MemoryBuffer1D remainderBuffer = accelerator.Allocate1D(length); - AcceleratorStream? stream = AcceleratorStreamPool.Rent(acceleratorIndex); - exponentBuffer.View.CopyFromCPU(stream, exponentSpan); + MemoryBuffer1D exponentBuffer; + MemoryBuffer1D remainderBuffer; - gpu.Pow2ModWideKernel.Launch(stream, length, exponentBuffer.View, modulus, remainderBuffer.View); + lock(accelerator) + { + exponentBuffer = accelerator.Allocate1D(length); + remainderBuffer = accelerator.Allocate1D(length); + } + + exponentBuffer.View.CopyFromCPU(stream, exponentSpan); + var kernelLauncher = gpu.Pow2ModWideKernel.CreateLauncherDelegate, GpuUInt128, ArrayView1D>>(); + + kernelLauncher(stream, length, exponentBuffer.View, modulus, remainderBuffer.View); remainderBuffer.View.CopyToCPU(stream, ref MemoryMarshal.GetReference(resultSpan), length); stream.Synchronize(); diff --git a/PerfectNumbers.Core/HeuristicCombinedPrimeTester.cs b/PerfectNumbers.Core/HeuristicCombinedPrimeTester.cs index ec84e5a..1277bea 100644 --- a/PerfectNumbers.Core/HeuristicCombinedPrimeTester.cs +++ b/PerfectNumbers.Core/HeuristicCombinedPrimeTester.cs @@ -240,13 +240,12 @@ public sealed class HeuristicCombinedPrimeTester var kernel = gpu.HeuristicCombinedTrialDivisionKernel; var flagView1D = gpu.OutputInt!.View; - bool compositeDetected = false; - int divisorLength = GetCombinedDivisors(nMod10).Length; + bool compositeDetected; + // int compositeFlag = 0; + Span compositeFlag = stackalloc int[1]; + flagView1D.MemSetToZero(stream); - int compositeFlag = 0; - flagView1D.CopyFromCPU(stream, ref compositeFlag, 1); - - var kernelLauncher = kernel.CreateLauncherDelegate, ulong, ulong, HeuristicCombinedGpuViews>>(); + var kernelLauncher = gpu.HeuristicCombinedTrialDivisionKernelLauncher; kernelLauncher( stream, 1, @@ -255,13 +254,13 @@ public sealed class HeuristicCombinedPrimeTester n, maxDivisorSquare, gpu.DivisorTables); - flagView1D.CopyToCPU(stream, ref compositeFlag, 1); + flagView1D.CopyToCPU(stream, compositeFlag); stream.Synchronize(); AcceleratorStreamPool.Return(acceleratorIndex, stream); // GpuPrimeWorkLimiter.Release(); - compositeDetected = compositeFlag != 0; + compositeDetected = compositeFlag[0] != 0; return compositeDetected; } diff --git a/PerfectNumbers.Core/MersenneDivisorCycles.cs b/PerfectNumbers.Core/MersenneDivisorCycles.cs index 90530b5..d27a0f5 100644 --- a/PerfectNumbers.Core/MersenneDivisorCycles.cs +++ b/PerfectNumbers.Core/MersenneDivisorCycles.cs @@ -840,6 +840,8 @@ public class MersenneDivisorCycles } var divisorCycleKernel = GetDivisorCycleKernel(acceleratorIndex); + var kernelLauncher = divisorCycleKernel.CreateLauncherDelegate, ArrayView1D>>(); + while (start <= maxDivisor) { end = Math.Min(start + batchSizeUL - 1UL, maxDivisor); @@ -860,15 +862,14 @@ public class MersenneDivisorCycles // GpuKernelPool.Run((accelerator, stream) => MemoryBuffer1D? bufferDiv; MemoryBuffer1D? bufferCycle; - // lock(accelerator) + lock(accelerator) { bufferDiv = accelerator.Allocate1D(validDivisors); bufferCycle = accelerator.Allocate1D(idx); } - divisorCycleKernel.Launch( + kernelLauncher( stream, - 1, idx, bufferDiv.View, bufferCycle.View); diff --git a/PerfectNumbers.Core/PerfectNumberConstants.cs b/PerfectNumbers.Core/PerfectNumberConstants.cs index 2fe0eb7..98dd3ee 100644 --- a/PerfectNumbers.Core/PerfectNumberConstants.cs +++ b/PerfectNumbers.Core/PerfectNumberConstants.cs @@ -13,7 +13,7 @@ public static class PerfectNumberConstants public const int MaxOddPowersCount = 128; public const int PooledArrayThreshold = 64; public static readonly int RollingAccelerators = 298; //SharedGpuContext.Device.MaxNumThreadsPerGroup; - public const int ThreadsByAccelerator = 4096; + public const int ThreadsByAccelerator = 1; // TODO: Load these limits from the benchmark-driven configuration so CPU and GPU scans stay aligned with the optimal // divisor-cycle datasets we generate offline. // TODO: Promote these magic numbers into a runtime profile derived from EvenPerfectBitScanner.Benchmarks so we can retune diff --git a/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs b/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs index 563daf8..7d4da13 100644 --- a/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs +++ b/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using ILGPU; using PerfectNumbers.Core.Cpu; using PerfectNumbers.Core.Gpu; using PerfectNumbers.Core.Gpu.Accelerators; @@ -65,9 +66,9 @@ internal static partial class PrimeOrderCalculator ulong result; if (phiFactors.Factors is null) { - result = prime <= PerfectNumberConstants.MaxQForDivisorCycles + result = /*prime <= PerfectNumberConstants.MaxQForDivisorCycles ? CalculateByFactorizationGpu(gpu, prime, divisorData) - : CalculateByFactorizationCpu(gpu, prime, divisorData); + : */CalculateByFactorizationCpu(gpu, prime, divisorData); phiFactors.Dispose(); PrimeOrderCalculatorAccelerator.Return(gpu); @@ -108,7 +109,8 @@ internal static partial class PrimeOrderCalculator { orderFactors?.Dispose(); // GpuPrimeWorkLimiter.Release(); - return CalculateByFactorizationGpu(gpu, prime, divisorData); + return CalculateByFactorizationCpu(gpu, prime, divisorData); + // return CalculateByFactorizationGpu(gpu, prime, divisorData); } if (TryHeuristicFinishCpu(gpu, prime, candidateOrder, previousOrder, divisorData, config, phiFactors, orderFactors, out ulong order)) @@ -136,7 +138,7 @@ internal static partial class PrimeOrderCalculator Span stackBuffer = stackalloc ulong[length]; - if (length <= 7) + if (length <= 9) { return EvaluateSpecialMaxCandidates(stackBuffer, factorSpan, phi, prime, divisorData); } @@ -1055,17 +1057,17 @@ internal static partial class PrimeOrderCalculator private static ulong _pow2CpuHits; private static bool Pow2EqualsOneCpu(PrimeOrderCalculatorAccelerator gpu, ulong exponent, ulong prime, in MontgomeryDivisorData divisorData) { - if (exponent <= (PerfectNumberConstants.MaxQForDivisorCycles) || prime <= (PerfectNumberConstants.MaxQForDivisorCycles)) - { - // Atomic.Add(ref _pow2GpuHits, 1); - // Console.WriteLine($"pow2 GPU Hits {_pow2GpuHits}"); - ulong remainder = exponent.Pow2MontgomeryModWindowedConvertGpu(gpu, divisorData); - // GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(exponent, prime, out ulong remainder, divisorData); - // if (status == GpuPow2ModStatus.Success) - // { - return remainder == 1UL; - // } - } + // if (exponent >= PerfectNumberConstants.MaxQForDivisorCycles || prime >= PerfectNumberConstants.MaxQForDivisorCycles) + // { + // // Atomic.Add(ref _pow2GpuHits, 1); + // // Console.WriteLine($"pow2 GPU Hits {_pow2GpuHits}"); + // ulong remainder = exponent.Pow2MontgomeryModWindowedConvertGpu(gpu, divisorData); + // // GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(exponent, prime, out ulong remainder, divisorData); + // // if (status == GpuPow2ModStatus.Success) + // // { + // return remainder == 1UL; + // // } + // } // Atomic.Add(ref _pow2CpuHits, 1); // Console.WriteLine($"pow2 CPU Hits {_pow2CpuHits}"); @@ -1077,6 +1079,7 @@ internal static partial class PrimeOrderCalculator // private static ulong _partialFactorCofactorHits; private static bool _goToGpu = true; + private static int _cpuCount; private static PartialFactorResult PartialFactor(PrimeOrderCalculatorAccelerator gpu, ulong value, in PrimeOrderSearchConfig config) { @@ -1163,11 +1166,19 @@ internal static partial class PrimeOrderCalculator // Console.WriteLine($"Partial factor hits {Volatile.Read(ref _partialFactorHits)}"); // bool isPrime = PrimeTester.IsPrimeCpu(composite, CancellationToken.None); - bool goToGpu = Volatile.Read(ref _goToGpu); - Volatile.Write(ref _goToGpu, !goToGpu); - bool isPrime = goToGpu - ? HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite) - : PrimeTester.IsPrime(composite); + // bool goToGpu = Volatile.Read(ref _goToGpu); + // Volatile.Write(ref _goToGpu, !goToGpu); + // bool isPrime = goToGpu + // ? HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite) + // : PrimeTester.IsPrime(composite); + // bool isPrime = composite > PerfectNumberConstants.MaxQForDivisorCycles + // ? HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite) + // : PrimeTester.IsPrime(composite); + // bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite); + bool runOnGpu = RunOnGpu(); + + bool isPrime = runOnGpu ? PrimeTester.IsPrime(composite) : HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite); + // bool isPrime = PrimeTester.IsPrime(composite); // bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite); if (isPrime) @@ -1184,8 +1195,8 @@ internal static partial class PrimeOrderCalculator continue; } - if (!TryPollardRhoGpu(gpu, composite, out ulong factor)) - // if (!TryPollardRhoCpu(composite, deadlineTimestamp, out ulong factor)) + // if (!TryPollardRhoGpu(gpu, composite, out ulong factor)) + if (!TryPollardRhoCpu(composite, deadlineTimestamp, out ulong factor)) { pending.Add(new PendingEntry(composite, knownComposite: true)); continue; @@ -1238,8 +1249,8 @@ internal static partial class PrimeOrderCalculator // Atomic.Add(ref _partialFactorPendingHits, 1UL); // Console.WriteLine($"Partial factor pending hits {Volatile.Read(ref _partialFactorPendingHits)}"); - // bool isPrime = PrimeTester.IsPrimeCpu(composite, CancellationToken.None); - bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite); + bool isPrime = PrimeTester.IsPrime(composite); + // bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite); // bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite); entry = entry.WithPrimality(isPrime); @@ -1276,9 +1287,9 @@ internal static partial class PrimeOrderCalculator // Atomic.Add(ref _partialFactorCofactorHits, 1UL); // Console.WriteLine($"Partial factor cofactor hits {Volatile.Read(ref _partialFactorCofactorHits)}"); - cofactorIsPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, cofactor); + // cofactorIsPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, cofactor); // cofactorIsPrime = PrimeTester.IsPrimeGpu(gpu, cofactor); - // cofactorIsPrime = PrimeTester.IsPrimeGpu(cofactor); + cofactorIsPrime = PrimeTester.IsPrime(cofactor); // cofactorIsPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(cofactor); } @@ -1362,6 +1373,23 @@ internal static partial class PrimeOrderCalculator return result; } + private static bool RunOnGpu() + { + const int GpuFrequency = 1024 - 1; + + int cpuCount = Atomic.Add(target: ref _cpuCount, 1); + if (cpuCount == GpuFrequency) + { + Atomic.Add(ref _cpuCount, -GpuFrequency); + } + else if (cpuCount > GpuFrequency) + { + cpuCount -= GpuFrequency; + } + + return cpuCount != GpuFrequency; + } + private static void PopulateSmallPrimeFactorsCpu( ulong value, uint limit, @@ -1731,7 +1759,8 @@ internal static partial class PrimeOrderCalculator // ulong candidate = order / primeFactor; // if (candidate.Pow2MontgomeryModWindowedCpu(divisorData, keepMontgomery: false) == 1UL) - if (candidate.Pow2MontgomeryModWindowedConvertGpu(gpu, divisorData) == 1UL) + if (candidate.Pow2MontgomeryModWindowedCpu(divisorData, keepMontgomery: false) == 1UL) + // if (candidate.Pow2MontgomeryModWindowedConvertGpu(gpu, divisorData) == 1UL) // if (Pow2EqualsOneCpu(candidate, prime, divisorData)) { order = candidate; @@ -1768,9 +1797,9 @@ internal static partial class PrimeOrderCalculator // HeuristicPrimeTester tester = _tester ??= new(); // bool isPrime = primeTester.HeuristicIsPrimeGpu(value); - bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, value); - // bool isPrime = PrimeTester.IsPrimeGpu(value); + // bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, value); // bool isPrime = PrimeTester.IsPrimeGpu(value); + bool isPrime = PrimeTester.IsPrime(value); // bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(value); if (!knownComposite && isPrime) { @@ -1785,8 +1814,9 @@ internal static partial class PrimeOrderCalculator // Console.WriteLine($"Factor completely after PollardRho hits {Volatile.Read(ref _factorCompletelyPollardRhoHits)}"); // isPrime = primeTester.HeuristicIsPrimeGpu(factor); - isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, factor); + // isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, factor); // isPrime = PrimeTester.IsPrimeGpu(factor); + isPrime = PrimeTester.IsPrime(factor); // isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(factor); if (isPrime) { @@ -1822,7 +1852,8 @@ internal static partial class PrimeOrderCalculator // Atomic.Add(ref _partialFactorCofactorHits, 1UL); // Console.WriteLine($"Partial factor cofactor hits {Volatile.Read(ref _partialFactorCofactorHits)}"); - isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, quotient); + // isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, quotient); + isPrime = PrimeTester.IsPrime(quotient); // isPrime = PrimeTester.IsPrimeGpu(quotient); // isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(quotient); } diff --git a/PerfectNumbers.Core/PrimeOrderCalculator.Gpu.cs b/PerfectNumbers.Core/PrimeOrderCalculator.Gpu.cs index 0294304..d243a26 100644 --- a/PerfectNumbers.Core/PrimeOrderCalculator.Gpu.cs +++ b/PerfectNumbers.Core/PrimeOrderCalculator.Gpu.cs @@ -145,10 +145,11 @@ internal static partial class PrimeOrderCalculator ArrayView1D specialMaxResultView = gpu.SpecialMaxResult.View; - kernel.Launch( + var kernelLauncher = kernel.CreateLauncherDelegate, int, MontgomeryDivisorData, ArrayView1D, ArrayView1D>>(); + + kernelLauncher( stream, 1, - 1, phi, specialMaxFactorsView, factorCount, diff --git a/PerfectNumbers.Core/PrimeTester.cs b/PerfectNumbers.Core/PrimeTester.cs index 09ff8c2..6310fd1 100644 --- a/PerfectNumbers.Core/PrimeTester.cs +++ b/PerfectNumbers.Core/PrimeTester.cs @@ -207,6 +207,8 @@ public sealed class PrimeTester int pos = 0; AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex); + var kernelLauncher = kernel.CreateLauncherDelegate, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView>>(); + while (pos < totalLength) { int remaining = totalLength - pos; @@ -215,7 +217,7 @@ public sealed class PrimeTester var valueSlice = values.Slice(pos, count); inputView.CopyFromCPU(stream, valueSlice); - kernel.Launch( + kernelLauncher( stream, count, inputView, @@ -285,8 +287,9 @@ public sealed class PrimeTester AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex); inputBuffer.View.CopyFromCPU(stream, values); + var kernelLauncher = kernel.CreateLauncherDelegate, ArrayView>>(); - kernel.Launch(stream, length, inputBuffer.View, resultBuffer.View); + kernelLauncher(stream, length, inputBuffer.View, resultBuffer.View); resultBuffer.View.CopyToCPU(stream, in results); stream.Synchronize();