Move pending entry pooling into shared thread pools
This commit is contained in:
1 parent
be7c2b7ae5
commit
83bcd8a0de
2 files changed
+134
-11
No files matched your search
@@ -1,4 +1,5 @@
|
|||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
@@ -10,6 +11,19 @@ namespace PerfectNumbers.Core;
|
|||||||
|
|
||||||
internal static partial class PrimeOrderCalculator
|
internal static partial class PrimeOrderCalculator
|
||||||
{
|
{
|
||||||
|
|
||||||
|
internal readonly struct PendingEntry
|
||||||
|
{
|
||||||
|
public readonly ulong Value;
|
||||||
|
public readonly bool KnownComposite;
|
||||||
|
|
||||||
|
public PendingEntry(ulong value, bool knownComposite)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
KnownComposite = knownComposite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static ulong CalculateInternal(ulong prime, ulong? previousOrder, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config)
|
private static ulong CalculateInternal(ulong prime, ulong? previousOrder, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config)
|
||||||
{
|
{
|
||||||
// TODO: Is this condition ever met on EvenPerfectBitScanner's execution path? If not, we can add a clarification comment and comment out the entire block. We want to support p candidates at least greater or equal to 31.
|
// TODO: Is this condition ever met on EvenPerfectBitScanner's execution path? If not, we can add a clarification comment and comment out the entire block. We want to support p candidates at least greater or equal to 31.
|
||||||
@@ -729,7 +743,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
gpuFactored = PrimeOrderGpuHeuristics.TryPartialFactor(value, limit, primeSlots, exponentSlots, out factorCount, out remaining, out _);
|
gpuFactored = PrimeOrderGpuHeuristics.TryPartialFactor(value, limit, primeSlots, exponentSlots, out factorCount, out remaining, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ulong> pending = ThreadStaticPools.RentUlongList(2);
|
List<PendingEntry> pending = ThreadStaticPools.RentPrimeOrderPendingEntryList(2);
|
||||||
Stack<ulong>? compositeStack = null;
|
Stack<ulong>? compositeStack = null;
|
||||||
PartialFactorResult result;
|
PartialFactorResult result;
|
||||||
|
|
||||||
@@ -775,7 +789,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
|
|
||||||
if (remaining > 1UL)
|
if (remaining > 1UL)
|
||||||
{
|
{
|
||||||
pending.Add(remaining);
|
pending.Add(new PendingEntry(remaining, knownComposite: false));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.PollardRhoMilliseconds > 0 && pending.Count > 0)
|
if (config.PollardRhoMilliseconds > 0 && pending.Count > 0)
|
||||||
@@ -807,7 +821,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
|
|
||||||
if (!TryPollardRho(composite, deadlineTimestamp, out ulong factor))
|
if (!TryPollardRho(composite, deadlineTimestamp, out ulong factor))
|
||||||
{
|
{
|
||||||
pending.Add(composite);
|
pending.Add(new PendingEntry(composite, knownComposite: true));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -823,17 +837,27 @@ internal static partial class PrimeOrderCalculator
|
|||||||
{
|
{
|
||||||
while (compositeStack.Count > 0)
|
while (compositeStack.Count > 0)
|
||||||
{
|
{
|
||||||
pending.Add(compositeStack.Pop());
|
pending.Add(new PendingEntry(compositeStack.Pop(), knownComposite: false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong cofactor = 1UL;
|
ulong cofactor = 1UL;
|
||||||
|
bool cofactorContainsComposite = false;
|
||||||
int pendingCount = pending.Count;
|
int pendingCount = pending.Count;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (; index < pendingCount; index++)
|
for (; index < pendingCount; index++)
|
||||||
{
|
{
|
||||||
ulong composite = pending[index];
|
PendingEntry entry = pending[index];
|
||||||
|
ulong composite = entry.Value;
|
||||||
|
|
||||||
|
if (entry.KnownComposite)
|
||||||
|
{
|
||||||
|
cofactor = checked(cofactor * composite);
|
||||||
|
cofactorContainsComposite = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
bool isPrime = GetOrComputePrimality(composite);
|
bool isPrime = GetOrComputePrimality(composite);
|
||||||
|
|
||||||
if (isPrime)
|
if (isPrime)
|
||||||
@@ -845,10 +869,23 @@ internal static partial class PrimeOrderCalculator
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
cofactor = checked(cofactor * composite);
|
cofactor = checked(cofactor * composite);
|
||||||
|
cofactorContainsComposite = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cofactorIsPrime = GetOrComputePrimality(cofactor);
|
bool cofactorIsPrime;
|
||||||
|
if (cofactor <= 1UL)
|
||||||
|
{
|
||||||
|
cofactorIsPrime = false;
|
||||||
|
}
|
||||||
|
else if (cofactorContainsComposite)
|
||||||
|
{
|
||||||
|
cofactorIsPrime = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cofactorIsPrime = GetOrComputePrimality(cofactor);
|
||||||
|
}
|
||||||
ArrayPool<FactorEntry> pool = ThreadStaticPools.FactorEntryPool;
|
ArrayPool<FactorEntry> pool = ThreadStaticPools.FactorEntryPool;
|
||||||
bool temp;
|
bool temp;
|
||||||
if (useDictionary)
|
if (useDictionary)
|
||||||
@@ -931,7 +968,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
}
|
}
|
||||||
|
|
||||||
pending.Clear();
|
pending.Clear();
|
||||||
ThreadStaticPools.ReturnUlongList(pending);
|
ThreadStaticPools.ReturnPrimeOrderPendingEntryList(pending);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1360,22 +1397,67 @@ internal static partial class PrimeOrderCalculator
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void FactorCompletely(ulong value, Dictionary<ulong, int> counts)
|
private static void FactorCompletely(ulong value, Dictionary<ulong, int> counts)
|
||||||
|
{
|
||||||
|
FactorCompletely(value, counts, knownComposite: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void FactorCompletely(ulong value, Dictionary<ulong, int> counts, bool knownComposite)
|
||||||
{
|
{
|
||||||
if (value <= 1UL)
|
if (value <= 1UL)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (Open.Numeric.Primes.Prime.Numbers.IsPrime(value))
|
if (!knownComposite && GetOrComputePrimality(value))
|
||||||
if (GetOrComputePrimality(value))
|
|
||||||
{
|
{
|
||||||
AddFactor(counts, value, 1);
|
AddFactor(counts, value, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong factor = PollardRhoStrict(value);
|
ulong factor = PollardRhoStrict(value);
|
||||||
FactorCompletely(factor, counts);
|
ulong quotient = value / factor;
|
||||||
FactorCompletely(value / factor, counts);
|
|
||||||
|
bool factorIsPrime = GetOrComputePrimality(factor);
|
||||||
|
if (factorIsPrime)
|
||||||
|
{
|
||||||
|
int exponent = 1;
|
||||||
|
ulong remaining = quotient;
|
||||||
|
while ((remaining % factor) == 0UL)
|
||||||
|
{
|
||||||
|
remaining /= factor;
|
||||||
|
exponent++;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddFactor(counts, factor, exponent);
|
||||||
|
|
||||||
|
if (remaining > 1UL)
|
||||||
|
{
|
||||||
|
FactorCompletely(remaining, counts, knownComposite: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FactorCompletely(factor, counts, knownComposite: true);
|
||||||
|
|
||||||
|
bool quotientIsPrime;
|
||||||
|
if (quotient == factor)
|
||||||
|
{
|
||||||
|
quotientIsPrime = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
quotientIsPrime = GetOrComputePrimality(quotient);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quotientIsPrime)
|
||||||
|
{
|
||||||
|
AddFactor(counts, quotient, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FactorCompletely(quotient, counts, knownComposite: true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ulong PollardRhoStrict(ulong n)
|
private static ulong PollardRhoStrict(ulong n)
|
||||||
|
|||||||
@@ -131,6 +131,47 @@ namespace PerfectNumbers.Core
|
|||||||
pool.Add(list);
|
pool.Add(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ThreadStatic]
|
||||||
|
private static List<List<PrimeOrderCalculator.PendingEntry>>? _primeOrderPendingEntryListPool;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal static List<PrimeOrderCalculator.PendingEntry> RentPrimeOrderPendingEntryList(int capacityHint)
|
||||||
|
{
|
||||||
|
List<List<PrimeOrderCalculator.PendingEntry>>? pool = _primeOrderPendingEntryListPool;
|
||||||
|
if (pool is not null && pool.Count > 0)
|
||||||
|
{
|
||||||
|
int lastIndex = pool.Count - 1;
|
||||||
|
List<PrimeOrderCalculator.PendingEntry> list = pool[lastIndex];
|
||||||
|
pool.RemoveAt(lastIndex);
|
||||||
|
if (list.Count > 0)
|
||||||
|
{
|
||||||
|
list.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list.Capacity < capacityHint)
|
||||||
|
{
|
||||||
|
list.Capacity = capacityHint;
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new List<PrimeOrderCalculator.PendingEntry>(capacityHint);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal static void ReturnPrimeOrderPendingEntryList(List<PrimeOrderCalculator.PendingEntry> list)
|
||||||
|
{
|
||||||
|
List<List<PrimeOrderCalculator.PendingEntry>>? pool = _primeOrderPendingEntryListPool;
|
||||||
|
if (pool is null)
|
||||||
|
{
|
||||||
|
pool = new List<List<PrimeOrderCalculator.PendingEntry>>(4);
|
||||||
|
_primeOrderPendingEntryListPool = pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
pool.Add(list);
|
||||||
|
}
|
||||||
|
|
||||||
[ThreadStatic]
|
[ThreadStatic]
|
||||||
private static List<Stack<ulong>>? _ulongStackPool;
|
private static List<Stack<ulong>>? _ulongStackPool;
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user