Batch size made dynamic - dependent on the value

This commit is contained in:
mlemanczyk committed 2025-10-30 02:43:15 +01:00
1 parent 30af16a4f6
commit e14b77e504
4 files changed
+51 -66

No files matched your search

@@ -71,7 +71,16 @@ 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,12 +195,20 @@ 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 limiter = GpuPrimeWorkLimiter.Acquire();
var gpu = PrimeTester.PrimeTesterGpuContextPool.Rent(batchCapacity); var gpu = PrimeTester.PrimeTesterGpuContextPool.Rent(batchCapacity);
@@ -222,6 +220,7 @@ public sealed class HeuristicCombinedPrimeTester
var inputView = gpu.Input.View; var inputView = gpu.Input.View;
var flagView = gpu.HeuristicFlag.View; var flagView = gpu.HeuristicFlag.View;
ulong[] divisorArray = gpu.DivisorArray;
bool ProcessBatch(int length) bool ProcessBatch(int length)
{ {
@@ -270,8 +269,7 @@ public sealed class HeuristicCombinedPrimeTester
} }
Cleanup: Cleanup:
divisorPool.Return(divisorArray);
gpu.Dispose(); gpu.Dispose();
limiter.Dispose(); limiter.Dispose();
return compositeDetected; return compositeDetected;
@@ -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)]
@@ -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)
{ {
+12 -39
View File
@@ -1,13 +1,5 @@
using System;
using System.Buffers;
using System.Collections.Concurrent;
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;
@@ -68,9 +60,6 @@ public sealed class HeuristicPrimeTester
} }
public static int HeuristicGpuDivisorBatchSize { get; set; } = 4_096;
public static int HeuristicDivisorInterleaveBatchSize { get; set; } = 64;
[ThreadStatic] [ThreadStatic]
private static HeuristicPrimeTester? _tester; private static HeuristicPrimeTester? _tester;
@@ -120,12 +109,11 @@ public sealed class HeuristicPrimeTester
return !compositeDetected; return !compositeDetected;
} }
private static bool HeuristicTrialDivisionCpu(ulong n, ulong maxDivisorSquare, byte nMod10, bool includeGroupB) private static bool HeuristicTrialDivisionCpu(ulong n, ulong maxDivisorSquare, byte nMod10, bool includeGroupB)
{ {
ReadOnlySpan<int> groupADivisors = HeuristicPrimeSieves.GroupADivisors; ReadOnlySpan<int> groupADivisors = HeuristicPrimeSieves.GroupADivisors;
ReadOnlySpan<ulong> groupADivisorSquares = HeuristicPrimeSieves.GroupADivisorSquares; ReadOnlySpan<ulong> groupADivisorSquares = HeuristicPrimeSieves.GroupADivisorSquares;
int interleaveBatchSize = Math.Max(1, HeuristicDivisorInterleaveBatchSize); int interleaveBatchSize = HeuristicCombinedPrimeTester.GetBatchSize(n);
int groupAIndex = 0; int groupAIndex = 0;
if (!includeGroupB) if (!includeGroupB)
@@ -249,19 +237,11 @@ public sealed class HeuristicPrimeTester
return true; return true;
} }
private bool HeuristicTrialDivisionGpuDetectsDivisor(ulong n, ulong maxDivisorSquare, byte nMod10) private bool HeuristicTrialDivisionGpuDetectsDivisor(ulong n, ulong maxDivisorSquare, byte nMod10)
{ {
int batchCapacity = HeuristicGpuDivisorBatchSize; int batchCapacity = HeuristicCombinedPrimeTester.GetBatchSize(n);
int interleaveBatchSize = HeuristicDivisorInterleaveBatchSize; int interleaveBatchSize = batchCapacity;
var divisorPool = ThreadStaticPools.UlongPool;
ulong[] divisorArray = divisorPool.Rent(batchCapacity);
var limiter = GpuPrimeWorkLimiter.Acquire(); var limiter = GpuPrimeWorkLimiter.Acquire();
var gpu = PrimeTester.PrimeTesterGpuContextPool.Rent(batchCapacity); var gpu = PrimeTester.PrimeTesterGpuContextPool.Rent(batchCapacity);
@@ -273,6 +253,7 @@ public sealed class HeuristicPrimeTester
var inputView = gpu.Input.View; var inputView = gpu.Input.View;
var flagView = gpu.HeuristicFlag.View; var flagView = gpu.HeuristicFlag.View;
ulong[] divisorArray = gpu.DivisorArray;
bool ProcessBatch(int length) bool ProcessBatch(int length)
{ {
@@ -393,14 +374,11 @@ public sealed class HeuristicPrimeTester
compositeDetected = true; compositeDetected = true;
} }
divisorPool.Return(divisorArray);
gpu.Dispose(); gpu.Dispose();
limiter.Dispose(); limiter.Dispose();
return compositeDetected; return compositeDetected;
} }
private static bool EvaluateWithOpenNumericFallback(ulong n) private static bool EvaluateWithOpenNumericFallback(ulong n)
{ {
return Prime.Numbers.IsPrime(n); return Prime.Numbers.IsPrime(n);
@@ -419,8 +397,6 @@ public sealed class HeuristicPrimeTester
_ => ReadOnlySpan<byte>.Empty, _ => ReadOnlySpan<byte>.Empty,
}; };
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool TrySelectNextGroupBDivisor(ReadOnlySpan<byte> endingOrder, Span<int> indices, ulong maxDivisorSquare, out ulong divisor) private static bool TrySelectNextGroupBDivisor(ReadOnlySpan<byte> endingOrder, Span<int> indices, ulong maxDivisorSquare, out ulong divisor)
{ {
@@ -444,7 +420,7 @@ public sealed class HeuristicPrimeTester
continue; continue;
} }
ulong candidate = (ulong)divisors[index]; ulong candidate = divisors[index];
if (bestEndingIndex == -1 || candidate < bestCandidate) if (bestEndingIndex == -1 || candidate < bestCandidate)
{ {
bestCandidate = candidate; bestCandidate = candidate;
@@ -459,14 +435,11 @@ public sealed class HeuristicPrimeTester
} }
ReadOnlySpan<uint> selectedDivisors = GetGroupBDivisors(endingOrder[bestEndingIndex]); ReadOnlySpan<uint> selectedDivisors = GetGroupBDivisors(endingOrder[bestEndingIndex]);
divisor = (ulong)selectedDivisors[indices[bestEndingIndex]]; divisor = selectedDivisors[indices[bestEndingIndex]];
indices[bestEndingIndex]++; indices[bestEndingIndex]++;
return true; return true;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool HasGroupBCandidates(ReadOnlySpan<byte> endingOrder, Span<int> indices, ulong maxDivisorSquare) private static bool HasGroupBCandidates(ReadOnlySpan<byte> endingOrder, Span<int> indices, ulong maxDivisorSquare)
{ {
@@ -605,8 +578,8 @@ public sealed class HeuristicPrimeTester
} }
internal ref struct HeuristicDivisorEnumerator internal ref struct HeuristicDivisorEnumerator
{ {
private readonly ulong maxDivisorSquare; private readonly ulong maxDivisorSquare;
private readonly ReadOnlySpan<int> groupADivisors; private readonly ReadOnlySpan<int> groupADivisors;
private readonly ReadOnlySpan<ulong> groupADivisorSquares; private readonly ReadOnlySpan<ulong> groupADivisorSquares;
@@ -687,12 +660,12 @@ internal ref struct HeuristicDivisorEnumerator
(ushort)(bestCandidate % Wheel210)); (ushort)(bestCandidate % Wheel210));
return true; return true;
} }
} }
internal struct HeuristicGroupBSequenceState internal struct HeuristicGroupBSequenceState
{ {
public byte Ending; public byte Ending;
public byte PriorityIndex; public byte PriorityIndex;
public int Index; public int Index;
@@ -739,7 +712,7 @@ internal struct HeuristicGroupBSequenceState
Index = next; Index = next;
} }
} }
} }
internal ref struct MersenneHeuristicDivisorEnumerator internal ref struct MersenneHeuristicDivisorEnumerator
+10 -5
View File
@@ -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;
} }