Batch size made dynamic - dependent on the value
This commit is contained in:
1 parent
30af16a4f6
commit
e14b77e504
4 files changed
+846
-861
No files matched your search
@@ -70,8 +70,17 @@ internal static class PrimeTesterKernels
|
|||||||
|
|
||||||
public static void HeuristicTrialDivisionKernel(Index1D index, ArrayView<ulong> divisors, ulong n, ArrayView<int> resultFlag)
|
public static void HeuristicTrialDivisionKernel(Index1D index, ArrayView<ulong> divisors, ulong n, ArrayView<int> resultFlag)
|
||||||
{
|
{
|
||||||
ulong divisor = divisors[index];
|
ulong divisor = divisors[index];
|
||||||
Atomic.Or(ref resultFlag[0], divisor <= 1UL ? 0 : (n % divisor == 0UL ? 1 : 0));
|
if (divisor <= 1UL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong residue = n % divisor;
|
||||||
|
if (residue == 0UL)
|
||||||
|
{
|
||||||
|
resultFlag[0] = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SharesFactorKernel(Index1D index, ArrayView<ulong> numbers, ArrayView<byte> results)
|
public static void SharesFactorKernel(Index1D index, ArrayView<ulong> numbers, ArrayView<byte> results)
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
using System;
|
|
||||||
using Open.Numeric.Primes;
|
using Open.Numeric.Primes;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Numerics;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
|
||||||
using ILGPU;
|
|
||||||
using ILGPU.Algorithms;
|
|
||||||
using ILGPU.Runtime;
|
using ILGPU.Runtime;
|
||||||
using PerfectNumbers.Core.Gpu;
|
using PerfectNumbers.Core.Gpu;
|
||||||
|
|
||||||
@@ -48,8 +42,6 @@ public sealed class HeuristicCombinedPrimeTester
|
|||||||
|
|
||||||
private const ulong Wheel210 = 210UL;
|
private const ulong Wheel210 = 210UL;
|
||||||
|
|
||||||
private static readonly bool UseHeuristicGroupBTrialDivision = false; // Temporary fallback gate for Group B.
|
|
||||||
|
|
||||||
private static readonly uint[] CombinedDivisorsEnding1TwoAOneB;
|
private static readonly uint[] CombinedDivisorsEnding1TwoAOneB;
|
||||||
private static readonly uint[] CombinedDivisorsEnding3TwoAOneB;
|
private static readonly uint[] CombinedDivisorsEnding3TwoAOneB;
|
||||||
private static readonly uint[] CombinedDivisorsEnding7TwoAOneB;
|
private static readonly uint[] CombinedDivisorsEnding7TwoAOneB;
|
||||||
@@ -141,8 +133,6 @@ public sealed class HeuristicCombinedPrimeTester
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal static int HeuristicGpuDivisorBatchSize = 4_096;
|
|
||||||
internal static int HeuristicDivisorInterleaveBatchSize = 64;
|
|
||||||
|
|
||||||
[ThreadStatic]
|
[ThreadStatic]
|
||||||
private static HeuristicCombinedPrimeTester? _tester;
|
private static HeuristicCombinedPrimeTester? _tester;
|
||||||
@@ -205,76 +195,84 @@ public sealed class HeuristicCombinedPrimeTester
|
|||||||
return EvaluateWithOpenNumericFallback(n);
|
return EvaluateWithOpenNumericFallback(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal static int GetBatchSize(ulong n) => n switch
|
||||||
|
{
|
||||||
|
< 1_000 => 8,
|
||||||
|
< 10_000 => 16,
|
||||||
|
< 100_000 => 32,
|
||||||
|
< 1_000_000 => 128,
|
||||||
|
_ => 256,
|
||||||
|
};
|
||||||
|
|
||||||
private static bool HeuristicTrialDivisionGpuDetectsDivisor(ulong n, ulong maxDivisorSquare, byte nMod10)
|
private static bool HeuristicTrialDivisionGpuDetectsDivisor(ulong n, ulong maxDivisorSquare, byte nMod10)
|
||||||
{
|
{
|
||||||
int batchCapacity = HeuristicGpuDivisorBatchSize;
|
int batchCapacity = GetBatchSize(n);
|
||||||
var divisorPool = ThreadStaticPools.UlongPool;
|
|
||||||
|
|
||||||
ulong[] divisorArray = divisorPool.Rent(batchCapacity);
|
|
||||||
|
|
||||||
var limiter = GpuPrimeWorkLimiter.Acquire();
|
|
||||||
var gpu = PrimeTester.PrimeTesterGpuContextPool.Rent(batchCapacity);
|
|
||||||
var accelerator = gpu.Accelerator;
|
|
||||||
var kernel = gpu.HeuristicTrialDivisionKernel;
|
|
||||||
|
|
||||||
bool compositeDetected = false;
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
var inputView = gpu.Input.View;
|
|
||||||
var flagView = gpu.HeuristicFlag.View;
|
|
||||||
|
|
||||||
bool ProcessBatch(int length)
|
|
||||||
{
|
|
||||||
inputView.CopyFromCPU(ref divisorArray[0], length);
|
|
||||||
int compositeFlag = 0;
|
|
||||||
flagView.CopyFromCPU(ref compositeFlag, 1);
|
|
||||||
kernel(length, inputView, n, flagView);
|
|
||||||
accelerator.Synchronize();
|
|
||||||
flagView.CopyToCPU(ref compositeFlag, 1);
|
|
||||||
|
|
||||||
return compositeFlag != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReadOnlySpan<uint> combinedDivisors = GetCombinedDivisors(nMod10);
|
|
||||||
ReadOnlySpan<ulong> combinedDivisorSquares = GetCombinedDivisorSquares(nMod10);
|
|
||||||
|
|
||||||
int length = combinedDivisors.Length;
|
|
||||||
|
|
||||||
for (int i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
ulong divisorSquare = combinedDivisorSquares[i];
|
|
||||||
if (divisorSquare > maxDivisorSquare)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
divisorArray[count] = combinedDivisors[i];
|
|
||||||
count++;
|
|
||||||
|
|
||||||
if (count == batchCapacity)
|
|
||||||
{
|
|
||||||
if (ProcessBatch(count))
|
|
||||||
{
|
|
||||||
compositeDetected = true;
|
|
||||||
goto Cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count > 0 && ProcessBatch(count))
|
|
||||||
{
|
|
||||||
compositeDetected = true;
|
|
||||||
goto Cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Cleanup:
|
var limiter = GpuPrimeWorkLimiter.Acquire();
|
||||||
divisorPool.Return(divisorArray);
|
var gpu = PrimeTester.PrimeTesterGpuContextPool.Rent(batchCapacity);
|
||||||
gpu.Dispose();
|
var accelerator = gpu.Accelerator;
|
||||||
limiter.Dispose();
|
var kernel = gpu.HeuristicTrialDivisionKernel;
|
||||||
return compositeDetected;
|
|
||||||
|
bool compositeDetected = false;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
var inputView = gpu.Input.View;
|
||||||
|
var flagView = gpu.HeuristicFlag.View;
|
||||||
|
ulong[] divisorArray = gpu.DivisorArray;
|
||||||
|
|
||||||
|
bool ProcessBatch(int length)
|
||||||
|
{
|
||||||
|
inputView.CopyFromCPU(ref divisorArray[0], length);
|
||||||
|
int compositeFlag = 0;
|
||||||
|
flagView.CopyFromCPU(ref compositeFlag, 1);
|
||||||
|
kernel(length, inputView, n, flagView);
|
||||||
|
accelerator.Synchronize();
|
||||||
|
flagView.CopyToCPU(ref compositeFlag, 1);
|
||||||
|
|
||||||
|
return compositeFlag != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadOnlySpan<uint> combinedDivisors = GetCombinedDivisors(nMod10);
|
||||||
|
ReadOnlySpan<ulong> combinedDivisorSquares = GetCombinedDivisorSquares(nMod10);
|
||||||
|
|
||||||
|
int length = combinedDivisors.Length;
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
ulong divisorSquare = combinedDivisorSquares[i];
|
||||||
|
if (divisorSquare > maxDivisorSquare)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
divisorArray[count] = combinedDivisors[i];
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (count == batchCapacity)
|
||||||
|
{
|
||||||
|
if (ProcessBatch(count))
|
||||||
|
{
|
||||||
|
compositeDetected = true;
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0 && ProcessBatch(count))
|
||||||
|
{
|
||||||
|
compositeDetected = true;
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Cleanup:
|
||||||
|
gpu.Dispose();
|
||||||
|
limiter.Dispose();
|
||||||
|
return compositeDetected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -282,10 +280,10 @@ Cleanup:
|
|||||||
{
|
{
|
||||||
return Prime.Numbers.IsPrime(n);
|
return Prime.Numbers.IsPrime(n);
|
||||||
}
|
}
|
||||||
internal static ulong ComputeHeuristicDivisorSquareLimit(ulong n)
|
internal static ulong ComputeHeuristicDivisorSquareLimit(ulong n)
|
||||||
{
|
{
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReadOnlySpan<uint> GetCombinedDivisors(byte nMod10)
|
private static ReadOnlySpan<uint> GetCombinedDivisors(byte nMod10)
|
||||||
{
|
{
|
||||||
@@ -451,7 +449,7 @@ Cleanup:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint[] result = combined.ToArray();
|
uint[] result = [.. combined];
|
||||||
ulong[] resultSquares = new ulong[result.Length];
|
ulong[] resultSquares = new ulong[result.Length];
|
||||||
for (int i = 0; i < result.Length; i++)
|
for (int i = 0; i < result.Length; i++)
|
||||||
{
|
{
|
||||||
@@ -488,10 +486,10 @@ Cleanup:
|
|||||||
private static ReadOnlySpan<uint> GetGroupBDivisors(byte ending) => ending switch
|
private static ReadOnlySpan<uint> GetGroupBDivisors(byte ending) => ending switch
|
||||||
{
|
{
|
||||||
1 => DivisorGenerator.SmallPrimesLastOneWithoutLastThree,
|
1 => DivisorGenerator.SmallPrimesLastOneWithoutLastThree,
|
||||||
3 => ReadOnlySpan<uint>.Empty,
|
3 => [],
|
||||||
7 => DivisorGenerator.SmallPrimesLastSevenWithoutLastThree,
|
7 => DivisorGenerator.SmallPrimesLastSevenWithoutLastThree,
|
||||||
9 => DivisorGenerator.SmallPrimesLastNineWithoutLastThree,
|
9 => DivisorGenerator.SmallPrimesLastNineWithoutLastThree,
|
||||||
_ => ReadOnlySpan<uint>.Empty,
|
_ => [],
|
||||||
};
|
};
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -578,50 +576,50 @@ Cleanup:
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal ref struct HeuristicDivisorEnumerator
|
internal ref struct HeuristicDivisorEnumerator
|
||||||
{
|
{
|
||||||
private readonly ulong maxDivisorSquare;
|
private readonly ulong maxDivisorSquare;
|
||||||
private readonly ReadOnlySpan<uint> combinedDivisors;
|
private readonly ReadOnlySpan<uint> combinedDivisors;
|
||||||
private readonly ReadOnlySpan<ulong> combinedDivisorSquares;
|
private readonly ReadOnlySpan<ulong> combinedDivisorSquares;
|
||||||
private int index;
|
private int index;
|
||||||
|
|
||||||
public HeuristicDivisorEnumerator(ulong maxDivisorSquare, byte nMod10, Span<HeuristicGroupBSequenceState> groupBBuffer)
|
public HeuristicDivisorEnumerator(ulong maxDivisorSquare, byte nMod10, Span<HeuristicGroupBSequenceState> groupBBuffer)
|
||||||
{
|
{
|
||||||
this.maxDivisorSquare = maxDivisorSquare;
|
this.maxDivisorSquare = maxDivisorSquare;
|
||||||
_ = groupBBuffer;
|
_ = groupBBuffer;
|
||||||
combinedDivisors = GetCombinedDivisors(nMod10);
|
combinedDivisors = GetCombinedDivisors(nMod10);
|
||||||
combinedDivisorSquares = GetCombinedDivisorSquares(nMod10);
|
combinedDivisorSquares = GetCombinedDivisorSquares(nMod10);
|
||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetNext(out HeuristicDivisorCandidate candidate)
|
public bool TryGetNext(out HeuristicDivisorCandidate candidate)
|
||||||
{
|
{
|
||||||
while (index < combinedDivisors.Length)
|
while (index < combinedDivisors.Length)
|
||||||
{
|
{
|
||||||
int currentIndex = index;
|
int currentIndex = index;
|
||||||
ulong divisorSquare = combinedDivisorSquares[currentIndex];
|
ulong divisorSquare = combinedDivisorSquares[currentIndex];
|
||||||
if (divisorSquare > maxDivisorSquare)
|
if (divisorSquare > maxDivisorSquare)
|
||||||
{
|
{
|
||||||
index = combinedDivisors.Length;
|
index = combinedDivisors.Length;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint entry = combinedDivisors[currentIndex];
|
uint entry = combinedDivisors[currentIndex];
|
||||||
index = currentIndex + 1;
|
index = currentIndex + 1;
|
||||||
|
|
||||||
HeuristicDivisorGroup group = ResolveGroup(entry);
|
HeuristicDivisorGroup group = ResolveGroup(entry);
|
||||||
ulong value = entry;
|
ulong value = entry;
|
||||||
byte ending = (byte)(value % 10UL);
|
byte ending = (byte)(value % 10UL);
|
||||||
ushort residue = (ushort)(value % Wheel210);
|
ushort residue = (ushort)(value % Wheel210);
|
||||||
candidate = new HeuristicDivisorCandidate(value, group, ending, 0, residue);
|
candidate = new HeuristicDivisorCandidate(value, group, ending, 0, residue);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
candidate = default;
|
candidate = default;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ref struct MersenneHeuristicDivisorEnumerator
|
internal ref struct MersenneHeuristicDivisorEnumerator
|
||||||
{
|
{
|
||||||
private readonly GpuUInt128 step;
|
private readonly GpuUInt128 step;
|
||||||
private readonly GpuUInt128 limit;
|
private readonly GpuUInt128 limit;
|
||||||
@@ -690,11 +688,11 @@ Cleanup:
|
|||||||
residueStepper.Advance();
|
residueStepper.Advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong ProcessedCount => processedCount;
|
public readonly ulong ProcessedCount => processedCount;
|
||||||
|
|
||||||
public ulong LastDivisor => lastDivisor;
|
public readonly ulong LastDivisor => lastDivisor;
|
||||||
|
|
||||||
public bool Exhausted => !active;
|
public readonly bool Exhausted => !active;
|
||||||
|
|
||||||
private static HeuristicDivisorCandidate CreateCandidate(ulong value)
|
private static HeuristicDivisorCandidate CreateCandidate(ulong value)
|
||||||
{
|
{
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -273,6 +273,7 @@ public sealed class PrimeTester
|
|||||||
public MemoryBuffer1D<byte, Stride1D.Dense> Output;
|
public MemoryBuffer1D<byte, Stride1D.Dense> Output;
|
||||||
public MemoryBuffer1D<int, Stride1D.Dense> HeuristicFlag;
|
public MemoryBuffer1D<int, Stride1D.Dense> HeuristicFlag;
|
||||||
public int BufferCapacity;
|
public int BufferCapacity;
|
||||||
|
public ulong[] DivisorArray;
|
||||||
|
|
||||||
internal PrimeTesterGpuContextLease(int minBufferCapacity)
|
internal PrimeTesterGpuContextLease(int minBufferCapacity)
|
||||||
{
|
{
|
||||||
@@ -321,16 +322,18 @@ public sealed class PrimeTester
|
|||||||
DevicePrimesPow2LastNine = Accelerator.Allocate1D<ulong>(primesPow2LastNine.Length);
|
DevicePrimesPow2LastNine = Accelerator.Allocate1D<ulong>(primesPow2LastNine.Length);
|
||||||
DevicePrimesPow2LastNine.View.CopyFromCPU(primesPow2LastNine);
|
DevicePrimesPow2LastNine.View.CopyFromCPU(primesPow2LastNine);
|
||||||
|
|
||||||
BufferCapacity = minBufferCapacity < 1 ? 1 : minBufferCapacity;
|
BufferCapacity = minBufferCapacity;
|
||||||
Input = Accelerator.Allocate1D<ulong>(BufferCapacity);
|
Input = Accelerator.Allocate1D<ulong>(minBufferCapacity);
|
||||||
Output = Accelerator.Allocate1D<byte>(BufferCapacity);
|
Output = Accelerator.Allocate1D<byte>(minBufferCapacity);
|
||||||
HeuristicFlag = Accelerator.Allocate1D<int>(BufferCapacity);
|
HeuristicFlag = Accelerator.Allocate1D<int>(minBufferCapacity);
|
||||||
|
DivisorArray = ThreadStaticPools.UlongPool.Rent(minBufferCapacity);
|
||||||
|
|
||||||
_returned = false;
|
_returned = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EnsureCapacity(int minCapacity)
|
public void EnsureCapacity(int minCapacity)
|
||||||
{
|
{
|
||||||
int required = minCapacity < 1 ? 1 : minCapacity;
|
int required = minCapacity;
|
||||||
if (required <= BufferCapacity)
|
if (required <= BufferCapacity)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -339,9 +342,11 @@ public sealed class PrimeTester
|
|||||||
Input.Dispose();
|
Input.Dispose();
|
||||||
Output.Dispose();
|
Output.Dispose();
|
||||||
HeuristicFlag.Dispose();
|
HeuristicFlag.Dispose();
|
||||||
|
ThreadStaticPools.UlongPool.Return(DivisorArray);
|
||||||
Input = Accelerator.Allocate1D<ulong>(required);
|
Input = Accelerator.Allocate1D<ulong>(required);
|
||||||
Output = Accelerator.Allocate1D<byte>(required);
|
Output = Accelerator.Allocate1D<byte>(required);
|
||||||
HeuristicFlag = Accelerator.Allocate1D<int>(required);
|
HeuristicFlag = Accelerator.Allocate1D<int>(required);
|
||||||
|
DivisorArray = ThreadStaticPools.UlongPool.Rent(required);
|
||||||
BufferCapacity = required;
|
BufferCapacity = required;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user