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

@@ -23,7 +23,7 @@ public class PrimeOrderGpuHeuristicsTests
try
{
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);
status.Should().Be(GpuPow2ModStatus.Overflow);
@@ -40,7 +40,7 @@ public class PrimeOrderGpuHeuristicsTests
{
const ulong exponent = 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);
status.Should().Be(GpuPow2ModStatus.Success);
@@ -55,7 +55,7 @@ public class PrimeOrderGpuHeuristicsTests
PrimeOrderGpuHeuristics.OverrideCapabilitiesForTesting(capability);
try
{
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(prime);
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(1UL, prime, out ulong remainder, divisorData);
status.Should().Be(GpuPow2ModStatus.Overflow);
@@ -76,7 +76,7 @@ public class PrimeOrderGpuHeuristicsTests
try
{
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);
status.Should().Be(GpuPow2ModStatus.Overflow);
@@ -102,7 +102,7 @@ public class PrimeOrderGpuHeuristicsTests
ulong[] remainders = new ulong[2];
ulong[] exponents = { 1UL, 2UL };
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(prime);
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(exponents, prime, remainders, divisorData);
status.Should().Be(GpuPow2ModStatus.Overflow);
@@ -121,7 +121,7 @@ public class PrimeOrderGpuHeuristicsTests
ulong[] remainders = { 123UL, 456UL };
ulong[] exponents = { 138_000_001UL, 138_000_011UL };
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);
ulong expectedFirst = (ulong)BigInteger.ModPow(2, exponents[0], prime);
@@ -145,7 +145,7 @@ public class PrimeOrderGpuHeuristicsTests
ulong[] exponents = { 1UL, 2UL };
ulong[] remainders = { 5UL, 6UL };
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(prime);
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(exponents, prime, remainders, divisorData);
status.Should().Be(GpuPow2ModStatus.Overflow);
@@ -170,7 +170,7 @@ public class PrimeOrderGpuHeuristicsTests
ulong[] remainders = { 9UL, 11UL };
const ulong prime = 193UL;
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(prime);
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(exponents, prime, remainders, divisorData);
status.Should().Be(GpuPow2ModStatus.Overflow);
@@ -362,7 +362,7 @@ public class PrimeOrderGpuHeuristicsTests
{
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);
result.Should().Be(3UL);
@@ -17,7 +17,7 @@ public class ULongExtensionsGpuTests
[InlineData(65535UL, 2147483647UL)]
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);
exponent.Pow2ModWindowedGpu(modulus).Should().Be(expected);
@@ -51,7 +51,7 @@ public class ULongExtensionsGpuTests
foreach (ulong modulus in moduli)
{
MontgomeryDivisorData divisor = MontgomeryDivisorData.FromModulus(modulus);
MontgomeryDivisorData divisor = MontgomeryDivisorDataPool.Shared.FromModulus(modulus);
foreach (ulong exponent in exponents)
{
ulong expected = exponent.Pow2MontgomeryModWindowedCpu(divisor, keepMontgomery: false);
@@ -38,7 +38,7 @@ public class MersenneDivisorCyclesGenerateGpuTests
foreach (var pair in pairs)
{
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));
}
}
@@ -87,7 +87,7 @@ public class MersenneDivisorCyclesGenerateGpuTests
foreach (var pair in pairs)
{
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));
}
@@ -18,7 +18,7 @@ public class MersenneDivisorCyclesTests
[MemberData(nameof(Divisors))]
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.CalculateCycleLengthGpu(divisor).Should().Be(expected);
}
@@ -39,13 +39,13 @@ public class MersenneNumberDivisorCpuTesterTests
ulong[] primes = { 5UL, 7UL, 11UL, 13UL };
byte[] hits = new byte[primes.Length];
ulong cycle23 = MersenneDivisorCycles.CalculateCycleLength(23UL, MontgomeryDivisorData.FromModulus(23UL));
session.CheckDivisor(23UL, MontgomeryDivisorData.FromModulus(23UL), cycle23, primes, hits);
ulong cycle23 = MersenneDivisorCycles.CalculateCycleLength(23UL, MontgomeryDivisorDataPool.Shared.FromModulus(23UL));
session.CheckDivisor(23UL, MontgomeryDivisorDataPool.Shared.FromModulus(23UL), cycle23, primes, hits);
hits.Should().ContainInOrder(new byte[] { 0, 0, 1, 0 });
Array.Fill(hits, (byte)0);
ulong cycle31 = MersenneDivisorCycles.CalculateCycleLength(31UL, MontgomeryDivisorData.FromModulus(31UL));
session.CheckDivisor(31UL, MontgomeryDivisorData.FromModulus(31UL), cycle31, primes, hits);
ulong cycle31 = MersenneDivisorCycles.CalculateCycleLength(31UL, MontgomeryDivisorDataPool.Shared.FromModulus(31UL));
session.CheckDivisor(31UL, MontgomeryDivisorDataPool.Shared.FromModulus(31UL), cycle31, primes, hits);
hits.Should().ContainInOrder(new byte[] { 1, 0, 0, 0 });
}
finally
@@ -67,7 +67,7 @@ public class MersenneNumberDivisorCpuTesterTests
ulong[] exponents = { 6UL, 7UL, 9UL, 10UL, 12UL };
byte[] hits = new byte[exponents.Length];
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(7UL);
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(7UL);
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(7UL, divisorData);
session.CheckDivisor(7UL, divisorData, cycle, exponents, hits);
@@ -92,7 +92,7 @@ public class MersenneNumberDivisorCpuTesterTests
ulong[] exponents = { 10UL, 11UL, 20UL, 21UL, 30UL };
byte[] hits = new byte[exponents.Length];
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(11UL);
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(11UL);
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(11UL, divisorData);
session.CheckDivisor(11UL, divisorData, cycle, exponents, hits);
@@ -170,7 +170,7 @@ public class MersenneNumberDivisorGpuTesterTests
ulong[] primes = { 31UL, 37UL, 41UL };
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 });
}
@@ -193,13 +193,13 @@ public class MersenneNumberDivisorGpuTesterTests
ulong[] primes = { 31UL, 37UL, 41UL, 43UL };
byte[] hits = new byte[primes.Length];
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLength(223UL, MontgomeryDivisorData.FromModulus(223UL));
session.CheckDivisor(223UL, MontgomeryDivisorData.FromModulus(223UL), cycle223, primes, hits);
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLength(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL));
session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primes, hits);
hits.Should().ContainInOrder(new byte[] { 0, 1, 0, 0 });
Array.Fill(hits, (byte)0);
ulong cycle13367 = MersenneDivisorCycles.CalculateCycleLength(13367UL, MontgomeryDivisorData.FromModulus(13367UL));
session.CheckDivisor(13367UL, MontgomeryDivisorData.FromModulus(13367UL), cycle13367, primes, hits);
ulong cycle13367 = MersenneDivisorCycles.CalculateCycleLength(13367UL, MontgomeryDivisorDataPool.Shared.FromModulus(13367UL));
session.CheckDivisor(13367UL, MontgomeryDivisorDataPool.Shared.FromModulus(13367UL), cycle13367, primes, hits);
hits.Should().ContainInOrder(new byte[] { 0, 0, 1, 0 });
}
finally
@@ -225,8 +225,8 @@ public class MersenneNumberDivisorGpuTesterTests
ulong[] primes = { 31UL, 37UL, 41UL, 43UL, 47UL };
byte[] hits = new byte[primes.Length];
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLength(223UL, MontgomeryDivisorData.FromModulus(223UL));
session.CheckDivisor(223UL, MontgomeryDivisorData.FromModulus(223UL), cycle223, primes, hits);
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLength(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL));
session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primes, hits);
hits.Should().ContainInOrder(new byte[] { 0, 1, 0, 0, 0 });
}
@@ -252,7 +252,7 @@ public class MersenneNumberDivisorGpuTesterTests
ulong[] exponents = { 6UL, 7UL, 9UL, 10UL, 12UL };
byte[] hits = new byte[exponents.Length];
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(7UL);
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(7UL);
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(7UL, divisorData);
session.CheckDivisor(7UL, divisorData, cycle, exponents, hits);
@@ -281,7 +281,7 @@ public class MersenneNumberDivisorGpuTesterTests
ulong[] exponents = { 10UL, 11UL, 20UL, 21UL, 30UL };
byte[] hits = new byte[exponents.Length];
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(11UL);
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(11UL);
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(11UL, divisorData);
session.CheckDivisor(11UL, divisorData, cycle, exponents, hits);
@@ -310,7 +310,7 @@ public class MersenneNumberDivisorGpuTesterTests
var patchedTable = new List<(ulong Divisor, ulong Cycle)>();
ulong[] patchedSmall = new ulong[PerfectNumberConstants.MaxQForDivisorCycles + 1];
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(191UL);
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(191UL);
patchedSmall[191] = MersenneDivisorCycles.CalculateCycleLength(191UL, divisorData);
tableField.SetValue(cycles, patchedTable);
@@ -353,8 +353,8 @@ public class MersenneNumberDivisorGpuTesterTests
ulong[] primes = { 31UL, 37UL, 41UL, 43UL, 47UL };
byte[] hits = new byte[primes.Length];
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLength(223UL, MontgomeryDivisorData.FromModulus(223UL));
session.CheckDivisor(223UL, MontgomeryDivisorData.FromModulus(223UL), cycle223, primes, hits);
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLength(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL));
session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primes, hits);
hits.Should().ContainInOrder(new byte[] { 0, 1, 0, 0, 0 });
}
@@ -46,7 +46,7 @@ public class PrimeOrderCalculatorTests
ulong result = PrimeOrderCalculator.Calculate(
prime,
previousOrder: null,
MontgomeryDivisorData.FromModulus(prime),
MontgomeryDivisorDataPool.Shared.FromModulus(prime),
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
@@ -63,14 +63,14 @@ public class PrimeOrderCalculatorTests
ulong heuristic = PrimeOrderCalculator.Calculate(
prime,
previousOrder,
MontgomeryDivisorData.FromModulus(prime),
MontgomeryDivisorDataPool.Shared.FromModulus(prime),
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
ulong strict = PrimeOrderCalculator.Calculate(
prime,
previousOrder: null,
MontgomeryDivisorData.FromModulus(prime),
MontgomeryDivisorDataPool.Shared.FromModulus(prime),
PrimeOrderCalculator.PrimeOrderSearchConfig.StrictDefault,
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
@@ -86,7 +86,7 @@ public class PrimeOrderCalculatorTests
ulong result = PrimeOrderCalculator.Calculate(
prime,
previousOrder: null,
MontgomeryDivisorData.FromModulus(prime),
MontgomeryDivisorDataPool.Shared.FromModulus(prime),
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
@@ -106,7 +106,7 @@ public class PrimeOrderCalculatorTests
ulong result = PrimeOrderCalculator.Calculate(
prime: 13UL,
previousOrder: null,
MontgomeryDivisorData.FromModulus(13UL),
MontgomeryDivisorDataPool.Shared.FromModulus(13UL),
config,
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
@@ -123,7 +123,7 @@ public class PrimeOrderCalculatorTests
maxPowChecks: 1,
mode: PrimeOrderCalculator.PrimeOrderMode.Heuristic);
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(239UL);
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(239UL);
ulong heuristic = PrimeOrderCalculator.Calculate(
prime: 239UL,
previousOrder: null,