Recycle small prime stepper arrays

This commit is contained in:
Marek Lemańczyk committed 2025-10-17 02:34:41 +02:00
1 parent 06b08708d9
commit ca0f498d0d
5 files changed
+1744 -1642

No files matched your search

File diff suppressed because it is too large. Load diff
@@ -0,0 +1,48 @@
using System;
using System.Buffers;
using System.Collections.Generic;
using PerfectNumbers.Core.Gpu;
namespace PerfectNumbers.Core;
internal static partial class PrimeOrderCalculator
{
private static bool IsGpuPow2Allowed => s_pow2ModeInitialized && s_allowGpuPow2;
private const int GpuSmallPrimeFactorSlots = 64;
private static bool TryPopulateSmallPrimeFactorsGpu(ulong value, uint limit, Dictionary<ulong, int> counts, out ulong remaining)
{
ulong[] primeBufferArray = ThreadStaticPools.UlongPool.Rent(GpuSmallPrimeFactorSlots);
int[] exponentBufferArray = ThreadStaticPools.IntPool.Rent(GpuSmallPrimeFactorSlots);
Span<ulong> primeBuffer = primeBufferArray.AsSpan(0, GpuSmallPrimeFactorSlots);
Span<int> 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;
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;
}
counts[primeValue] = exponent;
}
ThreadStaticPools.UlongPool.Return(primeBufferArray);
ThreadStaticPools.IntPool.Return(exponentBufferArray);
return true;
}
}
@@ -1,54 +1,90 @@
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Threading;
using PerfectNumbers.Core.Gpu;
namespace PerfectNumbers.Core;
internal static partial class PrimeOrderCalculator
{
public static UInt128 Calculate(
in UInt128 prime,
in UInt128? previousOrder,
in PrimeOrderSearchConfig config,
in PrimeOrderHeuristicDevice device)
{
var scope = UsePow2Mode(device);
MontgomeryDivisorData divisorData;
UInt128 result;
if (prime <= ulong.MaxValue)
{
ulong? previous = null;
if (previousOrder.HasValue)
{
UInt128 previousValue = previousOrder.Value;
if (previousValue <= ulong.MaxValue)
{
previous = (ulong)previousValue;
}
else
{
previous = ulong.MaxValue;
}
}
[ThreadStatic]
private static bool s_pow2ModeInitialized;
ulong prime64 = (ulong)prime;
divisorData = MontgomeryDivisorData.FromModulus(prime64);
ulong order64 = Calculate(prime64, previous, divisorData, config, device);
result = order64 == 0UL ? UInt128.Zero : (UInt128)order64;
}
else
[ThreadStatic]
private static bool s_allowGpuPow2;
[ThreadStatic]
private static PrimeOrderHeuristicDevice s_deviceMode;
[ThreadStatic]
private static bool s_debugLoggingEnabled;
private static bool IsGpuHeuristicDevice => s_pow2ModeInitialized && s_deviceMode == PrimeOrderHeuristicDevice.Gpu;
private readonly struct Pow2ModeScope
{
divisorData = default;
result = CalculateWideInternal(prime, previousOrder, divisorData, config);
private readonly bool _previousInitialized;
private readonly bool _previousAllow;
private readonly PrimeOrderHeuristicDevice _previousDevice;
public Pow2ModeScope(PrimeOrderHeuristicDevice device)
{
_previousInitialized = s_pow2ModeInitialized;
_previousAllow = s_allowGpuPow2;
_previousDevice = s_deviceMode;
s_pow2ModeInitialized = true;
s_allowGpuPow2 = device == PrimeOrderHeuristicDevice.Gpu;
s_deviceMode = device;
}
public void Dispose()
{
s_allowGpuPow2 = _previousAllow;
s_pow2ModeInitialized = _previousInitialized;
s_deviceMode = _previousDevice;
}
}
scope.Dispose();
return result;
}
private readonly struct DebugLoggingScope
{
private readonly bool _previous;
public DebugLoggingScope(bool enabled)
{
_previous = s_debugLoggingEnabled;
s_debugLoggingEnabled = enabled;
}
public void Dispose()
{
s_debugLoggingEnabled = _previous;
}
}
private static Pow2ModeScope UsePow2Mode(PrimeOrderHeuristicDevice device) => new(device);
private static DebugLoggingScope UseDebugLogging(bool enabled) => new(enabled);
[Conditional("DEBUG")]
private static void DebugLog(string message)
{
if (s_debugLoggingEnabled)
{
Console.WriteLine(message);
}
}
[Conditional("DEBUG")]
private static void DebugLog(Func<string> messageFactory)
{
if (s_debugLoggingEnabled)
{
Console.WriteLine(messageFactory());
}
}
private static UInt128 CalculateWideInternal(in UInt128 prime, in UInt128? previousOrder, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config)
{
if (prime <= UInt128.One)
File diff suppressed because it is too large. Load diff
+24
View File
@@ -11,6 +11,18 @@ namespace PerfectNumbers.Core
[ThreadStatic]
private static ArrayPool<FactorEntry>? _factorEntryPool;
[ThreadStatic]
private static ArrayPool<CycleRemainderStepper>? _cycleRemainderStepperPool;
public static ArrayPool<CycleRemainderStepper> CycleRemainderStepperPool
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return _cycleRemainderStepperPool ??= ArrayPool<CycleRemainderStepper>.Create();
}
}
public static ArrayPool<FactorEntry> FactorEntryPool
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -70,6 +82,18 @@ namespace PerfectNumbers.Core
[ThreadStatic]
private static ArrayPool<ulong>? _ulongPool;
[ThreadStatic]
private static ArrayPool<bool>? _boolPool;
public static ArrayPool<bool> BoolPool
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return _boolPool ??= ArrayPool<bool>.Create();
}
}
public static ArrayPool<ulong> UlongPool
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]