Use thread-static pools in CPU divisor testing

This commit is contained in:
Marek Lemańczyk committed 2025-10-15 18:10:39 +02:00
1 parent a70113a99d
commit e44662413a
3 files changed
+257 -105

No files matched your search

+70 -34
View File
@@ -17,13 +17,32 @@ public class MersenneDivisorCycles
private List<(ulong divisor, ulong cycleLength)> _table = [];
// Lightweight read-mostly cache for small divisors (<= 4,000,000). 0 => unknown
private ulong[]? _smallCycles;
public static MersenneDivisorCycles Shared { get; } = new MersenneDivisorCycles();
public MersenneDivisorCycles()
{
}
private static Dictionary<ulong, int> RentFactorCountDictionary()
{
return ThreadStaticPools.TakeFactorCountDictionary();
}
private static void ReturnFactorCountDictionary(Dictionary<ulong, int> dictionary)
{
ThreadStaticPools.ReturnFactorCountDictionary(dictionary);
}
private static Dictionary<ulong, int> RentFactorScratchDictionary()
{
return ThreadStaticPools.TakeFactorScratchDictionary();
}
private static void ReturnFactorScratchDictionary(Dictionary<ulong, int> dictionary)
{
ThreadStaticPools.ReturnFactorScratchDictionary(dictionary);
}
public void LoadFrom(string path)
{
EnsureSmallBuffer();
@@ -316,19 +335,27 @@ public class MersenneDivisorCycles
return false;
}
Dictionary<ulong, int> factorCounts = new(8);
if (twoCount > 0)
{
factorCounts[2UL] = twoCount;
}
Dictionary<ulong, int> factorCounts = RentFactorCountDictionary();
if (!AccumulateFactors(exponent, factorCache, factorCounts, cacheResult: true) || !AccumulateFactors(k, factorCache, factorCounts, cacheResult: false))
try
{
return false;
}
if (twoCount > 0)
{
factorCounts[2UL] = twoCount;
}
cycleLength = ReduceOrder(divisorData, phi, factorCounts);
return true;
if (!AccumulateFactors(exponent, factorCache, factorCounts, cacheResult: true) || !AccumulateFactors(k, factorCache, factorCounts, cacheResult: false))
{
return false;
}
cycleLength = ReduceOrder(divisorData, phi, factorCounts);
return true;
}
finally
{
ReturnFactorCountDictionary(factorCounts);
}
}
private static bool AccumulateFactors(
@@ -370,37 +397,46 @@ public class MersenneDivisorCycles
return true;
}
Dictionary<ulong, int> scratch = new(8);
if (!TryFactorIntoCountsInternal(value, scratch))
Dictionary<ulong, int> scratch = RentFactorScratchDictionary();
try
{
factorization = default!;
return false;
}
if (!TryFactorIntoCountsInternal(value, scratch))
{
factorization = default!;
return false;
}
int count = scratch.Count;
ulong[] primes = new ulong[count];
byte[] exponents = new byte[count];
int index = 0;
foreach (KeyValuePair<ulong, int> entry in scratch)
int count = scratch.Count;
ulong[] primes = new ulong[count];
byte[] exponents = new byte[count];
int index = 0;
foreach (KeyValuePair<ulong, int> entry in scratch)
{
primes[index] = entry.Key;
exponents[index] = checked((byte)entry.Value);
index++;
}
Array.Sort(primes, exponents);
factorization = new FactorCacheEntry(primes, exponents, count);
if (cache is not null && cacheResult)
{
cache[value] = factorization;
}
return true;
}
finally
{
primes[index] = entry.Key;
exponents[index] = checked((byte)entry.Value);
index++;
ReturnFactorScratchDictionary(scratch);
}
Array.Sort(primes, exponents);
factorization = new FactorCacheEntry(primes, exponents, count);
if (cache is not null && cacheResult)
{
cache[value] = factorization;
}
return true;
}
private static bool TryFactorIntoCountsInternal(ulong value, Dictionary<ulong, int> counts)
{
// This guard terminates the recursion once Pollard-Rho factorization has reduced the input to 1.
if (value <= 1UL)
{
return true;