From 534141e5a7c720c631acf35ed673fc2fded89180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Lema=C5=84czyk?= Date: Fri, 17 Oct 2025 03:50:09 +0200 Subject: [PATCH] Remove small prime stepper remainder cache --- .../PrimeOrderCalculator.Cpu.cs | 173 +----------------- PerfectNumbers.Core/ThreadStaticPools.cs | 24 --- 2 files changed, 2 insertions(+), 195 deletions(-) diff --git a/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs b/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs index bf04f37..bff32dc 100644 --- a/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs +++ b/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs @@ -10,18 +10,6 @@ namespace PerfectNumbers.Core; internal static partial class PrimeOrderCalculator { - [ThreadStatic] - private static CycleRemainderStepper[]? s_smallPrimeCycleSteppers; - - [ThreadStatic] - private static ulong[]? s_smallPrimeStepperPreviousValues; - - [ThreadStatic] - private static ulong[]? s_smallPrimeStepperRemainders; - - [ThreadStatic] - private static bool[]? s_smallPrimeStepperHasState; - private static ulong CalculateInternal(ulong prime, ulong? previousOrder, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config) { // TODO: Is this condition ever met on EvenPerfectBitScanner's execution path? If not, we can add a clarification comment and comment out the entire block. We want to support p candidates at least greater or equal to 31. @@ -907,128 +895,6 @@ internal static partial class PrimeOrderCalculator return result; } - private static CycleRemainderStepper[] EnsureSmallPrimeCycleSteppers(uint[] primes) - { - int primeCount = primes.Length; - CycleRemainderStepper[]? steppers = s_smallPrimeCycleSteppers; - ArrayPool stepperPool = ThreadStaticPools.CycleRemainderStepperPool; - ArrayPool ulongPool = ThreadStaticPools.UlongPool; - ArrayPool boolPool = ThreadStaticPools.BoolPool; - if (steppers is null || steppers.Length < primeCount) - { - CycleRemainderStepper[]? previousSteppers = steppers; - steppers = stepperPool.Rent(primeCount); - int stepperLength = steppers.Length; - for (int i = 0; i < primeCount; i++) - { - steppers[i] = new CycleRemainderStepper(primes[i]); - } - for (int i = primeCount; i < stepperLength; i++) - { - steppers[i] = default; - } - - if (previousSteppers is not null) - { - stepperPool.Return(previousSteppers, clearArray: false); - } - - if (s_smallPrimeStepperPreviousValues is not null) - { - ulongPool.Return(s_smallPrimeStepperPreviousValues, clearArray: false); - } - - if (s_smallPrimeStepperRemainders is not null) - { - ulongPool.Return(s_smallPrimeStepperRemainders, clearArray: false); - } - - if (s_smallPrimeStepperHasState is not null) - { - boolPool.Return(s_smallPrimeStepperHasState, clearArray: false); - } - - ulong[] previousValues = ulongPool.Rent(stepperLength); - Array.Clear(previousValues, 0, stepperLength); - ulong[] remainders = ulongPool.Rent(stepperLength); - Array.Clear(remainders, 0, stepperLength); - bool[] hasState = boolPool.Rent(stepperLength); - Array.Clear(hasState, 0, stepperLength); - - s_smallPrimeCycleSteppers = steppers; - s_smallPrimeStepperPreviousValues = previousValues; - s_smallPrimeStepperRemainders = remainders; - s_smallPrimeStepperHasState = hasState; - return steppers; - } - - int stepperCapacity = steppers.Length; - if (s_smallPrimeStepperPreviousValues is null || s_smallPrimeStepperPreviousValues.Length != stepperCapacity) - { - ulong[] newPrevious = ulongPool.Rent(stepperCapacity); - if (s_smallPrimeStepperPreviousValues is { } existingPrevious) - { - int copyLength = Math.Min(existingPrevious.Length, stepperCapacity); - System.Array.Copy(existingPrevious, newPrevious, copyLength); - if (copyLength < stepperCapacity) - { - Array.Clear(newPrevious, copyLength, stepperCapacity - copyLength); - } - ulongPool.Return(existingPrevious, clearArray: false); - } - else - { - Array.Clear(newPrevious, 0, stepperCapacity); - } - - s_smallPrimeStepperPreviousValues = newPrevious; - } - - if (s_smallPrimeStepperRemainders is null || s_smallPrimeStepperRemainders.Length != stepperCapacity) - { - ulong[] newRemainders = ulongPool.Rent(stepperCapacity); - if (s_smallPrimeStepperRemainders is { } existingRemainders) - { - int copyLength = Math.Min(existingRemainders.Length, stepperCapacity); - System.Array.Copy(existingRemainders, newRemainders, copyLength); - if (copyLength < stepperCapacity) - { - Array.Clear(newRemainders, copyLength, stepperCapacity - copyLength); - } - ulongPool.Return(existingRemainders, clearArray: false); - } - else - { - Array.Clear(newRemainders, 0, stepperCapacity); - } - - s_smallPrimeStepperRemainders = newRemainders; - } - - if (s_smallPrimeStepperHasState is null || s_smallPrimeStepperHasState.Length != stepperCapacity) - { - bool[] newHasState = boolPool.Rent(stepperCapacity); - if (s_smallPrimeStepperHasState is { } existingHasState) - { - int copyLength = Math.Min(existingHasState.Length, stepperCapacity); - System.Array.Copy(existingHasState, newHasState, copyLength); - if (copyLength < stepperCapacity) - { - Array.Clear(newHasState, copyLength, stepperCapacity - copyLength); - } - boolPool.Return(existingHasState, clearArray: false); - } - else - { - Array.Clear(newHasState, 0, stepperCapacity); - } - - s_smallPrimeStepperHasState = newHasState; - } - - return steppers; - } - private static bool TryPopulateSmallPrimeFactorsCpu( ulong value, @@ -1059,11 +925,6 @@ internal static partial class PrimeOrderCalculator int primeCount = primes.Length; ulong remainingLocal = value; uint effectiveLimit = limit == 0 ? uint.MaxValue : limit; - CycleRemainderStepper[] cycleSteppers = EnsureSmallPrimeCycleSteppers(primes); - ulong[] stepperPreviousValues = s_smallPrimeStepperPreviousValues!; - ulong[] stepperRemainders = s_smallPrimeStepperRemainders!; - bool[] stepperHasState = s_smallPrimeStepperHasState!; - ulong valueForSteppers = value; for (int i = 0; i < primeCount && remainingLocal > 1UL; i++) { @@ -1087,42 +948,12 @@ internal static partial class PrimeOrderCalculator // continue; // } - ref CycleRemainderStepper stepper = ref cycleSteppers[i]; - ulong remainder; - - if (!stepperHasState[i]) - { - stepper.Reset(); - remainder = stepper.Initialize(valueForSteppers); - stepperHasState[i] = true; - } - else - { - ulong previousValue = stepperPreviousValues[i]; - if (valueForSteppers > previousValue) - { - remainder = stepper.ComputeNext(valueForSteppers); - } - else if (valueForSteppers < previousValue) - { - stepper.Reset(); - remainder = stepper.Initialize(valueForSteppers); - } - else - { - remainder = stepperRemainders[i]; - } - } - - stepperPreviousValues[i] = valueForSteppers; - stepperRemainders[i] = remainder; - - if (remainder != 0UL) + ulong primeValue = primeCandidate; + if ((remainingLocal % primeValue) != 0UL) { continue; } - ulong primeValue = primeCandidate; int exponent = ExtractSmallPrimeExponent(ref remainingLocal, primeValue); if (exponent == 0) { diff --git a/PerfectNumbers.Core/ThreadStaticPools.cs b/PerfectNumbers.Core/ThreadStaticPools.cs index a3346d0..50aa0f3 100644 --- a/PerfectNumbers.Core/ThreadStaticPools.cs +++ b/PerfectNumbers.Core/ThreadStaticPools.cs @@ -9,18 +9,6 @@ namespace PerfectNumbers.Core [ThreadStatic] private static ArrayPool? _factorEntryPool; - [ThreadStatic] - private static ArrayPool? _cycleRemainderStepperPool; - - public static ArrayPool CycleRemainderStepperPool - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return _cycleRemainderStepperPool ??= ArrayPool.Create(); - } - } - public static ArrayPool FactorEntryPool { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -80,18 +68,6 @@ namespace PerfectNumbers.Core [ThreadStatic] private static ArrayPool? _ulongPool; - [ThreadStatic] - private static ArrayPool? _boolPool; - - public static ArrayPool BoolPool - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return _boolPool ??= ArrayPool.Create(); - } - } - public static ArrayPool UlongPool { [MethodImpl(MethodImplOptions.AggressiveInlining)]