MontgomeryDivisorData converted to a pooled class to limit GC pressure. MontgomeryDivisorDataGpu added for GPU operations. PrimeOrderCalculator kernels precompiled during warmup.

This commit is contained in:
mlemanczyk committed 2025-11-24 15:14:31 +01:00
1 parent 07efd5d2a1
commit 070e2a14fd
32 files changed
+310 -192

No files matched your search

@@ -470,7 +470,7 @@ public class Pow2ModBenchmarks
Console.WriteLine($"Calculating small cycle {smallModulus}"); Console.WriteLine($"Calculating small cycle {smallModulus}");
smallDivisors[i] = CreateMontgomeryDivisorData(smallModulus); smallDivisors[i] = CreateMontgomeryDivisorData(smallModulus);
smallExponents[i] = NextSmallExponent(random); smallExponents[i] = NextSmallExponent(random);
smallCycles[i] = MersenneDivisorCycles.CalculateCycleLength(smallModulus, MontgomeryDivisorData.FromModulus(smallModulus)); smallCycles[i] = MersenneDivisorCycles.CalculateCycleLength(smallModulus, MontgomeryDivisorDataPool.Shared.FromModulus(smallModulus));
(ulong largeModulus, ulong largeCycle) = NextLargeModulusAndCycle(random); (ulong largeModulus, ulong largeCycle) = NextLargeModulusAndCycle(random);
Console.WriteLine($"Calculating large cycle {largeModulus}"); Console.WriteLine($"Calculating large cycle {largeModulus}");
@@ -582,7 +582,7 @@ public class Pow2ModBenchmarks
private static ulong CalculateCycleLengthWithHeuristics(ulong modulus, ref ulong? previousPrimeOrder) private static ulong CalculateCycleLengthWithHeuristics(ulong modulus, ref ulong? previousPrimeOrder)
{ {
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(modulus); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(modulus);
if (modulus <= 1UL || (modulus & 1UL) == 0UL) if (modulus <= 1UL || (modulus & 1UL) == 0UL)
{ {
return MersenneDivisorCycles.CalculateCycleLength(modulus, divisorData); return MersenneDivisorCycles.CalculateCycleLength(modulus, divisorData);
@@ -651,7 +651,7 @@ public class Pow2ModBenchmarks
private ulong CalculateCycleLengthWithHeuristics(ulong modulus, ulong fallbackOrder = 0UL) private ulong CalculateCycleLengthWithHeuristics(ulong modulus, ulong fallbackOrder = 0UL)
{ {
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(modulus); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(modulus);
if (modulus <= 1UL || (modulus & 1UL) == 0UL) if (modulus <= 1UL || (modulus & 1UL) == 0UL)
{ {
return fallbackOrder != 0UL ? fallbackOrder : MersenneDivisorCycles.CalculateCycleLength(modulus, divisorData); return fallbackOrder != 0UL ? fallbackOrder : MersenneDivisorCycles.CalculateCycleLength(modulus, divisorData);
@@ -37,7 +37,7 @@ public class Pow2MontgomeryModBenchmarks
ulong smallModulus = NextSmallOddModulus(); ulong smallModulus = NextSmallOddModulus();
_smallDivisors[i] = CreateMontgomeryDivisorData(smallModulus); _smallDivisors[i] = CreateMontgomeryDivisorData(smallModulus);
_smallExponents[i] = NextSmallExponent(); _smallExponents[i] = NextSmallExponent();
_smallCycles[i] = MersenneDivisorCycles.CalculateCycleLength(smallModulus, MontgomeryDivisorData.FromModulus(smallModulus)); _smallCycles[i] = MersenneDivisorCycles.CalculateCycleLength(smallModulus, MontgomeryDivisorDataPool.Shared.FromModulus(smallModulus));
Console.WriteLine($"Calculating large cycle {i + 1} with heuristics"); Console.WriteLine($"Calculating large cycle {i + 1} with heuristics");
(ulong largeModulus, ulong largeCycle) = NextLargeModulusAndCycle(); (ulong largeModulus, ulong largeCycle) = NextLargeModulusAndCycle();
@@ -64,7 +64,7 @@ internal static class Pow2MontgomeryModWindowedBenchmarkInputsProvider
{ {
Pow2MontgomeryModWindowedBenchmarkSeed seed = seeds[i]; Pow2MontgomeryModWindowedBenchmarkSeed seed = seeds[i];
ulong modulus = 2UL * seed.Multiplier * seed.Exponent + 1UL; ulong modulus = 2UL * seed.Multiplier * seed.Exponent + 1UL;
MontgomeryDivisorData divisor = MontgomeryDivisorData.FromModulus(modulus); MontgomeryDivisorData divisor = MontgomeryDivisorDataPool.Shared.FromModulus(modulus);
ulong cycleLength = MersenneDivisorCycles.CalculateCycleLength(modulus, divisor); ulong cycleLength = MersenneDivisorCycles.CalculateCycleLength(modulus, divisor);
ulong reducedExponent = seed.Exponent % cycleLength; ulong reducedExponent = seed.Exponent % cycleLength;
cases[i] = new Pow2MontgomeryModWindowedBenchmarkCase( cases[i] = new Pow2MontgomeryModWindowedBenchmarkCase(
@@ -23,7 +23,7 @@ public class PrimeOrderGpuHeuristicsTests
try try
{ {
PrimeOrderGpuHeuristics.OverflowRegistry[prime] = 0; PrimeOrderGpuHeuristics.OverflowRegistry[prime] = 0;
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(prime); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(1UL, prime, out ulong remainder, divisorData); GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(1UL, prime, out ulong remainder, divisorData);
status.Should().Be(GpuPow2ModStatus.Overflow); status.Should().Be(GpuPow2ModStatus.Overflow);
@@ -40,7 +40,7 @@ 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 = MontgomeryDivisorData.FromModulus(prime); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(exponent, prime, out ulong remainder, divisorData); GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(exponent, prime, out ulong remainder, divisorData);
status.Should().Be(GpuPow2ModStatus.Success); status.Should().Be(GpuPow2ModStatus.Success);
@@ -55,7 +55,7 @@ public class PrimeOrderGpuHeuristicsTests
PrimeOrderGpuHeuristics.OverrideCapabilitiesForTesting(capability); PrimeOrderGpuHeuristics.OverrideCapabilitiesForTesting(capability);
try try
{ {
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(prime); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(1UL, prime, out ulong remainder, divisorData); GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(1UL, prime, out ulong remainder, divisorData);
status.Should().Be(GpuPow2ModStatus.Overflow); status.Should().Be(GpuPow2ModStatus.Overflow);
@@ -76,7 +76,7 @@ public class PrimeOrderGpuHeuristicsTests
try try
{ {
const ulong prime = 193UL; const ulong prime = 193UL;
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(prime); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(16UL, prime, out ulong remainder, divisorData); GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(16UL, prime, out ulong remainder, divisorData);
status.Should().Be(GpuPow2ModStatus.Overflow); status.Should().Be(GpuPow2ModStatus.Overflow);
@@ -102,7 +102,7 @@ public class PrimeOrderGpuHeuristicsTests
ulong[] remainders = new ulong[2]; ulong[] remainders = new ulong[2];
ulong[] exponents = { 1UL, 2UL }; ulong[] exponents = { 1UL, 2UL };
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(prime); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(exponents, prime, remainders, divisorData); GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(exponents, prime, remainders, divisorData);
status.Should().Be(GpuPow2ModStatus.Overflow); status.Should().Be(GpuPow2ModStatus.Overflow);
@@ -121,7 +121,7 @@ public class PrimeOrderGpuHeuristicsTests
ulong[] remainders = { 123UL, 456UL }; ulong[] remainders = { 123UL, 456UL };
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 = MontgomeryDivisorData.FromModulus(prime); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(exponents, prime, remainders, divisorData); GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(exponents, prime, remainders, divisorData);
ulong expectedFirst = (ulong)BigInteger.ModPow(2, exponents[0], prime); ulong expectedFirst = (ulong)BigInteger.ModPow(2, exponents[0], prime);
@@ -145,7 +145,7 @@ public class PrimeOrderGpuHeuristicsTests
ulong[] exponents = { 1UL, 2UL }; ulong[] exponents = { 1UL, 2UL };
ulong[] remainders = { 5UL, 6UL }; ulong[] remainders = { 5UL, 6UL };
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(prime); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(exponents, prime, remainders, divisorData); GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(exponents, prime, remainders, divisorData);
status.Should().Be(GpuPow2ModStatus.Overflow); status.Should().Be(GpuPow2ModStatus.Overflow);
@@ -170,7 +170,7 @@ public class PrimeOrderGpuHeuristicsTests
ulong[] remainders = { 9UL, 11UL }; ulong[] remainders = { 9UL, 11UL };
const ulong prime = 193UL; const ulong prime = 193UL;
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(prime); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(exponents, prime, remainders, divisorData); GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(exponents, prime, remainders, divisorData);
status.Should().Be(GpuPow2ModStatus.Overflow); status.Should().Be(GpuPow2ModStatus.Overflow);
@@ -362,7 +362,7 @@ public class PrimeOrderGpuHeuristicsTests
{ {
PrimeOrderGpuHeuristics.OverflowRegistry[prime] = 0; PrimeOrderGpuHeuristics.OverflowRegistry[prime] = 0;
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(prime); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
ulong result = PrimeOrderCalculator.Calculate(prime, null, divisorData, PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault, PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu); ulong result = PrimeOrderCalculator.Calculate(prime, null, divisorData, PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault, PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
result.Should().Be(3UL); result.Should().Be(3UL);
@@ -17,7 +17,7 @@ public class ULongExtensionsGpuTests
[InlineData(65535UL, 2147483647UL)] [InlineData(65535UL, 2147483647UL)]
public void Pow2ModWindowedGpu_matches_montgomery_cpu_for_known_values(ulong exponent, ulong modulus) public void Pow2ModWindowedGpu_matches_montgomery_cpu_for_known_values(ulong exponent, ulong modulus)
{ {
MontgomeryDivisorData divisor = MontgomeryDivisorData.FromModulus(modulus); MontgomeryDivisorData divisor = MontgomeryDivisorDataPool.Shared.FromModulus(modulus);
ulong expected = exponent.Pow2MontgomeryModWindowedCpu(divisor, keepMontgomery: false); ulong expected = exponent.Pow2MontgomeryModWindowedCpu(divisor, keepMontgomery: false);
exponent.Pow2ModWindowedGpu(modulus).Should().Be(expected); exponent.Pow2ModWindowedGpu(modulus).Should().Be(expected);
@@ -51,7 +51,7 @@ public class ULongExtensionsGpuTests
foreach (ulong modulus in moduli) foreach (ulong modulus in moduli)
{ {
MontgomeryDivisorData divisor = MontgomeryDivisorData.FromModulus(modulus); MontgomeryDivisorData divisor = MontgomeryDivisorDataPool.Shared.FromModulus(modulus);
foreach (ulong exponent in exponents) foreach (ulong exponent in exponents)
{ {
ulong expected = exponent.Pow2MontgomeryModWindowedCpu(divisor, keepMontgomery: false); ulong expected = exponent.Pow2MontgomeryModWindowedCpu(divisor, keepMontgomery: false);
@@ -38,7 +38,7 @@ public class MersenneDivisorCyclesGenerateGpuTests
foreach (var pair in pairs) foreach (var pair in pairs)
{ {
expected.Should().Contain(pair.divisor); expected.Should().Contain(pair.divisor);
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(pair.divisor); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(pair.divisor);
pair.cycle.Should().Be(MersenneDivisorCycles.CalculateCycleLength(pair.divisor, divisorData)); pair.cycle.Should().Be(MersenneDivisorCycles.CalculateCycleLength(pair.divisor, divisorData));
} }
} }
@@ -87,7 +87,7 @@ public class MersenneDivisorCyclesGenerateGpuTests
foreach (var pair in pairs) foreach (var pair in pairs)
{ {
uniqueDivisors.Add(pair.divisor).Should().BeTrue(); uniqueDivisors.Add(pair.divisor).Should().BeTrue();
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(pair.divisor); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(pair.divisor);
pair.cycle.Should().Be(MersenneDivisorCycles.CalculateCycleLength(pair.divisor, divisorData)); pair.cycle.Should().Be(MersenneDivisorCycles.CalculateCycleLength(pair.divisor, divisorData));
} }
@@ -18,7 +18,7 @@ public class MersenneDivisorCyclesTests
[MemberData(nameof(Divisors))] [MemberData(nameof(Divisors))]
public void CalculateCycleLength_returns_expected_value(ulong divisor, ulong expected) public void CalculateCycleLength_returns_expected_value(ulong divisor, ulong expected)
{ {
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(divisor);
MersenneDivisorCycles.CalculateCycleLength(divisor, divisorData).Should().Be(expected); MersenneDivisorCycles.CalculateCycleLength(divisor, divisorData).Should().Be(expected);
MersenneDivisorCycles.CalculateCycleLengthGpu(divisor).Should().Be(expected); MersenneDivisorCycles.CalculateCycleLengthGpu(divisor).Should().Be(expected);
} }
@@ -39,13 +39,13 @@ public class MersenneNumberDivisorCpuTesterTests
ulong[] primes = { 5UL, 7UL, 11UL, 13UL }; ulong[] primes = { 5UL, 7UL, 11UL, 13UL };
byte[] hits = new byte[primes.Length]; byte[] hits = new byte[primes.Length];
ulong cycle23 = MersenneDivisorCycles.CalculateCycleLength(23UL, MontgomeryDivisorData.FromModulus(23UL)); ulong cycle23 = MersenneDivisorCycles.CalculateCycleLength(23UL, MontgomeryDivisorDataPool.Shared.FromModulus(23UL));
session.CheckDivisor(23UL, MontgomeryDivisorData.FromModulus(23UL), cycle23, primes, hits); session.CheckDivisor(23UL, MontgomeryDivisorDataPool.Shared.FromModulus(23UL), cycle23, primes, hits);
hits.Should().ContainInOrder(new byte[] { 0, 0, 1, 0 }); hits.Should().ContainInOrder(new byte[] { 0, 0, 1, 0 });
Array.Fill(hits, (byte)0); Array.Fill(hits, (byte)0);
ulong cycle31 = MersenneDivisorCycles.CalculateCycleLength(31UL, MontgomeryDivisorData.FromModulus(31UL)); ulong cycle31 = MersenneDivisorCycles.CalculateCycleLength(31UL, MontgomeryDivisorDataPool.Shared.FromModulus(31UL));
session.CheckDivisor(31UL, MontgomeryDivisorData.FromModulus(31UL), cycle31, primes, hits); session.CheckDivisor(31UL, MontgomeryDivisorDataPool.Shared.FromModulus(31UL), cycle31, primes, hits);
hits.Should().ContainInOrder(new byte[] { 1, 0, 0, 0 }); hits.Should().ContainInOrder(new byte[] { 1, 0, 0, 0 });
} }
finally finally
@@ -67,7 +67,7 @@ public class MersenneNumberDivisorCpuTesterTests
ulong[] exponents = { 6UL, 7UL, 9UL, 10UL, 12UL }; ulong[] exponents = { 6UL, 7UL, 9UL, 10UL, 12UL };
byte[] hits = new byte[exponents.Length]; byte[] hits = new byte[exponents.Length];
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(7UL); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(7UL);
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(7UL, divisorData); ulong cycle = MersenneDivisorCycles.CalculateCycleLength(7UL, divisorData);
session.CheckDivisor(7UL, divisorData, cycle, exponents, hits); session.CheckDivisor(7UL, divisorData, cycle, exponents, hits);
@@ -92,7 +92,7 @@ public class MersenneNumberDivisorCpuTesterTests
ulong[] exponents = { 10UL, 11UL, 20UL, 21UL, 30UL }; ulong[] exponents = { 10UL, 11UL, 20UL, 21UL, 30UL };
byte[] hits = new byte[exponents.Length]; byte[] hits = new byte[exponents.Length];
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(11UL); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(11UL);
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(11UL, divisorData); ulong cycle = MersenneDivisorCycles.CalculateCycleLength(11UL, divisorData);
session.CheckDivisor(11UL, divisorData, cycle, exponents, hits); session.CheckDivisor(11UL, divisorData, cycle, exponents, hits);
@@ -170,7 +170,7 @@ public class MersenneNumberDivisorGpuTesterTests
ulong[] primes = { 31UL, 37UL, 41UL }; ulong[] primes = { 31UL, 37UL, 41UL };
byte[] hits = new byte[primes.Length]; byte[] hits = new byte[primes.Length];
session.CheckDivisor(223UL, MontgomeryDivisorData.FromModulus(223UL), 0UL, primes, hits); session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), 0UL, primes, hits);
hits.Should().ContainInOrder(new byte[] { 0, 1, 0 }); hits.Should().ContainInOrder(new byte[] { 0, 1, 0 });
} }
@@ -193,13 +193,13 @@ public class MersenneNumberDivisorGpuTesterTests
ulong[] primes = { 31UL, 37UL, 41UL, 43UL }; ulong[] primes = { 31UL, 37UL, 41UL, 43UL };
byte[] hits = new byte[primes.Length]; byte[] hits = new byte[primes.Length];
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLength(223UL, MontgomeryDivisorData.FromModulus(223UL)); ulong cycle223 = MersenneDivisorCycles.CalculateCycleLength(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL));
session.CheckDivisor(223UL, MontgomeryDivisorData.FromModulus(223UL), cycle223, primes, hits); session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primes, hits);
hits.Should().ContainInOrder(new byte[] { 0, 1, 0, 0 }); hits.Should().ContainInOrder(new byte[] { 0, 1, 0, 0 });
Array.Fill(hits, (byte)0); Array.Fill(hits, (byte)0);
ulong cycle13367 = MersenneDivisorCycles.CalculateCycleLength(13367UL, MontgomeryDivisorData.FromModulus(13367UL)); ulong cycle13367 = MersenneDivisorCycles.CalculateCycleLength(13367UL, MontgomeryDivisorDataPool.Shared.FromModulus(13367UL));
session.CheckDivisor(13367UL, MontgomeryDivisorData.FromModulus(13367UL), cycle13367, primes, hits); session.CheckDivisor(13367UL, MontgomeryDivisorDataPool.Shared.FromModulus(13367UL), cycle13367, primes, hits);
hits.Should().ContainInOrder(new byte[] { 0, 0, 1, 0 }); hits.Should().ContainInOrder(new byte[] { 0, 0, 1, 0 });
} }
finally finally
@@ -225,8 +225,8 @@ public class MersenneNumberDivisorGpuTesterTests
ulong[] primes = { 31UL, 37UL, 41UL, 43UL, 47UL }; ulong[] primes = { 31UL, 37UL, 41UL, 43UL, 47UL };
byte[] hits = new byte[primes.Length]; byte[] hits = new byte[primes.Length];
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLength(223UL, MontgomeryDivisorData.FromModulus(223UL)); ulong cycle223 = MersenneDivisorCycles.CalculateCycleLength(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL));
session.CheckDivisor(223UL, MontgomeryDivisorData.FromModulus(223UL), cycle223, primes, hits); session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primes, hits);
hits.Should().ContainInOrder(new byte[] { 0, 1, 0, 0, 0 }); hits.Should().ContainInOrder(new byte[] { 0, 1, 0, 0, 0 });
} }
@@ -252,7 +252,7 @@ public class MersenneNumberDivisorGpuTesterTests
ulong[] exponents = { 6UL, 7UL, 9UL, 10UL, 12UL }; ulong[] exponents = { 6UL, 7UL, 9UL, 10UL, 12UL };
byte[] hits = new byte[exponents.Length]; byte[] hits = new byte[exponents.Length];
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(7UL); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(7UL);
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(7UL, divisorData); ulong cycle = MersenneDivisorCycles.CalculateCycleLength(7UL, divisorData);
session.CheckDivisor(7UL, divisorData, cycle, exponents, hits); session.CheckDivisor(7UL, divisorData, cycle, exponents, hits);
@@ -281,7 +281,7 @@ public class MersenneNumberDivisorGpuTesterTests
ulong[] exponents = { 10UL, 11UL, 20UL, 21UL, 30UL }; ulong[] exponents = { 10UL, 11UL, 20UL, 21UL, 30UL };
byte[] hits = new byte[exponents.Length]; byte[] hits = new byte[exponents.Length];
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(11UL); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(11UL);
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(11UL, divisorData); ulong cycle = MersenneDivisorCycles.CalculateCycleLength(11UL, divisorData);
session.CheckDivisor(11UL, divisorData, cycle, exponents, hits); session.CheckDivisor(11UL, divisorData, cycle, exponents, hits);
@@ -310,7 +310,7 @@ public class MersenneNumberDivisorGpuTesterTests
var patchedTable = new List<(ulong Divisor, ulong Cycle)>(); var patchedTable = new List<(ulong Divisor, ulong Cycle)>();
ulong[] patchedSmall = new ulong[PerfectNumberConstants.MaxQForDivisorCycles + 1]; ulong[] patchedSmall = new ulong[PerfectNumberConstants.MaxQForDivisorCycles + 1];
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(191UL); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(191UL);
patchedSmall[191] = MersenneDivisorCycles.CalculateCycleLength(191UL, divisorData); patchedSmall[191] = MersenneDivisorCycles.CalculateCycleLength(191UL, divisorData);
tableField.SetValue(cycles, patchedTable); tableField.SetValue(cycles, patchedTable);
@@ -353,8 +353,8 @@ public class MersenneNumberDivisorGpuTesterTests
ulong[] primes = { 31UL, 37UL, 41UL, 43UL, 47UL }; ulong[] primes = { 31UL, 37UL, 41UL, 43UL, 47UL };
byte[] hits = new byte[primes.Length]; byte[] hits = new byte[primes.Length];
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLength(223UL, MontgomeryDivisorData.FromModulus(223UL)); ulong cycle223 = MersenneDivisorCycles.CalculateCycleLength(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL));
session.CheckDivisor(223UL, MontgomeryDivisorData.FromModulus(223UL), cycle223, primes, hits); session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primes, hits);
hits.Should().ContainInOrder(new byte[] { 0, 1, 0, 0, 0 }); hits.Should().ContainInOrder(new byte[] { 0, 1, 0, 0, 0 });
} }
@@ -46,7 +46,7 @@ public class PrimeOrderCalculatorTests
ulong result = PrimeOrderCalculator.Calculate( ulong result = PrimeOrderCalculator.Calculate(
prime, prime,
previousOrder: null, previousOrder: null,
MontgomeryDivisorData.FromModulus(prime), MontgomeryDivisorDataPool.Shared.FromModulus(prime),
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault, PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu); PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
@@ -63,14 +63,14 @@ public class PrimeOrderCalculatorTests
ulong heuristic = PrimeOrderCalculator.Calculate( ulong heuristic = PrimeOrderCalculator.Calculate(
prime, prime,
previousOrder, previousOrder,
MontgomeryDivisorData.FromModulus(prime), MontgomeryDivisorDataPool.Shared.FromModulus(prime),
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault, PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu); PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
ulong strict = PrimeOrderCalculator.Calculate( ulong strict = PrimeOrderCalculator.Calculate(
prime, prime,
previousOrder: null, previousOrder: null,
MontgomeryDivisorData.FromModulus(prime), MontgomeryDivisorDataPool.Shared.FromModulus(prime),
PrimeOrderCalculator.PrimeOrderSearchConfig.StrictDefault, PrimeOrderCalculator.PrimeOrderSearchConfig.StrictDefault,
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu); PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
@@ -86,7 +86,7 @@ public class PrimeOrderCalculatorTests
ulong result = PrimeOrderCalculator.Calculate( ulong result = PrimeOrderCalculator.Calculate(
prime, prime,
previousOrder: null, previousOrder: null,
MontgomeryDivisorData.FromModulus(prime), MontgomeryDivisorDataPool.Shared.FromModulus(prime),
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault, PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu); PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
@@ -106,7 +106,7 @@ public class PrimeOrderCalculatorTests
ulong result = PrimeOrderCalculator.Calculate( ulong result = PrimeOrderCalculator.Calculate(
prime: 13UL, prime: 13UL,
previousOrder: null, previousOrder: null,
MontgomeryDivisorData.FromModulus(13UL), MontgomeryDivisorDataPool.Shared.FromModulus(13UL),
config, config,
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu); PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
@@ -123,7 +123,7 @@ public class PrimeOrderCalculatorTests
maxPowChecks: 1, maxPowChecks: 1,
mode: PrimeOrderCalculator.PrimeOrderMode.Heuristic); mode: PrimeOrderCalculator.PrimeOrderMode.Heuristic);
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(239UL); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(239UL);
ulong heuristic = PrimeOrderCalculator.Calculate( ulong heuristic = PrimeOrderCalculator.Calculate(
prime: 239UL, prime: 239UL,
previousOrder: null, previousOrder: null,
@@ -21,10 +21,10 @@ internal sealed class MersenneCpuDivisorScanSession : IMersenneNumberDivisorByDi
// return; // return;
// } // }
MontgomeryDivisorData cachedData = divisorData; if (divisorData.Modulus != divisor)
if (cachedData.Modulus != divisor)
{ {
cachedData = MontgomeryDivisorData.FromModulus(divisor); throw new InvalidOperationException("Divisor data is for a different modulus");
// cachedData = MontgomeryDivisorData.FromModulus(divisor);
} }
if (divisorCycle == 0UL) if (divisorCycle == 0UL)
@@ -39,7 +39,7 @@ internal sealed class MersenneCpuDivisorScanSession : IMersenneNumberDivisorByDi
// Keep these remainder steppers in place so future updates continue reusing the previously computed residues. // Keep these remainder steppers in place so future updates continue reusing the previously computed residues.
// They are critical for avoiding repeated full Montgomery exponentiation work when scanning divisors. // They are critical for avoiding repeated full Montgomery exponentiation work when scanning divisors.
var exponentStepper = new ExponentRemainderStepperCpu(cachedData); var exponentStepper = new ExponentRemainderStepperCpu(divisorData);
var cycleStepper = new CycleRemainderStepper(divisorCycle); var cycleStepper = new CycleRemainderStepper(divisorCycle);
@@ -204,43 +204,37 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
remainder11 = (byte)((((divisorHigh % 11UL) * 5UL) + (divisorLow % 11UL)) % 11UL); remainder11 = (byte)((((divisorHigh % 11UL) * 5UL) + (divisorLow % 11UL)) % 11UL);
var gpu = PrimeOrderCalculatorAccelerator.Rent(1); var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
var divisorPool = MontgomeryDivisorDataPool.Shared;
while (divisor.CompareTo(limit) <= 0) while (divisor.CompareTo(limit) <= 0)
{ {
bool passesSmallModuli = remainder3 != 0 && remainder7 != 0 && remainder11 != 0; bool passesSmallModuli = remainder3 != 0 && remainder7 != 0 && remainder11 != 0;
if (passesSmallModuli && (remainder8 == 1 || remainder8 == 7) && ((decimalMask >> remainder10) & 1) != 0) if (passesSmallModuli && (remainder8 == 1 || remainder8 == 7) && ((decimalMask >> remainder10) & 1) != 0)
{ {
ulong candidate = divisor.Low; ulong candidate = divisor.Low;
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(candidate); MontgomeryDivisorData divisorData = divisorPool.FromModulus(candidate);
ulong divisorCycle; ulong divisorCycle;
// Divisors generated from 2 * k * p + 1 exceed the small-cycle snapshot when p >= 138,000,000, so the short path below never runs. // Divisors generated from 2 * k * p + 1 exceed the small-cycle snapshot when p >= 138,000,000, so the short path below never runs.
// if (candidate <= PerfectNumberConstants.MaxQForDivisorCycles) if (!MersenneDivisorCycles.TryCalculateCycleLengthForExponentCpu(
// { gpu,
// divisorCycle = cycleCache.GetCycleLength(candidate); candidate,
// } prime,
// else divisorData,
out ulong computedCycle,
out bool primeOrderFailed) || computedCycle == 0UL)
{ {
if (!MersenneDivisorCycles.TryCalculateCycleLengthForExponentCpu( // Divisors produced by 2 * k * p + 1 always exceed PerfectNumberConstants.MaxQForDivisorCycles
gpu, // for the exponents scanned here, so skip the unused cache fallback and compute directly.
candidate, divisorCycle = MersenneDivisorCycles.CalculateCycleLength(
prime, candidate,
divisorData, divisorData,
out ulong computedCycle, skipPrimeOrderHeuristic: primeOrderFailed);
out bool primeOrderFailed) || computedCycle == 0UL) }
{ else
// Divisors produced by 2 * k * p + 1 always exceed PerfectNumberConstants.MaxQForDivisorCycles {
// for the exponents scanned here, so skip the unused cache fallback and compute directly. divisorCycle = computedCycle;
divisorCycle = MersenneDivisorCycles.CalculateCycleLength(
candidate,
divisorData,
skipPrimeOrderHeuristic: primeOrderFailed);
}
else
{
divisorCycle = computedCycle;
}
} }
divisorPool.Return(divisorData);
if (divisorCycle == prime) if (divisorCycle == prime)
{ {
// A cycle equal to the tested exponent (which is prime in this path) guarantees that the candidate divides // A cycle equal to the tested exponent (which is prime in this path) guarantees that the candidate divides
@@ -290,18 +284,16 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
out bool processedAll, out bool processedAll,
out ulong foundDivisor) out ulong foundDivisor)
{ {
processedAll = false;
foundDivisor = 0UL;
bool canAdvance = step <= limit; bool canAdvance = step <= limit;
var gpu = PrimeOrderCalculatorAccelerator.Rent(1); var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
Queue<MontgomeryDivisorData> divisorPool = MontgomeryDivisorDataPool.Shared;
if (!canAdvance) if (!canAdvance)
{ {
if (divisor <= limit) if (divisor <= limit)
{ {
if (remainder3 != 0 && remainder7 != 0 && remainder11 != 0 && (remainder8 == 1 || remainder8 == 7) && ((decimalMask >> remainder10) & 1) != 0) if (remainder3 != 0 && remainder7 != 0 && remainder11 != 0 && (remainder8 == 1 || remainder8 == 7) && ((decimalMask >> remainder10) & 1) != 0)
{ {
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor); MontgomeryDivisorData divisorData = divisorPool.FromModulus(divisor);
ulong divisorCycle; ulong divisorCycle;
if (!MersenneDivisorCycles.TryCalculateCycleLengthForExponentCpu( if (!MersenneDivisorCycles.TryCalculateCycleLengthForExponentCpu(
gpu, gpu,
@@ -321,6 +313,8 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
divisorCycle = computedCycle; divisorCycle = computedCycle;
} }
divisorPool.Return(divisorData);
if (divisorCycle == prime) if (divisorCycle == prime)
{ {
foundDivisor = divisor; foundDivisor = divisor;
@@ -351,13 +345,12 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
} }
ulong remainingIterations = ((limit - divisor) / step) + 1UL; ulong remainingIterations = ((limit - divisor) / step) + 1UL;
while (true) while (true)
{ {
bool passesSmallModuli = remainder3 != 0 && remainder7 != 0 && remainder11 != 0; bool passesSmallModuli = remainder3 != 0 && remainder7 != 0 && remainder11 != 0;
if (passesSmallModuli && (remainder8 == 1 || remainder8 == 7) && ((decimalMask >> remainder10) & 1) != 0) if (passesSmallModuli && (remainder8 == 1 || remainder8 == 7) && ((decimalMask >> remainder10) & 1) != 0)
{ {
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor); MontgomeryDivisorData divisorData = divisorPool.FromModulus(divisor);
ulong divisorCycle; ulong divisorCycle;
if (!MersenneDivisorCycles.TryCalculateCycleLengthForExponentCpu( if (!MersenneDivisorCycles.TryCalculateCycleLengthForExponentCpu(
gpu, gpu,
@@ -377,6 +370,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
divisorCycle = computedCycle; divisorCycle = computedCycle;
} }
divisorPool.Return(divisorData);
if (divisorCycle == prime) if (divisorCycle == prime)
{ {
foundDivisor = divisor; foundDivisor = divisor;
+12 -6
View File
@@ -76,19 +76,23 @@ public sealed class DivisorCycleCache
// } // }
ulong[] snapshot = _snapshot; ulong[] snapshot = _snapshot;
ulong cycleLength;
if (divisor < (ulong)snapshot.Length) if (divisor < (ulong)snapshot.Length)
{ {
ulong cached = snapshot[divisor]; cycleLength = snapshot[divisor];
if (cached == 0UL) if (cycleLength == 0UL)
{ {
throw new InvalidDataException($"Divisor cycle is missing for {divisor}"); throw new InvalidDataException($"Divisor cycle is missing for {divisor}");
} }
return cached; return cycleLength;
} }
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor); Queue<MontgomeryDivisorData> divisorPool = MontgomeryDivisorDataPool.Shared;
return MersenneDivisorCycles.CalculateCycleLength(divisor, divisorData, skipPrimeOrderHeuristic: true); MontgomeryDivisorData divisorData = divisorPool.FromModulus(divisor);
cycleLength = MersenneDivisorCycles.CalculateCycleLength(divisor, divisorData, skipPrimeOrderHeuristic: true);
divisorPool.Return(divisorData);
return cycleLength;
} }
public void GetCycleLengths(ReadOnlySpan<ulong> divisors, Span<ulong> cycles) public void GetCycleLengths(ReadOnlySpan<ulong> divisors, Span<ulong> cycles)
@@ -185,12 +189,14 @@ public sealed class DivisorCycleCache
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void ComputeCyclesCpu(ReadOnlySpan<ulong> divisors, Span<ulong> cycles, ReadOnlySpan<int> indices) private static void ComputeCyclesCpu(ReadOnlySpan<ulong> divisors, Span<ulong> cycles, ReadOnlySpan<int> indices)
{ {
Queue<MontgomeryDivisorData> divisorPool = MontgomeryDivisorDataPool.Shared;
for (int i = 0; i < indices.Length; i++) for (int i = 0; i < indices.Length; i++)
{ {
int targetIndex = indices[i]; int targetIndex = indices[i];
ulong divisor = divisors[targetIndex]; ulong divisor = divisors[targetIndex];
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor); MontgomeryDivisorData divisorData = divisorPool.FromModulus(divisor);
cycles[targetIndex] = MersenneDivisorCycles.CalculateCycleLength(divisor, divisorData); cycles[targetIndex] = MersenneDivisorCycles.CalculateCycleLength(divisor, divisorData);
divisorPool.Return(divisorData);
} }
} }
@@ -69,6 +69,7 @@ public sealed class PrimeOrderCalculatorAccelerator
AcceleratorStream stream = accelerator.CreateStream(); AcceleratorStream stream = accelerator.CreateStream();
// TODO: Review which tables are needed when final execution path is defined. // TODO: Review which tables are needed when final execution path is defined.
LastDigitGpuTables.WarmUp(i, stream); LastDigitGpuTables.WarmUp(i, stream);
_kernels[i] = new CalculatorKernels(accelerator);
// HeuristicCombinedGpuTables.WarmUp(i, stream); // HeuristicCombinedGpuTables.WarmUp(i, stream);
// SmallPrimeFactorGpuTables.WarmUp(i, stream); // SmallPrimeFactorGpuTables.WarmUp(i, stream);
// SharedHeuristicGpuTables.EnsureStaticTables(accelerator, stream); // SharedHeuristicGpuTables.EnsureStaticTables(accelerator, stream);
@@ -115,18 +116,41 @@ public sealed class PrimeOrderCalculatorAccelerator
public Dictionary<ulong, int> Pow2ModEntriesToTestOnHost = []; public Dictionary<ulong, int> Pow2ModEntriesToTestOnHost = [];
private static readonly CalculatorKernels[] _kernels =new CalculatorKernels[AcceleratorPool.Shared.Accelerators.Length];
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, 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, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews> HeuristicCombinedTrialDivisionKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews>(PrimeTesterKernels.HeuristicTrialCombinedDivisionKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews>>();
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 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, 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, 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 = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<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>>(SmallPrimeFactorKernels.SmallPrimeFactorKernelScan)).CreateLauncherDelegate<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>>>();
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 = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>(PrimeTesterKernels.SmallPrimeSieveKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>>();
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 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>, MontgomeryDivisorData, 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>, MontgomeryDivisorData, 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 Kernel PollardRhoKernel; public readonly Kernel PollardRhoKernel;
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, MontgomeryDivisorData, 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 EnsureCapacity(int factorsCount, int primeTesterCapacity) public void EnsureCapacity(int factorsCount, int primeTesterCapacity)
{ {
@@ -260,25 +284,18 @@ public sealed class PrimeOrderCalculatorAccelerator
SmallPrimeFactorSquares = tables.Squares.View; SmallPrimeFactorSquares = tables.Squares.View;
} }
CheckFactorsKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel<int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.CheckFactorsKernel)); var kernels = _kernels[acceleratorIndex];
ConvertToStandardKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelConvertToStandard)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>(); CheckFactorsKernel = kernels.CheckFactorsKernel;
ConvertToStandardKernelLauncher = kernels.ConvertToStandardKernelLauncher;
HeuristicCombinedTrialDivisionKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews>(PrimeTesterKernels.HeuristicTrialCombinedDivisionKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews>>(); HeuristicCombinedTrialDivisionKernelLauncher = kernels.HeuristicCombinedTrialDivisionKernelLauncher;
KeepMontgomeryKernelLauncher = kernels.KeepMontgomeryKernelLauncher;
KeepMontgomeryKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelKeepMontgomery)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>(); PollardRhoKernel = kernels.PollardRhoKernel;
Pow2ModWideKernelLauncher = kernels.Pow2ModWideKernelLauncher;
PollardRhoKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel<ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.TryPollardRhoKernel)); SharesFactorKernelLauncher = kernels.SharesFactorKernelLauncher;
SmallPrimeFactorKernelLauncher = kernels.SmallPrimeFactorKernelLauncher;
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>>>(); SmallPrimeSieveKernelLauncher = kernels.SmallPrimeSieveKernelLauncher;
SpecialMaxKernelLauncher = kernels.SpecialMaxKernelLauncher;
SharesFactorKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<byte>>(PrimeTesterKernels.SharesFactorKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<byte>>>();
SmallPrimeFactorKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<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>>(SmallPrimeFactorKernels.SmallPrimeFactorKernelScan)).CreateLauncherDelegate<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>>>();
SmallPrimeSieveKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>(PrimeTesterKernels.SmallPrimeSieveKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>>();
SpecialMaxKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.EvaluateSpecialMaxCandidatesKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>();
} }
} }
@@ -17,18 +17,28 @@ internal static class Pow2MontgomeryKernels
public static void Pow2MontgomeryKernelKeepMontgomery( public static void Pow2MontgomeryKernelKeepMontgomery(
Index1D index, Index1D index,
ArrayView1D<ulong, Stride1D.Dense> exponents, ArrayView1D<ulong, Stride1D.Dense> exponents,
MontgomeryDivisorData divisor, ulong divisorModulus,
ulong divisorNPrime,
ulong divisorMontgomeryOne,
ulong divisorMontgomeryTwo,
ulong divisorMontgomeryTwoSquared,
ArrayView1D<ulong, Stride1D.Dense> results) ArrayView1D<ulong, Stride1D.Dense> results)
{ {
MontgomeryDivisorDataGpu divisor = new(divisorModulus, divisorNPrime, divisorMontgomeryOne, divisorMontgomeryTwo, divisorMontgomeryTwoSquared);
results[0] = ULongExtensions.Pow2MontgomeryModWindowedGpuKeepMontgomery(divisor, exponents[0]); results[0] = ULongExtensions.Pow2MontgomeryModWindowedGpuKeepMontgomery(divisor, exponents[0]);
} }
public static void Pow2MontgomeryKernelConvertToStandard( public static void Pow2MontgomeryKernelConvertToStandard(
Index1D index, Index1D index,
ArrayView1D<ulong, Stride1D.Dense> exponents, ArrayView1D<ulong, Stride1D.Dense> exponents,
MontgomeryDivisorData divisor, ulong divisorModulus,
ulong divisorNPrime,
ulong divisorMontgomeryOne,
ulong divisorMontgomeryTwo,
ulong divisorMontgomeryTwoSquared,
ArrayView1D<ulong, Stride1D.Dense> results) ArrayView1D<ulong, Stride1D.Dense> results)
{ {
MontgomeryDivisorDataGpu divisor = new(divisorModulus, divisorNPrime, divisorMontgomeryOne, divisorMontgomeryTwo, divisorMontgomeryTwoSquared);
results[0] = ULongExtensions.Pow2MontgomeryModWindowedGpuConvertToStandard(divisor, exponents[0]); results[0] = ULongExtensions.Pow2MontgomeryModWindowedGpuConvertToStandard(divisor, exponents[0]);
} }
@@ -11,12 +11,17 @@ internal static partial class PrimeOrderGpuHeuristics
int count, int count,
ulong phi, ulong phi,
ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense> toTest, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense> toTest,
MontgomeryDivisorData divisorData, ulong divisorModulus,
ulong divisorNPrime,
ulong divisorMontgomeryOne,
ulong divisorMontgomeryTwo,
ulong divisorMontgomeryTwoSquared,
ArrayView1D<ulong, Stride1D.Dense> result ArrayView1D<ulong, Stride1D.Dense> result
) )
{ {
ulong order = phi; ulong order = phi;
int entryCount = count; int entryCount = count;
MontgomeryDivisorDataGpu divisorData = new(divisorModulus, divisorNPrime, divisorMontgomeryOne, divisorMontgomeryTwo, divisorMontgomeryTwoSquared);
for (int i = 0; i < entryCount; i++) for (int i = 0; i < entryCount; i++)
{ {
@@ -155,7 +160,11 @@ internal static partial class PrimeOrderGpuHeuristics
Index1D index, Index1D index,
ulong prime, ulong prime,
OrderKernelConfig config, OrderKernelConfig config,
MontgomeryDivisorData divisor, ulong divisorModulus,
ulong divisorNPrime,
ulong divisorMontgomeryOne,
ulong divisorMontgomeryTwo,
ulong divisorMontgomeryTwoSquared,
ArrayView1D<uint, Stride1D.Dense> primes, ArrayView1D<uint, Stride1D.Dense> primes,
ArrayView1D<ulong, Stride1D.Dense> squares, ArrayView1D<ulong, Stride1D.Dense> squares,
int primeCount, int primeCount,
@@ -227,6 +236,8 @@ internal static partial class PrimeOrderGpuHeuristics
SortFactors(phiFactors, phiExponents, phiFactorCount); SortFactors(phiFactors, phiExponents, phiFactorCount);
MontgomeryDivisorDataGpu divisor = new(divisorModulus, divisorNPrime, divisorMontgomeryOne, divisorMontgomeryTwo, divisorMontgomeryTwoSquared);
if (TrySpecialMaxKernel(phi, prime, phiFactors, phiFactorCount, divisor)) if (TrySpecialMaxKernel(phi, prime, phiFactors, phiFactorCount, divisor))
{ {
resultOut[0] = phi; resultOut[0] = phi;
@@ -381,7 +392,7 @@ internal static partial class PrimeOrderGpuHeuristics
ulong prime, ulong prime,
ArrayView1D<ulong, Stride1D.Dense> factors, ArrayView1D<ulong, Stride1D.Dense> factors,
int factorCount, int factorCount,
in MontgomeryDivisorData divisor) in MontgomeryDivisorDataGpu divisor)
{ {
for (int i = 0; i < factorCount; i++) for (int i = 0; i < factorCount; i++)
{ {
@@ -401,7 +412,7 @@ internal static partial class PrimeOrderGpuHeuristics
return true; return true;
} }
private static ulong InitializeStartingOrderKernel(ulong prime, ulong phi, in MontgomeryDivisorData divisor) private static ulong InitializeStartingOrderKernel(ulong prime, ulong phi, in MontgomeryDivisorDataGpu divisor)
{ {
ulong order = phi; ulong order = phi;
ulong residue = prime & 7UL; ulong residue = prime & 7UL;
@@ -423,7 +434,7 @@ internal static partial class PrimeOrderGpuHeuristics
ArrayView1D<ulong, Stride1D.Dense> factors, ArrayView1D<ulong, Stride1D.Dense> factors,
ArrayView1D<int, Stride1D.Dense> exponents, ArrayView1D<int, Stride1D.Dense> exponents,
int factorCount, int factorCount,
in MontgomeryDivisorData divisor) in MontgomeryDivisorDataGpu divisor)
{ {
for (int i = 0; i < factorCount; i++) for (int i = 0; i < factorCount; i++)
{ {
@@ -458,7 +469,7 @@ internal static partial class PrimeOrderGpuHeuristics
private static bool TryConfirmOrderKernel( private static bool TryConfirmOrderKernel(
ulong prime, ulong prime,
ulong order, ulong order,
in MontgomeryDivisorData divisor, in MontgomeryDivisorDataGpu divisor,
uint limit, uint limit,
ArrayView1D<uint, Stride1D.Dense> primes, ArrayView1D<uint, Stride1D.Dense> primes,
ArrayView1D<ulong, Stride1D.Dense> squares, ArrayView1D<ulong, Stride1D.Dense> squares,
@@ -532,7 +543,7 @@ internal static partial class PrimeOrderGpuHeuristics
ulong order, ulong order,
ulong previousOrder, ulong previousOrder,
byte hasPreviousOrder, byte hasPreviousOrder,
in MontgomeryDivisorData divisor, in MontgomeryDivisorDataGpu divisor,
uint limit, uint limit,
int maxPowChecks, int maxPowChecks,
ArrayView1D<uint, Stride1D.Dense> primes, ArrayView1D<uint, Stride1D.Dense> primes,
@@ -851,7 +862,7 @@ internal static partial class PrimeOrderGpuHeuristics
private static bool TryConfirmCandidateKernel( private static bool TryConfirmCandidateKernel(
ulong prime, ulong prime,
ulong candidate, ulong candidate,
in MontgomeryDivisorData divisor, in MontgomeryDivisorDataGpu divisor,
uint limit, uint limit,
ArrayView1D<uint, Stride1D.Dense> primes, ArrayView1D<uint, Stride1D.Dense> primes,
ArrayView1D<ulong, Stride1D.Dense> squares, ArrayView1D<ulong, Stride1D.Dense> squares,
@@ -1174,7 +1185,7 @@ internal static partial class PrimeOrderGpuHeuristics
} }
} }
private static bool Pow2EqualsOneKernel(ulong exponent, in MontgomeryDivisorData divisor) private static bool Pow2EqualsOneKernel(ulong exponent, in MontgomeryDivisorDataGpu divisor)
{ {
return ULongExtensions.Pow2MontgomeryModWindowedGpuConvertToStandard(divisor, exponent) == 1UL; return ULongExtensions.Pow2MontgomeryModWindowedGpuConvertToStandard(divisor, exponent) == 1UL;
} }
@@ -1200,9 +1211,10 @@ internal static partial class PrimeOrderGpuHeuristics
/// This kernel always sets the result of the corresponding element. Callers don't need to clear the output buffers. /// This kernel always sets the result of the corresponding element. Callers don't need to clear the output buffers.
internal static void Pow2ModKernel(Index1D index, ArrayView1D<ulong, Stride1D.Dense> exponents, MontgomeryDivisorData divisor, ArrayView1D<ulong, Stride1D.Dense> remainders) internal static void Pow2ModKernel(Index1D index, ArrayView1D<ulong, Stride1D.Dense> exponents, ulong divisorModulus, ulong divisorNPrime, ulong divisorMontgomeryOne, ulong divisorMontgomeryTwo, ulong divisorMontgomeryTwoSquared, ArrayView1D<ulong, Stride1D.Dense> remainders)
{ {
ulong exponent = exponents[index]; ulong exponent = exponents[index];
MontgomeryDivisorDataGpu divisor = new(divisorModulus, divisorNPrime, divisorMontgomeryOne, divisorMontgomeryTwo, divisorMontgomeryTwoSquared);
remainders[index] = ULongExtensions.Pow2MontgomeryModWindowedGpuConvertToStandard(divisor, exponent); remainders[index] = ULongExtensions.Pow2MontgomeryModWindowedGpuConvertToStandard(divisor, exponent);
} }
@@ -10,7 +10,7 @@ internal static partial class PrimeOrderGpuHeuristics
ulong phi, ulong phi,
ArrayView1D<ulong, Stride1D.Dense> factors, ArrayView1D<ulong, Stride1D.Dense> factors,
int factorCount, int factorCount,
MontgomeryDivisorData divisor, ulong divisorModulus,
ArrayView1D<ulong, Stride1D.Dense> candidates, ArrayView1D<ulong, Stride1D.Dense> candidates,
ArrayView1D<ulong, Stride1D.Dense> resultOut) ArrayView1D<ulong, Stride1D.Dense> resultOut)
{ {
@@ -57,7 +57,7 @@ internal static partial class PrimeOrderGpuHeuristics
candidates[insert + 1] = current; candidates[insert + 1] = current;
} }
var divisorPartial = new GpuDivisorPartialData(divisor.Modulus); var divisorPartial = new GpuDivisorPartialData(divisorModulus);
var stepper = new ExponentRemainderStepperGpu(divisorPartial); var stepper = new ExponentRemainderStepperGpu(divisorPartial);
if (stepper.InitializeIsUnityGpu(candidates[0])) if (stepper.InitializeIsUnityGpu(candidates[0]))
{ {
@@ -260,7 +260,7 @@ public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneN
ArrayView1D<ulong, Stride1D.Dense> exponentViewDevice = exponentBuffer.View; ArrayView1D<ulong, Stride1D.Dense> exponentViewDevice = exponentBuffer.View;
ArrayView1D<byte, Stride1D.Dense> hitsView = hitsBuffer.View; ArrayView1D<byte, Stride1D.Dense> hitsView = hitsBuffer.View;
ArrayView1D<int, Stride1D.Dense> hitIndexView = hitIndexBuffer.View; ArrayView1D<int, Stride1D.Dense> hitIndexView = hitIndexBuffer.View;
Queue<MontgomeryDivisorData> divisorPool = MontgomeryDivisorDataPool.Shared;
while (remainingCount > 0UL && !composite) while (remainingCount > 0UL && !composite)
{ {
int chunkCount = chunkCountBaseline; int chunkCount = chunkCountBaseline;
@@ -284,7 +284,7 @@ public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneN
if (passesSmallModuli && (localRemainder8 == 1 || localRemainder8 == 7) && ((decimalMask >> localRemainder10) & 1) != 0) if (passesSmallModuli && (localRemainder8 == 1 || localRemainder8 == 7) && ((decimalMask >> localRemainder10) & 1) != 0)
{ {
ulong divisorValue = (ulong)nextDivisor128; ulong divisorValue = (ulong)nextDivisor128;
MontgomeryDivisorData montgomeryData = MontgomeryDivisorData.FromModulus(divisorValue); MontgomeryDivisorData montgomeryData = divisorPool.FromModulus(divisorValue);
ulong divisorCycle = ResolveDivisorCycle(gpu, divisorValue, prime, in montgomeryData); ulong divisorCycle = ResolveDivisorCycle(gpu, divisorValue, prime, in montgomeryData);
if (divisorCycle == prime) if (divisorCycle == prime)
{ {
@@ -294,6 +294,7 @@ public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneN
return true; return true;
} }
divisorPool.Return(montgomeryData);
divisorSpan[admissibleCount] = divisorValue; divisorSpan[admissibleCount] = divisorValue;
divisorDataSpan[admissibleCount] = new GpuDivisorPartialData(divisorValue); divisorDataSpan[admissibleCount] = new GpuDivisorPartialData(divisorValue);
offsetSpan[admissibleCount] = admissibleCount; offsetSpan[admissibleCount] = admissibleCount;
@@ -0,0 +1,10 @@
namespace PerfectNumbers.Core.Gpu;
public readonly struct MontgomeryDivisorDataGpu(ulong modulus, ulong nPrime, ulong montgomeryOne, ulong montgomeryTwo, ulong montgomeryTwoSquared)
{
public readonly ulong Modulus = modulus;
public readonly ulong NPrime = nPrime;
public readonly ulong MontgomeryOne = montgomeryOne;
public readonly ulong MontgomeryTwo = montgomeryTwo;
public readonly ulong MontgomeryTwoSquared = montgomeryTwoSquared;
}
@@ -25,7 +25,7 @@ public static class Pow2MontgomeryGpuCalculator
// resultBuffer.MemSetToZero(stream); // resultBuffer.MemSetToZero(stream);
var kernelLauncher = gpu.KeepMontgomeryKernelLauncher; var kernelLauncher = gpu.KeepMontgomeryKernelLauncher;
kernelLauncher(stream, 1, exponentBuffer.View, divisor, resultBuffer.View); kernelLauncher(stream, 1, exponentBuffer.View, divisor.Modulus, divisor.NPrime, divisor.MontgomeryOne, divisor.MontgomeryTwo, divisor.MontgomeryTwoSquared, resultBuffer.View);
resultBuffer.View.CopyToCPU(stream, ref result, 1); resultBuffer.View.CopyToCPU(stream, ref result, 1);
stream.Synchronize(); stream.Synchronize();
@@ -54,7 +54,7 @@ public static class Pow2MontgomeryGpuCalculator
var kernelLauncher = gpu.ConvertToStandardKernelLauncher!; var kernelLauncher = gpu.ConvertToStandardKernelLauncher!;
kernelLauncher(stream, 1, exponentBuffer.View, divisor, resultBuffer.View); kernelLauncher(stream, 1, exponentBuffer.View, divisor.Modulus, divisor.NPrime, divisor.MontgomeryOne, divisor.MontgomeryTwo, divisor.MontgomeryTwoSquared, resultBuffer.View);
resultBuffer.View.CopyToCPU(stream, ref result, 1); resultBuffer.View.CopyToCPU(stream, ref result, 1);
stream.Synchronize(); stream.Synchronize();
@@ -82,7 +82,7 @@ public static class Pow2MontgomeryGpuCalculator
var accelerator = gpu.Accelerator; var accelerator = gpu.Accelerator;
var kernelLauncher = gpu.ConvertToStandardKernelLauncher; var kernelLauncher = gpu.ConvertToStandardKernelLauncher;
kernelLauncher(stream, 1, exponentBuffer.View, divisor, resultBuffer.View); kernelLauncher(stream, 1, exponentBuffer.View, divisor.Modulus, divisor.NPrime, divisor.MontgomeryOne, divisor.MontgomeryTwo, divisor.MontgomeryTwoSquared, resultBuffer.View);
resultBuffer.View.CopyToCPU(stream, ref result, 1); resultBuffer.View.CopyToCPU(stream, ref result, 1);
stream.Synchronize(); stream.Synchronize();
@@ -398,14 +398,18 @@ internal static partial class PrimeOrderGpuHeuristics
statusBuffer.View); statusBuffer.View);
var orderKernel = GetOrderKernel(acceleratorIndex); var orderKernel = GetOrderKernel(acceleratorIndex);
var kernelLauncher = orderKernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, OrderKernelConfig, MontgomeryDivisorData, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, OrderKernelBuffers>>(); var kernelLauncher = orderKernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, OrderKernelConfig, ulong, ulong, ulong, ulong, ulong, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, OrderKernelBuffers>>();
kernelLauncher( kernelLauncher(
stream, stream,
1, 1,
prime, prime,
kernelConfig, kernelConfig,
divisorData, divisorData.Modulus,
divisorData.NPrime,
divisorData.MontgomeryOne,
divisorData.MontgomeryTwo,
divisorData.MontgomeryTwoSquared,
smallPrimesView, smallPrimesView,
smallSquaresView, smallSquaresView,
(int)smallPrimesView.Length, (int)smallPrimesView.Length,
@@ -417,7 +421,7 @@ internal static partial class PrimeOrderGpuHeuristics
resultBuffer.View.CopyToCPU(stream, ref order, 1); resultBuffer.View.CopyToCPU(stream, ref order, 1);
stream.Synchronize(); stream.Synchronize();
stream.Dispose(); AcceleratorStreamPool.Return(acceleratorIndex, stream);
phiFactorBuffer.Dispose(); phiFactorBuffer.Dispose();
phiExponentBuffer.Dispose(); phiExponentBuffer.Dispose();
workFactorBuffer.Dispose(); workFactorBuffer.Dispose();
@@ -458,7 +462,7 @@ internal static partial class PrimeOrderGpuHeuristics
} }
var accelerator = _accelerators[acceleratorIndex]; var accelerator = _accelerators[acceleratorIndex];
var loaded = accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, OrderKernelConfig, MontgomeryDivisorData, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, OrderKernelBuffers>(CalculateOrderKernel); 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); var kernel = KernelUtil.GetKernel(loaded);
pool[acceleratorIndex] = kernel; pool[acceleratorIndex] = kernel;
@@ -530,11 +534,12 @@ internal static partial class PrimeOrderGpuHeuristics
// remainderBuffer.MemSetToZero(stream); // remainderBuffer.MemSetToZero(stream);
var pow2ModKernel = GetPow2ModKernel(acceleratorIndex); var pow2ModKernel = GetPow2ModKernel(acceleratorIndex);
var kernelLauncher = pow2ModKernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>(); var kernelLauncher = pow2ModKernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>>>();
try try
{ {
kernelLauncher(stream, exponents.Length, exponentBuffer.View, divisorData, remainderBuffer.View); kernelLauncher(stream, exponents.Length, exponentBuffer.View, divisorData.Modulus, divisorData.NPrime, divisorData.MontgomeryOne, divisorData.MontgomeryTwo, divisorData.MontgomeryTwoSquared, remainderBuffer.View);
remainderBuffer.View.CopyToCPU(stream, ref MemoryMarshal.GetReference(results), exponents.Length); remainderBuffer.View.CopyToCPU(stream, ref MemoryMarshal.GetReference(results), exponents.Length);
stream.Synchronize(); stream.Synchronize();
@@ -557,7 +562,7 @@ internal static partial class PrimeOrderGpuHeuristics
return true; return true;
} }
private static void ComputePow2ModCpu(ReadOnlySpan<ulong> exponents, ulong prime, in MontgomeryDivisorData divisorData, Span<ulong> results) private static void ComputePow2ModCpu(ReadOnlySpan<ulong> exponents, ulong prime, in MontgomeryDivisorDataGpu divisorData, Span<ulong> results)
{ {
int length = exponents.Length; int length = exponents.Length;
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
@@ -636,7 +641,7 @@ internal static partial class PrimeOrderGpuHeuristics
} }
} }
private static ulong Pow2ModCpu(ulong exponent, ulong modulus, in MontgomeryDivisorData divisorData) private static ulong Pow2ModCpu(ulong exponent, ulong modulus, in MontgomeryDivisorDataGpu divisorData)
{ {
if (modulus <= 1UL) if (modulus <= 1UL)
{ {
@@ -655,7 +660,7 @@ internal static partial class PrimeOrderGpuHeuristics
} }
var accelerator = _accelerators[acceleratorIndex]; var accelerator = _accelerators[acceleratorIndex];
var loaded = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2ModKernel)); var loaded = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>>(Pow2ModKernel));
pool[acceleratorIndex] = loaded; pool[acceleratorIndex] = loaded;
return loaded; return loaded;
@@ -478,7 +478,7 @@ public sealed class HeuristicCombinedPrimeTester
internal static HeuristicDivisorPreparation PrepareHeuristicDivisor(in HeuristicDivisorCandidate candidate) internal static HeuristicDivisorPreparation PrepareHeuristicDivisor(in HeuristicDivisorCandidate candidate)
{ {
ulong divisor = candidate.Value; ulong divisor = candidate.Value;
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(divisor);
bool hasCycleHint = TryGetCycleLengthHint(divisor, out ulong cycleLength); bool hasCycleHint = TryGetCycleLengthHint(divisor, out ulong cycleLength);
return new(candidate, divisorData, cycleLength, hasCycleHint); return new(candidate, divisorData, cycleLength, hasCycleHint);
} }
+1 -1
View File
@@ -445,7 +445,7 @@ public sealed class HeuristicPrimeTester
internal static HeuristicDivisorPreparation PrepareHeuristicDivisor(in HeuristicDivisorCandidate candidate) internal static HeuristicDivisorPreparation PrepareHeuristicDivisor(in HeuristicDivisorCandidate candidate)
{ {
ulong divisor = candidate.Value; ulong divisor = candidate.Value;
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(divisor);
bool hasCycleHint = TryGetCycleLengthHint(divisor, out ulong cycleLength); bool hasCycleHint = TryGetCycleLengthHint(divisor, out ulong cycleLength);
return new HeuristicDivisorPreparation(candidate, divisorData, cycleLength, hasCycleHint); return new HeuristicDivisorPreparation(candidate, divisorData, cycleLength, hasCycleHint);
} }
+6 -2
View File
@@ -222,8 +222,10 @@ public class MersenneDivisorCycles
if (divisor <= ulong.MaxValue) if (divisor <= ulong.MaxValue)
{ {
ulong divisor64 = (ulong)divisor; ulong divisor64 = (ulong)divisor;
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor64); Queue<MontgomeryDivisorData> divisorPool = MontgomeryDivisorDataPool.Shared;
MontgomeryDivisorData divisorData = divisorPool.FromModulus(divisor64);
ulong cycle = CalculateCycleLength(divisor64, divisorData); ulong cycle = CalculateCycleLength(divisor64, divisorData);
divisorPool.Return(divisorData);
return (UInt128)cycle; return (UInt128)cycle;
} }
@@ -733,6 +735,7 @@ public class MersenneDivisorCycles
ulong localStart = threadStart; ulong localStart = threadStart;
ulong localEnd = threadEnd; ulong localEnd = threadEnd;
Queue<MontgomeryDivisorData> divisorPool = MontgomeryDivisorDataPool.Shared;
tasks[taskIndex] = Task.Run(() => tasks[taskIndex] = Task.Run(() =>
{ {
ulong rangeLength = localEnd - localStart + 1UL; ulong rangeLength = localEnd - localStart + 1UL;
@@ -758,8 +761,9 @@ public class MersenneDivisorCycles
// TODO: Migrate this generation path to the shared // TODO: Migrate this generation path to the shared
// unrolled-hex calculator so the CPU generator matches // unrolled-hex calculator so the CPU generator matches
// the GPU benchmark leader for large divisors. // the GPU benchmark leader for large divisors.
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor); MontgomeryDivisorData divisorData = divisorPool.FromModulus(divisor);
ulong cycle = CalculateCycleLength(divisor, divisorData); ulong cycle = CalculateCycleLength(divisor, divisorData);
divisorPool.Return(divisorData);
localCycles[localCycleIndex++] = (divisor, cycle); localCycles[localCycleIndex++] = (divisor, cycle);
} }
+18 -41
View File
@@ -1,47 +1,24 @@
using System.Runtime.CompilerServices;
namespace PerfectNumbers.Core; namespace PerfectNumbers.Core;
public readonly struct MontgomeryDivisorData(ulong modulus, ulong nPrime, ulong montgomeryOne, ulong montgomeryTwo, ulong montgomeryTwoSquared) public sealed class MontgomeryDivisorData
{ {
public readonly ulong Modulus = modulus; public static readonly MontgomeryDivisorData Empty = new();
public ulong Modulus;
public ulong NPrime;
public ulong MontgomeryOne;
public ulong MontgomeryTwo;
public ulong MontgomeryTwoSquared;
public readonly ulong NPrime = nPrime; public MontgomeryDivisorData()
{
public readonly ulong MontgomeryOne = montgomeryOne; }
public readonly ulong MontgomeryTwo = montgomeryTwo;
public readonly ulong MontgomeryTwoSquared = montgomeryTwoSquared;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong ComputeMontgomeryResidue(UInt128 value, ulong modulus) => (ulong)(value % modulus);
private static ulong ComputeMontgomeryNPrime(ulong modulus)
{
ulong inv = modulus;
inv *= unchecked(2UL - modulus * inv);
inv *= unchecked(2UL - modulus * inv);
inv *= unchecked(2UL - modulus * inv);
inv *= unchecked(2UL - modulus * inv);
inv *= unchecked(2UL - modulus * inv);
inv *= unchecked(2UL - modulus * inv);
inv *= unchecked(2UL - modulus * inv);
return unchecked(0UL - inv);
}
public static MontgomeryDivisorData FromModulus(ulong modulus)
{
ulong nPrime = ComputeMontgomeryNPrime(modulus);
ulong montgomeryOne = ComputeMontgomeryResidue(UInt128Numbers.OneShiftedLeft64, modulus);
ulong montgomeryTwo = ComputeMontgomeryResidue(UInt128Numbers.OneShiftedLeft64x2, modulus);
ulong montgomeryTwoSquared = ULongExtensions.MontgomeryMultiplyCpu(montgomeryTwo, montgomeryTwo, modulus, nPrime);
return new MontgomeryDivisorData(
modulus,
nPrime,
montgomeryOne,
montgomeryTwo,
montgomeryTwoSquared);
}
public MontgomeryDivisorData(ulong modulus, ulong nPrime, ulong montgomeryOne, ulong montgomeryTwo, ulong montgomeryTwoSquared)
{
Modulus = modulus;
NPrime = nPrime;
MontgomeryOne = montgomeryOne;
MontgomeryTwo = montgomeryTwo;
MontgomeryTwoSquared = montgomeryTwoSquared;
}
} }
@@ -0,0 +1,80 @@
using System.Runtime.CompilerServices;
namespace PerfectNumbers.Core;
public static class MontgomeryDivisorDataPool
{
[ThreadStatic]
private static Queue<MontgomeryDivisorData>? _pool;
public static Queue<MontgomeryDivisorData> Shared => _pool ??= new();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong ComputeMontgomeryResidue(UInt128 value, ulong modulus) => (ulong)(value % modulus);
private static ulong ComputeMontgomeryNPrime(ulong modulus)
{
ulong inv = modulus;
inv *= unchecked(2UL - modulus * inv);
inv *= unchecked(2UL - modulus * inv);
inv *= unchecked(2UL - modulus * inv);
inv *= unchecked(2UL - modulus * inv);
inv *= unchecked(2UL - modulus * inv);
inv *= unchecked(2UL - modulus * inv);
inv *= unchecked(2UL - modulus * inv);
return unchecked(0UL - inv);
}
public static MontgomeryDivisorData Rent(ulong modulus, ulong nPrime, ulong montgomeryOne, ulong montgomeryTwo, ulong montgomeryTwoSquared)
{
var pool = _pool ??= new();
if (pool.TryDequeue(out var pooled))
{
pooled.Modulus = modulus;
pooled.NPrime = nPrime;
pooled.MontgomeryOne = montgomeryOne;
pooled.MontgomeryTwo = montgomeryTwo;
pooled.MontgomeryTwoSquared = montgomeryTwoSquared;
return pooled;
}
return new(modulus, nPrime, montgomeryOne, montgomeryTwo, montgomeryTwoSquared);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Return(MontgomeryDivisorData divisorData) => _pool!.Enqueue(divisorData);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static MontgomeryDivisorData FromModulus(this Queue<MontgomeryDivisorData> queue, ulong modulus)
{
ulong nPrime = ComputeMontgomeryNPrime(modulus);
ulong montgomeryOne = ComputeMontgomeryResidue(UInt128Numbers.OneShiftedLeft64, modulus);
ulong montgomeryTwo = ComputeMontgomeryResidue(UInt128Numbers.OneShiftedLeft64x2, modulus);
ulong montgomeryTwoSquared = ULongExtensions.MontgomeryMultiplyCpu(montgomeryTwo, montgomeryTwo, modulus, nPrime);
return queue.Rent(
modulus,
nPrime,
montgomeryOne,
montgomeryTwo,
montgomeryTwoSquared);
}
public static MontgomeryDivisorData Rent(this Queue<MontgomeryDivisorData> queue, ulong modulus, ulong nPrime, ulong montgomeryOne, ulong montgomeryTwo, ulong montgomeryTwoSquared)
{
if (queue.TryDequeue(out var pooled))
{
pooled.Modulus = modulus;
pooled.NPrime = nPrime;
pooled.MontgomeryOne = montgomeryOne;
pooled.MontgomeryTwo = montgomeryTwo;
pooled.MontgomeryTwoSquared = montgomeryTwoSquared;
return pooled;
}
return new(modulus, nPrime, montgomeryOne, montgomeryTwo, montgomeryTwoSquared);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Return(this Queue<MontgomeryDivisorData> queue, MontgomeryDivisorData divisorData) => queue.Enqueue(divisorData);
}
@@ -8,7 +8,7 @@ public static class PerfectNumberConstants
public const int DefaultSmallPrimeFactorSlotCount = 64; public const int DefaultSmallPrimeFactorSlotCount = 64;
public const int DefaultSpecialMaxFactorCapacity = 1024; public const int DefaultSpecialMaxFactorCapacity = 1024;
public const ulong ExtraDivisorCycleSearchLimit = 64UL; public const ulong ExtraDivisorCycleSearchLimit = 64UL;
public const int GpuFrequency = 16 - 1; public const int GpuFrequency = 4 - 1;
public const int MaxQForDivisorCycles = 4_000_000; public const int MaxQForDivisorCycles = 4_000_000;
public static readonly uint PrimesLimit = 1_000_000; //(ulong)Array.MaxLength;// 1_000_000; public static readonly uint PrimesLimit = 1_000_000; //(ulong)Array.MaxLength;// 1_000_000;
public const int MaxOddPowersCount = 128; public const int MaxOddPowersCount = 128;
@@ -1389,7 +1389,7 @@ internal static partial class PrimeOrderCalculator
private static bool RunOnGpu() private static bool RunOnGpu()
{ {
// return false; // return false;
// return true; return true;
// int cpuCount; // int cpuCount;
// lock(_sync) // lock(_sync)
@@ -44,7 +44,7 @@ internal static partial class PrimeOrderCalculator
// var kernelLauncher = gpu.CheckFactorsKernelLauncher; // var kernelLauncher = gpu.CheckFactorsKernelLauncher;
var kernel = gpu.CheckFactorsKernel; var kernel = gpu.CheckFactorsKernel;
kernel.Launch(stream, 1, entryCount, phi, gpu.Pow2ModEntriesToTestOnDevice.View, divisorData, gpu.OutputUlong.View); 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.OutputUlong.View.CopyToCPU(stream, ref order, 1);
stream.Synchronize(); stream.Synchronize();
@@ -146,7 +146,7 @@ internal static partial class PrimeOrderCalculator
phi, phi,
specialMaxFactorsView, specialMaxFactorsView,
factorCount, factorCount,
divisorData, divisorData.Modulus,
gpu.OutputUlong.View, gpu.OutputUlong.View,
specialMaxResultView); specialMaxResultView);
@@ -82,7 +82,7 @@ internal static partial class PrimeOrderCalculator
Console.WriteLine(messageFactory()); Console.WriteLine(messageFactory());
} }
} }
private static UInt128 CalculateWideInternal(in UInt128 prime, in UInt128? previousOrder, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config) private static UInt128 CalculateWideInternal(in UInt128 prime, in UInt128? previousOrder, in MontgomeryDivisorData? divisorData, in PrimeOrderSearchConfig config)
{ {
if (prime <= UInt128.One) if (prime <= UInt128.One)
{ {
+4 -2
View File
@@ -86,13 +86,15 @@ internal static partial class PrimeOrderCalculator
} }
ulong prime64 = (ulong)prime; ulong prime64 = (ulong)prime;
divisorData = MontgomeryDivisorData.FromModulus(prime64); Queue<MontgomeryDivisorData> divisorPool = MontgomeryDivisorDataPool.Shared;
divisorData = divisorPool.FromModulus(prime64);
ulong order64 = Calculate(prime64, previous, divisorData, config, device); ulong order64 = Calculate(prime64, previous, divisorData, config, device);
divisorPool.Return(divisorData);
result = order64 == 0UL ? UInt128.Zero : (UInt128)order64; result = order64 == 0UL ? UInt128.Zero : (UInt128)order64;
} }
else else
{ {
divisorData = default; divisorData = MontgomeryDivisorData.Empty;
result = CalculateWideInternal(prime, previousOrder, divisorData, config); result = CalculateWideInternal(prime, previousOrder, divisorData, config);
} }
+4 -4
View File
@@ -229,13 +229,13 @@ public static partial class ULongExtensions
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static ulong Pow2MontgomeryModWindowedGpuKeepMontgomery(in MontgomeryDivisorData divisor, ulong exponent) internal static ulong Pow2MontgomeryModWindowedGpuKeepMontgomery(in MontgomeryDivisorDataGpu divisor, ulong exponent)
{ {
return Pow2MontgomeryModWindowedGpuMontgomeryResult(divisor, exponent); return Pow2MontgomeryModWindowedGpuMontgomeryResult(divisor, exponent);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static ulong Pow2MontgomeryModWindowedGpuConvertToStandard(in MontgomeryDivisorData divisor, ulong exponent) internal static ulong Pow2MontgomeryModWindowedGpuConvertToStandard(in MontgomeryDivisorDataGpu divisor, ulong exponent)
{ {
ulong modulus = divisor.Modulus; ulong modulus = divisor.Modulus;
ulong nPrime = divisor.NPrime; ulong nPrime = divisor.NPrime;
@@ -244,7 +244,7 @@ public static partial class ULongExtensions
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong Pow2MontgomeryModWindowedGpuMontgomeryResult(in MontgomeryDivisorData divisor, ulong exponent) private static ulong Pow2MontgomeryModWindowedGpuMontgomeryResult(in MontgomeryDivisorDataGpu divisor, ulong exponent)
{ {
ulong modulus = divisor.Modulus; ulong modulus = divisor.Modulus;
// Reuse the GPU-compatible MontgomeryMultiply helper highlighted in MontgomeryMultiplyBenchmarks so the accelerator path // Reuse the GPU-compatible MontgomeryMultiply helper highlighted in MontgomeryMultiplyBenchmarks so the accelerator path
@@ -349,7 +349,7 @@ public static partial class ULongExtensions
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong ComputeMontgomeryOddPowerGpu(ulong exponent, in MontgomeryDivisorData divisor, ulong modulus, ulong nPrime) private static ulong ComputeMontgomeryOddPowerGpu(ulong exponent, in MontgomeryDivisorDataGpu divisor, ulong modulus, ulong nPrime)
{ {
ulong baseValue = divisor.MontgomeryTwo; ulong baseValue = divisor.MontgomeryTwo;
ulong power = divisor.MontgomeryOne; ulong power = divisor.MontgomeryOne;