Cache divisor cycle suppression scopes

This commit is contained in:
Marek Lemańczyk committed 2025-10-11 17:35:00 +02:00
1 parent e1be80048f
commit 3c926e4909
1 file changed
+120 -29
+120 -29
View File
@@ -61,6 +61,18 @@ internal static partial class PrimeOrderCalculator
[ThreadStatic]
private static Dictionary<ulong, int>? s_partialFactorCounts;
[ThreadStatic]
private static ulong s_cachedDivisorCycleModulus;
[ThreadStatic]
private static ulong s_cachedDivisorCycleLength;
[ThreadStatic]
private static bool s_hasCachedDivisorCycle;
[ThreadStatic]
private static int s_divisorCycleSuppressionDepth;
private static bool IsGpuHeuristicDevice => s_pow2ModeInitialized && s_deviceMode == PrimeOrderHeuristicDevice.Gpu;
private readonly struct Pow2ModeScope
@@ -110,10 +122,45 @@ internal static partial class PrimeOrderCalculator
}
}
private static bool IsDivisorCycleSuppressed => s_divisorCycleSuppressionDepth > 0;
private readonly struct DivisorCycleSuppressionScope
{
private readonly bool _suppress;
private DivisorCycleSuppressionScope(bool suppress)
{
_suppress = suppress;
}
public static readonly DivisorCycleSuppressionScope Suppressed = new(true);
public static readonly DivisorCycleSuppressionScope Unsuppressed = new(false);
public void Enter()
{
if (_suppress)
{
s_divisorCycleSuppressionDepth++;
}
}
public void Exit()
{
if (_suppress)
{
s_divisorCycleSuppressionDepth--;
}
}
}
private static Pow2ModeScope UsePow2Mode(PrimeOrderHeuristicDevice device) => new(device);
private static DebugLoggingScope UseDebugLogging(bool enabled) => new(enabled);
private static DivisorCycleSuppressionScope SuppressDivisorCycleUsage(bool suppress) =>
suppress ? DivisorCycleSuppressionScope.Suppressed : DivisorCycleSuppressionScope.Unsuppressed;
[Conditional("DEBUG")]
private static void DebugLog(string message)
{
@@ -187,43 +234,52 @@ internal static partial class PrimeOrderCalculator
ulong phi,
PartialFactorResult phiFactors)
{
if (phiFactors.FullyFactored && TrySpecialMaxCpu(phi, prime, phiFactors, divisorData))
var cycleScope = SuppressDivisorCycleUsage(config.Mode == PrimeOrderMode.Heuristic && !IsGpuHeuristicDevice);
cycleScope.Enter();
try
{
return phi;
}
if (phiFactors.FullyFactored && TrySpecialMaxCpu(phi, prime, phiFactors, divisorData))
{
return phi;
}
ulong candidateOrder = InitializeStartingOrderCpu(prime, phi, divisorData);
candidateOrder = ExponentLoweringCpu(candidateOrder, prime, phiFactors, divisorData);
ulong candidateOrder = InitializeStartingOrderCpu(prime, phi, divisorData);
candidateOrder = ExponentLoweringCpu(candidateOrder, prime, phiFactors, divisorData);
PartialFactorResult orderFactors = PartialFactor(candidateOrder, config);
if (orderFactors.Factors is null)
{
orderFactors.Dispose();
return candidateOrder;
}
// Reuse the computed factorization for both the confirmation check and the heuristic pass
// to avoid factoring the same order twice on the by-divisor CPU pipeline.
if (TryConfirmOrderCpu(prime, candidateOrder, divisorData, ref orderFactors))
{
orderFactors.Dispose();
return candidateOrder;
}
if (config.Mode == PrimeOrderMode.Strict)
{
orderFactors.Dispose();
return CalculateByFactorizationCpu(prime, divisorData, config);
}
if (TryHeuristicFinishCpu(prime, candidateOrder, previousOrder, divisorData, config, ref orderFactors, phiFactors, out ulong order))
{
orderFactors.Dispose();
return order;
}
PartialFactorResult orderFactors = PartialFactor(candidateOrder, config);
if (orderFactors.Factors is null)
{
orderFactors.Dispose();
return candidateOrder;
}
// Reuse the computed factorization for both the confirmation check and the heuristic pass
// to avoid factoring the same order twice on the by-divisor CPU pipeline.
if (TryConfirmOrderCpu(prime, candidateOrder, divisorData, ref orderFactors))
finally
{
orderFactors.Dispose();
return candidateOrder;
cycleScope.Exit();
}
if (config.Mode == PrimeOrderMode.Strict)
{
orderFactors.Dispose();
return CalculateByFactorizationCpu(prime, divisorData, config);
}
if (TryHeuristicFinishCpu(prime, candidateOrder, previousOrder, divisorData, config, ref orderFactors, phiFactors, out ulong order))
{
orderFactors.Dispose();
return order;
}
orderFactors.Dispose();
return candidateOrder;
}
private static bool TrySpecialMaxCpu(ulong phi, ulong prime, PartialFactorResult factors, in MontgomeryDivisorData divisorData)
@@ -787,6 +843,36 @@ internal static partial class PrimeOrderCalculator
}
}
private static bool TryGetDivisorCycle(ulong prime, in MontgomeryDivisorData divisorData, out ulong cycleLength)
{
if (prime <= 1UL || IsDivisorCycleSuppressed)
{
cycleLength = 0UL;
return false;
}
if (s_hasCachedDivisorCycle && s_cachedDivisorCycleModulus == prime)
{
cycleLength = s_cachedDivisorCycleLength;
return cycleLength != 0UL;
}
var suppression = SuppressDivisorCycleUsage(true);
suppression.Enter();
try
{
cycleLength = MersenneDivisorCycles.CalculateCycleLength(prime, divisorData);
s_cachedDivisorCycleModulus = prime;
s_cachedDivisorCycleLength = cycleLength;
s_hasCachedDivisorCycle = true;
return cycleLength != 0UL;
}
finally
{
suppression.Exit();
}
}
private static bool Pow2EqualsOneCpu(ulong exponent, ulong prime, in MontgomeryDivisorData divisorData)
{
if (IsGpuPow2Allowed)
@@ -798,6 +884,11 @@ internal static partial class PrimeOrderCalculator
}
}
if (TryGetDivisorCycle(prime, divisorData, out ulong cycleLength) && cycleLength != 0UL)
{
return exponent.Pow2MontgomeryModWithCycleCpu(cycleLength, divisorData) == 1UL;
}
return exponent.Pow2MontgomeryModWindowedCpu(divisorData, keepMontgomery: false) == 1UL;
}