Hybrid device mode implemented as the current --mersenne=bydivisor CPU execution path. CPU path is now limited to CPU calculations, only.
This commit is contained in:
1 parent
353a121d03
commit
941733905b
49 files changed
+4965
-1726
No files matched your search
@@ -54,7 +54,7 @@ internal static class CandidatesCalculator
|
||||
return trackers.Value!;
|
||||
}
|
||||
|
||||
internal static bool IsCompositeByResidues(PrimeOrderCalculatorAccelerator gpu, ulong p)
|
||||
internal static bool IsCompositeByResiduesCpu(ulong p)
|
||||
{
|
||||
ModResidueTracker tracker = AcquireResidueTracker();
|
||||
// Use ModResidueTracker with a small set of primes to pre-filter composite p.
|
||||
@@ -72,7 +72,57 @@ internal static class CandidatesCalculator
|
||||
break;
|
||||
}
|
||||
|
||||
if (tracker.MergeOrAppend(gpu, p, primes[primeIndex], out bool divisible) && divisible)
|
||||
if (tracker.MergeOrAppendCpu(p, primes[primeIndex], out bool divisible) && divisible)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool IsCompositeByResiduesGpu(PrimeOrderCalculatorAccelerator gpu, ulong p)
|
||||
{
|
||||
ModResidueTracker tracker = AcquireResidueTracker();
|
||||
// Use ModResidueTracker with a small set of primes to pre-filter composite p.
|
||||
tracker.BeginMerge(p);
|
||||
// TODO: Integrate the divisor-cycle cache here so the small-prime sweep reuses precomputed remainders instead of
|
||||
// running MergeOrAppend for every candidate and missing the cycle-accelerated early exits.
|
||||
// Use the small prime list from PerfectNumbers.Core to the extent of sqrt(p)
|
||||
var primes = PrimesGenerator.SmallPrimes;
|
||||
var primesPow2 = PrimesGenerator.SmallPrimesPow2;
|
||||
int len = primes.Length;
|
||||
for (int primeIndex = 0; primeIndex < len; primeIndex++)
|
||||
{
|
||||
if (primesPow2[primeIndex] > p)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (tracker.MergeOrAppendGpu(gpu, p, primes[primeIndex], out bool divisible) && divisible)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool IsCompositeByResiduesHybrid(PrimeOrderCalculatorAccelerator gpu, ulong p)
|
||||
{
|
||||
ModResidueTracker tracker = AcquireResidueTracker();
|
||||
tracker.BeginMerge(p);
|
||||
var primes = PrimesGenerator.SmallPrimes;
|
||||
var primesPow2 = PrimesGenerator.SmallPrimesPow2;
|
||||
int len = primes.Length;
|
||||
for (int primeIndex = 0; primeIndex < len; primeIndex++)
|
||||
{
|
||||
if (primesPow2[primeIndex] > p)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (tracker.MergeOrAppendHybrid(gpu, p, primes[primeIndex], out bool divisible) && divisible)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ internal readonly struct CliArguments
|
||||
internal readonly bool UseGcdFilter;
|
||||
internal readonly bool TestMode;
|
||||
internal readonly bool UseGpuCycles;
|
||||
internal readonly bool UseMersenneOnGpu;
|
||||
internal readonly bool UseOrderOnGpu;
|
||||
internal readonly ComputationDevice MersenneDevice;
|
||||
internal readonly ComputationDevice OrderDevice;
|
||||
internal readonly int ScanBatchSize;
|
||||
internal readonly int SliceSize;
|
||||
internal readonly ulong ResidueKMax;
|
||||
@@ -72,8 +72,8 @@ internal readonly struct CliArguments
|
||||
bool useGcdFilter,
|
||||
bool testMode,
|
||||
bool useGpuCycles,
|
||||
bool useMersenneOnGpu,
|
||||
bool useOrderOnGpu,
|
||||
ComputationDevice mersenneDevice,
|
||||
ComputationDevice orderDevice,
|
||||
int scanBatchSize,
|
||||
int sliceSize,
|
||||
ulong residueKMax,
|
||||
@@ -116,8 +116,8 @@ internal readonly struct CliArguments
|
||||
UseGcdFilter = useGcdFilter;
|
||||
TestMode = testMode;
|
||||
UseGpuCycles = useGpuCycles;
|
||||
UseMersenneOnGpu = useMersenneOnGpu;
|
||||
UseOrderOnGpu = useOrderOnGpu;
|
||||
MersenneDevice = mersenneDevice;
|
||||
OrderDevice = orderDevice;
|
||||
ScanBatchSize = scanBatchSize;
|
||||
SliceSize = sliceSize;
|
||||
ResidueKMax = residueKMax;
|
||||
@@ -165,8 +165,8 @@ internal readonly struct CliArguments
|
||||
bool useGcdFilter = false;
|
||||
bool testMode = false;
|
||||
bool useGpuCycles = true;
|
||||
bool useMersenneOnGpu = true;
|
||||
bool useOrderOnGpu = true;
|
||||
ComputationDevice mersenneDevice = ComputationDevice.Gpu;
|
||||
ComputationDevice orderDevice = ComputationDevice.Gpu;
|
||||
int scanBatchSize = 2_097_152;
|
||||
int sliceSize = 32;
|
||||
ulong residueKMax = 5_000_000UL;
|
||||
@@ -319,7 +319,8 @@ internal readonly struct CliArguments
|
||||
|
||||
if (argument.StartsWith("--mersenne-device=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
useMersenneOnGpu = !argument.AsSpan("--mersenne-device=".Length).Equals("cpu", StringComparison.OrdinalIgnoreCase);
|
||||
ReadOnlySpan<char> value = argument.AsSpan("--mersenne-device=".Length);
|
||||
mersenneDevice = ParseDevice(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -389,7 +390,8 @@ internal readonly struct CliArguments
|
||||
|
||||
if (argument.StartsWith("--order-device=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
useOrderOnGpu = !argument.AsSpan("--order-device=".Length).Equals("cpu", StringComparison.OrdinalIgnoreCase);
|
||||
ReadOnlySpan<char> value = argument.AsSpan("--order-device=".Length);
|
||||
orderDevice = ParseDevice(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -445,7 +447,7 @@ internal readonly struct CliArguments
|
||||
|
||||
if (argument.StartsWith("--lucas=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
useMersenneOnGpu = !argument.AsSpan("--lucas=".Length).Equals("cpu", StringComparison.OrdinalIgnoreCase);
|
||||
mersenneDevice = ParseDevice(argument.AsSpan("--lucas=".Length));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -565,8 +567,8 @@ internal readonly struct CliArguments
|
||||
useGcdFilter,
|
||||
testMode,
|
||||
useGpuCycles,
|
||||
useMersenneOnGpu,
|
||||
useOrderOnGpu,
|
||||
mersenneDevice,
|
||||
orderDevice,
|
||||
scanBatchSize,
|
||||
sliceSize,
|
||||
residueKMax,
|
||||
@@ -603,10 +605,10 @@ internal readonly struct CliArguments
|
||||
Console.WriteLine(" --block-size=<value> values processed per thread batch");
|
||||
Console.WriteLine(" --mersenne=pow2mod|incremental|lucas|residue|divisor|bydivisor Mersenne test method");
|
||||
Console.WriteLine(" --residue-max-k=<value> max k for residue Mersenne test (q = 2*p*k + 1)");
|
||||
Console.WriteLine(" --mersenne-device=cpu|gpu Device for Mersenne method (default gpu)");
|
||||
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)");
|
||||
Console.WriteLine(" --gpu-prime-batch=<n> Batch size for GPU primality sieve (default 262144)");
|
||||
Console.WriteLine(" --order-device=cpu|gpu Device for order computations (default gpu)");
|
||||
Console.WriteLine(" --order-device=cpu|gpu|hybrid Device for order computations (default gpu)");
|
||||
Console.WriteLine(" --ntt=reference|staged GPU NTT backend (default staged)");
|
||||
Console.WriteLine(" --mod-reduction=auto|uint128|mont64|barrett128 staged NTT reduction (default auto)");
|
||||
Console.WriteLine(" --gpu-prime-threads=<value> max concurrent GPU prime checks (default 1)");
|
||||
@@ -632,4 +634,19 @@ internal readonly struct CliArguments
|
||||
Console.WriteLine(" --min-k=<value> starting k for --mersenne=bydivisor divisor scan (default 1)");
|
||||
Console.WriteLine(" --help, -help, --?, -?, /? show this help message");
|
||||
}
|
||||
|
||||
private static ComputationDevice ParseDevice(ReadOnlySpan<char> value)
|
||||
{
|
||||
if (value.Equals("cpu", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return ComputationDevice.Cpu;
|
||||
}
|
||||
|
||||
if (value.Equals("hybrid", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return ComputationDevice.Hybrid;
|
||||
}
|
||||
|
||||
return ComputationDevice.Gpu;
|
||||
}
|
||||
}
|
||||
@@ -83,8 +83,11 @@ internal static class Program
|
||||
? PrimeTransformMode.Bit
|
||||
: (useResidue ? PrimeTransformMode.Add : PrimeTransformMode.AddPrimes);
|
||||
CandidatesCalculator.Configure(transformMode);
|
||||
bool mersenneOnGpu = _cliArguments.UseMersenneOnGpu;
|
||||
bool orderOnGpu = _cliArguments.UseOrderOnGpu;
|
||||
ComputationDevice mersenneDevice = _cliArguments.MersenneDevice;
|
||||
ComputationDevice orderDevice = _cliArguments.OrderDevice;
|
||||
bool mersenneOnGpu = mersenneDevice == ComputationDevice.Gpu;
|
||||
bool orderOnGpu = orderDevice == ComputationDevice.Gpu;
|
||||
bool orderOnHybrid = orderDevice == ComputationDevice.Hybrid;
|
||||
int scanBatchSize = Math.Max(1, _cliArguments.ScanBatchSize);
|
||||
int sliceSize = Math.Max(1, _cliArguments.SliceSize);
|
||||
ulong residueKMax = _cliArguments.ResidueKMax;
|
||||
@@ -165,7 +168,6 @@ internal static class Program
|
||||
}
|
||||
|
||||
DivisorCycleCache.SetDivisorCyclesBatchSize(cyclesBatchSize);
|
||||
DivisorCycleCache.Shared.ConfigureGeneratorDevice(useGpuCycles);
|
||||
// TODO: Keep a single cached block loaded from disk and honor the configured device when
|
||||
// computing ad-hoc cycles for divisors that fall outside that snapshot instead of queuing
|
||||
// generation of additional blocks.
|
||||
@@ -194,13 +196,25 @@ internal static class Program
|
||||
useOrder: useOrder,
|
||||
useGpuLucas: mersenneOnGpu,
|
||||
useGpuScan: mersenneOnGpu,
|
||||
useGpuOrder: orderOnGpu,
|
||||
useGpuOrder: orderOnGpu || orderOnHybrid,
|
||||
useResidue: useResidue,
|
||||
maxK: residueKMax);
|
||||
maxK: residueKMax,
|
||||
orderDevice: orderDevice);
|
||||
if (!useLucas)
|
||||
{
|
||||
Console.WriteLine("Warming up orders");
|
||||
tester.WarmUpOrders(currentP, orderWarmupLimitOverride ?? 5_000_000UL);
|
||||
if (orderDevice == ComputationDevice.Hybrid)
|
||||
{
|
||||
tester.WarmUpOrdersHybrid(currentP, orderWarmupLimitOverride ?? 5_000_000UL);
|
||||
}
|
||||
else if (orderDevice == ComputationDevice.Gpu)
|
||||
{
|
||||
tester.WarmUpOrdersGpu(currentP, orderWarmupLimitOverride ?? 5_000_000UL);
|
||||
}
|
||||
else
|
||||
{
|
||||
tester.WarmUpOrdersCpu(currentP, orderWarmupLimitOverride ?? 5_000_000UL);
|
||||
}
|
||||
}
|
||||
|
||||
return tester;
|
||||
@@ -216,7 +230,7 @@ internal static class Program
|
||||
{
|
||||
_byDivisorTester = mersenneOnGpu
|
||||
? new MersenneNumberDivisorByDivisorGpuTester()
|
||||
: new MersenneNumberDivisorByDivisorCpuTester();
|
||||
: new MersenneNumberDivisorByDivisorCpuTester(orderDevice);
|
||||
_byDivisorTester.MinK = _cliArguments.MinK;
|
||||
_byDivisorTester.BatchSize = scanBatchSize;
|
||||
}
|
||||
@@ -245,6 +259,20 @@ internal static class Program
|
||||
|
||||
Console.WriteLine("Initialization...");
|
||||
// Compose a results file name that encodes configuration (before opening file)
|
||||
string mersenneDeviceLabel = mersenneDevice switch
|
||||
{
|
||||
ComputationDevice.Hybrid => "hybrid",
|
||||
ComputationDevice.Gpu => "gpu",
|
||||
_ => "cpu",
|
||||
};
|
||||
|
||||
string orderDeviceLabel = orderDevice switch
|
||||
{
|
||||
ComputationDevice.Hybrid => "hybrid",
|
||||
ComputationDevice.Gpu => "gpu",
|
||||
_ => "cpu",
|
||||
};
|
||||
|
||||
var builtName = CalculationResultsFile.BuildFileName(
|
||||
useBitTransform,
|
||||
threadCount,
|
||||
@@ -257,14 +285,14 @@ internal static class Program
|
||||
useOrder,
|
||||
_cliArguments.UseGcdFilter,
|
||||
NttGpuMath.GpuTransformBackend,
|
||||
gpuPrimeThreads,
|
||||
sliceSize,
|
||||
scanBatchSize,
|
||||
orderWarmupLimitOverride ?? 5_000_000UL,
|
||||
NttGpuMath.ReductionMode,
|
||||
mersenneOnGpu ? "gpu" : "cpu",
|
||||
_runPrimesOnCpu ? "cpu" : "gpu",
|
||||
orderOnGpu ? "gpu" : "cpu");
|
||||
gpuPrimeThreads,
|
||||
sliceSize,
|
||||
scanBatchSize,
|
||||
orderWarmupLimitOverride ?? 5_000_000UL,
|
||||
NttGpuMath.ReductionMode,
|
||||
mersenneDeviceLabel,
|
||||
_runPrimesOnCpu ? "cpu" : "gpu",
|
||||
orderDeviceLabel);
|
||||
|
||||
if (!string.IsNullOrEmpty(_cliArguments.ResultsPrefix))
|
||||
{
|
||||
@@ -447,7 +475,18 @@ internal static class Program
|
||||
if (!useLucas)
|
||||
{
|
||||
Console.WriteLine("Warming up orders...");
|
||||
MersenneTesters.Value!.WarmUpOrders(currentP, orderWarmupLimitOverride ?? 5_000_000UL);
|
||||
if (orderDevice == ComputationDevice.Hybrid)
|
||||
{
|
||||
MersenneTesters.Value!.WarmUpOrdersHybrid(currentP, orderWarmupLimitOverride ?? 5_000_000UL);
|
||||
}
|
||||
else if (orderDevice == ComputationDevice.Gpu)
|
||||
{
|
||||
MersenneTesters.Value!.WarmUpOrdersGpu(currentP, orderWarmupLimitOverride ?? 5_000_000UL);
|
||||
}
|
||||
else
|
||||
{
|
||||
MersenneTesters.Value!.WarmUpOrdersCpu(currentP, orderWarmupLimitOverride ?? 5_000_000UL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -619,7 +658,12 @@ internal static class Program
|
||||
}
|
||||
|
||||
// Fast residue-based composite check for p using small primes
|
||||
if (!_cliArguments.UseDivisor && !_cliArguments.UseByDivisor && CandidatesCalculator.IsCompositeByResidues(gpu, p))
|
||||
if (!_cliArguments.UseDivisor && !_cliArguments.UseByDivisor &&
|
||||
(
|
||||
(_cliArguments.OrderDevice == ComputationDevice.Gpu && CandidatesCalculator.IsCompositeByResiduesGpu(gpu, p)) ||
|
||||
(_cliArguments.OrderDevice == ComputationDevice.Hybrid && CandidatesCalculator.IsCompositeByResiduesHybrid(gpu, p)) ||
|
||||
(_cliArguments.OrderDevice == ComputationDevice.Cpu && CandidatesCalculator.IsCompositeByResiduesCpu(p))
|
||||
))
|
||||
{
|
||||
searchedMersenne = false;
|
||||
detailedCheck = false;
|
||||
|
||||
Reference in new issue
Block a user