DivisorSet scans added as EnumDependentTemplate to MersenneNumberDivisorByDivisorCpuTesterWithTemplate. New Pow2Groups scan implemented based on statistics for high divisors. MersenneNumberDivisorByDivisorPrimeScan sessions integrated into MersenneNumberDivisorByDivisorPrimeScanSessionWithTemplate. Various micro optimizations to eliminate variable, unnecessary struct creations and continue scans in higher divisor ranges, when lower ranges are exhausted. --bydivisor-k-increment command-line argument added.

This commit is contained in:
mlemanczyk committed 2025-12-28 00:45:08 +01:00
1 parent 759614de54
commit 87a66e4eca
13 files changed
+2539 -496

No files matched your search

+87 -40
View File
@@ -5,8 +5,8 @@ using PerfectNumbers.Core.Gpu;
namespace EvenPerfectBitScanner;
internal readonly struct CliArguments
{
internal readonly struct CliArguments
{
private const string DefaultCyclesPath = "divisor_cycles.bin";
internal readonly ulong StartPrime;
@@ -24,8 +24,10 @@ internal readonly struct CliArguments
internal readonly bool UseLucas;
internal readonly bool UseResidue;
internal readonly bool UseDivisor;
internal readonly bool UseByDivisor;
internal readonly bool UseGcdFilter;
internal readonly bool UseByDivisor;
internal readonly bool UseDivisorPow2Increment;
internal readonly int ByDivisorSpecialRange;
internal readonly bool UseGcdFilter;
internal readonly bool TestMode;
internal readonly bool UseGpuCycles;
internal readonly ComputationDevice MersenneDevice;
@@ -72,6 +74,8 @@ internal readonly struct CliArguments
bool useDivisor,
bool useByDivisor,
bool useGcdFilter,
bool useDivisorPow2Increment,
int byDivisorSpecialRange,
bool testMode,
bool useGpuCycles,
ComputationDevice mersenneDevice,
@@ -116,6 +120,8 @@ internal readonly struct CliArguments
UseResidue = useResidue;
UseDivisor = useDivisor;
UseByDivisor = useByDivisor;
UseDivisorPow2Increment = useDivisorPow2Increment;
ByDivisorSpecialRange = byDivisorSpecialRange;
UseGcdFilter = useGcdFilter;
TestMode = testMode;
UseGpuCycles = useGpuCycles;
@@ -166,6 +172,8 @@ internal readonly struct CliArguments
bool useResidue = false;
bool useDivisor = false;
bool useByDivisor = false;
bool useDivisorPow2Increment = false;
int byDivisorSpecialRange = 0;
bool useGcdFilter = false;
bool testMode = false;
bool useGpuCycles = true;
@@ -293,6 +301,41 @@ internal readonly struct CliArguments
continue;
}
if (argument.StartsWith("--bydivisor-k-increment=", StringComparison.OrdinalIgnoreCase))
{
string value = argument["--bydivisor-k-increment=".Length..].Trim();
if (value.Equals("pow2groups", StringComparison.OrdinalIgnoreCase))
{
useDivisorPow2Increment = true;
}
else if (value.Equals("sequential", StringComparison.OrdinalIgnoreCase))
{
useDivisorPow2Increment = false;
}
else
{
Console.WriteLine("Invalid value for --bydivisor-k-increment. Use onebyone or pow2groups.");
return default;
}
continue;
}
if (argument.StartsWith("--bydivisor-special-range=", StringComparison.OrdinalIgnoreCase))
{
if (Utf8CliParser.TryParseInt32(argument.AsSpan("--bydivisor-special-range=".Length), out int parsedRange) && parsedRange >= 0)
{
byDivisorSpecialRange = parsedRange;
}
else
{
Console.WriteLine("Invalid value for --bydivisor-special-range. Use a non-negative integer.");
return default;
}
continue;
}
if (argument.StartsWith("--divisor-cycles-limit=", StringComparison.OrdinalIgnoreCase))
{
if (Utf8CliParser.TryParseUInt64(argument.AsSpan("--divisor-cycles-limit=".Length), out ulong parsedLimit))
@@ -576,10 +619,10 @@ internal readonly struct CliArguments
}
return new CliArguments(
startPrime,
startPrimeProvided,
maxPrimeLimit,
maxPrimeConfigured,
startPrime,
startPrimeProvided,
maxPrimeLimit,
maxPrimeConfigured,
threadCount,
blockSize,
gpuPrimeThreads,
@@ -589,37 +632,39 @@ internal readonly struct CliArguments
showHelp,
useBitTransform,
useLucas,
useResidue,
useDivisor,
useByDivisor,
useGcdFilter,
testMode,
useGpuCycles,
mersenneDevice,
orderDevice,
scanBatchSize,
sliceSize,
residueKMax,
filterFile,
forcePrimeKernelsOnCpu,
modReductionMode,
nttBackend,
resultsDirectory,
resultsPrefix,
writeBatchSize,
cyclesPath,
continueCyclesGeneration,
cyclesBatchSize,
divisorCyclesSearchLimit,
orderWarmupLimitOverride,
rleBlacklistPath,
rleHardMaxP,
rleOnlyLast7,
zeroFractionHard,
zeroFractionConjecture,
maxZeroConjecture,
minK,
gpuRatio);
useResidue,
useDivisor,
useByDivisor,
useGcdFilter,
useDivisorPow2Increment,
byDivisorSpecialRange,
testMode,
useGpuCycles,
mersenneDevice,
orderDevice,
scanBatchSize,
sliceSize,
residueKMax,
filterFile,
forcePrimeKernelsOnCpu,
modReductionMode,
nttBackend,
resultsDirectory,
resultsPrefix,
writeBatchSize,
cyclesPath,
continueCyclesGeneration,
cyclesBatchSize,
divisorCyclesSearchLimit,
orderWarmupLimitOverride,
rleBlacklistPath,
rleHardMaxP,
rleOnlyLast7,
zeroFractionHard,
zeroFractionConjecture,
maxZeroConjecture,
minK,
gpuRatio);
}
internal static void PrintHelp()
@@ -632,7 +677,9 @@ internal readonly struct CliArguments
Console.WriteLine(" --max-prime=<value> inclusive upper bound for primes from filter files");
Console.WriteLine(" --increment=bit|add exponent increment method (default add)");
Console.WriteLine(" --threads=<value> number of worker threads");
Console.WriteLine(" --mersenne=pow2mod|incremental|lucas|residue|divisor|bydivisor Mersenne test method");
S Console.WriteLine(" --mersenne=pow2mod|incremental|lucas|residue|divisor|bydivisor Mersenne test method");
Console.WriteLine(" --bydivisor-k-increment=sequential|pow2groups k iteration strategy for --mersenne=bydivisor (default sequential)");
Console.WriteLine(" --bydivisor-special-range=<n> widen pow2groups special values to +/- n percent (default 0 = points)");
Console.WriteLine(" --residue-max-k=<value> max k for residue Mersenne test (q = 2*p*k + 1)");
Console.WriteLine(" --mersenne-device=cpu|gpu|hybrid Device for Mersenne method (default gpu)");
Console.WriteLine(" --primes-device=cpu|gpu device for prime-scan kernels (default gpu)");
+138 -45
View File
@@ -8,6 +8,13 @@ using PerfectNumbers.Core;
using PerfectNumbers.Core.Cpu;
using PerfectNumbers.Core.Gpu;
using PerfectNumbers.Core.Gpu.Accelerators;
using MersenneNumberDivisorByDivisorCpuTesterWithCpuOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForOneByOneDivisorSetForCpuOrder;
using MersenneNumberDivisorByDivisorCpuTesterWithHybridOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForOneByOneDivisorSetForHybridOrder;
using MersenneNumberDivisorByDivisorCpuTesterWithGpuOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForOneByOneDivisorSetForGpuOrder;
using ByDivisorCpuOrderPow2 = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForCpuOrder;
using ByDivisorHybridOrderPow2 = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForHybridOrder;
using ByDivisorGpuOrderPow2 = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForPow2GroupsDivisorSetForGpuOrder;
using System.Globalization;
namespace EvenPerfectBitScanner;
@@ -21,6 +28,9 @@ private static ThreadLocal<object>? MersenneTesters;
private static MersenneNumberDivisorByDivisorCpuTesterWithCpuOrder _byDivisorCpuOrderTester;
private static MersenneNumberDivisorByDivisorCpuTesterWithHybridOrder _byDivisorHybridOrderTester;
private static MersenneNumberDivisorByDivisorCpuTesterWithGpuOrder _byDivisorGpuOrderTester;
private static ByDivisorCpuOrderPow2 _byDivisorCpuOrderTesterPow2;
private static ByDivisorHybridOrderPow2 _byDivisorHybridOrderTesterPow2;
private static ByDivisorGpuOrderPow2 _byDivisorGpuOrderTesterPow2;
private static Dictionary<ulong, (bool DetailedCheck, bool PassedAllTests)>? _byDivisorPreviousResults;
private static bool _limitReached;
private static ulong _byDivisorStartPrime;
@@ -56,16 +66,18 @@ private static ThreadLocal<object>? MersenneTesters;
return;
}
Console.WriteLine("Initializing");
int gpuPrimeThreads = Math.Max(1, _cliArguments.GpuPrimeThreads);
int threadCount = Math.Max(1, _cliArguments.ThreadCount);
Console.WriteLine("Initializing");
int gpuPrimeThreads = Math.Max(1, _cliArguments.GpuPrimeThreads);
int threadCount = Math.Max(1, _cliArguments.ThreadCount);
EnvironmentConfiguration.MinK = _cliArguments.MinK;
EnvironmentConfiguration.GpuBatchSize = Math.Max(1, _cliArguments.ScanBatchSize);
EnvironmentConfiguration.GpuRatio = _cliArguments.GpuRatio;
EnvironmentConfiguration.OrderDevice = _cliArguments.OrderDevice;
EnvironmentConfiguration.RollingAccelerators = Math.Min(Math.Min(PerfectNumberConstants.RollingAccelerators, gpuPrimeThreads), threadCount);
EnvironmentConfiguration.Initialize();
EnvironmentConfiguration.MinK = _cliArguments.MinK;
EnvironmentConfiguration.GpuBatchSize = Math.Max(1, _cliArguments.ScanBatchSize);
EnvironmentConfiguration.GpuRatio = _cliArguments.GpuRatio;
EnvironmentConfiguration.OrderDevice = _cliArguments.OrderDevice;
EnvironmentConfiguration.UsePow2GroupDivisors = _cliArguments.UseDivisorPow2Increment;
EnvironmentConfiguration.ByDivisorSpecialRange = _cliArguments.ByDivisorSpecialRange;
EnvironmentConfiguration.RollingAccelerators = Math.Min(Math.Min(PerfectNumberConstants.RollingAccelerators, gpuPrimeThreads), threadCount);
EnvironmentConfiguration.Initialize();
// NttGpuMath.GpuTransformBackend = _cliArguments.NttBackend;
// NttGpuMath.ReductionMode = _cliArguments.ModReductionMode;
@@ -257,17 +269,39 @@ private static ThreadLocal<object>? MersenneTesters;
throw new NotSupportedException("--mersenne-device=gpu is not supported for --mersenne=bydivisor on this execution path.");
}
bool usePow2Divisors = _cliArguments.UseDivisorPow2Increment;
if (EnvironmentConfiguration.UseCpuOrder)
{
_byDivisorCpuOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithCpuOrder();
if (usePow2Divisors)
{
_byDivisorCpuOrderTesterPow2 = new ByDivisorCpuOrderPow2();
}
else
{
_byDivisorCpuOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithCpuOrder();
}
}
else if (EnvironmentConfiguration.UseHybridOrder)
{
_byDivisorHybridOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithHybridOrder();
if (usePow2Divisors)
{
_byDivisorHybridOrderTesterPow2 = new ByDivisorHybridOrderPow2();
}
else
{
_byDivisorHybridOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithHybridOrder();
}
}
else
{
_byDivisorGpuOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithGpuOrder();
if (usePow2Divisors)
{
_byDivisorGpuOrderTesterPow2 = new ByDivisorGpuOrderPow2();
}
else
{
_byDivisorGpuOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithGpuOrder();
}
}
}
@@ -483,44 +517,96 @@ private static ThreadLocal<object>? MersenneTesters;
if (useByDivisor)
{
int byDivisorPrimeRange = Math.Max(1, _cliArguments.BlockSize);
bool usePow2Divisors = _cliArguments.UseDivisorPow2Increment;
if (EnvironmentConfiguration.UseCpuOrder)
{
MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates,
ref _byDivisorCpuOrderTester,
_byDivisorPreviousResults,
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
if (usePow2Divisors)
{
Console.WriteLine("Using by-divisor pow2groups increment (CPU order).");
MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates,
ref _byDivisorCpuOrderTesterPow2,
_byDivisorPreviousResults,
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
}
else
{
MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates,
ref _byDivisorCpuOrderTester,
_byDivisorPreviousResults,
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
}
}
else if (EnvironmentConfiguration.UseHybridOrder)
{
MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates,
ref _byDivisorHybridOrderTester,
_byDivisorPreviousResults,
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
if (usePow2Divisors)
{
Console.WriteLine("Using by-divisor pow2groups increment (Hybrid order).");
MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates,
ref _byDivisorHybridOrderTesterPow2,
_byDivisorPreviousResults,
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
}
else
{
MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates,
ref _byDivisorHybridOrderTester,
_byDivisorPreviousResults,
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
}
}
else
{
MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates,
ref _byDivisorGpuOrderTester,
_byDivisorPreviousResults,
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
if (usePow2Divisors)
{
Console.WriteLine("Using by-divisor pow2groups increment (GPU order).");
MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates,
ref _byDivisorGpuOrderTesterPow2,
_byDivisorPreviousResults,
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
}
else
{
MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates,
ref _byDivisorGpuOrderTester,
_byDivisorPreviousResults,
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
}
}
CalculationResultHandler.FlushBuffer();
@@ -907,17 +993,24 @@ private static ThreadLocal<object>? MersenneTesters;
if (_cliArguments.UseByDivisor)
{
// Windowed pow2mod kernel handles by-divisor scans.
bool usePow2Divisors = _cliArguments.UseDivisorPow2Increment;
if (EnvironmentConfiguration.UseCpuOrder)
{
return _byDivisorCpuOrderTester.IsPrime(p, out detailedCheck, out _);
return usePow2Divisors
? _byDivisorCpuOrderTesterPow2.IsPrime(p, out detailedCheck, out _)
: _byDivisorCpuOrderTester.IsPrime(p, out detailedCheck, out _);
}
if (EnvironmentConfiguration.UseHybridOrder)
{
return _byDivisorHybridOrderTester.IsPrime(p, out detailedCheck, out _);
return usePow2Divisors
? _byDivisorHybridOrderTesterPow2.IsPrime(p, out detailedCheck, out _)
: _byDivisorHybridOrderTester.IsPrime(p, out detailedCheck, out _);
}
return _byDivisorGpuOrderTester.IsPrime(p, out detailedCheck, out _);
return usePow2Divisors
? _byDivisorGpuOrderTesterPow2.IsPrime(p, out detailedCheck, out _)
: _byDivisorGpuOrderTester.IsPrime(p, out detailedCheck, out _);
}
detailedCheck = IsMersennePrime(gpu, p);