diff --git a/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs b/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs index 237aac1..bf04f37 100644 --- a/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs +++ b/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Threading; using PerfectNumbers.Core.Gpu; namespace PerfectNumbers.Core; @@ -661,8 +662,41 @@ internal static partial class PrimeOrderCalculator return exponent.Pow2MontgomeryModWindowedCpu(divisorData, keepMontgomery: false) == 1UL; } - [ThreadStatic] - private static Dictionary? _primalityCache; + // [ThreadStatic] + private static readonly Dictionary _primalityCache = []; + private static readonly ReaderWriterLockSlim _primalityCacheLock = new(LockRecursionPolicy.NoRecursion); + + // [ThreadStatic] + // private static UInt128 _isPrimeHits; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryGetCachedPrimality(ulong value, out bool isPrime) + { + _primalityCacheLock.EnterReadLock(); + bool result = _primalityCache.TryGetValue(value, out isPrime); + _primalityCacheLock.ExitReadLock(); + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void CachePrimalityResult(ulong value, bool isPrime) + { + _primalityCacheLock.EnterWriteLock(); + _primalityCache[value] = isPrime; + _primalityCacheLock.ExitWriteLock(); + } + + private static bool GetOrComputePrimality(ulong value) + { + if (TryGetCachedPrimality(value, out bool isPrime)) + { + return isPrime; + } + + isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(value); + CachePrimalityResult(value, isPrime); + return isPrime; + } private static PartialFactorResult PartialFactor(ulong value, in PrimeOrderSearchConfig config) { @@ -700,7 +734,6 @@ internal static partial class PrimeOrderCalculator List pending = ThreadStaticPools.RentUlongList(2); Stack? compositeStack = null; PartialFactorResult result; - var cache = _primalityCache ??= []; if (!gpuFactored) { @@ -739,11 +772,7 @@ internal static partial class PrimeOrderCalculator // continue; // } - if (!cache.TryGetValue(composite, out bool isPrime)) - { - isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite); - cache.Add(composite, isPrime); - } + bool isPrime = GetOrComputePrimality(composite); if (isPrime) { @@ -779,11 +808,7 @@ internal static partial class PrimeOrderCalculator for (int i = 0; i < pendingCount; i++) { ulong composite = pending[i]; - if (!cache.TryGetValue(composite, out bool isPrime)) - { - isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite); - cache.Add(composite, isPrime); - } + bool isPrime = GetOrComputePrimality(composite); if (isPrime) {