Reusable buffers introduced.

This commit is contained in:
mlemanczyk committed 2025-12-13 04:16:05 +01:00
1 parent fd58079c5a
commit 39a66fdef1
8 files changed
+829 -1056

No files matched your search

+64 -109
View File
@@ -1,154 +1,109 @@
using System.Collections.Generic;
using System.Numerics;
using System.Runtime.CompilerServices;
using PerfectNumbers.Core.Gpu;
namespace PerfectNumbers.Core
{
public sealed class PartialFactorResult
{
private const int ExponentHardLimit = 256;
[ThreadStatic]
private static PartialFactorResult? s_poolHead;
public ulong[]? Factors;
public int[]? Exponents;
private PartialFactorResult? _next;
public ulong Cofactor;
public bool FullyFactored;
public int Count;
public bool CofactorIsPrime;
private PartialFactorResult()
{
}
public static PartialFactorResult Rent(in ulong[]? factors, in int[]? exponents, ulong cofactor, bool fullyFactored, int count, bool cofactorIsPrime)
{
PartialFactorResult? instance = s_poolHead;
if (instance is null)
{
instance = new PartialFactorResult();
}
else
{
s_poolHead = instance._next;
}
instance._next = null;
instance.Factors = factors;
instance.Exponents = exponents;
instance.Cofactor = cofactor;
instance.FullyFactored = fullyFactored;
instance.Count = count;
instance.CofactorIsPrime = cofactorIsPrime;
return instance;
}
public static PartialFactorResult Rent(ulong cofactor, bool fullyFactored, int count, bool cofactorIsPrime)
{
PartialFactorResult? instance = s_poolHead;
if (instance is null)
{
instance = new PartialFactorResult();
}
else
{
s_poolHead = instance._next;
}
instance._next = null;
instance.Factors = null;
instance.Exponents = null;
instance.Cofactor = cofactor;
instance.FullyFactored = fullyFactored;
instance.Count = count;
instance.CofactorIsPrime = cofactorIsPrime;
return instance;
}
public static readonly PartialFactorResult Empty = new()
public static readonly PartialFactorResult Empty = new(MontgomeryDivisorData.Empty)
{
Cofactor = 1UL,
FullyFactored = true
};
internal readonly List<PartialFactorPendingEntry> Pending = new(PrimeOrderConstants.GpuSmallPrimeFactorSlots);
internal readonly FixedCapacityStack<ulong> CompositeStack = new(PrimeOrderConstants.GpuSmallPrimeFactorSlots);
internal readonly ulong[] SpecialMaxBuffer = new ulong[PrimeOrderConstants.GpuSmallPrimeFactorSlots];
public readonly ulong[] Factors = new ulong[ExponentHardLimit];
public readonly int[] Exponents = new int[ExponentHardLimit];
public readonly ulong[] FactorCandidates = new ulong[ExponentHardLimit];
public readonly List<ulong> FactorCandidatesList = new(ExponentHardLimit);
public readonly ulong[] ValidateOrderFactorCandidates = new ulong[ExponentHardLimit];
public readonly bool[] FactorCandidateEvaluations = new bool[ExponentHardLimit];
internal readonly Dictionary<ulong, int> FactorCounts = new(capacity: 8);
public ExponentRemainderStepperCpu ExponentRemainderStepper;
private PartialFactorResult? _next;
public ulong Cofactor;
public bool CofactorIsPrime;
public int Count;
public bool FullyFactored;
public bool HasFactors;
private PartialFactorResult(in MontgomeryDivisorData divisorData)
{
ExponentRemainderStepper = new(divisorData);
}
public static PartialFactorResult Rent(in MontgomeryDivisorData divisorData)
{
if (s_poolHead is { } instance)
{
s_poolHead = instance._next;
instance._next = null;
instance.Cofactor = 0UL;
instance.FullyFactored = false;
instance.Count = 0;
instance.CofactorIsPrime = false;
instance.HasFactors = false;
if (!instance.ExponentRemainderStepper.MatchesDivisor(divisorData, 0UL))
{
instance.ExponentRemainderStepper = new ExponentRemainderStepperCpu(divisorData, 0UL);
}
return instance;
}
return new PartialFactorResult(divisorData);
}
public void WithAdditionalPrime(ulong prime)
{
ulong[]? sourceFactors = Factors;
ulong[] sourceFactors = Factors;
int sourceCount = Count;
if (sourceFactors is null || sourceCount == 0)
if (sourceCount == 0)
{
InitializeWithPrime(prime);
return;
}
int newSize = (int)BitOperations.RoundUpToPowerOf2((uint)sourceCount + 1U);
ulong[] extendedFactors = sourceFactors.Length >= newSize
? sourceFactors
: ResizeFactors(sourceFactors, sourceCount, newSize);
int[] sourceExponents = Exponents;
int[] sourceExponents = Exponents!;
int[] extendedExponents = sourceExponents.Length >= newSize
? sourceExponents
: ResizeExponents(sourceCount, newSize, sourceExponents);
int newSize = sourceCount + 1;
sourceFactors[sourceCount] = prime;
sourceExponents[sourceCount] = 1;
Array.Sort(sourceFactors, sourceExponents, 0, newSize);
newSize = sourceCount + 1;
extendedFactors[sourceCount] = prime;
extendedExponents[sourceCount] = 1;
Array.Sort(extendedFactors, extendedExponents, 0, newSize);
Factors = extendedFactors;
Exponents = extendedExponents;
Cofactor = 1UL;
FullyFactored = true;
Count = newSize;
CofactorIsPrime = false;
}
private static int[] ResizeExponents(int sourceCount, int newSize, in int[] sourceExponents)
{
int[] extendedExponents = FixedCapacityPools.ExclusiveIntArray.Rent(newSize);
Array.Copy(sourceExponents, 0, extendedExponents, 0, sourceCount);
FixedCapacityPools.ExclusiveIntArray.Return(sourceExponents);
return extendedExponents;
}
private static ulong[] ResizeFactors(in ulong[] sourceFactors, int sourceCount, int newSize)
{
ulong[] extendedFactors = FixedCapacityPools.ExclusiveUlongArray.Rent(newSize);
Array.Copy(sourceFactors, 0, extendedFactors, 0, sourceCount);
FixedCapacityPools.ExclusiveUlongArray.Return(sourceFactors);
return extendedFactors;
HasFactors = true;
}
private void InitializeWithPrime(ulong prime)
{
ulong[] factors = FixedCapacityPools.ExclusiveUlongArray.Rent(1);
int[] exponents = FixedCapacityPools.ExclusiveIntArray.Rent(1);
factors[0] = prime;
exponents[0] = 1;
Factors = factors;
Exponents = exponents;
Factors[0] = prime;
Exponents[0] = 1;
Cofactor = 1UL;
FullyFactored = true;
Count = 1;
CofactorIsPrime = false;
HasFactors = true;
}
public void Dispose()
{
if (this != Empty)
{
ulong[]? factors = Factors;
if (factors is not null)
{
int[] exponents = Exponents!;
Factors = null;
Exponents = null;
FixedCapacityPools.ExclusiveUlongArray.Return(factors);
FixedCapacityPools.ExclusiveIntArray.Return(exponents);
}
_next = s_poolHead;
s_poolHead = this;
}