From fb08a61c66c81eeacfb5ceb021092e2860fdeea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Lema=C5=84czyk?= Date: Thu, 16 Oct 2025 17:18:19 +0200 Subject: [PATCH] Restore pooled small factor buffers --- PerfectNumbers.Core/PrimeOrderCalculator.cs | 63 ++++++++++++--------- PerfectNumbers.Core/ThreadStaticPools.cs | 12 ++++ 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/PerfectNumbers.Core/PrimeOrderCalculator.cs b/PerfectNumbers.Core/PrimeOrderCalculator.cs index b3da51d..5ca1876 100644 --- a/PerfectNumbers.Core/PrimeOrderCalculator.cs +++ b/PerfectNumbers.Core/PrimeOrderCalculator.cs @@ -781,8 +781,10 @@ internal static partial class PrimeOrderCalculator } const int FactorSlotCount = GpuSmallPrimeFactorSlots; - Span primeSlots = stackalloc ulong[FactorSlotCount]; - Span exponentSlots = stackalloc int[FactorSlotCount]; + ulong[] primeSlotsArray = ThreadStaticPools.UlongPool.Rent(FactorSlotCount); + int[] exponentSlotsArray = ThreadStaticPools.IntPool.Rent(FactorSlotCount); + Span primeSlots = primeSlotsArray.AsSpan(0, FactorSlotCount); + Span exponentSlots = exponentSlotsArray.AsSpan(0, FactorSlotCount); primeSlots.Clear(); exponentSlots.Clear(); @@ -951,6 +953,9 @@ internal static partial class PrimeOrderCalculator result = PartialFactorResult.Rent(array, cofactor, fullyFactoredArray, arrayIndex); ReturnResult: + ThreadStaticPools.UlongPool.Return(primeSlotsArray); + ThreadStaticPools.IntPool.Return(exponentSlotsArray); + if (counts is not null) { ThreadStaticPools.ReturnUlongIntDictionary(counts); @@ -1079,34 +1084,40 @@ internal static partial class PrimeOrderCalculator return remaining; } - private static bool TryPopulateSmallPrimeFactorsGpu(ulong value, uint limit, Dictionary counts, out ulong remaining) - { - Span primeBuffer = stackalloc ulong[GpuSmallPrimeFactorSlots]; - Span exponentBuffer = stackalloc int[GpuSmallPrimeFactorSlots]; - primeBuffer.Clear(); - exponentBuffer.Clear(); + private static bool TryPopulateSmallPrimeFactorsGpu(ulong value, uint limit, Dictionary counts, out ulong remaining) + { + ulong[] primeBufferArray = ThreadStaticPools.UlongPool.Rent(GpuSmallPrimeFactorSlots); + int[] exponentBufferArray = ThreadStaticPools.IntPool.Rent(GpuSmallPrimeFactorSlots); + Span primeBuffer = primeBufferArray.AsSpan(0, GpuSmallPrimeFactorSlots); + Span exponentBuffer = exponentBufferArray.AsSpan(0, GpuSmallPrimeFactorSlots); + primeBuffer.Clear(); + exponentBuffer.Clear(); - if (!PrimeOrderGpuHeuristics.TryPartialFactor(value, limit, primeBuffer, exponentBuffer, out int factorCount, out ulong gpuRemaining, out _)) - { - remaining = value; - return false; - } + if (!PrimeOrderGpuHeuristics.TryPartialFactor(value, limit, primeBuffer, exponentBuffer, out int factorCount, out ulong gpuRemaining, out _)) + { + remaining = value; + ThreadStaticPools.UlongPool.Return(primeBufferArray); + ThreadStaticPools.IntPool.Return(exponentBufferArray); + return false; + } - remaining = gpuRemaining; - for (int i = 0; i < factorCount; i++) - { - ulong primeValue = primeBuffer[i]; - int exponent = exponentBuffer[i]; - if (primeValue == 0UL || exponent == 0) - { - continue; - } + remaining = gpuRemaining; + for (int i = 0; i < factorCount; i++) + { + ulong primeValue = primeBuffer[i]; + int exponent = exponentBuffer[i]; + if (primeValue == 0UL || exponent == 0) + { + continue; + } - counts[primeValue] = exponent; - } + counts[primeValue] = exponent; + } - return true; - } + ThreadStaticPools.UlongPool.Return(primeBufferArray); + ThreadStaticPools.IntPool.Return(exponentBufferArray); + return true; + } private static long CreateDeadlineTimestamp(int milliseconds) { if (milliseconds <= 0) diff --git a/PerfectNumbers.Core/ThreadStaticPools.cs b/PerfectNumbers.Core/ThreadStaticPools.cs index 9ba6060..ed00820 100644 --- a/PerfectNumbers.Core/ThreadStaticPools.cs +++ b/PerfectNumbers.Core/ThreadStaticPools.cs @@ -79,6 +79,18 @@ namespace PerfectNumbers.Core } } + [ThreadStatic] + private static ArrayPool? _intPool; + + public static ArrayPool IntPool + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return _intPool ??= ArrayPool.Create(); + } + } + [ThreadStatic] private static List>? _ulongListPool;