BuildDivisorCandidates moved to MersenneNumberDivisorGpuTester. Micro-optimizations.
This commit is contained in:
1 parent
82737b99fd
commit
0535ad2b7b
3 files changed
+216
-224
No files matched your search
@@ -26,11 +26,9 @@ internal static class Program
|
|||||||
private static int _primeCount;
|
private static int _primeCount;
|
||||||
private static bool _primeFoundAfterInit;
|
private static bool _primeFoundAfterInit;
|
||||||
private static bool _useGcdFilter;
|
private static bool _useGcdFilter;
|
||||||
private static bool _useResidue;
|
|
||||||
private static bool _useDivisor;
|
private static bool _useDivisor;
|
||||||
private static ulong _divisor;
|
private static ulong _divisor;
|
||||||
private static MersenneNumberDivisorGpuTester? _divisorTester;
|
private static MersenneNumberDivisorGpuTester? _divisorTester;
|
||||||
private static (ulong divisor, uint cycle)[]? _divisorCandidates;
|
|
||||||
private static ulong? _orderWarmupLimitOverride;
|
private static ulong? _orderWarmupLimitOverride;
|
||||||
private static unsafe delegate*<ulong, ref ulong, ulong> _transformP;
|
private static unsafe delegate*<ulong, ref ulong, ulong> _transformP;
|
||||||
private static long _state;
|
private static long _state;
|
||||||
@@ -367,7 +365,7 @@ internal static class Program
|
|||||||
|
|
||||||
// Apply GPU prime sieve runtime configuration
|
// Apply GPU prime sieve runtime configuration
|
||||||
GpuPrimeWorkLimiter.SetLimit(gpuPrimeThreads);
|
GpuPrimeWorkLimiter.SetLimit(gpuPrimeThreads);
|
||||||
PerfectNumbers.Core.PrimeTester.GpuBatchSize = Math.Max(1, gpuPrimeBatch);
|
PrimeTester.GpuBatchSize = Math.Max(1, gpuPrimeBatch);
|
||||||
|
|
||||||
MersenneDivisorCycles mersenneDivisorCycles = new();
|
MersenneDivisorCycles mersenneDivisorCycles = new();
|
||||||
if (!File.Exists(cyclesPath) || continueCyclesGeneration)
|
if (!File.Exists(cyclesPath) || continueCyclesGeneration)
|
||||||
@@ -412,7 +410,6 @@ internal static class Program
|
|||||||
|
|
||||||
Console.WriteLine("Divisor cycles are ready");
|
Console.WriteLine("Divisor cycles are ready");
|
||||||
|
|
||||||
_useResidue = useResidue;
|
|
||||||
_useDivisor = useDivisor;
|
_useDivisor = useDivisor;
|
||||||
_divisor = divisor;
|
_divisor = divisor;
|
||||||
_transformP = useBitTransform ? &TransformPBit : &TransformPAdd;
|
_transformP = useBitTransform ? &TransformPBit : &TransformPAdd;
|
||||||
@@ -445,17 +442,18 @@ internal static class Program
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_divisorTester = new MersenneNumberDivisorGpuTester();
|
|
||||||
if (divisor == 0UL)
|
if (divisor == 0UL)
|
||||||
{
|
{
|
||||||
_divisorCandidates = BuildDivisorCandidates();
|
MersenneNumberDivisorGpuTester.BuildDivisorCandidates();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_divisorTester = new MersenneNumberDivisorGpuTester();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load RLE blacklist (optional)
|
// Load RLE blacklist (optional)
|
||||||
if (!string.IsNullOrEmpty(_rleBlacklistPath))
|
if (!string.IsNullOrEmpty(_rleBlacklistPath))
|
||||||
{
|
{
|
||||||
PerfectNumbers.Core.RleBlacklist.Load(_rleBlacklistPath!);
|
RleBlacklist.Load(_rleBlacklistPath!);
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong remainder = currentP % 6UL;
|
ulong remainder = currentP % 6UL;
|
||||||
@@ -552,7 +550,7 @@ internal static class Program
|
|||||||
// Limit GPU concurrency only for prime checks (LL/NTT & GPU order scans).
|
// Limit GPU concurrency only for prime checks (LL/NTT & GPU order scans).
|
||||||
GpuPrimeWorkLimiter.SetLimit(gpuPrimeThreads);
|
GpuPrimeWorkLimiter.SetLimit(gpuPrimeThreads);
|
||||||
// Configure batch size for GPU primality sieve
|
// Configure batch size for GPU primality sieve
|
||||||
PerfectNumbers.Core.PrimeTester.GpuBatchSize = gpuPrimeBatch;
|
PrimeTester.GpuBatchSize = gpuPrimeBatch;
|
||||||
|
|
||||||
// Compose a results file name that encodes configuration
|
// Compose a results file name that encodes configuration
|
||||||
ResultsFileName = BuildResultsFileName(
|
ResultsFileName = BuildResultsFileName(
|
||||||
@@ -589,33 +587,33 @@ internal static class Program
|
|||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("Starting scan...");
|
Console.WriteLine("Starting scan...");
|
||||||
_state = ((long)currentP << 3) | (long)remainder;
|
_state = ((long)currentP << 3) | (long)remainder;
|
||||||
Task[] tasks = new Task[threadCount];
|
Task[] tasks = new Task[threadCount];
|
||||||
|
|
||||||
for (int i = 0; i < threadCount; i++)
|
for (int i = 0; i < threadCount; i++)
|
||||||
{
|
{
|
||||||
tasks[i] = Task.Run(() =>
|
tasks[i] = Task.Run(() =>
|
||||||
{
|
{
|
||||||
ulong[] buffer = new ulong[blockSize];
|
ulong[] buffer = new ulong[blockSize];
|
||||||
while (!Volatile.Read(ref _limitReached))
|
while (!Volatile.Read(ref _limitReached))
|
||||||
{
|
{
|
||||||
int count = ReserveBlock(buffer, blockSize);
|
int count = ReserveBlock(buffer, blockSize);
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < count && !Volatile.Read(ref _limitReached); j++)
|
for (int j = 0; j < count && !Volatile.Read(ref _limitReached); j++)
|
||||||
{
|
{
|
||||||
ulong p = buffer[j];
|
ulong p = buffer[j];
|
||||||
if (useFilter && !filter.Contains(p))
|
if (useFilter && !filter.Contains(p))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (useFilter)
|
else if (useFilter)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Testing {p}");
|
Console.WriteLine($"Testing {p}");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isPerfect = IsEvenPerfectCandidate(p, divisorCyclesSearchLimit, out bool searchedMersenne, out bool detailedCheck);
|
bool isPerfect = IsEvenPerfectCandidate(p, divisorCyclesSearchLimit, out bool searchedMersenne, out bool detailedCheck);
|
||||||
PrintResult(p, searchedMersenne, detailedCheck, isPerfect);
|
PrintResult(p, searchedMersenne, detailedCheck, isPerfect);
|
||||||
@@ -736,36 +734,39 @@ internal static class Program
|
|||||||
return $"even_perfect_bit_scan_inc-{inc}_thr-{threads}_blk-{block}_mers-{mers}_mersdev-{mersenneDevice}_ntt-{ntt}_red-{red}_primesdev-{primesDevice}_{order}_orderdev-{orderDevice}_{gcd}_{work}_gputh-{gpuPrimeThreads}_llslice-{llSlice}_scanb-{gpuScanBatch}_warm-{warmupLimit}.csv";
|
return $"even_perfect_bit_scan_inc-{inc}_thr-{threads}_blk-{block}_mers-{mers}_mersdev-{mersenneDevice}_ntt-{ntt}_red-{red}_primesdev-{primesDevice}_{order}_orderdev-{orderDevice}_{gcd}_{work}_gputh-{gpuPrimeThreads}_llslice-{llSlice}_scanb-{gpuScanBatch}_warm-{warmupLimit}.csv";
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static unsafe int ReserveBlock(ulong[] buffer, int blockSize)
|
private static unsafe int ReserveBlock(ulong[] buffer, int blockSize)
|
||||||
{
|
{
|
||||||
while (true)
|
Span<ulong> bufferSpan = new(buffer);
|
||||||
{
|
ulong p, remainder;
|
||||||
long state = Volatile.Read(ref _state);
|
long state, newState, original;
|
||||||
ulong current = (ulong)state >> 3;
|
int count;
|
||||||
ulong remainder = ((ulong)state) & 7UL;
|
while (true)
|
||||||
|
{
|
||||||
|
state = Volatile.Read(ref _state);
|
||||||
|
p = (ulong)state >> 3;
|
||||||
|
remainder = ((ulong)state) & 7UL;
|
||||||
|
|
||||||
ulong p = current;
|
count = 0;
|
||||||
int count = 0;
|
while (count < blockSize && !Volatile.Read(ref _limitReached))
|
||||||
while (count < blockSize && !Volatile.Read(ref _limitReached))
|
{
|
||||||
{
|
bufferSpan[count++] = p;
|
||||||
buffer[count++] = p;
|
p = _transformP(p, ref remainder);
|
||||||
p = _transformP(p, ref remainder);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
long newState = ((long)p << 3) | (long)remainder;
|
newState = ((long)p << 3) | (long)remainder;
|
||||||
long original = Interlocked.CompareExchange(ref _state, newState, state);
|
original = Interlocked.CompareExchange(ref _state, newState, state);
|
||||||
if (original == state)
|
if (original == state)
|
||||||
{
|
{
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static void PrintResult(ulong currentP, bool searchedMersenne, bool detailedCheck, bool isPerfect)
|
private static void PrintResult(ulong currentP, bool searchedMersenne, bool detailedCheck, bool isPerfect)
|
||||||
@@ -913,46 +914,6 @@ internal static class Program
|
|||||||
return next + value;
|
return next + value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (ulong divisor, uint cycle)[] BuildDivisorCandidates()
|
|
||||||
{
|
|
||||||
uint[] snapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot();
|
|
||||||
Span<(ulong divisor, uint cycle)> list = stackalloc (ulong divisor, uint cycle)[snapshot.Length / 2];// new(snapshot.Length / 2);
|
|
||||||
uint cycle;
|
|
||||||
int count = 0, i, snapshotLength = snapshot.Length;
|
|
||||||
for (i = 3; i < snapshotLength; i += 2)
|
|
||||||
{
|
|
||||||
cycle = snapshot[i];
|
|
||||||
if (cycle == 0U)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
list[count++] = ((ulong)i, cycle);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list[..count].ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsDivisible(ulong exponent, ulong divisor)
|
|
||||||
{
|
|
||||||
if (_divisorTester is not null)
|
|
||||||
{
|
|
||||||
return _divisorTester.IsDivisible(exponent, divisor);
|
|
||||||
}
|
|
||||||
|
|
||||||
ulong remainder = 1UL;
|
|
||||||
for (ulong i = 0; i < exponent; i++)
|
|
||||||
{
|
|
||||||
remainder <<= 1;
|
|
||||||
if (remainder >= divisor)
|
|
||||||
{
|
|
||||||
remainder -= divisor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return remainder == 1UL;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static bool IsEvenPerfectCandidate(ulong p, int divisorCyclesSearchLimit)
|
internal static bool IsEvenPerfectCandidate(ulong p, int divisorCyclesSearchLimit)
|
||||||
{
|
{
|
||||||
@@ -974,7 +935,7 @@ internal static class Program
|
|||||||
{
|
{
|
||||||
if (!_rleOnlyLast7 || (p % 10UL) == 7UL)
|
if (!_rleOnlyLast7 || (p % 10UL) == 7UL)
|
||||||
{
|
{
|
||||||
if (PerfectNumbers.Core.RleBlacklist.IsLoaded() && PerfectNumbers.Core.RleBlacklist.Matches(p))
|
if (RleBlacklist.IsLoaded() && RleBlacklist.Matches(p))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1025,59 +986,7 @@ internal static class Program
|
|||||||
searchedMersenne = true;
|
searchedMersenne = true;
|
||||||
if (_useDivisor)
|
if (_useDivisor)
|
||||||
{
|
{
|
||||||
if (_divisor != 0UL)
|
return _divisorTester!.IsPrime(p, _divisor, divisorCyclesSearchLimit, out detailedCheck);
|
||||||
{
|
|
||||||
if (IsDivisible(p, _divisor))
|
|
||||||
{
|
|
||||||
detailedCheck = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
detailedCheck = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var candidates = _divisorCandidates!;
|
|
||||||
int len = candidates.Length;
|
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
var (d, cycle) = candidates[i];
|
|
||||||
if (p % cycle != 0UL)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsDivisible(p, d))
|
|
||||||
{
|
|
||||||
detailedCheck = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int k = 1; k <= divisorCyclesSearchLimit; k++)
|
|
||||||
{
|
|
||||||
ulong kMul2 = 2UL * (ulong)k;
|
|
||||||
if (p > ulong.MaxValue / kMul2)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ulong d = kMul2 * p + 1UL;
|
|
||||||
ulong cycle = MersenneDivisorCycles.Shared.GetCycle(d);
|
|
||||||
if (p % cycle != 0UL)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsDivisible(p, d))
|
|
||||||
{
|
|
||||||
detailedCheck = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
detailedCheck = false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
detailedCheck = MersenneTesters.Value!.IsMersennePrime(p);
|
detailedCheck = MersenneTesters.Value!.IsMersennePrime(p);
|
||||||
|
|||||||
@@ -12,6 +12,26 @@ public sealed class MersenneNumberDivisorGpuTester
|
|||||||
private Action<Index1D, ulong, ulong, ArrayView<byte>> GetKernel(Accelerator accelerator) =>
|
private Action<Index1D, ulong, ulong, ArrayView<byte>> GetKernel(Accelerator accelerator) =>
|
||||||
_kernelCache.GetOrAdd(accelerator, acc => acc.LoadAutoGroupedStreamKernel<Index1D, ulong, ulong, ArrayView<byte>>(Kernel));
|
_kernelCache.GetOrAdd(accelerator, acc => acc.LoadAutoGroupedStreamKernel<Index1D, ulong, ulong, ArrayView<byte>>(Kernel));
|
||||||
|
|
||||||
|
public static void BuildDivisorCandidates()
|
||||||
|
{
|
||||||
|
uint[] snapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot();
|
||||||
|
Span<(ulong divisor, uint cycle)> list = stackalloc (ulong divisor, uint cycle)[snapshot.Length / 2];
|
||||||
|
uint cycle;
|
||||||
|
int count = 0, i, snapshotLength = snapshot.Length;
|
||||||
|
for (i = 3; i < snapshotLength; i += 2)
|
||||||
|
{
|
||||||
|
cycle = snapshot[i];
|
||||||
|
if (cycle == 0U)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list[count++] = ((ulong)i, cycle);
|
||||||
|
}
|
||||||
|
|
||||||
|
_divisorCandidates = list[..count].ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsDivisible(ulong exponent, ulong divisor)
|
public bool IsDivisible(ulong exponent, ulong divisor)
|
||||||
{
|
{
|
||||||
var gpu = GpuContextPool.RentPreferred(preferCpu: false);
|
var gpu = GpuContextPool.RentPreferred(preferCpu: false);
|
||||||
@@ -26,6 +46,71 @@ public sealed class MersenneNumberDivisorGpuTester
|
|||||||
return divisible;
|
return divisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static (ulong divisor, uint cycle)[]? _divisorCandidates;
|
||||||
|
|
||||||
|
public bool IsPrime(ulong p, ulong d, int divisorCyclesSearchLimit, out bool detailedCheck)
|
||||||
|
{
|
||||||
|
if (d != 0UL)
|
||||||
|
{
|
||||||
|
if (IsDivisible(p, d))
|
||||||
|
{
|
||||||
|
detailedCheck = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
detailedCheck = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var candidates = _divisorCandidates!;
|
||||||
|
int k, len = candidates.Length;
|
||||||
|
uint cycle;
|
||||||
|
|
||||||
|
// k is simple iterator here
|
||||||
|
for (k = 0; k < len; k++)
|
||||||
|
{
|
||||||
|
(d, cycle) = candidates[k];
|
||||||
|
if (p % cycle != 0UL)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsDivisible(p, d))
|
||||||
|
{
|
||||||
|
detailedCheck = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong kMul2;
|
||||||
|
var divisorCycles = MersenneDivisorCycles.Shared;
|
||||||
|
for (k = 1; k <= divisorCyclesSearchLimit; k++)
|
||||||
|
{
|
||||||
|
kMul2 = (ulong)k << 1;
|
||||||
|
if (p > ulong.MaxValue / kMul2)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
d = kMul2 * p + 1UL;
|
||||||
|
// kkMul2 now becomes cycle. We're reusing existing variable for the best performance
|
||||||
|
kMul2 = divisorCycles.GetCycle(d);
|
||||||
|
if (p % kMul2 != 0UL)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsDivisible(p, d))
|
||||||
|
{
|
||||||
|
detailedCheck = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
detailedCheck = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private static void Kernel(Index1D _, ulong exponent, ulong divisor, ArrayView<byte> result)
|
private static void Kernel(Index1D _, ulong exponent, ulong divisor, ArrayView<byte> result)
|
||||||
{
|
{
|
||||||
if (divisor <= 1UL)
|
if (divisor <= 1UL)
|
||||||
|
|||||||
@@ -6,82 +6,80 @@ namespace PerfectNumbers.Core.Gpu;
|
|||||||
|
|
||||||
public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
||||||
{
|
{
|
||||||
private readonly bool _useGpuOrder = useGpuOrder;
|
private readonly bool _useGpuOrder = useGpuOrder;
|
||||||
// TODO: Integrate MersenneDivisorCycles.Shared to consult cycle lengths for small q (<= 4M) and fast-reject
|
// TODO: Integrate MersenneDivisorCycles.Shared to consult cycle lengths for small q (<= 4M) and fast-reject
|
||||||
// candidates without launching heavy kernels. Consider a device-visible constant buffer per-accelerator
|
// candidates without launching heavy kernels. Consider a device-visible constant buffer per-accelerator
|
||||||
// via GpuKernelPool to avoid host round-trips.
|
// via GpuKernelPool to avoid host round-trips.
|
||||||
|
|
||||||
// GPU residue variant: check 2^p % q == 1 for q = 2*p*k + 1.
|
// GPU residue variant: check 2^p % q == 1 for q = 2*p*k + 1.
|
||||||
public void Scan(ulong exponent, UInt128 twoP, bool lastIsSeven, UInt128 maxK, ref bool isPrime)
|
public void Scan(ulong exponent, UInt128 twoP, bool lastIsSeven, UInt128 maxK, ref bool isPrime)
|
||||||
{
|
{
|
||||||
var gpuLease = GpuKernelPool.GetKernel(_useGpuOrder);
|
var gpuLease = GpuKernelPool.GetKernel(_useGpuOrder);
|
||||||
var accelerator = gpuLease.Accelerator;
|
var accelerator = gpuLease.Accelerator;
|
||||||
// Ensure device has small cycles table for in-kernel lookup
|
// Ensure device has small cycles table for in-kernel lookup
|
||||||
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
||||||
int batchSize = GpuConstants.ScanBatchSize;
|
int batchSize = GpuConstants.ScanBatchSize;
|
||||||
UInt128 kStart = 1UL;
|
UInt128 kStart = 1UL;
|
||||||
byte last = lastIsSeven ? (byte)1 : (byte)0;
|
byte last = lastIsSeven ? (byte)1 : (byte)0;
|
||||||
var kernel = gpuLease.Pow2ModKernel;
|
var kernel = gpuLease.Pow2ModKernel;
|
||||||
|
|
||||||
var orderBuffer = accelerator.Allocate1D<ulong>(batchSize);
|
var orderBuffer = accelerator.Allocate1D<ulong>(batchSize);
|
||||||
ulong[] orderArray = ArrayPool<ulong>.Shared.Rent(batchSize);
|
ulong[] orderArray = ArrayPool<ulong>.Shared.Rent(batchSize);
|
||||||
UInt128 remaining;
|
UInt128 remaining;
|
||||||
int currentSize;
|
int currentSize;
|
||||||
int i;
|
int i;
|
||||||
UInt128 batchSize128 = (UInt128)batchSize,
|
UInt128 batchSize128 = (UInt128)batchSize, q;
|
||||||
q = UInt128.Zero;
|
Span<ulong> orders = orderArray.AsSpan(0, batchSize);
|
||||||
Span<ulong> orders = orderArray.AsSpan(0, batchSize);
|
try
|
||||||
try
|
{
|
||||||
{
|
while (kStart < maxK && Volatile.Read(ref isPrime))
|
||||||
while (kStart < maxK && Volatile.Read(ref isPrime))
|
{
|
||||||
{
|
remaining = maxK - kStart;
|
||||||
remaining = maxK - kStart;
|
if (remaining > batchSize128)
|
||||||
if (remaining > batchSize128)
|
{
|
||||||
{
|
currentSize = batchSize;
|
||||||
currentSize = batchSize;
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
currentSize = (int)remaining;
|
||||||
currentSize = (int)remaining;
|
orders = orderArray.AsSpan(0, currentSize);
|
||||||
orders = orderArray.AsSpan(0, currentSize);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
q = twoP * kStart + UInt128.One;
|
q = twoP * kStart + UInt128.One;
|
||||||
q.Mod10_8_5_3(out ulong q0m10, out ulong q0m8, out ulong q0m5, out ulong q0m3);
|
q.Mod10_8_5_3(out ulong q0m10, out ulong q0m8, out ulong q0m5, out ulong q0m3);
|
||||||
ulong step10 = ((exponent % 10UL) << 1) % 10UL;
|
ulong step10 = ((exponent % 10UL) << 1) % 10UL;
|
||||||
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
||||||
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
||||||
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
||||||
|
|
||||||
kernel(currentSize, exponent, (GpuUInt128)twoP, (GpuUInt128)kStart, last, 0UL,
|
kernel(currentSize, exponent, (GpuUInt128)twoP, (GpuUInt128)kStart, last, 0UL,
|
||||||
q0m10, q0m8, q0m3, q0m5, orderBuffer.View, smallCyclesView);
|
q0m10, q0m8, q0m3, q0m5, orderBuffer.View, smallCyclesView);
|
||||||
|
|
||||||
accelerator.Synchronize();
|
accelerator.Synchronize();
|
||||||
orderBuffer.View.CopyToCPU(ref MemoryMarshal.GetReference(orders), currentSize);
|
orderBuffer.View.CopyToCPU(ref MemoryMarshal.GetReference(orders), currentSize);
|
||||||
accelerator.Synchronize();
|
accelerator.Synchronize();
|
||||||
if (!Volatile.Read(ref isPrime))
|
if (!Volatile.Read(ref isPrime))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < currentSize; i++, q += twoP)
|
for (i = 0; i < currentSize; i++, q += twoP)
|
||||||
{
|
{
|
||||||
if (orders[i] != 0UL && q.IsPrimeCandidate())
|
if (orders[i] != 0UL && q.IsPrimeCandidate())
|
||||||
{
|
{
|
||||||
Volatile.Write(ref isPrime, false);
|
Volatile.Write(ref isPrime, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kStart += batchSize128;
|
kStart += batchSize128;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
ArrayPool<ulong>.Shared.Return(orderArray);
|
ArrayPool<ulong>.Shared.Return(orderArray);
|
||||||
orderBuffer.Dispose();
|
orderBuffer.Dispose();
|
||||||
gpuLease.Dispose();
|
gpuLease.Dispose();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user