Most device buffers integrated into PrimeOrderCalculatorAccelerator. PrimeOrderCalculator switched to partial factoring on GPU.

This commit is contained in:
mlemanczyk committed 2025-11-26 03:16:39 +01:00
1 parent 5b48a89448
commit 13498dc460
17 files changed
+466 -415

No files matched your search

@@ -321,7 +321,7 @@ public class GpuKernelCompilationTests
private static void CompilePrimeOrderPow2ModWideKernel(Accelerator accelerator) private static void CompilePrimeOrderPow2ModWideKernel(Accelerator accelerator)
{ {
var kernel = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>(PrimeOrderGpuHeuristics.Pow2ModKernelWide); var kernel = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>(PrimeOrderKernels.Pow2ModKernelWide);
_ = kernel; _ = kernel;
} }
@@ -21,17 +21,19 @@ public class PrimeOrderGpuHeuristicsTests
public void TryPow2Mod_returns_overflow_for_marked_prime() public void TryPow2Mod_returns_overflow_for_marked_prime()
{ {
const ulong prime = 97UL; const ulong prime = 97UL;
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
try try
{ {
PrimeOrderGpuHeuristics.OverflowRegistry[prime] = 0; PrimeOrderGpuHeuristics.OverflowRegistry[prime] = 0;
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(1UL, prime, out ulong remainder, divisorData); GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(gpu, 1UL, prime, out ulong remainder, divisorData);
status.Should().Be(GpuPow2ModStatus.Overflow); status.Should().Be(GpuPow2ModStatus.Overflow);
remainder.Should().Be(0UL); remainder.Should().Be(0UL);
} }
finally finally
{ {
PrimeOrderCalculatorAccelerator.Return(gpu);
PrimeOrderGpuHeuristics.OverflowRegistry.TryRemove(prime, out _); PrimeOrderGpuHeuristics.OverflowRegistry.TryRemove(prime, out _);
} }
} }
@@ -42,7 +44,10 @@ public class PrimeOrderGpuHeuristicsTests
const ulong exponent = 138_000_001UL; const ulong exponent = 138_000_001UL;
const ulong prime = 138_000_001UL; const ulong prime = 138_000_001UL;
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(exponent, prime, out ulong remainder, divisorData); var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(gpu, exponent, prime, out ulong remainder, divisorData);
PrimeOrderCalculatorAccelerator.Return(gpu);
status.Should().Be(GpuPow2ModStatus.Success); status.Should().Be(GpuPow2ModStatus.Success);
remainder.Should().Be(2UL); remainder.Should().Be(2UL);
@@ -54,16 +59,18 @@ public class PrimeOrderGpuHeuristicsTests
const ulong prime = 97UL; const ulong prime = 97UL;
var capability = new PrimeOrderGpuHeuristics.PrimeOrderGpuCapability(6, 64); var capability = new PrimeOrderGpuHeuristics.PrimeOrderGpuCapability(6, 64);
PrimeOrderGpuHeuristics.OverrideCapabilitiesForTesting(capability); PrimeOrderGpuHeuristics.OverrideCapabilitiesForTesting(capability);
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
try try
{ {
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(1UL, prime, out ulong remainder, divisorData); GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(gpu, 1UL, prime, out ulong remainder, divisorData);
status.Should().Be(GpuPow2ModStatus.Overflow); status.Should().Be(GpuPow2ModStatus.Overflow);
remainder.Should().Be(0UL); remainder.Should().Be(0UL);
} }
finally finally
{ {
PrimeOrderCalculatorAccelerator.Return(gpu);
PrimeOrderGpuHeuristics.ResetCapabilitiesForTesting(); PrimeOrderGpuHeuristics.ResetCapabilitiesForTesting();
PrimeOrderGpuHeuristics.OverflowRegistry.TryRemove(prime, out _); PrimeOrderGpuHeuristics.OverflowRegistry.TryRemove(prime, out _);
} }
@@ -73,22 +80,24 @@ public class PrimeOrderGpuHeuristicsTests
public void TryPow2Mod_returns_overflow_when_exponent_exceeds_capability() public void TryPow2Mod_returns_overflow_when_exponent_exceeds_capability()
{ {
var capability = new PrimeOrderGpuHeuristics.PrimeOrderGpuCapability(64, 3); var capability = new PrimeOrderGpuHeuristics.PrimeOrderGpuCapability(64, 3);
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
PrimeOrderGpuHeuristics.OverrideCapabilitiesForTesting(capability); PrimeOrderGpuHeuristics.OverrideCapabilitiesForTesting(capability);
try try
{ {
const ulong prime = 193UL; const ulong prime = 193UL;
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(16UL, prime, out ulong remainder, divisorData); GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(gpu, 16UL, prime, out ulong remainder, divisorData);
status.Should().Be(GpuPow2ModStatus.Overflow); status.Should().Be(GpuPow2ModStatus.Overflow);
remainder.Should().Be(0UL); remainder.Should().Be(0UL);
GpuPow2ModStatus followUp = PrimeOrderGpuHeuristics.TryPow2Mod(4UL, prime, out ulong followUpRemainder, divisorData); GpuPow2ModStatus followUp = PrimeOrderGpuHeuristics.TryPow2Mod(gpu, 4UL, prime, out ulong followUpRemainder, divisorData);
followUp.Should().Be(GpuPow2ModStatus.Success); followUp.Should().Be(GpuPow2ModStatus.Success);
followUpRemainder.Should().Be(16UL); followUpRemainder.Should().Be(16UL);
} }
finally finally
{ {
PrimeOrderCalculatorAccelerator.Return(gpu);
PrimeOrderGpuHeuristics.ResetCapabilitiesForTesting(); PrimeOrderGpuHeuristics.ResetCapabilitiesForTesting();
} }
} }
@@ -97,6 +106,7 @@ public class PrimeOrderGpuHeuristicsTests
public void TryPow2ModBatch_returns_overflow_for_marked_prime() public void TryPow2ModBatch_returns_overflow_for_marked_prime()
{ {
const ulong prime = 193UL; const ulong prime = 193UL;
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
try try
{ {
PrimeOrderGpuHeuristics.OverflowRegistry[prime] = 0; PrimeOrderGpuHeuristics.OverflowRegistry[prime] = 0;
@@ -104,7 +114,7 @@ public class PrimeOrderGpuHeuristicsTests
ulong[] remainders = new ulong[2]; ulong[] remainders = new ulong[2];
ulong[] exponents = { 1UL, 2UL }; ulong[] exponents = { 1UL, 2UL };
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(exponents, prime, remainders, divisorData); GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(gpu, exponents, prime, remainders, divisorData);
status.Should().Be(GpuPow2ModStatus.Overflow); status.Should().Be(GpuPow2ModStatus.Overflow);
remainders[0].Should().Be(0UL); remainders[0].Should().Be(0UL);
@@ -112,6 +122,7 @@ public class PrimeOrderGpuHeuristicsTests
} }
finally finally
{ {
PrimeOrderCalculatorAccelerator.Return(gpu);
PrimeOrderGpuHeuristics.OverflowRegistry.TryRemove(prime, out _); PrimeOrderGpuHeuristics.OverflowRegistry.TryRemove(prime, out _);
} }
} }
@@ -123,7 +134,11 @@ public class PrimeOrderGpuHeuristicsTests
ulong[] exponents = { 138_000_001UL, 138_000_011UL }; ulong[] exponents = { 138_000_001UL, 138_000_011UL };
const ulong prime = 138_000_001UL; const ulong prime = 138_000_001UL;
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(exponents, prime, remainders, divisorData);
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(gpu, exponents, prime, remainders, divisorData);
PrimeOrderCalculatorAccelerator.Return(gpu);
ulong expectedFirst = (ulong)BigInteger.ModPow(2, exponents[0], prime); ulong expectedFirst = (ulong)BigInteger.ModPow(2, exponents[0], prime);
ulong expectedSecond = (ulong)BigInteger.ModPow(2, exponents[1], prime); ulong expectedSecond = (ulong)BigInteger.ModPow(2, exponents[1], prime);
@@ -140,6 +155,7 @@ public class PrimeOrderGpuHeuristicsTests
{ {
const ulong prime = 97UL; const ulong prime = 97UL;
var capability = new PrimeOrderGpuHeuristics.PrimeOrderGpuCapability(6, 64); var capability = new PrimeOrderGpuHeuristics.PrimeOrderGpuCapability(6, 64);
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
PrimeOrderGpuHeuristics.OverrideCapabilitiesForTesting(capability); PrimeOrderGpuHeuristics.OverrideCapabilitiesForTesting(capability);
try try
{ {
@@ -147,7 +163,7 @@ public class PrimeOrderGpuHeuristicsTests
ulong[] remainders = { 5UL, 6UL }; ulong[] remainders = { 5UL, 6UL };
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(exponents, prime, remainders, divisorData); GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(gpu, exponents, prime, remainders, divisorData);
status.Should().Be(GpuPow2ModStatus.Overflow); status.Should().Be(GpuPow2ModStatus.Overflow);
remainders[0].Should().Be(0UL); remainders[0].Should().Be(0UL);
@@ -155,6 +171,7 @@ public class PrimeOrderGpuHeuristicsTests
} }
finally finally
{ {
PrimeOrderCalculatorAccelerator.Return(gpu);
PrimeOrderGpuHeuristics.ResetCapabilitiesForTesting(); PrimeOrderGpuHeuristics.ResetCapabilitiesForTesting();
PrimeOrderGpuHeuristics.OverflowRegistry.TryRemove(prime, out _); PrimeOrderGpuHeuristics.OverflowRegistry.TryRemove(prime, out _);
} }
@@ -164,6 +181,7 @@ public class PrimeOrderGpuHeuristicsTests
public void TryPow2ModBatch_returns_overflow_when_any_exponent_exceeds_capability() public void TryPow2ModBatch_returns_overflow_when_any_exponent_exceeds_capability()
{ {
var capability = new PrimeOrderGpuHeuristics.PrimeOrderGpuCapability(64, 3); var capability = new PrimeOrderGpuHeuristics.PrimeOrderGpuCapability(64, 3);
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
PrimeOrderGpuHeuristics.OverrideCapabilitiesForTesting(capability); PrimeOrderGpuHeuristics.OverrideCapabilitiesForTesting(capability);
try try
{ {
@@ -172,7 +190,7 @@ public class PrimeOrderGpuHeuristicsTests
const ulong prime = 193UL; const ulong prime = 193UL;
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(exponents, prime, remainders, divisorData); GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(gpu, exponents, prime, remainders, divisorData);
status.Should().Be(GpuPow2ModStatus.Overflow); status.Should().Be(GpuPow2ModStatus.Overflow);
remainders[0].Should().Be(0UL); remainders[0].Should().Be(0UL);
@@ -180,6 +198,7 @@ public class PrimeOrderGpuHeuristicsTests
} }
finally finally
{ {
PrimeOrderCalculatorAccelerator.Return(gpu);
PrimeOrderGpuHeuristics.ResetCapabilitiesForTesting(); PrimeOrderGpuHeuristics.ResetCapabilitiesForTesting();
} }
} }
@@ -79,7 +79,6 @@ public sealed class PrimeOrderCalculatorAccelerator
stream.Synchronize(); stream.Synchronize();
stream.Dispose(); stream.Dispose();
} }
} }
#endregion #endregion
@@ -105,21 +104,57 @@ public sealed class PrimeOrderCalculatorAccelerator
public readonly Accelerator Accelerator; public readonly Accelerator Accelerator;
public readonly int AcceleratorIndex; public readonly int AcceleratorIndex;
public MemoryBuffer1D<ulong, Stride1D.Dense> Input; public MemoryBuffer1D<ulong, Stride1D.Dense> Input;
public MemoryBuffer1D<ulong, Stride1D.Dense> OutputUlong; public ArrayView1D<ulong, Stride1D.Dense> InputView;
public MemoryBuffer1D<byte, Stride1D.Dense> OutputByte; public MemoryBuffer1D<byte, Stride1D.Dense> OutputByte;
public ArrayView1D<byte, Stride1D.Dense> OutputByteView;
public MemoryBuffer1D<ulong, Stride1D.Dense> OutputUlong;
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> OutputUlong2;
public ArrayView1D<ulong, Stride1D.Dense> OutputUlongView;
public readonly ArrayView1D<ulong, Stride1D.Dense> OutputUlongView2;
public MemoryBuffer1D<int, Stride1D.Dense> OutputInt; public MemoryBuffer1D<int, Stride1D.Dense> OutputInt;
public readonly MemoryBuffer1D<int, Stride1D.Dense> OutputInt2;
public ArrayView1D<int, Stride1D.Dense> OutputIntView;
public readonly ArrayView1D<int, Stride1D.Dense> OutputIntView2;
public MemoryBuffer1D<KeyValuePair<ulong, int>, Stride1D.Dense> Pow2ModEntriesToTestOnDevice; public MemoryBuffer1D<KeyValuePair<ulong, int>, Stride1D.Dense> Pow2ModEntriesToTestOnDevice;
public readonly MemoryBuffer1D<int, Stride1D.Dense> SmallPrimeFactorCountSlot; public ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense> Pow2ModEntriesToTestOnDeviceView;
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> SpecialMaxResult;
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> WorkFactorBuffer;
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> CandidateBuffer;
public readonly MemoryBuffer1D<int, Stride1D.Dense> StackIndexBuffer;
public readonly MemoryBuffer1D<int, Stride1D.Dense> StackExponentBuffer;
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> StackProductBuffer;
public OrderKernelBuffers CalculateOrderKernelBuffers;
public readonly ArrayView1D<ulong, Stride1D.Dense> WorkFactorBufferView;
public readonly ArrayView1D<ulong, Stride1D.Dense> CandidateBufferView;
public readonly ArrayView1D<int, Stride1D.Dense> StackIndexBufferView;
public readonly ArrayView1D<int, Stride1D.Dense> StackExponentBufferView;
public readonly ArrayView1D<ulong, Stride1D.Dense> StackProductBufferView;
public MemoryBuffer1D<GpuUInt128, Stride1D.Dense> CalculateOrderWideExponentBuffer;
public MemoryBuffer1D<GpuUInt128, Stride1D.Dense> CalculateOrderWideRemainderBuffer;
public ArrayView1D<GpuUInt128, Stride1D.Dense> CalculateOrderWideExponentBufferView;
public ArrayView1D<GpuUInt128, Stride1D.Dense> CalculateOrderWideRemainderBufferView;
public Dictionary<ulong, int> Pow2ModEntriesToTestOnHost = []; public Dictionary<ulong, int> Pow2ModEntriesToTestOnHost = [];
private static readonly CalculatorKernels[] _kernels =new CalculatorKernels[AcceleratorPool.Shared.Accelerators.Length]; private static readonly CalculatorKernels[] _kernels = new CalculatorKernels[_accelerators.Length];
private sealed class CalculatorKernels(Accelerator accelerator) private sealed class CalculatorKernels(Accelerator accelerator)
{ {
public readonly Kernel CheckFactorsKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel<int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.CheckFactorsKernel)); public readonly Action<AcceleratorStream, Index1D, ulong, CalculateOrderKernelConfig, ulong, ulong, ulong, ulong, ulong, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, OrderKernelBuffers> CalculateOrderKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, CalculateOrderKernelConfig, ulong, ulong, ulong, ulong, ulong, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, OrderKernelBuffers>(PrimeOrderKernels.CalculateOrderKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, CalculateOrderKernelConfig, ulong, ulong, ulong, ulong, ulong, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, OrderKernelBuffers>>();
public readonly Kernel CheckFactorsKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel<int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderKernels.CheckFactorsKernel));
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>> ConvertToStandardKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelConvertToStandard)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>>>(); public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>> ConvertToStandardKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelConvertToStandard)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>>>();
@@ -127,9 +162,13 @@ public sealed class PrimeOrderCalculatorAccelerator
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>> KeepMontgomeryKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelKeepMontgomery)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>>>(); public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>> KeepMontgomeryKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelKeepMontgomery)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>>>();
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, int, ulong, uint, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>> PartialFactorKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, int, ulong, uint, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>>(PrimeOrderKernels.PartialFactorKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, int, ulong, uint, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>>>();
public readonly Kernel PollardRhoKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel<ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.TryPollardRhoKernel)); public readonly Kernel PollardRhoKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel<ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.TryPollardRhoKernel));
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>> Pow2ModWideKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>(PrimeOrderGpuHeuristics.Pow2ModKernelWide)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>>(); public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>> Pow2ModKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderKernels.Pow2ModKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>>>();
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>> Pow2ModWideKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>(PrimeOrderKernels.Pow2ModKernelWide)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>>();
public readonly Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<byte>> SharesFactorKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<byte>>(PrimeTesterKernels.SharesFactorKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<byte>>>(); public readonly Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<byte>> SharesFactorKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<byte>>(PrimeTesterKernels.SharesFactorKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<byte>>>();
@@ -140,17 +179,38 @@ public sealed class PrimeOrderCalculatorAccelerator
public readonly Action<AcceleratorStream, Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, ulong, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> SpecialMaxKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, ulong, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.EvaluateSpecialMaxCandidatesKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, ulong, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>(); public readonly Action<AcceleratorStream, Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, ulong, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> SpecialMaxKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, ulong, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.EvaluateSpecialMaxCandidatesKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, ulong, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>();
} }
public readonly Action<AcceleratorStream, Index1D, ulong, CalculateOrderKernelConfig, ulong, ulong, ulong, ulong, ulong, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, OrderKernelBuffers> CalculateOrderKernelLauncher;
public readonly Kernel CheckFactorsKernel; public readonly Kernel CheckFactorsKernel;
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>> ConvertToStandardKernelLauncher; public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>> ConvertToStandardKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews> HeuristicCombinedTrialDivisionKernelLauncher; public readonly Action<AcceleratorStream, Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews> HeuristicCombinedTrialDivisionKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>> KeepMontgomeryKernelLauncher; public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>> KeepMontgomeryKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, int, ulong, uint, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>> PartialFactorKernelLauncher;
public readonly Kernel PollardRhoKernel; public readonly Kernel PollardRhoKernel;
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>> Pow2ModKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>> Pow2ModWideKernelLauncher; public readonly Action<AcceleratorStream, Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>> Pow2ModWideKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<byte>> SharesFactorKernelLauncher; public readonly Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<byte>> SharesFactorKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, ulong, uint, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> SmallPrimeFactorKernelLauncher; public readonly Action<AcceleratorStream, Index1D, ulong, uint, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> SmallPrimeFactorKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>> SmallPrimeSieveKernelLauncher; public readonly Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>> SmallPrimeSieveKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, ulong, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> SpecialMaxKernelLauncher; public readonly Action<AcceleratorStream, Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, ulong, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> SpecialMaxKernelLauncher;
public void EnsureCalculateOrderWideCapacity(int newSize)
{
if (newSize > Input.Length)
{
CalculateOrderWideExponentBuffer.Dispose();
CalculateOrderWideRemainderBuffer.Dispose();
var accelerator = Accelerator;
// lock (accelerator)
// {
CalculateOrderWideExponentBuffer = accelerator.Allocate1D<GpuUInt128>(newSize);
CalculateOrderWideRemainderBuffer = accelerator.Allocate1D<GpuUInt128>(newSize);
CalculateOrderWideExponentBufferView = CalculateOrderWideExponentBuffer.View;
CalculateOrderWideRemainderBufferView = CalculateOrderWideRemainderBuffer.View;
// }
}
}
public void EnsureCapacity(int factorsCount, int primeTesterCapacity) public void EnsureCapacity(int factorsCount, int primeTesterCapacity)
{ {
Accelerator accelerator = Accelerator; Accelerator accelerator = Accelerator;
@@ -159,40 +219,76 @@ public sealed class PrimeOrderCalculatorAccelerator
if (pow2ModEntriesToTestOnDevice.Length < factorsCount) if (pow2ModEntriesToTestOnDevice.Length < factorsCount)
{ {
// lock (accelerator) // lock (accelerator)
{ // {
pow2ModEntriesToTestOnDevice.Dispose(); pow2ModEntriesToTestOnDevice.Dispose();
Pow2ModEntriesToTestOnDevice = accelerator.Allocate1D<KeyValuePair<ulong, int>>(factorsCount); pow2ModEntriesToTestOnDevice = accelerator.Allocate1D<KeyValuePair<ulong, int>>(factorsCount);
} Pow2ModEntriesToTestOnDevice = pow2ModEntriesToTestOnDevice;
Pow2ModEntriesToTestOnDeviceView = pow2ModEntriesToTestOnDevice.View;
// }
} }
MemoryBuffer1D<ulong, Stride1D.Dense> input = Input; MemoryBuffer1D<ulong, Stride1D.Dense> input = Input;
if (input.Length < primeTesterCapacity) if (input.Length < primeTesterCapacity)
{ {
// lock (accelerator) // lock (accelerator)
{ // {
input.Dispose(); input.Dispose();
Input = accelerator.Allocate1D<ulong>(primeTesterCapacity);
} input = accelerator.Allocate1D<ulong>(primeTesterCapacity);
Input = input;
InputView = input.View;
// }
} }
MemoryBuffer1D<byte, Stride1D.Dense> outputByte = OutputByte; MemoryBuffer1D<byte, Stride1D.Dense> outputByte = OutputByte;
if (outputByte.Length < primeTesterCapacity) if (outputByte.Length < primeTesterCapacity)
{ {
// lock (accelerator) // lock (accelerator)
{ // {
outputByte.Dispose(); outputByte.Dispose();
OutputByte = accelerator.Allocate1D<byte>(primeTesterCapacity);
} outputByte = accelerator.Allocate1D<byte>(primeTesterCapacity);
OutputByte = outputByte;
OutputByteView = outputByte.View;
// }
} }
MemoryBuffer1D<int, Stride1D.Dense> outputInt = OutputInt; MemoryBuffer1D<int, Stride1D.Dense> outputInt = OutputInt;
if (outputInt.Length < primeTesterCapacity) if (outputInt.Length < primeTesterCapacity)
{ {
// lock (accelerator) // lock (accelerator)
// {
outputInt.Dispose();
outputInt = accelerator.Allocate1D<int>(primeTesterCapacity);
OutputInt = outputInt;
OutputIntView = outputInt.View;
// }
}
}
public void EnsurePartialFactorCapacity(int newSize)
{
var accelerator = Accelerator;
var outputUlong = OutputUlong;
if (newSize > outputUlong.Length)
{
outputUlong.Dispose();
outputUlong = accelerator.Allocate1D<ulong>(newSize);
OutputUlong = outputUlong;
OutputUlongView = outputUlong.View;
}
var outputInt = OutputInt;
if (newSize > outputInt.Length)
{ {
outputInt.Dispose(); outputInt.Dispose();
OutputInt = accelerator.Allocate1D<int>(primeTesterCapacity);
} outputInt = accelerator.Allocate1D<int>(newSize);
OutputInt = outputInt;
OutputIntView = outputInt.View;
} }
} }
@@ -204,44 +300,56 @@ public sealed class PrimeOrderCalculatorAccelerator
if (outputUlong.Length < newSize) if (outputUlong.Length < newSize)
{ {
// lock (accelerator) // lock (accelerator)
{ // {
outputUlong.Dispose(); outputUlong.Dispose();
OutputUlong = accelerator.Allocate1D<ulong>(newSize);
} outputUlong = accelerator.Allocate1D<ulong>(newSize);
OutputUlong = outputUlong;
OutputUlongView = outputUlong.View;
// }
} }
MemoryBuffer1D<int, Stride1D.Dense> outputInt = OutputInt; MemoryBuffer1D<int, Stride1D.Dense> outputInt = OutputInt;
if (outputInt.Length < newSize) if (outputInt.Length < newSize)
{ {
// lock (accelerator) // lock (accelerator)
{ // {
outputInt.Dispose(); outputInt.Dispose();
OutputInt = accelerator.Allocate1D<int>(newSize);
} outputInt = accelerator.Allocate1D<int>(newSize);
OutputInt = outputInt;
OutputIntView = outputInt.View;
// }
} }
} }
public void EnsureSpecialMaxFactorsCapacity(int newSize) public void EnsureUlongInputOutputCapacity(int newSize)
{ {
var accelerator = Accelerator; var accelerator = Accelerator;
MemoryBuffer1D<ulong, Stride1D.Dense> input = Input; MemoryBuffer1D<ulong, Stride1D.Dense> buffer = Input;
if (input.Length < newSize) if (buffer.Length < newSize)
{ {
// lock (accelerator) // lock (accelerator)
{ // {
input.Dispose(); buffer.Dispose();
Input = accelerator.Allocate1D<ulong>(newSize);
} buffer = accelerator.Allocate1D<ulong>(newSize);
Input = buffer;
InputView = buffer.View;
// }
} }
MemoryBuffer1D<ulong, Stride1D.Dense> outputUlong = OutputUlong; buffer = OutputUlong;
if (outputUlong.Length < newSize) if (buffer.Length < newSize)
{ {
// lock (accelerator) // lock (accelerator)
{ // {
outputUlong.Dispose(); buffer.Dispose();
OutputUlong = accelerator.Allocate1D<ulong>(newSize);
} buffer = accelerator.Allocate1D<ulong>(newSize);
OutputUlong = buffer;
OutputUlongView = buffer.View;
// }
} }
} }
@@ -250,15 +358,59 @@ public sealed class PrimeOrderCalculatorAccelerator
var accelerator = _accelerators[acceleratorIndex]; var accelerator = _accelerators[acceleratorIndex];
Accelerator = accelerator; Accelerator = accelerator;
AcceleratorIndex = acceleratorIndex; AcceleratorIndex = acceleratorIndex;
// lock (accelerator) // lock (accelerator)
{ // {
Input = accelerator.Allocate1D<ulong>(Math.Max(specialMaxFactorCapacity, primeTesterCapacity)); Input = accelerator.Allocate1D<ulong>(Math.Max(Math.Max(specialMaxFactorCapacity, primeTesterCapacity), PrimeOrderConstants.MaxGpuBatchSize));
InputView = Input.View;
OutputByte = Accelerator.Allocate1D<byte>(primeTesterCapacity); OutputByte = Accelerator.Allocate1D<byte>(primeTesterCapacity);
OutputInt = Accelerator.Allocate1D<int>(Math.Max(primeTesterCapacity, smallPrimeFactorSlotCount)); OutputByteView = OutputByte.View;
OutputUlong = accelerator.Allocate1D<ulong>(Math.Max(specialMaxFactorCapacity, smallPrimeFactorSlotCount));
OutputInt = Accelerator.Allocate1D<int>(Math.Max(Math.Max(primeTesterCapacity, smallPrimeFactorSlotCount), PrimeOrderConstants.GpuSmallPrimeFactorSlots));
OutputIntView = OutputInt.View;
OutputInt2 = accelerator.Allocate1D<int>(PrimeOrderConstants.GpuSmallPrimeFactorSlots);
OutputIntView2 = OutputInt2.View;
OutputUlong = accelerator.Allocate1D<ulong>(Math.Max(Math.Max(Math.Max(specialMaxFactorCapacity, smallPrimeFactorSlotCount), PrimeOrderConstants.MaxGpuBatchSize), PrimeOrderConstants.GpuSmallPrimeFactorSlots));
OutputUlongView = OutputUlong.View;
OutputUlong2 = accelerator.Allocate1D<ulong>(1);
OutputUlongView2 = OutputUlong2.View;
Pow2ModEntriesToTestOnDevice = accelerator.Allocate1D<KeyValuePair<ulong, int>>(factorsCount); Pow2ModEntriesToTestOnDevice = accelerator.Allocate1D<KeyValuePair<ulong, int>>(factorsCount);
SmallPrimeFactorCountSlot = accelerator.Allocate1D<int>(1); Pow2ModEntriesToTestOnDeviceView = Pow2ModEntriesToTestOnDevice.View;
SpecialMaxResult = accelerator.Allocate1D<ulong>(1);
WorkFactorBuffer = accelerator.Allocate1D<ulong>(PrimeOrderConstants.GpuSmallPrimeFactorSlots);
CandidateBuffer = accelerator.Allocate1D<ulong>(PrimeOrderConstants.HeuristicCandidateLimit);
StackIndexBuffer = accelerator.Allocate1D<int>(PrimeOrderConstants.HeuristicStackCapacity);
StackExponentBuffer = accelerator.Allocate1D<int>(PrimeOrderConstants.HeuristicStackCapacity);
StackProductBuffer = accelerator.Allocate1D<ulong>(PrimeOrderConstants.HeuristicStackCapacity);
WorkFactorBufferView = WorkFactorBuffer.View;
CandidateBufferView = CandidateBuffer.View;
StackIndexBufferView = StackIndexBuffer.View;
StackExponentBufferView = StackExponentBuffer.View;
StackProductBufferView = StackProductBuffer.View;
CalculateOrderKernelBuffers = new OrderKernelBuffers(
OutputUlongView,
OutputIntView,
WorkFactorBufferView,
OutputIntView2,
CandidateBufferView,
StackIndexBufferView,
StackExponentBufferView,
StackProductBufferView,
OutputUlongView2,
OutputByteView
);
CalculateOrderWideExponentBuffer = accelerator.Allocate1D<GpuUInt128>(PrimeOrderConstants.MaxGpuBatchSize);
CalculateOrderWideRemainderBuffer = accelerator.Allocate1D<GpuUInt128>(PrimeOrderConstants.MaxGpuBatchSize);
CalculateOrderWideExponentBufferView = CalculateOrderWideExponentBuffer.View;
CalculateOrderWideRemainderBufferView = CalculateOrderWideRemainderBuffer.View;
LastDigitGpuTables lastDigitSharedTables = LastDigitGpuTables.GetStaticTables(acceleratorIndex); LastDigitGpuTables lastDigitSharedTables = LastDigitGpuTables.GetStaticTables(acceleratorIndex);
DevicePrimesLastOne = lastDigitSharedTables.DevicePrimesLastOne.View; DevicePrimesLastOne = lastDigitSharedTables.DevicePrimesLastOne.View;
@@ -285,17 +437,20 @@ public sealed class PrimeOrderCalculatorAccelerator
var kernels = _kernels[acceleratorIndex]; var kernels = _kernels[acceleratorIndex];
CalculateOrderKernelLauncher = kernels.CalculateOrderKernelLauncher;
CheckFactorsKernel = kernels.CheckFactorsKernel; CheckFactorsKernel = kernels.CheckFactorsKernel;
ConvertToStandardKernelLauncher = kernels.ConvertToStandardKernelLauncher; ConvertToStandardKernelLauncher = kernels.ConvertToStandardKernelLauncher;
HeuristicCombinedTrialDivisionKernelLauncher = kernels.HeuristicCombinedTrialDivisionKernelLauncher; HeuristicCombinedTrialDivisionKernelLauncher = kernels.HeuristicCombinedTrialDivisionKernelLauncher;
KeepMontgomeryKernelLauncher = kernels.KeepMontgomeryKernelLauncher; KeepMontgomeryKernelLauncher = kernels.KeepMontgomeryKernelLauncher;
PartialFactorKernelLauncher = kernels.PartialFactorKernelLauncher;
PollardRhoKernel = kernels.PollardRhoKernel; PollardRhoKernel = kernels.PollardRhoKernel;
Pow2ModKernelLauncher = kernels.Pow2ModKernelLauncher;
Pow2ModWideKernelLauncher = kernels.Pow2ModWideKernelLauncher; Pow2ModWideKernelLauncher = kernels.Pow2ModWideKernelLauncher;
SharesFactorKernelLauncher = kernels.SharesFactorKernelLauncher; SharesFactorKernelLauncher = kernels.SharesFactorKernelLauncher;
SmallPrimeFactorKernelLauncher = kernels.SmallPrimeFactorKernelLauncher; SmallPrimeFactorKernelLauncher = kernels.SmallPrimeFactorKernelLauncher;
SmallPrimeSieveKernelLauncher = kernels.SmallPrimeSieveKernelLauncher; SmallPrimeSieveKernelLauncher = kernels.SmallPrimeSieveKernelLauncher;
SpecialMaxKernelLauncher = kernels.SpecialMaxKernelLauncher; SpecialMaxKernelLauncher = kernels.SpecialMaxKernelLauncher;
} // }
} }
public void Dispose() public void Dispose()
@@ -303,10 +458,20 @@ public sealed class PrimeOrderCalculatorAccelerator
Input.Dispose(); Input.Dispose();
OutputByte.Dispose(); OutputByte.Dispose();
OutputInt.Dispose(); OutputInt.Dispose();
OutputInt2.Dispose();
OutputUlong.Dispose(); OutputUlong.Dispose();
OutputUlong2.Dispose();
Pow2ModEntriesToTestOnDevice.Dispose(); Pow2ModEntriesToTestOnDevice.Dispose();
SmallPrimeFactorCountSlot.Dispose();
SpecialMaxResult.Dispose(); WorkFactorBuffer.Dispose();
CandidateBuffer.Dispose();
StackIndexBuffer.Dispose();
StackExponentBuffer.Dispose();
StackProductBuffer.Dispose();
CalculateOrderWideExponentBuffer.Dispose();
CalculateOrderWideRemainderBuffer.Dispose();
// These resources are shared between GPU leases // These resources are shared between GPU leases
// Stream.Dispose(); // Stream.Dispose();
@@ -0,0 +1,10 @@
namespace PerfectNumbers.Core.Gpu;
public readonly struct CalculateOrderKernelConfig(ulong previousOrder, byte hasPreviousOrder, uint smallFactorLimit, int maxPowChecks, int mode)
{
public readonly ulong PreviousOrder = previousOrder;
public readonly byte HasPreviousOrder = hasPreviousOrder;
public readonly uint SmallFactorLimit = smallFactorLimit;
public readonly int MaxPowChecks = maxPowChecks;
public readonly int Mode = mode;
}
@@ -0,0 +1,10 @@
namespace PerfectNumbers.Core.Gpu.Kernels;
public enum PrimeOrderKernelStatus : byte
{
Fallback = 0,
Found = 1,
HeuristicUnresolved = 2,
PollardOverflow = 3,
FactoringFailure = 4,
}
@@ -6,7 +6,7 @@ using PerfectNumbers.Core.Gpu.Kernels;
namespace PerfectNumbers.Core.Gpu; namespace PerfectNumbers.Core.Gpu;
internal static partial class PrimeOrderGpuHeuristics internal static partial class PrimeOrderKernels
{ {
internal static void CheckFactorsKernel( internal static void CheckFactorsKernel(
int count, int count,
@@ -115,15 +115,6 @@ internal static partial class PrimeOrderGpuHeuristics
fullyFactoredOut[0] = remainingLocal == 1UL ? (byte)1 : (byte)0; fullyFactoredOut[0] = remainingLocal == 1UL ? (byte)1 : (byte)0;
} }
internal enum PrimeOrderKernelStatus : byte
{
Fallback = 0,
Found = 1,
HeuristicUnresolved = 2,
PollardOverflow = 3,
FactoringFailure = 4,
}
private readonly struct CandidateKey private readonly struct CandidateKey
{ {
public CandidateKey(int primary, long secondary, long tertiary) public CandidateKey(int primary, long secondary, long tertiary)
@@ -160,7 +151,7 @@ internal static partial class PrimeOrderGpuHeuristics
internal static void CalculateOrderKernel( internal static void CalculateOrderKernel(
Index1D index, Index1D index,
ulong prime, ulong prime,
OrderKernelConfig config, CalculateOrderKernelConfig config,
ulong divisorModulus, ulong divisorModulus,
ulong divisorNPrime, ulong divisorNPrime,
ulong divisorMontgomeryOne, ulong divisorMontgomeryOne,
@@ -189,7 +180,7 @@ internal static partial class PrimeOrderGpuHeuristics
ArrayView1D<ulong, Stride1D.Dense> resultOut = buffers.Result; ArrayView1D<ulong, Stride1D.Dense> resultOut = buffers.Result;
ArrayView1D<byte, Stride1D.Dense> statusOut = buffers.Status; ArrayView1D<byte, Stride1D.Dense> statusOut = buffers.Status;
uint limit = config.SmallFactorLimit == 0 ? uint.MaxValue : config.SmallFactorLimit; uint limit = config.SmallFactorLimit;
ulong previousOrder = config.PreviousOrder; ulong previousOrder = config.PreviousOrder;
byte hasPreviousOrder = config.HasPreviousOrder; byte hasPreviousOrder = config.HasPreviousOrder;
int maxPowChecks = config.MaxPowChecks; int maxPowChecks = config.MaxPowChecks;
@@ -589,7 +580,7 @@ internal static partial class PrimeOrderGpuHeuristics
SortFactors(workFactors, workExponents, factorCount); SortFactors(workFactors, workExponents, factorCount);
long candidateCapacity = candidates.Length; long candidateCapacity = candidates.Length;
int candidateLimit = candidateCapacity < HeuristicCandidateLimit ? (int)candidateCapacity : HeuristicCandidateLimit; int candidateLimit = candidateCapacity < PrimeOrderConstants.HeuristicCandidateLimit ? (int)candidateCapacity : PrimeOrderConstants.HeuristicCandidateLimit;
int candidateCount = BuildCandidatesKernel(order, workFactors, workExponents, factorCount, candidates, stackIndex, stackExponent, stackProduct, candidateLimit); int candidateCount = BuildCandidatesKernel(order, workFactors, workExponents, factorCount, candidates, stackIndex, stackExponent, stackProduct, candidateLimit);
if (candidateCount == 0) if (candidateCount == 0)
{ {
@@ -1328,11 +1319,11 @@ internal static partial class PrimeOrderGpuHeuristics
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool ShouldUseSingleBit(GpuUInt128 exponent) => exponent.High == 0UL && exponent.Low <= Pow2WindowFallbackThreshold; private static bool ShouldUseSingleBit(GpuUInt128 exponent) => exponent.High == 0UL && exponent.Low <= PrimeOrderConstants.Pow2WindowFallbackThreshold;
private static int GetWindowSize(int bitLength) private static int GetWindowSize(int bitLength)
{ {
if (bitLength <= Pow2WindowSizeBits) if (bitLength <= PrimeOrderConstants.Pow2WindowSizeBits)
{ {
return Math.Max(bitLength, 1); return Math.Max(bitLength, 1);
} }
@@ -1357,7 +1348,7 @@ internal static partial class PrimeOrderGpuHeuristics
return 7; return 7;
} }
return Pow2WindowSizeBits; return PrimeOrderConstants.Pow2WindowSizeBits;
} }
private static GpuUInt128 Pow2MontgomeryModSingleBit(GpuUInt128 exponent, GpuUInt128 modulus, GpuUInt128 baseValue) private static GpuUInt128 Pow2MontgomeryModSingleBit(GpuUInt128 exponent, GpuUInt128 modulus, GpuUInt128 baseValue)
@@ -0,0 +1,28 @@
using ILGPU;
using ILGPU.Runtime;
namespace PerfectNumbers.Core.Gpu;
public readonly struct OrderKernelBuffers(
ArrayView1D<ulong, Stride1D.Dense> phiFactors,
ArrayView1D<int, Stride1D.Dense> phiExponents,
ArrayView1D<ulong, Stride1D.Dense> workFactors,
ArrayView1D<int, Stride1D.Dense> workExponents,
ArrayView1D<ulong, Stride1D.Dense> candidates,
ArrayView1D<int, Stride1D.Dense> stackIndex,
ArrayView1D<int, Stride1D.Dense> stackExponent,
ArrayView1D<ulong, Stride1D.Dense> stackProduct,
ArrayView1D<ulong, Stride1D.Dense> result,
ArrayView1D<byte, Stride1D.Dense> status)
{
public readonly ArrayView1D<ulong, Stride1D.Dense> PhiFactors = phiFactors;
public readonly ArrayView1D<int, Stride1D.Dense> PhiExponents = phiExponents;
public readonly ArrayView1D<ulong, Stride1D.Dense> WorkFactors = workFactors;
public readonly ArrayView1D<int, Stride1D.Dense> WorkExponents = workExponents;
public readonly ArrayView1D<ulong, Stride1D.Dense> Candidates = candidates;
public readonly ArrayView1D<int, Stride1D.Dense> StackIndex = stackIndex;
public readonly ArrayView1D<int, Stride1D.Dense> StackExponent = stackExponent;
public readonly ArrayView1D<ulong, Stride1D.Dense> StackProduct = stackProduct;
public readonly ArrayView1D<ulong, Stride1D.Dense> Result = result;
public readonly ArrayView1D<byte, Stride1D.Dense> Status = status;
}
@@ -15,18 +15,18 @@ public static class Pow2MontgomeryGpuCalculator
ulong result = 0UL; ulong result = 0UL;
int acceleratorIndex = gpu.AcceleratorIndex; int acceleratorIndex = gpu.AcceleratorIndex;
Accelerator? accelerator = gpu.Accelerator; Accelerator? accelerator = gpu.Accelerator;
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input; var exponentBufferView = gpu.InputView;
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.OutputUlong; var resultBufferView = gpu.OutputUlongView;
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex); AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
exponentBuffer.View.CopyFromCPU(stream, ref exponent, 1); exponentBufferView.CopyFromCPU(stream, ref exponent, 1);
// We don't need to worry about any left-overs here. // We don't need to worry about any left-overs here.
// resultBuffer.MemSetToZero(stream); // resultBuffer.MemSetToZero(stream);
var kernelLauncher = gpu.KeepMontgomeryKernelLauncher; var kernelLauncher = gpu.KeepMontgomeryKernelLauncher;
kernelLauncher(stream, 1, exponentBuffer.View, divisor.Modulus, divisor.NPrime, divisor.MontgomeryOne, divisor.MontgomeryTwo, divisor.MontgomeryTwoSquared, resultBuffer.View); kernelLauncher(stream, 1, exponentBufferView, divisor.Modulus, divisor.NPrime, divisor.MontgomeryOne, divisor.MontgomeryTwo, divisor.MontgomeryTwoSquared, resultBufferView);
resultBuffer.View.CopyToCPU(stream, ref result, 1); resultBufferView.CopyToCPU(stream, ref result, 1);
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(acceleratorIndex, stream); AcceleratorStreamPool.Return(acceleratorIndex, stream);
// GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
@@ -38,21 +38,21 @@ public static class Pow2MontgomeryGpuCalculator
public static ulong CalculateConvert(PrimeOrderCalculatorAccelerator gpu, ulong exponent, in MontgomeryDivisorData divisor) public static ulong CalculateConvert(PrimeOrderCalculatorAccelerator gpu, ulong exponent, in MontgomeryDivisorData divisor)
{ {
ulong result = 0UL; ulong result = 0UL;
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input; var exponentBufferView = gpu.InputView;
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.OutputUlong; var resultBufferView = gpu.OutputUlongView;
int acceleratorIndex = gpu.AcceleratorIndex; int acceleratorIndex = gpu.AcceleratorIndex;
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex); AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
exponentBuffer.View.CopyFromCPU(stream, ref exponent, 1); exponentBufferView.CopyFromCPU(stream, ref exponent, 1);
// We don't need to worry about any left-overs here. // We don't need to worry about any left-overs here.
// resultBuffer.MemSetToZero(stream); // resultBuffer.MemSetToZero(stream);
var accelerator = gpu.Accelerator; var accelerator = gpu.Accelerator;
var kernelLauncher = gpu.ConvertToStandardKernelLauncher; var kernelLauncher = gpu.ConvertToStandardKernelLauncher;
kernelLauncher(stream, 1, exponentBuffer.View, divisor.Modulus, divisor.NPrime, divisor.MontgomeryOne, divisor.MontgomeryTwo, divisor.MontgomeryTwoSquared, resultBuffer.View); kernelLauncher(stream, 1, exponentBufferView, divisor.Modulus, divisor.NPrime, divisor.MontgomeryOne, divisor.MontgomeryTwo, divisor.MontgomeryTwoSquared, resultBufferView);
resultBuffer.View.CopyToCPU(stream, ref result, 1); resultBufferView.CopyToCPU(stream, ref result, 1);
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(acceleratorIndex, stream); AcceleratorStreamPool.Return(acceleratorIndex, stream);
@@ -0,0 +1,14 @@
namespace PerfectNumbers.Core.Gpu;
public static class PrimeOrderConstants
{
public const int GpuSmallPrimeFactorSlots = 64;
public const int HeuristicCandidateLimit = 512;
public const int HeuristicStackCapacity = 256;
public const int MaxGpuBatchSize = 256;
public const ulong Pow2WindowFallbackThreshold = 32UL;
public const int Pow2WindowOddPowerCount = 1 << (Pow2WindowSizeBits - 1);
public const int Pow2WindowSizeBits = 8;
public const int WideStackThreshold = 12;
}
@@ -1,9 +1,7 @@
using System.Buffers; using System.Buffers;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using ILGPU;
using ILGPU.Runtime; using ILGPU.Runtime;
using ILGPU.Runtime.OpenCL;
using PerfectNumbers.Core.Gpu.Accelerators; using PerfectNumbers.Core.Gpu.Accelerators;
using PerfectNumbers.Core.Gpu.Kernels; using PerfectNumbers.Core.Gpu.Kernels;
@@ -26,58 +24,9 @@ internal static partial class PrimeOrderGpuHeuristics
private static readonly ConcurrentDictionary<ulong, byte> OverflowedPrimes = new(); private static readonly ConcurrentDictionary<ulong, byte> OverflowedPrimes = new();
private static readonly ConcurrentDictionary<UInt128, byte> OverflowedPrimesWide = new(); private static readonly ConcurrentDictionary<UInt128, byte> OverflowedPrimesWide = new();
[ThreadStatic]
private static Kernel[]? _pow2ModKernel;
[ThreadStatic]
private static Kernel[]? _partialFactorKernel;
[ThreadStatic]
private static Kernel[]? _orderKernel;
public readonly struct OrderKernelConfig(ulong previousOrder, byte hasPreviousOrder, uint smallFactorLimit, int maxPowChecks, int mode)
{
public readonly ulong PreviousOrder = previousOrder;
public readonly byte HasPreviousOrder = hasPreviousOrder;
public readonly uint SmallFactorLimit = smallFactorLimit;
public readonly int MaxPowChecks = maxPowChecks;
public readonly int Mode = mode;
}
public readonly struct OrderKernelBuffers(
ArrayView1D<ulong, Stride1D.Dense> phiFactors,
ArrayView1D<int, Stride1D.Dense> phiExponents,
ArrayView1D<ulong, Stride1D.Dense> workFactors,
ArrayView1D<int, Stride1D.Dense> workExponents,
ArrayView1D<ulong, Stride1D.Dense> candidates,
ArrayView1D<int, Stride1D.Dense> stackIndex,
ArrayView1D<int, Stride1D.Dense> stackExponent,
ArrayView1D<ulong, Stride1D.Dense> stackProduct,
ArrayView1D<ulong, Stride1D.Dense> result,
ArrayView1D<byte, Stride1D.Dense> status)
{
public readonly ArrayView1D<ulong, Stride1D.Dense> PhiFactors = phiFactors;
public readonly ArrayView1D<int, Stride1D.Dense> PhiExponents = phiExponents;
public readonly ArrayView1D<ulong, Stride1D.Dense> WorkFactors = workFactors;
public readonly ArrayView1D<int, Stride1D.Dense> WorkExponents = workExponents;
public readonly ArrayView1D<ulong, Stride1D.Dense> Candidates = candidates;
public readonly ArrayView1D<int, Stride1D.Dense> StackIndex = stackIndex;
public readonly ArrayView1D<int, Stride1D.Dense> StackExponent = stackExponent;
public readonly ArrayView1D<ulong, Stride1D.Dense> StackProduct = stackProduct;
public readonly ArrayView1D<ulong, Stride1D.Dense> Result = result;
public readonly ArrayView1D<byte, Stride1D.Dense> Status = status;
}
private const int WideStackThreshold = 12;
private static PrimeOrderGpuCapability s_capability = PrimeOrderGpuCapability.Default; private static PrimeOrderGpuCapability s_capability = PrimeOrderGpuCapability.Default;
private const int Pow2WindowSizeBits = 8;
private const int Pow2WindowOddPowerCount = 1 << (Pow2WindowSizeBits - 1);
private const ulong Pow2WindowFallbackThreshold = 32UL;
private const int HeuristicCandidateLimit = 512;
private const int HeuristicStackCapacity = 256;
private const int GpuSmallPrimeFactorSlots = 64;
internal static ConcurrentDictionary<ulong, byte> OverflowRegistry => OverflowedPrimes; internal static ConcurrentDictionary<ulong, byte> OverflowRegistry => OverflowedPrimes;
internal static ConcurrentDictionary<UInt128, byte> OverflowRegistryWide => OverflowedPrimesWide; internal static ConcurrentDictionary<UInt128, byte> OverflowRegistryWide => OverflowedPrimesWide;
@@ -92,22 +41,6 @@ internal static partial class PrimeOrderGpuHeuristics
s_capability = PrimeOrderGpuCapability.Default; s_capability = PrimeOrderGpuCapability.Default;
} }
private static Kernel GetPartialFactorKernel(int acceleratorIndex)
{
var pool = _partialFactorKernel ??= [];
if (pool[acceleratorIndex] is {} cached)
{
return cached;
}
var accelerator = _accelerators[acceleratorIndex];
var loaded = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, int, ulong, uint, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>>(PartialFactorKernel);
cached = KernelUtil.GetKernel(loaded);
pool[acceleratorIndex] = cached;
return cached;
}
public static bool TryPartialFactor( public static bool TryPartialFactor(
PrimeOrderCalculatorAccelerator gpu, PrimeOrderCalculatorAccelerator gpu,
ulong value, ulong value,
@@ -167,32 +100,30 @@ internal static partial class PrimeOrderGpuHeuristics
factorCount = 0; factorCount = 0;
remaining = value; remaining = value;
try
{
// GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
int acceleratorIndex = AcceleratorPool.Shared.Rent(); int acceleratorIndex = gpu.AcceleratorIndex;
Accelerator accelerator = _accelerators[acceleratorIndex];
AcceleratorStream stream = accelerator.CreateStream();
var smallPrimesView = gpu.SmallPrimeFactorPrimes; var smallPrimesView = gpu.SmallPrimeFactorPrimes;
var smallSquaresView = gpu.SmallPrimeFactorSquares; var smallSquaresView = gpu.SmallPrimeFactorSquares;
// TODO: We should create / reallocate these buffer only once or if the new required length is bigger than capacity. var kernelLauncher = gpu.PartialFactorKernelLauncher;
MemoryBuffer1D<ulong, Stride1D.Dense>? factorBuffer = accelerator.Allocate1D<ulong>(primeTargets.Length);
MemoryBuffer1D<int, Stride1D.Dense>? exponentBuffer = accelerator.Allocate1D<int>(exponentTargets.Length); int primeTargetsLength = primeTargets.Length;
MemoryBuffer1D<int, Stride1D.Dense>? countBuffer = accelerator.Allocate1D<int>(1); gpu.EnsurePartialFactorCapacity(primeTargetsLength);
MemoryBuffer1D<ulong, Stride1D.Dense>? remainingBuffer = accelerator.Allocate1D<ulong>(1);
MemoryBuffer1D<byte, Stride1D.Dense>? fullyFactoredBuffer = accelerator.Allocate1D<byte>(1); var factorBufferView = gpu.OutputUlongView;
var exponentBufferView = gpu.OutputIntView;
var countBufferView = gpu.OutputIntView2;
var remainingBufferView = gpu.OutputUlongView2;
var fullyFactoredBufferView = gpu.OutputByteView;
// There is no need to clear these buffers because the kernel will always assign values within the required bounds. Keep it commented out. // There is no need to clear these buffers because the kernel will always assign values within the required bounds. Keep it commented out.
// factorBuffer.MemSetToZero(stream); // factorBufferView.MemSetToZero(stream);
// exponentBuffer.MemSetToZero(stream); // exponentBufferView.MemSetToZero(stream);
// countBuffer.MemSetToZero(stream); // countBufferView.MemSetToZero(stream);
// remainingBuffer.MemSetToZero(stream); // remainingBufferView.MemSetToZero(stream);
// fullyFactoredBuffer.MemSetToZero(stream); // fullyFactoredBufferView.MemSetToZero(stream);
var partialFactorKernel = GetPartialFactorKernel(acceleratorIndex); AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
var kernelLauncher = partialFactorKernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, int, ulong, uint, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>>>();
kernelLauncher( kernelLauncher(
stream, stream,
@@ -200,61 +131,43 @@ internal static partial class PrimeOrderGpuHeuristics
smallPrimesView, smallPrimesView,
smallSquaresView, smallSquaresView,
(int)smallPrimesView.Length, (int)smallPrimesView.Length,
primeTargets.Length, primeTargetsLength,
value, value,
limit, limit,
factorBuffer.View, factorBufferView,
exponentBuffer.View, exponentBufferView,
countBuffer.View, countBufferView,
remainingBuffer.View, remainingBufferView,
fullyFactoredBuffer.View); fullyFactoredBufferView);
countBuffer.View.CopyToCPU(stream, ref factorCount, 1);
factorBuffer.View.CopyToCPU(stream, ref MemoryMarshal.GetReference(primeTargets), primeTargets.Length);
exponentBuffer.View.CopyToCPU(stream, ref MemoryMarshal.GetReference(exponentTargets), exponentTargets.Length);
remainingBuffer.View.CopyToCPU(stream, ref remaining, 1);
byte fullyFactoredFlag = 0; byte fullyFactoredFlag = 0;
fullyFactoredBuffer.View.CopyToCPU(stream, ref fullyFactoredFlag, 1); factorBufferView.CopyToCPU(stream, primeTargets);
exponentBufferView.CopyToCPU(stream, exponentTargets);
countBufferView.CopyToCPU(stream, ref factorCount, 1);
remainingBufferView.CopyToCPU(stream, ref remaining, 1);
fullyFactoredBufferView.CopyToCPU(stream, ref fullyFactoredFlag, 1);
stream.Synchronize(); stream.Synchronize();
stream.Dispose(); AcceleratorStreamPool.Return(acceleratorIndex, stream);
factorCount = Math.Min(factorCount, primeTargets.Length); factorCount = Math.Min(factorCount, primeTargetsLength);
// TODO: These buffers shouldn't be disposed but rather reused accross call with the assigned accelerator.
factorBuffer.Dispose();
exponentBuffer.Dispose();
countBuffer.Dispose();
remainingBuffer.Dispose();
fullyFactoredBuffer.Dispose();
// GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
return true; return true;
} }
catch (CLException ex)
{
Console.WriteLine($"GPU ERROR ({ex.Error}): {ex.Message}");
throw;
}
catch (Exception ex) when (ex is AcceleratorException or InternalCompilerException or NotSupportedException or InvalidOperationException or AggregateException)
{
Console.WriteLine($"GPU ERROR: {ex.Message}");
throw;
}
}
public static GpuPow2ModStatus TryPow2Mod(ulong exponent, ulong prime, out ulong remainder, in MontgomeryDivisorData? divisorData) public static GpuPow2ModStatus TryPow2Mod(PrimeOrderCalculatorAccelerator gpu, ulong exponent, ulong prime, out ulong remainder, in MontgomeryDivisorData? divisorData)
{ {
Span<ulong> exponents = stackalloc ulong[1]; Span<ulong> exponents = stackalloc ulong[1];
Span<ulong> remainders = stackalloc ulong[1]; Span<ulong> remainders = stackalloc ulong[1];
exponents[0] = exponent; exponents[0] = exponent;
GpuPow2ModStatus status = TryPow2ModBatch(exponents, prime, remainders, divisorData); GpuPow2ModStatus status = TryPow2ModBatch(gpu, exponents, prime, remainders, divisorData);
remainder = remainders[0]; remainder = remainders[0];
return status; return status;
} }
public static GpuPow2ModStatus TryPow2ModBatch(ReadOnlySpan<ulong> exponents, ulong prime, Span<ulong> remainders, in MontgomeryDivisorData? divisorData) public static GpuPow2ModStatus TryPow2ModBatch(PrimeOrderCalculatorAccelerator gpu, ReadOnlySpan<ulong> exponents, ulong prime, Span<ulong> remainders, in MontgomeryDivisorData? divisorData)
{ {
// This will never occur in production code // This will never occur in production code
// if (exponents.Length == 0) // if (exponents.Length == 0)
@@ -305,7 +218,7 @@ internal static partial class PrimeOrderGpuHeuristics
} }
} }
bool computed = TryComputeOnGpu(exponents, prime, divisorData, remainders); bool computed = TryComputeOnGpu(gpu, exponents, prime, divisorData, remainders);
return computed ? GpuPow2ModStatus.Success : GpuPow2ModStatus.Unavailable; return computed ? GpuPow2ModStatus.Success : GpuPow2ModStatus.Unavailable;
} }
@@ -336,71 +249,41 @@ internal static partial class PrimeOrderGpuHeuristics
order = 0UL; order = 0UL;
// GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
int acceleratorIndex = AcceleratorPool.Shared.Rent(); int acceleratorIndex = gpu.AcceleratorIndex;
Accelerator accelerator = _accelerators[acceleratorIndex];
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
var smallPrimesView = gpu.SmallPrimeFactorPrimes; var smallPrimesView = gpu.SmallPrimeFactorPrimes;
var smallSquaresView = gpu.SmallPrimeFactorSquares; var smallSquaresView = gpu.SmallPrimeFactorSquares;
// var phiFactorBufferView = gpu.PhiFactorBufferView;
// TODO: These buffers should be created reallocated once and assigned to an accelerator. Callers should use their own // var phiExponentBufferView = gpu.PhiExponentBufferView;
// thread static cache to prevent other threads from using taking accelerators with pre-allocated buffers if they don't // var workFactorBufferView = gpu.WorkFactorBufferView;
// use them. // var workExponentBufferView = gpu.WorkExponentBufferView;
MemoryBuffer1D<ulong, Stride1D.Dense>? phiFactorBuffer; // var candidateBufferView = gpu.CandidateBufferView;
MemoryBuffer1D<int, Stride1D.Dense>? phiExponentBuffer; // var stackIndexBufferView = gpu.StackIndexBufferView;
MemoryBuffer1D<ulong, Stride1D.Dense>? workFactorBuffer; // var stackExponentBufferView = gpu.StackExponentBufferView;
MemoryBuffer1D<int, Stride1D.Dense>? workExponentBuffer; // var stackProductBufferView = gpu.StackProductBufferView;
MemoryBuffer1D<ulong, Stride1D.Dense>? candidateBuffer; var resultBufferView = gpu.OutputUlongView2;
MemoryBuffer1D<int, Stride1D.Dense>? stackIndexBuffer; var statusBufferView = gpu.OutputByteView;
MemoryBuffer1D<int, Stride1D.Dense>? stackExponentBuffer;
MemoryBuffer1D<ulong, Stride1D.Dense>? stackProductBuffer;
MemoryBuffer1D<ulong, Stride1D.Dense>? resultBuffer;
MemoryBuffer1D<byte, Stride1D.Dense>? statusBuffer;
// lock (accelerator)
{
phiFactorBuffer = accelerator.Allocate1D<ulong>(GpuSmallPrimeFactorSlots);
phiExponentBuffer = accelerator.Allocate1D<int>(GpuSmallPrimeFactorSlots);
workFactorBuffer = accelerator.Allocate1D<ulong>(GpuSmallPrimeFactorSlots);
workExponentBuffer = accelerator.Allocate1D<int>(GpuSmallPrimeFactorSlots);
candidateBuffer = accelerator.Allocate1D<ulong>(HeuristicCandidateLimit);
stackIndexBuffer = accelerator.Allocate1D<int>(HeuristicStackCapacity);
stackExponentBuffer = accelerator.Allocate1D<int>(HeuristicStackCapacity);
stackProductBuffer = accelerator.Allocate1D<ulong>(HeuristicStackCapacity);
resultBuffer = accelerator.Allocate1D<ulong>(1);
statusBuffer = accelerator.Allocate1D<byte>(1);
}
// TODO: Remove the cleaning after the order kernel is modified to always set the result.
phiFactorBuffer.MemSetToZero(stream);
phiExponentBuffer.MemSetToZero(stream);
workFactorBuffer.MemSetToZero(stream);
workExponentBuffer.MemSetToZero(stream);
candidateBuffer.MemSetToZero(stream);
stackIndexBuffer.MemSetToZero(stream);
stackExponentBuffer.MemSetToZero(stream);
stackProductBuffer.MemSetToZero(stream);
resultBuffer.MemSetToZero(stream);
statusBuffer.MemSetToZero(stream);
uint limit = config.SmallFactorLimit == 0 ? uint.MaxValue : config.SmallFactorLimit; uint limit = config.SmallFactorLimit == 0 ? uint.MaxValue : config.SmallFactorLimit;
byte hasPrevious = previousOrder.HasValue ? (byte)1 : (byte)0; byte hasPrevious = previousOrder.HasValue ? (byte)1 : (byte)0;
ulong previousValue = previousOrder ?? 0UL; ulong previousValue = previousOrder ?? 0UL;
var kernelConfig = new OrderKernelConfig(previousValue, hasPrevious, limit, config.MaxPowChecks, (int)config.Mode); var kernelConfig = new CalculateOrderKernelConfig(previousValue, hasPrevious, limit, config.MaxPowChecks, (int)config.Mode);
var buffers = new OrderKernelBuffers( ref var buffers = ref gpu.CalculateOrderKernelBuffers;
phiFactorBuffer.View,
phiExponentBuffer.View,
workFactorBuffer.View,
workExponentBuffer.View,
candidateBuffer.View,
stackIndexBuffer.View,
stackExponentBuffer.View,
stackProductBuffer.View,
resultBuffer.View,
statusBuffer.View);
var orderKernel = GetOrderKernel(acceleratorIndex); var kernelLauncher = gpu.CalculateOrderKernelLauncher;
var kernelLauncher = orderKernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, OrderKernelConfig, ulong, ulong, ulong, ulong, ulong, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, OrderKernelBuffers>>();
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
// TODO: Remove the cleaning after the order kernel is modified to always set the result.
// phiFactorBufferView.MemSetToZero(stream);
// phiExponentBufferView.MemSetToZero(stream);
// workFactorBufferView.MemSetToZero(stream);
// workExponentBufferView.MemSetToZero(stream);
// candidateBufferView.MemSetToZero(stream);
// stackIndexBufferView.MemSetToZero(stream);
// stackExponentBufferView.MemSetToZero(stream);
// stackProductBufferView.MemSetToZero(stream);
resultBufferView.MemSetToZero(stream);
statusBufferView.MemSetToZero(stream);
kernelLauncher( kernelLauncher(
stream, stream,
@@ -419,21 +302,11 @@ internal static partial class PrimeOrderGpuHeuristics
byte status = 0; byte status = 0;
statusBuffer.View.CopyToCPU(stream, ref status, 1); statusBufferView.CopyToCPU(stream, ref status, 1);
resultBuffer.View.CopyToCPU(stream, ref order, 1); resultBufferView.CopyToCPU(stream, ref order, 1);
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(acceleratorIndex, stream); AcceleratorStreamPool.Return(acceleratorIndex, stream);
phiFactorBuffer.Dispose();
phiExponentBuffer.Dispose();
workFactorBuffer.Dispose();
workExponentBuffer.Dispose();
candidateBuffer.Dispose();
stackIndexBuffer.Dispose();
stackExponentBuffer.Dispose();
stackProductBuffer.Dispose();
resultBuffer.Dispose();
statusBuffer.Dispose();
// GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
PrimeOrderKernelStatus kernelStatus = (PrimeOrderKernelStatus)status; PrimeOrderKernelStatus kernelStatus = (PrimeOrderKernelStatus)status;
@@ -455,22 +328,6 @@ internal static partial class PrimeOrderGpuHeuristics
return order != 0UL; return order != 0UL;
} }
private static Kernel GetOrderKernel(int acceleratorIndex)
{
var pool = _orderKernel ??= [];
if (pool[acceleratorIndex] is {} cached)
{
return cached;
}
var accelerator = _accelerators[acceleratorIndex];
var loaded = accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, OrderKernelConfig, ulong, ulong, ulong, ulong, ulong, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, OrderKernelBuffers>(CalculateOrderKernel);
var kernel = KernelUtil.GetKernel(loaded);
pool[acceleratorIndex] = kernel;
return kernel;
}
private static GpuPow2ModStatus TryPow2ModBatchInternal(PrimeOrderCalculatorAccelerator gpu, ReadOnlySpan<UInt128> exponents, UInt128 prime, Span<UInt128> remainders) private static GpuPow2ModStatus TryPow2ModBatchInternal(PrimeOrderCalculatorAccelerator gpu, ReadOnlySpan<UInt128> exponents, UInt128 prime, Span<UInt128> remainders)
{ {
if (exponents.Length == 0) if (exponents.Length == 0)
@@ -513,58 +370,39 @@ internal static partial class PrimeOrderGpuHeuristics
return GpuPow2ModStatus.Success; return GpuPow2ModStatus.Success;
} }
private static bool TryComputeOnGpu(ReadOnlySpan<ulong> exponents, ulong prime, MontgomeryDivisorData? divisorData, Span<ulong> results) private static bool TryComputeOnGpu(PrimeOrderCalculatorAccelerator gpu, ReadOnlySpan<ulong> exponents, ulong prime, MontgomeryDivisorData? divisorData, Span<ulong> results)
{ {
// GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
int acceleratorIndex = AcceleratorPool.Shared.Rent(); int acceleratorIndex = gpu.AcceleratorIndex;
Accelerator accelerator = _accelerators[acceleratorIndex]; Accelerator accelerator = gpu.Accelerator;
AcceleratorStream? stream = accelerator.CreateStream(); var kernelLauncher = gpu.Pow2ModKernelLauncher;
// TODO: These buffers should be allocated once per accelerator and only reallocated when the new length exceeds capacity.
// Modify the callers to use their own pool of buffers per accelerator, so that other threads don't use the accelerators // Modify the callers to use their own pool of buffers per accelerator, so that other threads don't use the accelerators
// with out preallocated buffers. Share the pool with Pow2ModWide kernel. // with out preallocated buffers. Share the pool with Pow2ModWide kernel.
MemoryBuffer1D<ulong, Stride1D.Dense>? exponentBuffer;
MemoryBuffer1D<ulong, Stride1D.Dense>? remainderBuffer;
// lock (accelerator)
{
exponentBuffer = accelerator.Allocate1D<ulong>(exponents.Length);
remainderBuffer = accelerator.Allocate1D<ulong>(exponents.Length);
}
exponentBuffer.View.CopyFromCPU(stream, ref MemoryMarshal.GetReference(exponents), exponents.Length); gpu.EnsureUlongInputOutputCapacity(exponents.Length);
// Pow2Mod kernel always assigns the required output elements so we don't need to worry about clearing these. var exponentBufferView = gpu.InputView;
// remainderBuffer.MemSetToZero(stream); var remainderBufferView = gpu.OutputUlongView;
var pow2ModKernel = GetPow2ModKernel(acceleratorIndex);
var kernelLauncher = pow2ModKernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>>>();
try
{
if (divisorData is null) if (divisorData is null)
{ {
divisorData = MontgomeryDivisorData.Empty; divisorData = MontgomeryDivisorData.Empty;
} }
kernelLauncher(stream, exponents.Length, exponentBuffer.View, divisorData.Modulus, divisorData.NPrime, divisorData.MontgomeryOne, divisorData.MontgomeryTwo, divisorData.MontgomeryTwoSquared, remainderBuffer.View); AcceleratorStream? stream = AcceleratorStreamPool.Rent(acceleratorIndex);
exponentBufferView.CopyFromCPU(stream, exponents);
remainderBuffer.View.CopyToCPU(stream, ref MemoryMarshal.GetReference(results), exponents.Length); // Pow2Mod kernel always assigns the required output elements so we don't need to worry about clearing these.
// remainderBuffer.MemSetToZero(stream);
kernelLauncher(stream, exponents.Length, exponentBufferView, divisorData.Modulus, divisorData.NPrime, divisorData.MontgomeryOne, divisorData.MontgomeryTwo, divisorData.MontgomeryTwoSquared, remainderBufferView);
remainderBufferView.CopyToCPU(stream, results);
stream.Synchronize(); stream.Synchronize();
stream.Dispose(); AcceleratorStreamPool.Return(acceleratorIndex, stream);
stream = null;
exponentBuffer.Dispose();
remainderBuffer.Dispose();
// GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
}
catch (Exception)
{
Console.WriteLine($"Exception for {prime} and exponents: {string.Join(",", exponents.ToArray())}.");
stream?.Dispose();
exponentBuffer.Dispose();
remainderBuffer.Dispose();
// GpuPrimeWorkLimiter.Release();
throw;
}
return true; return true;
} }
@@ -585,11 +423,11 @@ internal static partial class PrimeOrderGpuHeuristics
GpuUInt128[]? rentedExponents = null; GpuUInt128[]? rentedExponents = null;
GpuUInt128[]? rentedResults = null; GpuUInt128[]? rentedResults = null;
ArrayPool<GpuUInt128> gpuUInt128Pool = ThreadStaticPools.GpuUInt128Pool; ArrayPool<GpuUInt128> gpuUInt128Pool = ThreadStaticPools.GpuUInt128Pool;
bool poolingRequired = length > WideStackThreshold; bool poolingRequired = length > PrimeOrderConstants.WideStackThreshold;
Span<GpuUInt128> exponentSpan = poolingRequired Span<GpuUInt128> exponentSpan = poolingRequired
? stackalloc GpuUInt128[length] ? stackalloc GpuUInt128[length]
: new Span<GpuUInt128>(rentedExponents = gpuUInt128Pool.Rent(length), 0, length); : new Span<GpuUInt128>(rentedExponents = gpuUInt128Pool.Rent(length), 0, length);
Span<GpuUInt128> resultSpan = length <= WideStackThreshold Span<GpuUInt128> resultSpan = length <= PrimeOrderConstants.WideStackThreshold
? stackalloc GpuUInt128[length] ? stackalloc GpuUInt128[length]
: new Span<GpuUInt128>(rentedResults = gpuUInt128Pool.Rent(length), 0, length); : new Span<GpuUInt128>(rentedResults = gpuUInt128Pool.Rent(length), 0, length);
@@ -603,32 +441,26 @@ internal static partial class PrimeOrderGpuHeuristics
int acceleratorIndex = gpu.AcceleratorIndex; int acceleratorIndex = gpu.AcceleratorIndex;
Accelerator accelerator = gpu.Accelerator; Accelerator accelerator = gpu.Accelerator;
AcceleratorStream? stream = AcceleratorStreamPool.Rent(acceleratorIndex); gpu.EnsureCalculateOrderWideCapacity(length);
MemoryBuffer1D<GpuUInt128, Stride1D.Dense> exponentBuffer;
MemoryBuffer1D<GpuUInt128, Stride1D.Dense> remainderBuffer;
// lock (accelerator) var exponentBufferView = gpu.CalculateOrderWideExponentBufferView;
{ var remainderBufferView = gpu.CalculateOrderWideRemainderBufferView;
exponentBuffer = accelerator.Allocate1D<GpuUInt128>(length);
remainderBuffer = accelerator.Allocate1D<GpuUInt128>(length);
}
exponentBuffer.View.CopyFromCPU(stream, exponentSpan); AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
exponentBufferView.CopyFromCPU(stream, exponentSpan);
var kernelLauncher = gpu.Pow2ModWideKernelLauncher; var kernelLauncher = gpu.Pow2ModWideKernelLauncher;
kernelLauncher(stream, length, exponentBuffer.View, modulus, remainderBuffer.View); kernelLauncher(stream, length, exponentBufferView, modulus, remainderBufferView);
remainderBuffer.View.CopyToCPU(stream, ref MemoryMarshal.GetReference(resultSpan), length); remainderBufferView.CopyToCPU(stream, ref MemoryMarshal.GetReference(resultSpan), length);
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(acceleratorIndex, stream); AcceleratorStreamPool.Return(acceleratorIndex, stream);
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
{ {
results[i] = (UInt128)resultSpan[i]; results[i] = (UInt128)resultSpan[i];
} }
remainderBuffer.Dispose();
exponentBuffer.Dispose();
if (rentedExponents is not null) if (rentedExponents is not null)
{ {
gpuUInt128Pool.Return(rentedExponents, clearArray: false); gpuUInt128Pool.Return(rentedExponents, clearArray: false);
@@ -655,21 +487,6 @@ internal static partial class PrimeOrderGpuHeuristics
return divisorData.Pow2MontgomeryModWindowedGpuConvertToStandard(exponent); return divisorData.Pow2MontgomeryModWindowedGpuConvertToStandard(exponent);
} }
private static Kernel GetPow2ModKernel(int acceleratorIndex)
{
var pool = _pow2ModKernel ??= [];
if (pool[acceleratorIndex] is {} cached)
{
return cached;
}
var accelerator = _accelerators[acceleratorIndex];
var loaded = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>>(Pow2ModKernel));
pool[acceleratorIndex] = loaded;
return loaded;
}
internal readonly record struct PrimeOrderGpuCapability(int ModulusBits, int ExponentBits) internal readonly record struct PrimeOrderGpuCapability(int ModulusBits, int ExponentBits)
{ {
public static PrimeOrderGpuCapability Default => new(128, 128); public static PrimeOrderGpuCapability Default => new(128, 128);
@@ -225,24 +225,24 @@ public sealed class HeuristicCombinedPrimeTester
private static bool HeuristicTrialDivisionGpuDetectsDivisor(PrimeOrderCalculatorAccelerator gpu, ulong n, ulong maxDivisorSquare, byte nMod10) private static bool HeuristicTrialDivisionGpuDetectsDivisor(PrimeOrderCalculatorAccelerator gpu, ulong n, ulong maxDivisorSquare, byte nMod10)
{ {
var acceleratorIndex = gpu.AcceleratorIndex; var acceleratorIndex = gpu.AcceleratorIndex;
var flagView1D = gpu.OutputInt!.View; var flagView1DView = gpu.OutputIntView;
var kernelLauncher = gpu.HeuristicCombinedTrialDivisionKernelLauncher;
bool compositeDetected; bool compositeDetected;
Span<int> compositeFlag = stackalloc int[1]; Span<int> compositeFlag = stackalloc int[1];
// int compositeFlag = 0; // int compositeFlag = 0;
var stream = AcceleratorStreamPool.Rent(acceleratorIndex); var stream = AcceleratorStreamPool.Rent(acceleratorIndex);
flagView1D.MemSetToZero(stream); flagView1DView.MemSetToZero(stream);
var kernelLauncher = gpu.HeuristicCombinedTrialDivisionKernelLauncher;
kernelLauncher( kernelLauncher(
stream, stream,
1, 1,
nMod10, nMod10,
flagView1D, flagView1DView,
n, n,
maxDivisorSquare, maxDivisorSquare,
gpu.DivisorTables); gpu.DivisorTables);
flagView1D.CopyToCPU(stream, compositeFlag); flagView1DView.CopyToCPU(stream, compositeFlag);
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(acceleratorIndex, stream); AcceleratorStreamPool.Return(acceleratorIndex, stream);
+5 -5
View File
@@ -244,12 +244,12 @@ public sealed class HeuristicPrimeTester
// GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
int acceleratorIndex = gpu.AcceleratorIndex; int acceleratorIndex = gpu.AcceleratorIndex;
var stream = AcceleratorStreamPool.Rent(acceleratorIndex); var stream = AcceleratorStreamPool.Rent(acceleratorIndex);
var flagView1D = gpu.OutputInt!.View; var flagView1DView = gpu.OutputIntView;
bool compositeDetected; bool compositeDetected;
int compositeFlag = 0; int compositeFlag = 0;
flagView1D.CopyFromCPU(stream, ref compositeFlag, 1); flagView1DView.CopyFromCPU(stream, ref compositeFlag, 1);
// Index1D index, // Index1D index,
// ArrayView<int> resultFlag, // ArrayView<int> resultFlag,
@@ -263,13 +263,13 @@ public sealed class HeuristicPrimeTester
stream, stream,
1, 1,
nMod10, nMod10,
flagView1D, flagView1DView,
n, n,
maxDivisorSquare, maxDivisorSquare,
gpu.DivisorTables); gpu.DivisorTables);
flagView1D.CopyToCPU(stream, ref compositeFlag, 1); flagView1DView.CopyToCPU(stream, ref compositeFlag, 1);
stream!.Synchronize(); stream.Synchronize();
compositeDetected = compositeFlag != 0; compositeDetected = compositeFlag != 0;
// compositeDetected = compositeFlag != 0; // compositeDetected = compositeFlag != 0;
+3 -2
View File
@@ -415,8 +415,9 @@ public class MersenneDivisorCycles
// Console.WriteLine($"MersenneDivisorCycles.TryFactorIntoCountsInternal hits {Volatile.Read(ref _tryFactorIntoCountsInternalHits)}"); // Console.WriteLine($"MersenneDivisorCycles.TryFactorIntoCountsInternal hits {Volatile.Read(ref _tryFactorIntoCountsInternalHits)}");
// HeuristicPrimeTester primeTester = _primeTester ??= new(); // HeuristicPrimeTester primeTester = _primeTester ??= new();
if (HeuristicCombinedPrimeTester.IsPrimeCpu(remaining))
// if (HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, remaining)) // if (HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, remaining))
if (PrimeTester.IsPrime(remaining)) // if (PrimeTester.IsPrime(remaining))
{ {
AddFactor(counts, remaining); AddFactor(counts, remaining);
return true; return true;
@@ -965,7 +966,7 @@ public class MersenneDivisorCycles
// HeuristicPrimeTester primeTester = _primeTester ??= new(); // HeuristicPrimeTester primeTester = _primeTester ??= new();
// if (!skipPrimeOrderHeuristic && HeuristicPrimeTester.Exclusive.IsPrimeCpu(divisor, CancellationToken.None)) // if (!skipPrimeOrderHeuristic && HeuristicPrimeTester.Exclusive.IsPrimeCpu(divisor, CancellationToken.None))
if (!skipPrimeOrderHeuristic && PrimeTester.IsPrime(divisor)) if (!skipPrimeOrderHeuristic && HeuristicCombinedPrimeTester.IsPrimeCpu(divisor))
// if (!skipPrimeOrderHeuristic && HeuristicCombinedPrimeTester.IsPrimeGpu(divisor)) // if (!skipPrimeOrderHeuristic && HeuristicCombinedPrimeTester.IsPrimeGpu(divisor))
{ {
ulong computedOrder = PrimeOrderCalculator.Calculate( ulong computedOrder = PrimeOrderCalculator.Calculate(
@@ -54,7 +54,8 @@ internal static partial class PrimeOrderCalculator
ulong phi = prime - 1UL; ulong phi = prime - 1UL;
if (IsGpuHeuristicDevice && PrimeOrderGpuHeuristics.TryCalculateOrder(gpu, prime, previousOrder, config, divisorData, out ulong gpuOrder)) if (PrimeOrderGpuHeuristics.TryCalculateOrder(gpu, prime, previousOrder, config, divisorData, out ulong gpuOrder))
// if (IsGpuHeuristicDevice && PrimeOrderGpuHeuristics.TryCalculateOrder(gpu, prime, previousOrder, config, divisorData, out ulong gpuOrder))
{ {
return gpuOrder; return gpuOrder;
} }
@@ -567,7 +568,6 @@ internal static partial class PrimeOrderCalculator
// DebugLog(() => $"Checking candidates ({candidateCount} candidates, {powBudget} pow budget)"); // DebugLog(() => $"Checking candidates ({candidateCount} candidates, {powBudget} pow budget)");
int index = 0; int index = 0;
const int MaxGpuBatchSize = 256;
const int StackGpuBatchSize = 64; const int StackGpuBatchSize = 64;
Span<ulong> stackGpuRemainders = stackalloc ulong[StackGpuBatchSize]; Span<ulong> stackGpuRemainders = stackalloc ulong[StackGpuBatchSize];
ArrayPool<ulong> pool = ThreadStaticPools.UlongPool; ArrayPool<ulong> pool = ThreadStaticPools.UlongPool;
@@ -575,7 +575,7 @@ internal static partial class PrimeOrderCalculator
{ {
int remaining = candidateCount - index; int remaining = candidateCount - index;
int budgetRemaining = powBudget - powUsed; int budgetRemaining = powBudget - powUsed;
int batchSize = Math.Min(remaining, Math.Min(budgetRemaining, MaxGpuBatchSize)); int batchSize = Math.Min(remaining, Math.Min(budgetRemaining, PrimeOrderConstants.MaxGpuBatchSize));
if (batchSize <= 0) if (batchSize <= 0)
{ {
break; break;
@@ -593,7 +593,7 @@ internal static partial class PrimeOrderCalculator
if (batchSize <= StackGpuBatchSize) if (batchSize <= StackGpuBatchSize)
{ {
Span<ulong> localRemainders = stackGpuRemainders[..batchSize]; Span<ulong> localRemainders = stackGpuRemainders[..batchSize];
status = PrimeOrderGpuHeuristics.TryPow2ModBatch(batch, prime, localRemainders, divisorData); status = PrimeOrderGpuHeuristics.TryPow2ModBatch(gpu, batch, prime, localRemainders, divisorData);
if (status == GpuPow2ModStatus.Success) if (status == GpuPow2ModStatus.Success)
{ {
gpuSuccess = true; gpuSuccess = true;
@@ -604,7 +604,7 @@ internal static partial class PrimeOrderCalculator
{ {
gpuPool = pool.Rent(batchSize); gpuPool = pool.Rent(batchSize);
Span<ulong> pooledRemainders = gpuPool.AsSpan(0, batchSize); Span<ulong> pooledRemainders = gpuPool.AsSpan(0, batchSize);
status = PrimeOrderGpuHeuristics.TryPow2ModBatch(batch, prime, pooledRemainders, divisorData); status = PrimeOrderGpuHeuristics.TryPow2ModBatch(gpu, batch, prime, pooledRemainders, divisorData);
if (status == GpuPow2ModStatus.Success) if (status == GpuPow2ModStatus.Success)
{ {
pooledGpuRemainders = pooledRemainders; pooledGpuRemainders = pooledRemainders;
@@ -1086,7 +1086,7 @@ internal static partial class PrimeOrderCalculator
return PartialFactorResult.Empty; return PartialFactorResult.Empty;
} }
const int FactorSlotCount = GpuSmallPrimeFactorSlots; const int FactorSlotCount = PrimeOrderConstants.GpuSmallPrimeFactorSlots;
// stackalloc is faster than pooling // stackalloc is faster than pooling
// ulong[] primeSlotsArray = ThreadStaticPools.UlongPool.Rent(FactorSlotCount); // ulong[] primeSlotsArray = ThreadStaticPools.UlongPool.Rent(FactorSlotCount);
@@ -1176,7 +1176,7 @@ internal static partial class PrimeOrderCalculator
// bool isPrime = HeuristicCombinedPrimeTester.IsPrimeCpu(composite); // bool isPrime = HeuristicCombinedPrimeTester.IsPrimeCpu(composite);
// bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite); // bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite);
bool runOnGpu = RunOnGpu(); bool runOnGpu = RunOnGpu();
bool isPrime = !runOnGpu ? PrimeTester.IsPrime(composite) : HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite); bool isPrime = !runOnGpu ? HeuristicCombinedPrimeTester.IsPrimeCpu(composite) : HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite);
// bool isPrime = PrimeTester.IsPrime(composite); // bool isPrime = PrimeTester.IsPrime(composite);
// bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite); // bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite);
@@ -1252,7 +1252,7 @@ internal static partial class PrimeOrderCalculator
bool isPrime = RunOnGpu() bool isPrime = RunOnGpu()
? HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite) ? HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite)
: PrimeTester.IsPrime(composite); : HeuristicCombinedPrimeTester.IsPrimeCpu(composite);
// bool isPrime = PrimeTester.IsPrime(composite); // bool isPrime = PrimeTester.IsPrime(composite);
// bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite); // bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite);
// bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite); // bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite);
@@ -1297,7 +1297,7 @@ internal static partial class PrimeOrderCalculator
// cofactorIsPrime = PrimeTester.IsPrimeGpu(gpu, cofactor); // cofactorIsPrime = PrimeTester.IsPrimeGpu(gpu, cofactor);
cofactorIsPrime = RunOnGpu() cofactorIsPrime = RunOnGpu()
? HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, cofactor) ? HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, cofactor)
: PrimeTester.IsPrime(cofactor); : HeuristicCombinedPrimeTester.IsPrimeCpu(cofactor);
// cofactorIsPrime = PrimeTester.IsPrime(cofactor); // cofactorIsPrime = PrimeTester.IsPrime(cofactor);
// cofactorIsPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(cofactor); // cofactorIsPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(cofactor);
} }
+23 -23
View File
@@ -36,20 +36,21 @@ internal static partial class PrimeOrderCalculator
ulong order = phi; ulong order = phi;
var acceleratorIndex = gpu.AcceleratorIndex; var acceleratorIndex = gpu.AcceleratorIndex;
var kernel = gpu.CheckFactorsKernel;
gpu.EnsureCapacity(entryCount, 1); gpu.EnsureCapacity(entryCount, 1);
var pow2ModEntriesToTestOnDeviceView = gpu.Pow2ModEntriesToTestOnDeviceView;
// GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex); AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
gpu.Pow2ModEntriesToTestOnDevice.View.CopyFromCPU(stream, entries); pow2ModEntriesToTestOnDeviceView.CopyFromCPU(stream, entries);
// var kernelLauncher = gpu.CheckFactorsKernelLauncher; kernel.Launch(stream, 1, entryCount, phi, pow2ModEntriesToTestOnDeviceView, divisorData.Modulus, divisorData.NPrime, divisorData.MontgomeryOne, divisorData.MontgomeryTwo, divisorData.MontgomeryTwoSquared, gpu.OutputUlongView);
var kernel = gpu.CheckFactorsKernel;
kernel.Launch(stream, 1, entryCount, phi, gpu.Pow2ModEntriesToTestOnDevice.View, divisorData.Modulus, divisorData.NPrime, divisorData.MontgomeryOne, divisorData.MontgomeryTwo, divisorData.MontgomeryTwoSquared, gpu.OutputUlong.View);
gpu.OutputUlong.View.CopyToCPU(stream, ref order, 1); gpu.OutputUlongView.CopyToCPU(stream, ref order, 1);
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(acceleratorIndex, stream);
AcceleratorStreamPool.Return(acceleratorIndex, stream);
// GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
return order; return order;
} }
@@ -67,10 +68,10 @@ internal static partial class PrimeOrderCalculator
var accelerator = gpu.Accelerator; var accelerator = gpu.Accelerator;
var kernelLauncher = gpu.SmallPrimeFactorKernelLauncher; var kernelLauncher = gpu.SmallPrimeFactorKernelLauncher;
ArrayView1D<int, Stride1D.Dense> smallPrimeFactorCountSlotView = gpu.SmallPrimeFactorCountSlot.View; ArrayView1D<int, Stride1D.Dense> smallPrimeFactorCountSlotView = gpu.OutputIntView2;
ArrayView1D<ulong, Stride1D.Dense> smallPrimeFactorRemainingSlotView = gpu.Input.View; ArrayView1D<ulong, Stride1D.Dense> smallPrimeFactorRemainingSlotView = gpu.InputView;
ArrayView1D<ulong, Stride1D.Dense> smallPrimeFactorPrimeSlotsView = gpu.OutputUlong.View; ArrayView1D<ulong, Stride1D.Dense> smallPrimeFactorPrimeSlotsView = gpu.OutputUlongView;
ArrayView1D<int, Stride1D.Dense> smallPrimeFactorExponentSlotsView = gpu.OutputInt.View; ArrayView1D<int, Stride1D.Dense> smallPrimeFactorExponentSlotsView = gpu.OutputIntView;
ArrayView1D<ulong, Stride1D.Dense> smallPrimeFactorsSquaresView = gpu.SmallPrimeFactorSquares; ArrayView1D<ulong, Stride1D.Dense> smallPrimeFactorsSquaresView = gpu.SmallPrimeFactorSquares;
ArrayView1D<uint, Stride1D.Dense> smallPrimeFactorsPrimesView = gpu.SmallPrimeFactorPrimes; ArrayView1D<uint, Stride1D.Dense> smallPrimeFactorsPrimesView = gpu.SmallPrimeFactorPrimes;
@@ -128,18 +129,17 @@ internal static partial class PrimeOrderCalculator
in MontgomeryDivisorData divisorData) in MontgomeryDivisorData divisorData)
{ {
int factorCount = factors.Length; int factorCount = factors.Length;
gpu.EnsureSpecialMaxFactorsCapacity(factorCount); gpu.EnsureUlongInputOutputCapacity(factorCount);
int acceleratorIndex = gpu.AcceleratorIndex; int acceleratorIndex = gpu.AcceleratorIndex;
// GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
ArrayView1D<ulong, Stride1D.Dense> specialMaxFactorsView = gpu.Input.View; ArrayView1D<ulong, Stride1D.Dense> specialMaxFactorsView = gpu.InputView;
ArrayView1D<ulong, Stride1D.Dense> specialMaxResultView = gpu.OutputUlongView2;
var kernelLauncher = gpu.SpecialMaxKernelLauncher;
var stream = AcceleratorStreamPool.Rent(acceleratorIndex); var stream = AcceleratorStreamPool.Rent(acceleratorIndex);
specialMaxFactorsView.SubView(0, factorCount).CopyFromCPU(stream, factors); specialMaxFactorsView.SubView(0, factorCount).CopyFromCPU(stream, factors);
ArrayView1D<ulong, Stride1D.Dense> specialMaxResultView = gpu.SpecialMaxResult.View;
var kernelLauncher = gpu.SpecialMaxKernelLauncher;
kernelLauncher( kernelLauncher(
stream, stream,
1, 1,
@@ -147,7 +147,7 @@ internal static partial class PrimeOrderCalculator
specialMaxFactorsView, specialMaxFactorsView,
factorCount, factorCount,
divisorData.Modulus, divisorData.Modulus,
gpu.OutputUlong.View, gpu.OutputUlongView,
specialMaxResultView); specialMaxResultView);
ulong result = 0UL; ulong result = 0UL;
@@ -168,16 +168,16 @@ internal static partial class PrimeOrderCalculator
Span<ulong> factorSpan = stackalloc ulong[1]; Span<ulong> factorSpan = stackalloc ulong[1];
int acceleratorIndex = gpu.AcceleratorIndex; int acceleratorIndex = gpu.AcceleratorIndex;
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
gpu.Input.View.CopyFromCPU(stream, randomStateSpan);
var kernel = gpu.PollardRhoKernel; var kernel = gpu.PollardRhoKernel;
kernel.Launch(stream, 1, n, 1, gpu.Input.View, gpu.OutputByte.View, gpu.OutputUlong.View); AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
gpu.InputView.CopyFromCPU(stream, randomStateSpan);
gpu.OutputByte.View.CopyToCPU(stream, factoredSpan); kernel.Launch(stream, 1, n, 1, gpu.InputView, gpu.OutputByteView, gpu.OutputUlongView);
gpu.OutputUlong.View.CopyToCPU(stream, factorSpan);
gpu.Input.View.CopyToCPU(stream, randomStateSpan); gpu.OutputByteView.CopyToCPU(stream, factoredSpan);
gpu.OutputUlongView.CopyToCPU(stream, factorSpan);
gpu.InputView.CopyToCPU(stream, randomStateSpan);
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(acceleratorIndex, stream); AcceleratorStreamPool.Return(acceleratorIndex, stream);
@@ -1042,7 +1042,7 @@ internal static partial class PrimeOrderCalculator
{ {
ulong prime64 = (ulong)modulus; ulong prime64 = (ulong)modulus;
ulong exponent64 = (ulong)exponent; ulong exponent64 = (ulong)exponent;
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(exponent64, prime64, out ulong remainder, divisorData); GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(gpu, exponent64, prime64, out ulong remainder, divisorData);
if (status == GpuPow2ModStatus.Success) if (status == GpuPow2ModStatus.Success)
{ {
return remainder; return remainder;
+10 -14
View File
@@ -91,10 +91,8 @@ public sealed class PrimeTester
public static bool IsPrimeGpu(PrimeOrderCalculatorAccelerator gpu, ulong n) public static bool IsPrimeGpu(PrimeOrderCalculatorAccelerator gpu, ulong n)
{ {
byte flag = 0; byte flag = 0;
var input = gpu.Input; var inputView = gpu.InputView;
var inputView = input.View; var outputView = gpu.OutputByteView;
var output = gpu.OutputByte;
var outputView = output.View;
int acceleratorIndex = gpu.AcceleratorIndex; int acceleratorIndex = gpu.AcceleratorIndex;
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex); AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
@@ -156,10 +154,8 @@ public sealed class PrimeTester
int totalLength = values.Length; int totalLength = values.Length;
int batchSize = GpuBatchSize; int batchSize = GpuBatchSize;
var input = gpu.Input; var inputView = gpu.InputView;
var output = gpu.OutputByte; var outputView = gpu.OutputByteView;
var inputView = input.View;
var outputView = output.View;
int pos = 0; int pos = 0;
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex); AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
@@ -235,16 +231,16 @@ public sealed class PrimeTester
int acceleratorIndex = gpu.AcceleratorIndex; int acceleratorIndex = gpu.AcceleratorIndex;
gpu.EnsureCapacity(0, length); gpu.EnsureCapacity(0, length);
MemoryBuffer1D<ulong, Stride1D.Dense>? inputBuffer = gpu.Input; var inputBufferView = gpu.InputView;
var resultBufferView = gpu.OutputByteView;
var kernelLauncher = gpu.SharesFactorKernelLauncher;
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex); AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
inputBuffer.View.CopyFromCPU(stream, values); inputBufferView.CopyFromCPU(stream, values);
MemoryBuffer1D<byte, Stride1D.Dense>? resultBuffer = gpu.OutputByte; kernelLauncher(stream, length, inputBufferView, resultBufferView);
var kernelLauncher = gpu.SharesFactorKernelLauncher;
kernelLauncher(stream, length, inputBuffer.View, resultBuffer.View);
resultBuffer.View.CopyToCPU(stream, in results); resultBufferView.CopyToCPU(stream, in results);
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(acceleratorIndex, stream); AcceleratorStreamPool.Return(acceleratorIndex, stream);