Dictionary and List pooling added in PrimeOrderCalculator.Cpu.
This commit is contained in:
1 parent
7518ba396e
commit
72890bf343
3 files changed
+133
-41
No files matched your search
@@ -12,28 +12,12 @@ namespace PerfectNumbers.Core;
|
||||
|
||||
internal static partial class PrimeOrderCalculator
|
||||
{
|
||||
internal struct PendingEntry
|
||||
internal struct PendingEntry(ulong value, bool knownComposite)
|
||||
{
|
||||
public ulong Value;
|
||||
public bool KnownComposite;
|
||||
public bool HasKnownPrimality;
|
||||
public bool IsPrime;
|
||||
|
||||
public PendingEntry(ulong value, bool knownComposite)
|
||||
{
|
||||
Value = value;
|
||||
KnownComposite = knownComposite;
|
||||
HasKnownPrimality = knownComposite;
|
||||
IsPrime = false;
|
||||
}
|
||||
|
||||
private PendingEntry(ulong value, bool knownComposite, bool hasKnownPrimality, bool isPrime)
|
||||
{
|
||||
Value = value;
|
||||
KnownComposite = knownComposite;
|
||||
HasKnownPrimality = hasKnownPrimality;
|
||||
IsPrime = isPrime;
|
||||
}
|
||||
public readonly ulong Value = value;
|
||||
public bool KnownComposite = knownComposite;
|
||||
public bool HasKnownPrimality = knownComposite;
|
||||
public bool IsPrime = false;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WithPrimality(bool isPrime)
|
||||
@@ -248,18 +232,24 @@ internal static partial class PrimeOrderCalculator
|
||||
private static UInt128 FinishStrictlyWideCpu(in UInt128 prime, in MontgomeryDivisorData? divisorData)
|
||||
{
|
||||
UInt128 phi = prime - UInt128.One;
|
||||
Dictionary<UInt128, int> counts = new(capacity: 8);
|
||||
Queue<Dictionary<UInt128, int>> uInt128IntDictionaryPool = ThreadStaticPools.UInt128IntDictionaryPool;
|
||||
Dictionary<UInt128, int> counts = uInt128IntDictionaryPool.Rent(capacity: 8);
|
||||
FactorCompletelyWide(phi, counts);
|
||||
if (counts.Count == 0)
|
||||
int entryCount = counts.Count;
|
||||
if (entryCount == 0)
|
||||
{
|
||||
uInt128IntDictionaryPool.Return(counts);
|
||||
return phi;
|
||||
}
|
||||
|
||||
List<KeyValuePair<UInt128, int>> entries = new(counts);
|
||||
entries.Sort(static (a, b) => a.Key.CompareTo(b.Key));
|
||||
Queue<List<KeyValuePair<UInt128, int>>> keyValuePairUInt128IntegerPool = ThreadStaticPools.KeyValuePairUInt128IntegerPool;
|
||||
var entries = keyValuePairUInt128IntegerPool.Rent(entryCount);
|
||||
entries.AddRange(counts);
|
||||
uInt128IntDictionaryPool.Return(counts);
|
||||
|
||||
entries.Sort(static (a, b) => a.Key.CompareTo(b.Key));
|
||||
|
||||
UInt128 order = phi;
|
||||
int entryCount = entries.Count;
|
||||
for (int i = 0; i < entryCount; i++)
|
||||
{
|
||||
UInt128 primeFactor = entries[i].Key;
|
||||
@@ -281,6 +271,7 @@ internal static partial class PrimeOrderCalculator
|
||||
}
|
||||
}
|
||||
|
||||
keyValuePairUInt128IntegerPool.Return(entries);
|
||||
return order;
|
||||
}
|
||||
|
||||
@@ -456,19 +447,23 @@ internal static partial class PrimeOrderCalculator
|
||||
}
|
||||
|
||||
int capacity = config.MaxPowChecks <= 0 ? 64 : config.MaxPowChecks * 4;
|
||||
List<UInt128> candidates = new(capacity);
|
||||
Queue<List<UInt128>> uInt128ListPool = ThreadStaticPools.UInt128ListPool;
|
||||
List<UInt128> candidates = uInt128ListPool.Rent(capacity);
|
||||
FactorEntry128[] factorArray = orderFactors.Factors!;
|
||||
|
||||
BuildCandidatesWide(order, factorArray, orderFactors.Count, candidates, capacity);
|
||||
if (candidates.Count == 0)
|
||||
|
||||
int candidateCount = candidates.Count;
|
||||
if (candidateCount == 0)
|
||||
{
|
||||
uInt128ListPool.Return(candidates);
|
||||
return false;
|
||||
}
|
||||
|
||||
SortCandidatesWide(prime, previousOrder, candidates);
|
||||
|
||||
int powBudget = config.MaxPowChecks <= 0 ? candidates.Count : config.MaxPowChecks;
|
||||
int powBudget = config.MaxPowChecks <= 0 ? candidateCount : config.MaxPowChecks;
|
||||
int powUsed = 0;
|
||||
int candidateCount = candidates.Count;
|
||||
|
||||
for (int i = 0; i < candidateCount; i++)
|
||||
{
|
||||
@@ -491,9 +486,11 @@ internal static partial class PrimeOrderCalculator
|
||||
}
|
||||
|
||||
result = candidate;
|
||||
uInt128ListPool.Return(candidates);
|
||||
return true;
|
||||
}
|
||||
|
||||
uInt128ListPool.Return(candidates);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -990,7 +987,8 @@ internal static partial class PrimeOrderCalculator
|
||||
int[] exponentsArray = orderFactors.Exponents!;
|
||||
|
||||
BuildCandidates(order, factorArray, exponentsArray, orderFactors.Count, candidates, capacity);
|
||||
if (candidates.Count == 0)
|
||||
int candidateCount = candidates.Count;
|
||||
if (candidateCount == 0)
|
||||
{
|
||||
ThreadStaticPools.ReturnUlongList(candidates);
|
||||
return false;
|
||||
@@ -998,9 +996,8 @@ internal static partial class PrimeOrderCalculator
|
||||
|
||||
SortCandidates(prime, previousOrder, candidates);
|
||||
|
||||
int powBudget = config.MaxPowChecks <= 0 ? candidates.Count : config.MaxPowChecks;
|
||||
int powBudget = config.MaxPowChecks <= 0 ? candidateCount : config.MaxPowChecks;
|
||||
int powUsed = 0;
|
||||
int candidateCount = candidates.Count;
|
||||
Span<ulong> candidateSpan = CollectionsMarshal.AsSpan(candidates);
|
||||
ExponentRemainderStepperCpu powStepper = ThreadStaticPools.RentExponentStepperCpu(divisorData);
|
||||
bool powStepperInitialized = false;
|
||||
@@ -1120,7 +1117,8 @@ internal static partial class PrimeOrderCalculator
|
||||
int[] exponentsArray = orderFactors.Exponents!;
|
||||
|
||||
BuildCandidates(order, factorArray, exponentsArray, orderFactors.Count, candidates, capacity);
|
||||
if (candidates.Count == 0)
|
||||
int candidateCount = candidates.Count;
|
||||
if (candidateCount == 0)
|
||||
{
|
||||
ThreadStaticPools.ReturnUlongList(candidates);
|
||||
return false;
|
||||
@@ -1128,9 +1126,8 @@ internal static partial class PrimeOrderCalculator
|
||||
|
||||
SortCandidates(prime, previousOrder, candidates);
|
||||
|
||||
int powBudget = config.MaxPowChecks <= 0 ? candidates.Count : config.MaxPowChecks;
|
||||
int powBudget = config.MaxPowChecks <= 0 ? candidateCount : config.MaxPowChecks;
|
||||
int powUsed = 0;
|
||||
int candidateCount = candidates.Count;
|
||||
Span<ulong> candidateSpan = CollectionsMarshal.AsSpan(candidates);
|
||||
ExponentRemainderStepperCpu powStepper = ThreadStaticPools.RentExponentStepperCpu(divisorData);
|
||||
bool powStepperInitialized = false;
|
||||
@@ -1252,7 +1249,8 @@ internal static partial class PrimeOrderCalculator
|
||||
int[] exponentsArray = orderFactors.Exponents!;
|
||||
|
||||
BuildCandidates(order, factorArray, exponentsArray, orderFactors.Count, candidates, capacity);
|
||||
if (candidates.Count == 0)
|
||||
int candidateCount = candidates.Count;
|
||||
if (candidateCount == 0)
|
||||
{
|
||||
ThreadStaticPools.ReturnUlongList(candidates);
|
||||
return false;
|
||||
@@ -1260,9 +1258,8 @@ internal static partial class PrimeOrderCalculator
|
||||
|
||||
SortCandidates(prime, previousOrder, candidates);
|
||||
|
||||
int powBudget = config.MaxPowChecks <= 0 ? candidates.Count : config.MaxPowChecks;
|
||||
int powBudget = config.MaxPowChecks <= 0 ? candidateCount : config.MaxPowChecks;
|
||||
int powUsed = 0;
|
||||
int candidateCount = candidates.Count;
|
||||
bool allowGpuBatch = true;
|
||||
Span<ulong> candidateSpan = CollectionsMarshal.AsSpan(candidates);
|
||||
ExponentRemainderStepperCpu powStepper = ThreadStaticPools.RentExponentStepperCpu(divisorData);
|
||||
@@ -2877,10 +2874,11 @@ internal static partial class PrimeOrderCalculator
|
||||
private static ulong CalculateByFactorizationCpu(ulong prime, in MontgomeryDivisorData divisorData)
|
||||
{
|
||||
ulong phi = prime - 1UL;
|
||||
Dictionary<ulong, int> counts = new(capacity: 8);
|
||||
Dictionary<ulong, int> counts = ThreadStaticPools.RentFactorCountDictionary();
|
||||
FactorCompletelyCpu(phi, counts, false);
|
||||
if (counts.Count == 0)
|
||||
{
|
||||
ThreadStaticPools.ReturnFactorCountDictionary(counts);
|
||||
return phi;
|
||||
}
|
||||
|
||||
@@ -2916,6 +2914,7 @@ internal static partial class PrimeOrderCalculator
|
||||
}
|
||||
}
|
||||
|
||||
ThreadStaticPools.ReturnFactorCountDictionary(counts);
|
||||
return order;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ using PeterO.Numbers;
|
||||
|
||||
namespace PerfectNumbers.Core
|
||||
{
|
||||
public readonly struct ThreadStaticPools
|
||||
public static class ThreadStaticPools
|
||||
{
|
||||
[ThreadStatic]
|
||||
private static ArrayPool<EInteger>? _eintegerPool;
|
||||
@@ -21,6 +21,98 @@ namespace PerfectNumbers.Core
|
||||
}
|
||||
|
||||
[ThreadStatic]
|
||||
private static Queue<List<KeyValuePair<UInt128, int>>>? _keyValuePairUInt128IntegerPool;
|
||||
|
||||
public static Queue<List<KeyValuePair<UInt128, int>>> KeyValuePairUInt128IntegerPool
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get
|
||||
{
|
||||
return _keyValuePairUInt128IntegerPool ??= [];
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static List<KeyValuePair<UInt128, int>> Rent(this Queue<List<KeyValuePair<UInt128, int>>> pool, int capacity)
|
||||
{
|
||||
if (pool.TryDequeue(out var pooled))
|
||||
{
|
||||
if (capacity > pooled.Capacity)
|
||||
{
|
||||
pooled.Capacity = capacity;
|
||||
}
|
||||
|
||||
pooled.Clear();
|
||||
return pooled;
|
||||
}
|
||||
|
||||
return new(capacity);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Return(this Queue<List<KeyValuePair<UInt128, int>>> pool, List<KeyValuePair<UInt128, int>> list) => pool.Enqueue(list);
|
||||
|
||||
[ThreadStatic]
|
||||
private static Queue<List<UInt128>>? _uint128ListPool;
|
||||
|
||||
public static Queue<List<UInt128>> UInt128ListPool
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get
|
||||
{
|
||||
return _uint128ListPool ??= [];
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static List<UInt128> Rent(this Queue<List<UInt128>> pool, int capacity)
|
||||
{
|
||||
if (pool.TryDequeue(out var pooled))
|
||||
{
|
||||
if (capacity > pooled.Capacity)
|
||||
{
|
||||
pooled.Capacity = capacity;
|
||||
}
|
||||
|
||||
pooled.Clear();
|
||||
return pooled;
|
||||
}
|
||||
|
||||
return new(capacity);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Return(this Queue<List<UInt128>> pool, List<UInt128> list) => pool.Enqueue(list);
|
||||
|
||||
[ThreadStatic]
|
||||
private static Queue<Dictionary<UInt128, int>>? _uint128IntDictionaryPool;
|
||||
|
||||
public static Queue<Dictionary<UInt128, int>> UInt128IntDictionaryPool
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get
|
||||
{
|
||||
return _uint128IntDictionaryPool ??= [];
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Dictionary<UInt128, int> Rent(this Queue<Dictionary<UInt128, int>> pool, int capacity)
|
||||
{
|
||||
if (pool.TryDequeue(out var pooled))
|
||||
{
|
||||
pooled.EnsureCapacity(capacity);
|
||||
pooled.Clear();
|
||||
return pooled;
|
||||
}
|
||||
|
||||
return new(capacity);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Return(this Queue<Dictionary<UInt128, int>> pool, Dictionary<UInt128, int> dictionary) => pool.Enqueue(dictionary);
|
||||
|
||||
[ThreadStatic]
|
||||
private static ArrayPool<FactorEntry>? _factorEntryPool;
|
||||
|
||||
public static ArrayPool<FactorEntry> FactorEntryPool
|
||||
|
||||
Reference in new issue
Block a user