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