From 0fbd635828feeb345282b596374ebea6dd26d17f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Lema=C5=84czyk?= Date: Sun, 19 Oct 2025 23:35:08 +0200 Subject: [PATCH] Reuse pooled local cache for partial factor primality checks --- .../PrimeOrderCalculator.Cpu.cs | 51 +++++++------------ 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs b/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs index adf11e0..9f1d5c8 100644 --- a/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs +++ b/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs @@ -721,34 +721,8 @@ internal static partial class PrimeOrderCalculator } - [ThreadStatic] - private static Dictionary? _partialFactorPrimalityCache; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ResetPartialFactorPrimalityCache() - { - Dictionary? cache = _partialFactorPrimalityCache; - if (cache is not null && cache.Count > 0) - { - cache.Clear(); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Dictionary GetPartialFactorPrimalityCache() - { - Dictionary? cache = _partialFactorPrimalityCache; - if (cache is null) - { - cache = ThreadStaticPools.RentUlongBoolDictionary(4); - _partialFactorPrimalityCache = cache; - } - - return cache; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool EvaluatePrimalityPartialFactor(ulong candidate) + private static bool EvaluatePrimalityPartialFactor(ref Dictionary? localCache, ulong candidate) { if (TryGetCachedPrimality(candidate, out bool cached)) { @@ -758,7 +732,7 @@ internal static partial class PrimeOrderCalculator ulong globalCacheLimit = (ulong)PerfectNumberConstants.MaxQForDivisorCycles; if (candidate > globalCacheLimit) { - Dictionary? cache = _partialFactorPrimalityCache; + Dictionary? cache = localCache; if (cache is not null && cache.TryGetValue(candidate, out bool cachedValue)) { return cachedValue; @@ -770,7 +744,13 @@ internal static partial class PrimeOrderCalculator if (candidate > globalCacheLimit) { - Dictionary cache = GetPartialFactorPrimalityCache(); + Dictionary? cache = localCache; + if (cache is null) + { + cache = ThreadStaticPools.RentUlongBoolDictionary(4); + localCache = cache; + } + cache[candidate] = isPrime; } @@ -813,8 +793,8 @@ internal static partial class PrimeOrderCalculator List pending = ThreadStaticPools.RentPrimeOrderPendingEntryList(2); Stack? compositeStack = null; PartialFactorResult result; + Dictionary? primalityCache = null; - ResetPartialFactorPrimalityCache(); if (!gpuFactored) { @@ -887,7 +867,7 @@ internal static partial class PrimeOrderCalculator // continue; // } - bool isPrime = EvaluatePrimalityPartialFactor(composite); + bool isPrime = EvaluatePrimalityPartialFactor(ref primalityCache, composite); if (isPrime) { @@ -937,7 +917,7 @@ internal static partial class PrimeOrderCalculator continue; } - bool isPrime = EvaluatePrimalityPartialFactor(composite); + bool isPrime = EvaluatePrimalityPartialFactor(ref primalityCache, composite); if (isPrime) { @@ -963,7 +943,7 @@ internal static partial class PrimeOrderCalculator } else { - cofactorIsPrime = EvaluatePrimalityPartialFactor(cofactor); + cofactorIsPrime = EvaluatePrimalityPartialFactor(ref primalityCache, cofactor); } ArrayPool pool = ThreadStaticPools.FactorEntryPool; @@ -1038,6 +1018,11 @@ internal static partial class PrimeOrderCalculator // ThreadStaticPools.IntPool.Return(exponentSlotsArray); + if (primalityCache is not null) + { + ThreadStaticPools.ReturnUlongBoolDictionary(primalityCache); + } + if (counts is not null) { ThreadStaticPools.ReturnUlongIntDictionary(counts);