Reduce GC pressure in divisor checking pipeline

This commit is contained in:
Marek Lemańczyk committed 2025-10-15 23:43:27 +02:00
1 parent 571b5a9938
commit 51730bcba3
2 files changed
+183 -142

No files matched your search

+60 -45
View File
@@ -346,48 +346,67 @@ public static class ULongExtensions
ulong result = divisor.MontgomeryOne;
ulong nPrime = divisor.NPrime;
ulong[] oddPowers = InitializeMontgomeryOddPowersCpu(divisor, modulus, nPrime, oddPowerCount);
const int StackOddPowerThreshold = PerfectNumberConstants.PooledArrayThreshold;
Span<ulong> oddPowersSpan = oddPowerCount <= StackOddPowerThreshold
? stackalloc ulong[StackOddPowerThreshold]
: default;
Span<ulong> oddPowers;
ulong[]? oddPowersArray = null;
if (!oddPowersSpan.IsEmpty)
{
oddPowers = oddPowersSpan.Slice(0, oddPowerCount);
}
else
{
oddPowersArray = ThreadStaticPools.UlongPool.Rent(oddPowerCount);
oddPowers = oddPowersArray.AsSpan(0, oddPowerCount);
}
InitializeMontgomeryOddPowersCpu(divisor, modulus, nPrime, oddPowers);
int index = bitLength - 1;
while (index >= 0)
{
if (((exponent >> index) & 1UL) == 0UL)
{
result = result.MontgomeryMultiply(result, modulus, nPrime);
index--;
continue;
}
while (index >= 0)
{
if (((exponent >> index) & 1UL) == 0UL)
{
result = result.MontgomeryMultiply(result, modulus, nPrime);
index--;
continue;
}
int windowStart = index - windowSize + 1;
if (windowStart < 0)
{
windowStart = 0;
}
int windowStart = index - windowSize + 1;
if (windowStart < 0)
{
windowStart = 0;
}
while (((exponent >> windowStart) & 1UL) == 0UL)
{
windowStart++;
}
while (((exponent >> windowStart) & 1UL) == 0UL)
{
windowStart++;
}
int windowLength = index - windowStart + 1;
for (int square = 0; square < windowLength; square++)
{
result = result.MontgomeryMultiply(result, modulus, nPrime);
}
int windowLength = index - windowStart + 1;
for (int square = 0; square < windowLength; square++)
{
result = result.MontgomeryMultiply(result, modulus, nPrime);
}
ulong mask = (1UL << windowLength) - 1UL;
ulong windowValue = (exponent >> windowStart) & mask;
int tableIndex = (int)((windowValue - 1UL) >> 1);
ulong multiplier = oddPowers[tableIndex];
result = result.MontgomeryMultiply(multiplier, modulus, nPrime);
ulong mask = (1UL << windowLength) - 1UL;
ulong windowValue = (exponent >> windowStart) & mask;
int tableIndex = (int)((windowValue - 1UL) >> 1);
ulong multiplier = oddPowers[tableIndex];
result = result.MontgomeryMultiply(multiplier, modulus, nPrime);
index = windowStart - 1;
}
if (oddPowerCount >= PerfectNumberConstants.PooledArrayThreshold)
{
ArrayPool<ulong>.Shared.Return(oddPowers);
}
index = windowStart - 1;
}
if (oddPowersArray is not null)
{
ThreadStaticPools.UlongPool.Return(oddPowersArray, clearArray: false);
}
if (keepMontgomery)
{
@@ -533,26 +552,22 @@ public static class ULongExtensions
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong[] InitializeMontgomeryOddPowersCpu(in MontgomeryDivisorData divisor, ulong modulus, ulong nPrime, int oddPowerCount)
private static void InitializeMontgomeryOddPowersCpu(in MontgomeryDivisorData divisor, ulong modulus, ulong nPrime, Span<ulong> oddPowers)
{
ulong[] oddPowers = oddPowerCount < PerfectNumberConstants.PooledArrayThreshold ? new ulong[oddPowerCount] : ArrayPool<ulong>.Shared.Rent(oddPowerCount);
oddPowers[0] = divisor.MontgomeryTwo;
if (oddPowerCount == 1)
if (oddPowers.Length == 1)
{
return oddPowers;
return;
}
ulong previous,
square = divisor.MontgomeryTwoSquared;
ulong previous;
ulong square = divisor.MontgomeryTwoSquared;
for (int i = 1; i < oddPowerCount; i++)
for (int i = 1; i < oddPowers.Length; i++)
{
previous = oddPowers[i - 1];
oddPowers[i] = previous.MontgomeryMultiply(square, modulus, nPrime);
}
return oddPowers;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]