Tasks will now save calculations progress and resume calculation upon restart.
This commit is contained in:
1 parent
941733905b
commit
f43c67c86f
9 files changed
+199
-34
No files matched your search
@@ -1,5 +1,6 @@
|
|||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using EvenPerfectBitScanner.Candidates;
|
using EvenPerfectBitScanner.Candidates;
|
||||||
using EvenPerfectBitScanner.IO;
|
using EvenPerfectBitScanner.IO;
|
||||||
@@ -124,6 +125,8 @@ internal static class Program
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Directory.CreateDirectory(PerfectNumberConstants.ByDivisorStateDirectory);
|
||||||
|
|
||||||
|
|
||||||
MersenneDivisorCycles mersenneDivisorCycles = new();
|
MersenneDivisorCycles mersenneDivisorCycles = new();
|
||||||
if (!File.Exists(cyclesPath) || continueCyclesGeneration)
|
if (!File.Exists(cyclesPath) || continueCyclesGeneration)
|
||||||
|
|||||||
@@ -48,6 +48,16 @@ public class MersenneNumberDivisorByDivisorTesterTests
|
|||||||
|
|
||||||
public ulong MinK { get; set; }
|
public ulong MinK { get; set; }
|
||||||
|
|
||||||
|
public string? StateFilePath { get; set; }
|
||||||
|
|
||||||
|
public void ResetStateTracking()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResumeFromState(ulong lastSavedK)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public ulong DivisorLimit => ConfiguredMaxPrime + 100UL;
|
public ulong DivisorLimit => ConfiguredMaxPrime + 100UL;
|
||||||
|
|
||||||
public void ConfigureFromMaxPrime(ulong maxPrime)
|
public void ConfigureFromMaxPrime(ulong maxPrime)
|
||||||
|
|||||||
@@ -1,28 +1,23 @@
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
using PerfectNumbers.Core.Gpu;
|
using PerfectNumbers.Core.Gpu;
|
||||||
using PerfectNumbers.Core.Gpu.Accelerators;
|
using PerfectNumbers.Core.Gpu.Accelerators;
|
||||||
|
|
||||||
namespace PerfectNumbers.Core.Cpu;
|
namespace PerfectNumbers.Core.Cpu;
|
||||||
|
|
||||||
public sealed class MersenneNumberDivisorByDivisorCpuTester(ComputationDevice orderDevice = ComputationDevice.Hybrid) : IMersenneNumberDivisorByDivisorTester
|
public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDivisorByDivisorTester
|
||||||
{
|
{
|
||||||
private ulong _divisorLimit;
|
private ulong _divisorLimit;
|
||||||
private int _batchSize = 1_024;
|
private int _batchSize = 1_024;
|
||||||
private ulong _minK = 1UL;
|
private ulong _minK = 1UL;
|
||||||
|
private readonly ComputationDevice _orderDevice;
|
||||||
private readonly TryCycleLengthDelegate _tryCalculateCycleLengthForExponent = orderDevice switch
|
private readonly TryCycleLengthDelegate _tryCalculateCycleLengthForExponent;
|
||||||
{
|
private readonly CalculateCycleLengthDelegate _calculateCycleLength;
|
||||||
ComputationDevice.Gpu => TryCalculateCycleLengthForExponentGpu,
|
private string? _stateFilePath;
|
||||||
ComputationDevice.Hybrid => TryCalculateCycleLengthForExponentHybrid,
|
private int _stateCounter;
|
||||||
_ => TryCalculateCycleLengthForExponentCpu,
|
private ulong _lastSavedK;
|
||||||
};
|
public ComputationDevice OrderDevice => _orderDevice;
|
||||||
|
|
||||||
private readonly CalculateCycleLengthDelegate _calculateCycleLength = orderDevice switch
|
|
||||||
{
|
|
||||||
ComputationDevice.Gpu => CalculateCycleLengthGpu,
|
|
||||||
ComputationDevice.Hybrid => CalculateCycleLengthHybrid,
|
|
||||||
_ => CalculateCycleLengthCpu,
|
|
||||||
};
|
|
||||||
|
|
||||||
private delegate bool TryCycleLengthDelegate(
|
private delegate bool TryCycleLengthDelegate(
|
||||||
ulong divisor,
|
ulong divisor,
|
||||||
@@ -48,6 +43,24 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester(ComputationDevice or
|
|||||||
public GpuUInt128 Limit;
|
public GpuUInt128 Limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MersenneNumberDivisorByDivisorCpuTester(ComputationDevice orderDevice = ComputationDevice.Hybrid)
|
||||||
|
{
|
||||||
|
_orderDevice = orderDevice;
|
||||||
|
_tryCalculateCycleLengthForExponent = orderDevice switch
|
||||||
|
{
|
||||||
|
ComputationDevice.Gpu => TryCalculateCycleLengthForExponentGpu,
|
||||||
|
ComputationDevice.Hybrid => TryCalculateCycleLengthForExponentHybrid,
|
||||||
|
_ => TryCalculateCycleLengthForExponentCpu,
|
||||||
|
};
|
||||||
|
|
||||||
|
_calculateCycleLength = orderDevice switch
|
||||||
|
{
|
||||||
|
ComputationDevice.Gpu => CalculateCycleLengthGpu,
|
||||||
|
ComputationDevice.Hybrid => CalculateCycleLengthHybrid,
|
||||||
|
_ => CalculateCycleLengthCpu,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public int BatchSize
|
public int BatchSize
|
||||||
{
|
{
|
||||||
get => _batchSize;
|
get => _batchSize;
|
||||||
@@ -60,6 +73,24 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester(ComputationDevice or
|
|||||||
set => _minK = value < 1UL ? 1UL : value;
|
set => _minK = value < 1UL ? 1UL : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string? StateFilePath
|
||||||
|
{
|
||||||
|
get => _stateFilePath;
|
||||||
|
set => _stateFilePath = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetStateTracking()
|
||||||
|
{
|
||||||
|
_stateCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResumeFromState(ulong lastSavedK)
|
||||||
|
{
|
||||||
|
_lastSavedK = lastSavedK;
|
||||||
|
_minK = lastSavedK + 1UL;
|
||||||
|
_stateCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
public void ConfigureFromMaxPrime(ulong maxPrime)
|
public void ConfigureFromMaxPrime(ulong maxPrime)
|
||||||
{
|
{
|
||||||
_divisorLimit = ComputeDivisorLimitFromMaxPrime(maxPrime);
|
_divisorLimit = ComputeDivisorLimitFromMaxPrime(maxPrime);
|
||||||
@@ -127,11 +158,11 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester(ComputationDevice or
|
|||||||
|
|
||||||
if (session is not null)
|
if (session is not null)
|
||||||
{
|
{
|
||||||
session.Configure(gpu, orderDevice);
|
session.Configure(gpu, _orderDevice);
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MersenneCpuDivisorScanSession(gpu, orderDevice);
|
return new MersenneCpuDivisorScanSession(gpu, _orderDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CheckDivisors(
|
private bool CheckDivisors(
|
||||||
@@ -144,6 +175,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester(ComputationDevice or
|
|||||||
{
|
{
|
||||||
foundDivisor = 0UL;
|
foundDivisor = 0UL;
|
||||||
processedAll = true;
|
processedAll = true;
|
||||||
|
ulong currentK = minK < 1UL ? 1UL : minK;
|
||||||
|
|
||||||
// The EvenPerfectBitScanner feeds primes >= 138,000,000 here, so allowedMax >= 3 in production runs.
|
// The EvenPerfectBitScanner feeds primes >= 138,000,000 here, so allowedMax >= 3 in production runs.
|
||||||
// Keeping the guard commented out documents the reasoning for benchmarks and tests.
|
// Keeping the guard commented out documents the reasoning for benchmarks and tests.
|
||||||
@@ -242,6 +274,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester(ComputationDevice or
|
|||||||
step3,
|
step3,
|
||||||
step7,
|
step7,
|
||||||
step11,
|
step11,
|
||||||
|
ref currentK,
|
||||||
out processedTop,
|
out processedTop,
|
||||||
out foundDivisor);
|
out foundDivisor);
|
||||||
if (composite)
|
if (composite)
|
||||||
@@ -252,9 +285,10 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester(ComputationDevice or
|
|||||||
}
|
}
|
||||||
|
|
||||||
ulong lowerEnd = startK > 1UL ? startK - 1UL : 0UL;
|
ulong lowerEnd = startK > 1UL ? startK - 1UL : 0UL;
|
||||||
if (lowerEnd >= 1UL)
|
if (lowerEnd >= 1UL && startK == 1UL)
|
||||||
{
|
{
|
||||||
lowerEnd = Math.Min(lowerEnd, maxK);
|
lowerEnd = Math.Min(lowerEnd, maxK);
|
||||||
|
currentK = 1UL;
|
||||||
composite = CheckDivisors64Range(
|
composite = CheckDivisors64Range(
|
||||||
gpu,
|
gpu,
|
||||||
prime,
|
prime,
|
||||||
@@ -268,6 +302,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester(ComputationDevice or
|
|||||||
step3,
|
step3,
|
||||||
step7,
|
step7,
|
||||||
step11,
|
step11,
|
||||||
|
ref currentK,
|
||||||
out processedBottom,
|
out processedBottom,
|
||||||
out foundDivisor);
|
out foundDivisor);
|
||||||
}
|
}
|
||||||
@@ -317,10 +352,11 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester(ComputationDevice or
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
divisorCycle = computedCycle;
|
divisorCycle = computedCycle;
|
||||||
}
|
}
|
||||||
|
|
||||||
divisorPool.Return(divisorData);
|
divisorPool.Return(divisorData);
|
||||||
|
RecordState(currentK);
|
||||||
if (divisorCycle == prime)
|
if (divisorCycle == prime)
|
||||||
{
|
{
|
||||||
// A cycle equal to the tested exponent (which is prime in this path) guarantees that the candidate divides
|
// A cycle equal to the tested exponent (which is prime in this path) guarantees that the candidate divides
|
||||||
@@ -337,6 +373,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester(ComputationDevice or
|
|||||||
}
|
}
|
||||||
|
|
||||||
divisor.Add(step);
|
divisor.Add(step);
|
||||||
|
currentK++;
|
||||||
remainder10 = AddMod10(remainder10, step10);
|
remainder10 = AddMod10(remainder10, step10);
|
||||||
remainder8 = AddMod8(remainder8, step8);
|
remainder8 = AddMod8(remainder8, step8);
|
||||||
remainder3 = AddMod3(remainder3, step3);
|
remainder3 = AddMod3(remainder3, step3);
|
||||||
@@ -362,6 +399,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester(ComputationDevice or
|
|||||||
byte step3,
|
byte step3,
|
||||||
byte step7,
|
byte step7,
|
||||||
byte step11,
|
byte step11,
|
||||||
|
ref ulong currentK,
|
||||||
out bool processedAll,
|
out bool processedAll,
|
||||||
out ulong foundDivisor)
|
out ulong foundDivisor)
|
||||||
{
|
{
|
||||||
@@ -371,6 +409,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester(ComputationDevice or
|
|||||||
foundDivisor = 0UL;
|
foundDivisor = 0UL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
currentK = startK;
|
||||||
|
|
||||||
UInt128 step128 = step;
|
UInt128 step128 = step;
|
||||||
UInt128 allowedMax128 = allowedMax;
|
UInt128 allowedMax128 = allowedMax;
|
||||||
@@ -414,11 +453,12 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester(ComputationDevice or
|
|||||||
remainder3,
|
remainder3,
|
||||||
remainder7,
|
remainder7,
|
||||||
remainder11,
|
remainder11,
|
||||||
|
ref currentK,
|
||||||
out processedAll,
|
out processedAll,
|
||||||
out foundDivisor);
|
out foundDivisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CheckDivisors64(
|
private bool CheckDivisors64(
|
||||||
PrimeOrderCalculatorAccelerator gpu,
|
PrimeOrderCalculatorAccelerator gpu,
|
||||||
ulong prime,
|
ulong prime,
|
||||||
ulong step,
|
ulong step,
|
||||||
@@ -435,6 +475,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester(ComputationDevice or
|
|||||||
byte remainder3,
|
byte remainder3,
|
||||||
byte remainder7,
|
byte remainder7,
|
||||||
byte remainder11,
|
byte remainder11,
|
||||||
|
ref ulong currentK,
|
||||||
out bool processedAll,
|
out bool processedAll,
|
||||||
out ulong foundDivisor)
|
out ulong foundDivisor)
|
||||||
{
|
{
|
||||||
@@ -523,6 +564,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester(ComputationDevice or
|
|||||||
}
|
}
|
||||||
|
|
||||||
divisorPool.Return(divisorData);
|
divisorPool.Return(divisorData);
|
||||||
|
RecordState(currentK);
|
||||||
if (divisorCycle == prime)
|
if (divisorCycle == prime)
|
||||||
{
|
{
|
||||||
foundDivisor = divisor;
|
foundDivisor = divisor;
|
||||||
@@ -545,6 +587,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester(ComputationDevice or
|
|||||||
}
|
}
|
||||||
|
|
||||||
divisor += step;
|
divisor += step;
|
||||||
|
currentK++;
|
||||||
remainder10 = AddMod10(remainder10, step10);
|
remainder10 = AddMod10(remainder10, step10);
|
||||||
remainder8 = AddMod8(remainder8, step8);
|
remainder8 = AddMod8(remainder8, step8);
|
||||||
remainder3 = AddMod3(remainder3, step3);
|
remainder3 = AddMod3(remainder3, step3);
|
||||||
@@ -559,6 +602,38 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester(ComputationDevice or
|
|||||||
return residue == 1UL ? (byte)1 : (byte)0;
|
return residue == 1UL ? (byte)1 : (byte)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RecordState(ulong k)
|
||||||
|
{
|
||||||
|
string? path = _stateFilePath;
|
||||||
|
if (string.IsNullOrEmpty(path))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k <= _lastSavedK)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int next = _stateCounter + 1;
|
||||||
|
if (next >= PerfectNumberConstants.ByDivisorStateSaveInterval)
|
||||||
|
{
|
||||||
|
string? directory = Path.GetDirectoryName(path);
|
||||||
|
if (!string.IsNullOrEmpty(directory))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
File.AppendAllText(path, k.ToString(CultureInfo.InvariantCulture) + Environment.NewLine);
|
||||||
|
_stateCounter = 0;
|
||||||
|
_lastSavedK = k;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_stateCounter = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static bool TryCalculateCycleLengthForExponentCpu(
|
private static bool TryCalculateCycleLengthForExponentCpu(
|
||||||
ulong divisor,
|
ulong divisor,
|
||||||
PrimeOrderCalculatorAccelerator gpu,
|
PrimeOrderCalculatorAccelerator gpu,
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ public static class AcceleratorStreamPool
|
|||||||
|
|
||||||
public static AcceleratorStream Rent(int acceleratorIndex)
|
public static AcceleratorStream Rent(int acceleratorIndex)
|
||||||
{
|
{
|
||||||
// var streamLock = _locks[acceleratorIndex];
|
var streamLock = _locks[acceleratorIndex];
|
||||||
var queue = _streams[acceleratorIndex];
|
var queue = _streams[acceleratorIndex];
|
||||||
|
|
||||||
// streamLock.Wait();
|
streamLock.Wait();
|
||||||
|
|
||||||
return queue.TryDequeue(out var stream)
|
return queue.TryDequeue(out var stream)
|
||||||
? stream
|
? stream
|
||||||
@@ -28,10 +28,10 @@ public static class AcceleratorStreamPool
|
|||||||
|
|
||||||
public static void Return(int acceleratorIndex, AcceleratorStream stream)
|
public static void Return(int acceleratorIndex, AcceleratorStream stream)
|
||||||
{
|
{
|
||||||
// var streamLock = _locks[acceleratorIndex];
|
var streamLock = _locks[acceleratorIndex];
|
||||||
var queue = _streams[acceleratorIndex];
|
var queue = _streams[acceleratorIndex];
|
||||||
queue.Enqueue(stream);
|
queue.Enqueue(stream);
|
||||||
// streamLock.Release();
|
streamLock.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void WarmUp(int acceleratorIndex)
|
public static void WarmUp(int acceleratorIndex)
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
namespace PerfectNumbers.Core.Gpu;
|
namespace PerfectNumbers.Core.Gpu;
|
||||||
|
|
||||||
public static class GpuPrimeWorkLimiter
|
public static class GpuPrimeWorkLimiter
|
||||||
{
|
{
|
||||||
private static SemaphoreSlim _semaphore = new(1, int.MaxValue);
|
private static readonly TimeSpan _pauseBetweenChecks = TimeSpan.FromSeconds(2);
|
||||||
|
private static PollingSemaphore _semaphore = new(1, _pauseBetweenChecks);
|
||||||
private static int _currentLimit = 1;
|
private static int _currentLimit = 1;
|
||||||
|
|
||||||
public static void Acquire() { } // => _semaphore.Wait();
|
public static void Acquire() => _semaphore.Wait();
|
||||||
public static void Release() { }// => _semaphore.Release();
|
public static void Release() => _semaphore.Release();
|
||||||
|
|
||||||
public static void SetLimit(int value)
|
public static void SetLimit(int value)
|
||||||
{
|
{
|
||||||
@@ -18,13 +21,13 @@ public static class GpuPrimeWorkLimiter
|
|||||||
if (value == _currentLimit)
|
if (value == _currentLimit)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Switch to a shared limiter implementation with GpuWorkLimiter so we can coordinate CPU/GPU prime work using
|
// TODO: Switch to a shared limiter implementation with GpuWorkLimiter so we can coordinate CPU/GPU prime work using
|
||||||
// the same semaphore pool without reallocating per adjustment.
|
// the same semaphore pool without reallocating per adjustment.
|
||||||
var previous = _semaphore;
|
// var previous = _semaphore;
|
||||||
_semaphore = new SemaphoreSlim(value, value);
|
_semaphore = new PollingSemaphore(value, _pauseBetweenChecks);
|
||||||
_currentLimit = value;
|
_currentLimit = value;
|
||||||
previous.Dispose();
|
// previous.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,6 +43,17 @@ public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneN
|
|||||||
set => _minK = value < 1UL ? 1UL : value;
|
set => _minK = value < 1UL ? 1UL : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string? StateFilePath { get; set; }
|
||||||
|
|
||||||
|
public void ResetStateTracking()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResumeFromState(ulong lastSavedK)
|
||||||
|
{
|
||||||
|
_minK = lastSavedK + 1UL;
|
||||||
|
}
|
||||||
|
|
||||||
public void ConfigureFromMaxPrime(ulong maxPrime)
|
public void ConfigureFromMaxPrime(ulong maxPrime)
|
||||||
{
|
{
|
||||||
// EvenPerfectBitScanner configures the GPU tester once before scanning and never mutates the configuration afterwards,
|
// EvenPerfectBitScanner configures the GPU tester once before scanning and never mutates the configuration afterwards,
|
||||||
|
|||||||
@@ -18,6 +18,12 @@ public interface IMersenneNumberDivisorByDivisorTester
|
|||||||
|
|
||||||
IDivisorScanSession CreateDivisorSession(PrimeOrderCalculatorAccelerator gpu);
|
IDivisorScanSession CreateDivisorSession(PrimeOrderCalculatorAccelerator gpu);
|
||||||
|
|
||||||
|
string? StateFilePath { get; set; }
|
||||||
|
|
||||||
|
void ResetStateTracking();
|
||||||
|
|
||||||
|
void ResumeFromState(ulong lastSavedK);
|
||||||
|
|
||||||
void PrepareCandidates(in ReadOnlySpan<ulong> primes, Span<ulong> allowedMaxValues);
|
void PrepareCandidates(in ReadOnlySpan<ulong> primes, Span<ulong> allowedMaxValues);
|
||||||
|
|
||||||
public interface IDivisorScanSession
|
public interface IDivisorScanSession
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Globalization;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using PerfectNumbers.Core.Gpu;
|
using PerfectNumbers.Core.Gpu;
|
||||||
using PerfectNumbers.Core.Gpu.Accelerators;
|
using PerfectNumbers.Core.Gpu.Accelerators;
|
||||||
|
using PerfectNumbers.Core.Cpu;
|
||||||
|
|
||||||
namespace PerfectNumbers.Core;
|
namespace PerfectNumbers.Core;
|
||||||
|
|
||||||
@@ -240,13 +241,67 @@ public static class MersenneNumberDivisorByDivisorTester
|
|||||||
|
|
||||||
int chunkSize = primesPerTask <= 0 ? 1 : primesPerTask;
|
int chunkSize = primesPerTask <= 0 ? 1 : primesPerTask;
|
||||||
|
|
||||||
|
IMersenneNumberDivisorByDivisorTester CreateTester(IMersenneNumberDivisorByDivisorTester prototype)
|
||||||
|
{
|
||||||
|
IMersenneNumberDivisorByDivisorTester tester = prototype switch
|
||||||
|
{
|
||||||
|
MersenneNumberDivisorByDivisorCpuTester cpu => new MersenneNumberDivisorByDivisorCpuTester(cpu.OrderDevice)
|
||||||
|
{
|
||||||
|
BatchSize = prototype.BatchSize,
|
||||||
|
MinK = prototype.MinK,
|
||||||
|
},
|
||||||
|
_ => CreateGpuTester(prototype),
|
||||||
|
};
|
||||||
|
|
||||||
|
tester.ConfigureFromMaxPrime(maxPrime);
|
||||||
|
return tester;
|
||||||
|
}
|
||||||
|
|
||||||
|
static IMersenneNumberDivisorByDivisorTester CreateGpuTester(IMersenneNumberDivisorByDivisorTester prototype)
|
||||||
|
{
|
||||||
|
var gpuTester = new MersenneNumberDivisorByDivisorGpuTester
|
||||||
|
{
|
||||||
|
MinK = prototype.MinK,
|
||||||
|
};
|
||||||
|
((IMersenneNumberDivisorByDivisorTester)gpuTester).BatchSize = prototype.BatchSize;
|
||||||
|
return gpuTester;
|
||||||
|
}
|
||||||
|
|
||||||
void ProcessPrime(PrimeOrderCalculatorAccelerator gpu, ulong prime)
|
void ProcessPrime(PrimeOrderCalculatorAccelerator gpu, ulong prime)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Processing {prime}");
|
Console.WriteLine($"Processing {prime}");
|
||||||
bool isPrime = tester.IsPrime(gpu, prime, out bool divisorsExhausted, out ulong divisor);
|
IMersenneNumberDivisorByDivisorTester testerForPrime = CreateTester(tester);
|
||||||
|
string stateFile = Path.Combine(PerfectNumberConstants.ByDivisorStateDirectory, prime.ToString(CultureInfo.InvariantCulture) + ".bin");
|
||||||
|
|
||||||
|
ulong resumeK = tester.MinK;
|
||||||
|
if (File.Exists(stateFile))
|
||||||
|
{
|
||||||
|
ulong lastK = File.ReadLines(stateFile)
|
||||||
|
.Where(static line => !string.IsNullOrWhiteSpace(line))
|
||||||
|
.Select(static line => ulong.Parse(line, NumberStyles.None, CultureInfo.InvariantCulture))
|
||||||
|
.Max();
|
||||||
|
|
||||||
|
resumeK = lastK + 1UL;
|
||||||
|
testerForPrime.ResumeFromState(lastK);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
testerForPrime.ResumeFromState(0UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
testerForPrime.MinK = resumeK;
|
||||||
|
testerForPrime.StateFilePath = stateFile;
|
||||||
|
testerForPrime.ResetStateTracking();
|
||||||
|
|
||||||
|
bool isPrime = testerForPrime.IsPrime(gpu, prime, out bool divisorsExhausted, out ulong divisor);
|
||||||
|
|
||||||
if (!isPrime)
|
if (!isPrime)
|
||||||
{
|
{
|
||||||
|
if (!string.IsNullOrEmpty(stateFile) && File.Exists(stateFile))
|
||||||
|
{
|
||||||
|
File.Delete(stateFile);
|
||||||
|
}
|
||||||
|
|
||||||
markComposite();
|
markComposite();
|
||||||
printResult(prime, true, true, false, divisor);
|
printResult(prime, true, true, false, divisor);
|
||||||
Console.WriteLine($"Finished processing {prime}");
|
Console.WriteLine($"Finished processing {prime}");
|
||||||
|
|||||||
@@ -15,10 +15,12 @@ public static class PerfectNumberConstants
|
|||||||
public const int PooledArrayThreshold = 64;
|
public const int PooledArrayThreshold = 64;
|
||||||
public const int Pow2WindowSize = 8;
|
public const int Pow2WindowSize = 8;
|
||||||
public static int RollingAccelerators = 298; //SharedGpuContext.Device.MaxNumThreadsPerGroup;
|
public static int RollingAccelerators = 298; //SharedGpuContext.Device.MaxNumThreadsPerGroup;
|
||||||
public const int ThreadsByAccelerator = 16;
|
public const int ThreadsByAccelerator = 8;
|
||||||
|
public const int ByDivisorStateSaveInterval = 10_000;
|
||||||
|
public const string ByDivisorStateDirectory = "Checks";
|
||||||
// TODO: Load these limits from the benchmark-driven configuration so CPU and GPU scans stay aligned with the optimal
|
// TODO: Load these limits from the benchmark-driven configuration so CPU and GPU scans stay aligned with the optimal
|
||||||
// divisor-cycle datasets we generate offline.
|
// divisor-cycle datasets we generate offline.
|
||||||
// TODO: Promote these magic numbers into a runtime profile derived from EvenPerfectBitScanner.Benchmarks so we can retune
|
// TODO: Promote these magic numbers into a runtime profile derived from EvenPerfectBitScanner.Benchmarks so we can retune
|
||||||
// them automatically when the optimal ranges for 2kp+1 >= 138M change.
|
// them automatically when the optimal ranges for 2kp+1 >= 138M change.
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user