--mersenne=bydivisor testers and sessions integrated and converted to structs.
This commit is contained in:
1 parent
3c80221105
commit
2abc6aae49
32 files changed
+3814
-1505
No files matched your search
@@ -48,7 +48,7 @@ namespace PerfectNumbers.Core.Gpu
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly AcceleratorPool Shared = new(PerfectNumberConstants.RollingAccelerators);
|
||||
public static readonly AcceleratorPool Shared = new(EnvironmentConfiguration.RollingAccelerators);
|
||||
|
||||
private readonly int Capacity;
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@ namespace PerfectNumbers.Core.Gpu.Accelerators;
|
||||
public static class AcceleratorStreamPool
|
||||
{
|
||||
private static readonly Accelerator[] _accelerators = AcceleratorPool.Shared.Accelerators;
|
||||
private static readonly PollingSemaphore[] _locks = new PollingSemaphore[PerfectNumberConstants.RollingAccelerators];
|
||||
private static readonly ConcurrentFixedCapacityStack<AcceleratorStream>[] _streams = new ConcurrentFixedCapacityStack<AcceleratorStream>[PerfectNumberConstants.RollingAccelerators];
|
||||
private static readonly PollingSemaphore[] _locks = new PollingSemaphore[EnvironmentConfiguration.RollingAccelerators];
|
||||
private static readonly ConcurrentFixedCapacityStack<AcceleratorStream>[] _streams = new ConcurrentFixedCapacityStack<AcceleratorStream>[EnvironmentConfiguration.RollingAccelerators];
|
||||
|
||||
private static PollingSemaphore CreateLock() => new(PerfectNumberConstants.ThreadsByAccelerator, TimeSpan.FromMilliseconds(1000), 1);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ internal readonly struct HeuristicCombinedGpuTables
|
||||
{
|
||||
private static readonly Accelerator[] _accelerators = AcceleratorPool.Shared.Accelerators;
|
||||
|
||||
private static readonly HeuristicCombinedGpuTables[] _sharedTables = new HeuristicCombinedGpuTables[PerfectNumberConstants.RollingAccelerators];
|
||||
private static readonly HeuristicCombinedGpuTables[] _sharedTables = new HeuristicCombinedGpuTables[EnvironmentConfiguration.RollingAccelerators];
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
|
||||
internal static void WarmUp(int acceleratorIndex, AcceleratorStream stream) => _sharedTables[acceleratorIndex] = new(_accelerators[acceleratorIndex], stream);
|
||||
|
||||
@@ -7,9 +7,9 @@ internal sealed class HeuristicGroupABGpuTables
|
||||
{
|
||||
private static readonly Accelerator[] _accelerators = AcceleratorPool.Shared.Accelerators;
|
||||
|
||||
private static readonly HeuristicGroupABGpuTables[] _sharedTables = new HeuristicGroupABGpuTables[PerfectNumberConstants.RollingAccelerators];
|
||||
private static readonly HeuristicGroupABGpuTables[] _sharedTables = new HeuristicGroupABGpuTables[EnvironmentConfiguration.RollingAccelerators];
|
||||
|
||||
private static readonly SemaphoreSlim[] _locks = [..Enumerable.Range(1, PerfectNumberConstants.RollingAccelerators).Select(_ => new SemaphoreSlim(1))];
|
||||
private static readonly SemaphoreSlim[] _locks = [..Enumerable.Range(1, EnvironmentConfiguration.RollingAccelerators).Select(_ => new SemaphoreSlim(1))];
|
||||
|
||||
internal static HeuristicGroupABGpuTables EnsureStaticTables(int acceleratorIndex, AcceleratorStream stream)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace PerfectNumbers.Core.Gpu.Accelerators;
|
||||
internal readonly struct LastDigitGpuTables
|
||||
{
|
||||
private static readonly Accelerator[] _accelerators = AcceleratorPool.Shared.Accelerators;
|
||||
private static readonly LastDigitGpuTables[] _sharedTables = new LastDigitGpuTables[PerfectNumberConstants.RollingAccelerators];
|
||||
private static readonly LastDigitGpuTables[] _sharedTables = new LastDigitGpuTables[EnvironmentConfiguration.RollingAccelerators];
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static LastDigitGpuTables GetStaticTables(int acceleratorIndex) => _sharedTables[acceleratorIndex];
|
||||
|
||||
@@ -9,6 +9,8 @@ public static class GpuPrimeWorkLimiter
|
||||
public static void Acquire() => _semaphore.Wait();
|
||||
public static void Release() => _semaphore.Release();
|
||||
|
||||
public static int CurrentLimit => _currentLimit;
|
||||
|
||||
public static void SetLimit(int value)
|
||||
{
|
||||
if (value <= 0)
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
|
||||
namespace PerfectNumbers.Core.Gpu;
|
||||
|
||||
internal struct MersenneNumberDivisorByDivisorGpuPrimeScanSession
|
||||
{
|
||||
private readonly MersenneNumberDivisorByDivisorGpuTester _tester;
|
||||
private readonly ulong _divisorLimit;
|
||||
private readonly Action _markComposite;
|
||||
private readonly Action _clearComposite;
|
||||
private readonly Action<ulong, bool, bool, bool, BigInteger> _printResult;
|
||||
|
||||
public MersenneNumberDivisorByDivisorGpuPrimeScanSession(
|
||||
MersenneNumberDivisorByDivisorGpuTester prototype,
|
||||
Action markComposite,
|
||||
Action clearComposite,
|
||||
Action<ulong, bool, bool, bool, BigInteger> printResult)
|
||||
{
|
||||
_tester = new MersenneNumberDivisorByDivisorGpuTester
|
||||
{
|
||||
MinK = EnvironmentConfiguration.MinK,
|
||||
};
|
||||
_divisorLimit = prototype.DivisorLimit;
|
||||
_tester.SetDivisorLimitForClone(_divisorLimit);
|
||||
|
||||
_markComposite = markComposite;
|
||||
_clearComposite = clearComposite;
|
||||
_printResult = printResult;
|
||||
}
|
||||
|
||||
public void ProcessPrime(ulong prime)
|
||||
{
|
||||
try
|
||||
{
|
||||
Console.WriteLine($"Processing {prime}");
|
||||
string stateFile = Path.Combine(
|
||||
PerfectNumberConstants.ByDivisorStateDirectory,
|
||||
prime.ToString(CultureInfo.InvariantCulture) + ".bin");
|
||||
|
||||
ConfigureForPrime(stateFile);
|
||||
|
||||
bool isPrime = _tester.IsPrime(prime, out bool divisorsExhausted, out BigInteger divisor);
|
||||
|
||||
if (!isPrime)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(stateFile) && File.Exists(stateFile))
|
||||
{
|
||||
File.Delete(stateFile);
|
||||
}
|
||||
|
||||
_markComposite();
|
||||
_printResult(prime, true, true, false, divisor);
|
||||
Console.WriteLine($"Finished processing {prime}");
|
||||
return;
|
||||
}
|
||||
|
||||
_clearComposite();
|
||||
_printResult(prime, true, divisorsExhausted, true, divisor);
|
||||
Console.WriteLine($"Finished processing {prime}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error processing {ex.Message} {ex.StackTrace}");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private void ConfigureForPrime(string stateFile)
|
||||
{
|
||||
BigInteger resumeK = EnvironmentConfiguration.MinK;
|
||||
if (File.Exists(stateFile))
|
||||
{
|
||||
if (MersenneNumberDivisorByDivisorTester.TryReadLastSavedK(stateFile, out BigInteger lastK))
|
||||
{
|
||||
resumeK = lastK + BigInteger.One;
|
||||
_tester.ResumeFromState(stateFile, lastK, resumeK);
|
||||
}
|
||||
else
|
||||
{
|
||||
_tester.ResumeFromState(stateFile, BigInteger.Zero, resumeK);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_tester.ResumeFromState(stateFile, BigInteger.Zero, resumeK);
|
||||
}
|
||||
|
||||
_tester.ResetStateTracking();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -14,67 +14,46 @@ namespace PerfectNumbers.Core.Gpu;
|
||||
/// </summary>
|
||||
public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDivisorByDivisorTester
|
||||
{
|
||||
private int _gpuBatchSize = GpuConstants.ScanBatchSize;
|
||||
// EvenPerfectBitScanner configures the GPU tester once before scanning and never mutates the configuration afterwards,
|
||||
// so the synchronization fields from the previous implementation remain commented out here.
|
||||
private readonly PrimeOrderCalculatorAccelerator Accelerator = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
private ulong _divisorLimit;
|
||||
private BigInteger _minK = BigInteger.One;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
internal void SetDivisorLimitForClone(ulong divisorLimit) => _divisorLimit = divisorLimit;
|
||||
public BigInteger MinK = BigInteger.One;
|
||||
public string? StateFilePath;
|
||||
|
||||
private readonly ConcurrentFixedCapacityStack<MersenneNumberDivisorByDivisorAccelerator>[] _resourcePool = [.. AcceleratorPool.Shared.Accelerators.Select(x => new ConcurrentFixedCapacityStack<MersenneNumberDivisorByDivisorAccelerator>(PerfectNumberConstants.DefaultPoolCapacity))];
|
||||
|
||||
private readonly ConcurrentFixedCapacityStack<DivisorScanSession> _sessionPool = new(PerfectNumberConstants.DefaultPoolCapacity);
|
||||
|
||||
public int GpuBatchSize
|
||||
{
|
||||
get => _gpuBatchSize;
|
||||
set => _gpuBatchSize = value < 1 ? 1 : value;
|
||||
}
|
||||
|
||||
int IMersenneNumberDivisorByDivisorTester.BatchSize
|
||||
{
|
||||
get => GpuBatchSize;
|
||||
set => GpuBatchSize = value;
|
||||
}
|
||||
|
||||
public BigInteger MinK
|
||||
{
|
||||
get => _minK;
|
||||
set => _minK = value < BigInteger.One ? BigInteger.One : value;
|
||||
}
|
||||
|
||||
public string? StateFilePath { get; set; }
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public void ResetStateTracking()
|
||||
{
|
||||
}
|
||||
|
||||
public void ResumeFromState(BigInteger lastSavedK)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public void ResumeFromState(in string stateFile, in BigInteger lastSavedK, in BigInteger minK)
|
||||
{
|
||||
StateFilePath = stateFile;
|
||||
if (lastSavedK > ulong.MaxValue)
|
||||
{
|
||||
throw new NotSupportedException("GPU by-divisor tester does not support MinK above UInt64.");
|
||||
ThrowNotSupportedLastSavedK();
|
||||
return; // We'll never get to here
|
||||
}
|
||||
|
||||
_minK = lastSavedK + BigInteger.One;
|
||||
MinK = minK;
|
||||
}
|
||||
|
||||
public void ConfigureFromMaxPrime(ulong maxPrime)
|
||||
{
|
||||
// EvenPerfectBitScanner configures the GPU tester once before scanning and never mutates the configuration afterwards,
|
||||
// so synchronization and runtime configuration guards are unnecessary here.
|
||||
private static void ThrowNotSupportedLastSavedK() => throw new NotSupportedException("GPU by-divisor tester does not support MinK above UInt64.");
|
||||
|
||||
_divisorLimit = ComputeDivisorLimitFromMaxPrimeGpu(maxPrime);
|
||||
}
|
||||
|
||||
public bool IsPrime(PrimeOrderCalculatorAccelerator gpu, ulong prime, out bool divisorsExhausted, out BigInteger divisor)
|
||||
public bool IsPrime(ulong prime, out bool divisorsExhausted, out BigInteger divisor)
|
||||
{
|
||||
ulong allowedMax;
|
||||
int batchCapacity;
|
||||
|
||||
// EvenPerfectBitScanner only calls into this tester after configuring it once, so we can read the cached values without locking.
|
||||
|
||||
allowedMax = ComputeAllowedMaxDivisorGpu(prime, _divisorLimit);
|
||||
batchCapacity = _gpuBatchSize;
|
||||
|
||||
// Production scans never shrink the divisor window below three, so this guard stays commented out.
|
||||
// if (allowedMax < 3UL)
|
||||
@@ -84,17 +63,16 @@ public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneN
|
||||
// }
|
||||
|
||||
bool composite;
|
||||
bool coveredRange;
|
||||
ulong lastProcessed;
|
||||
|
||||
// GpuPrimeWorkLimiter();
|
||||
// int acceleratorIndex = AcceleratorPool.Shared.Rent();
|
||||
// var accelerator = _accelerators[acceleratorIndex];
|
||||
PrimeOrderCalculatorAccelerator gpu = Accelerator;
|
||||
var acceleratorIndex = gpu.AcceleratorIndex;
|
||||
|
||||
// Monitor.Enter(gpuLease.ExecutionLock);
|
||||
|
||||
var resources = RentBatchResources(acceleratorIndex, batchCapacity);
|
||||
var resources = RentBatchResources(acceleratorIndex, EnvironmentConfiguration.GpuBatchSize);
|
||||
|
||||
composite = CheckDivisors(
|
||||
gpu,
|
||||
@@ -115,8 +93,8 @@ public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneN
|
||||
resources.Offsets,
|
||||
resources.Counts,
|
||||
resources.Cycles,
|
||||
out lastProcessed,
|
||||
out coveredRange);
|
||||
out ulong lastProcessed,
|
||||
out bool coveredRange);
|
||||
|
||||
ReturnBatchResources(acceleratorIndex, resources);
|
||||
// Monitor.Exit(gpuLease.ExecutionLock);
|
||||
@@ -134,17 +112,19 @@ public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneN
|
||||
return true;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private ulong GetMinKOrThrow()
|
||||
{
|
||||
if (_minK > ulong.MaxValue)
|
||||
if (MinK > ulong.MaxValue)
|
||||
{
|
||||
throw new NotSupportedException("GPU by-divisor tester does not support MinK above UInt64.");
|
||||
ThrowNotSupportedLastSavedK();
|
||||
return 0UL;
|
||||
}
|
||||
|
||||
return (ulong)_minK;
|
||||
return (ulong)MinK;
|
||||
}
|
||||
|
||||
public void PrepareCandidates(in ReadOnlySpan<ulong> primes, Span<ulong> allowedMaxValues)
|
||||
public void PrepareCandidates(ulong maxPrime, in ReadOnlySpan<ulong> primes, Span<ulong> allowedMaxValues)
|
||||
{
|
||||
// The scanner always supplies matching spans, so the previous validation remains commented out.
|
||||
// if (allowedMaxValues.Length < primes.Length)
|
||||
@@ -165,7 +145,12 @@ public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneN
|
||||
// divisorLimit = _divisorLimit;
|
||||
// }
|
||||
|
||||
divisorLimit = _divisorLimit;
|
||||
// EvenPerfectBitScanner configures the GPU tester once before scanning and never mutates the configuration afterwards,
|
||||
// so synchronization and runtime configuration guards are unnecessary here.
|
||||
|
||||
divisorLimit = ComputeDivisorLimitFromMaxPrimeGpu(maxPrime);
|
||||
|
||||
_divisorLimit = divisorLimit;
|
||||
|
||||
for (int index = 0; index < primes.Length; index++)
|
||||
{
|
||||
@@ -526,12 +511,12 @@ public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneN
|
||||
private readonly Accelerator _accelerator;
|
||||
private readonly PrimeOrderCalculatorAccelerator _primeOrderCalculatorAccelerator;
|
||||
private readonly AcceleratorStream _stream;
|
||||
private Action<AcceleratorStream, Index1D, ArrayView<GpuDivisorPartialData>, ArrayView<int>, ArrayView<int>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>, ArrayView<int>> _kernel = null!;
|
||||
private MemoryBuffer1D<GpuDivisorPartialData, Stride1D.Dense> _divisorBuffer = null!;
|
||||
private MemoryBuffer1D<int, Stride1D.Dense> _offsetBuffer = null!;
|
||||
private MemoryBuffer1D<int, Stride1D.Dense> _countBuffer = null!;
|
||||
private MemoryBuffer1D<ulong, Stride1D.Dense> _cycleBuffer = null!;
|
||||
private MemoryBuffer1D<int, Stride1D.Dense> _firstHitBuffer = null!;
|
||||
private readonly Action<AcceleratorStream, Index1D, ArrayView<GpuDivisorPartialData>, ArrayView<int>, ArrayView<int>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>, ArrayView<int>> _kernel = null!;
|
||||
private readonly MemoryBuffer1D<GpuDivisorPartialData, Stride1D.Dense> _divisorBuffer = null!;
|
||||
private readonly MemoryBuffer1D<int, Stride1D.Dense> _offsetBuffer = null!;
|
||||
private readonly MemoryBuffer1D<int, Stride1D.Dense> _countBuffer = null!;
|
||||
private readonly MemoryBuffer1D<ulong, Stride1D.Dense> _cycleBuffer = null!;
|
||||
private readonly MemoryBuffer1D<int, Stride1D.Dense> _firstHitBuffer = null!;
|
||||
private MemoryBuffer1D<ulong, Stride1D.Dense> _exponentsBuffer = null!;
|
||||
private MemoryBuffer1D<byte, Stride1D.Dense> _hitBuffer = null!;
|
||||
private ulong[] _hostBuffer = null!;
|
||||
@@ -546,7 +531,6 @@ public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneN
|
||||
Accelerator accelerator = gpu.Accelerator;
|
||||
_accelerator = accelerator;
|
||||
_stream = accelerator.CreateStream();
|
||||
_capacity = Math.Max(1, owner._gpuBatchSize);
|
||||
|
||||
// lock (accelerator)
|
||||
{
|
||||
@@ -559,11 +543,9 @@ public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneN
|
||||
|
||||
int desiredCapacity = PerfectNumberConstants.DefaultSmallPrimeFactorSlotCount;
|
||||
_capacity = desiredCapacity;
|
||||
// lock (accelerator)
|
||||
{
|
||||
_exponentsBuffer = accelerator.Allocate1D<ulong>(desiredCapacity);
|
||||
_hitBuffer = accelerator.Allocate1D<byte>(desiredCapacity);
|
||||
}
|
||||
|
||||
_exponentsBuffer = accelerator.Allocate1D<ulong>(desiredCapacity);
|
||||
_hitBuffer = accelerator.Allocate1D<byte>(desiredCapacity);
|
||||
|
||||
_hostBuffer = ThreadStaticPools.UlongPool.Rent(desiredCapacity);
|
||||
|
||||
@@ -729,23 +711,6 @@ public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneN
|
||||
public int GetHashCode(Accelerator obj) => RuntimeHelpers.GetHashCode(obj);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public ulong GetAllowedMaxDivisor(ulong prime)
|
||||
{
|
||||
// The configuration is immutable after setup, so the cached limit can be read without locking.
|
||||
// lock (_sync)
|
||||
// {
|
||||
// if (!_isConfigured)
|
||||
// {
|
||||
// throw new InvalidOperationException("ConfigureFromMaxPrime must be called before using the tester.");
|
||||
// }
|
||||
|
||||
// return ComputeAllowedMaxDivisorGpu(prime, _divisorLimit);
|
||||
// }
|
||||
|
||||
return ComputeAllowedMaxDivisorGpu(prime, _divisorLimit);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public IMersenneNumberDivisorByDivisorTester.IDivisorScanSession CreateDivisorSession(PrimeOrderCalculatorAccelerator gpu)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ public readonly struct SmallPrimeFactorGpuTables
|
||||
|
||||
{
|
||||
private static readonly Accelerator[] _accelerators = AcceleratorPool.Shared.Accelerators;
|
||||
private static readonly SmallPrimeFactorGpuTables?[] _sharedTables = new SmallPrimeFactorGpuTables?[PerfectNumberConstants.RollingAccelerators];
|
||||
private static readonly SmallPrimeFactorGpuTables?[] _sharedTables = new SmallPrimeFactorGpuTables?[EnvironmentConfiguration.RollingAccelerators];
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static SmallPrimeFactorGpuTables? GetStaticTables(int acceleratorIndex) => _sharedTables[acceleratorIndex];
|
||||
|
||||
Reference in new issue
Block a user