Collapse GPU by-divisor batching to a single launch

This commit is contained in:
Marek Lemańczyk committed 2025-10-24 01:23:38 +02:00
1 parent 1075ab1ea1
commit 8a258f7536
3 files changed
+52 -215

No files matched your search

@@ -78,10 +78,6 @@ public class GpuKernelCompilationTests
typeof(MersenneNumberDivisorByDivisorGpuTester).GetMethod("GetStepperKernel", BindingFlags.NonPublic | BindingFlags.Instance) typeof(MersenneNumberDivisorByDivisorGpuTester).GetMethod("GetStepperKernel", BindingFlags.NonPublic | BindingFlags.Instance)
?? throw new InvalidOperationException("MersenneNumberDivisorByDivisorGpuTester.GetKernelByPrimeExponent not found."); ?? throw new InvalidOperationException("MersenneNumberDivisorByDivisorGpuTester.GetKernelByPrimeExponent not found.");
private static readonly MethodInfo DivisorByDivisorGetFilteredCandidateKernelMethod =
typeof(MersenneNumberDivisorByDivisorGpuTester).GetMethod("GetFilteredCandidateKernel", BindingFlags.NonPublic | BindingFlags.Instance)
?? throw new InvalidOperationException("MersenneNumberDivisorByDivisorGpuTester.GetFilteredCandidateKernel not found.");
private static readonly MethodInfo DivisorTesterGetKernelMethod = private static readonly MethodInfo DivisorTesterGetKernelMethod =
typeof(MersenneNumberDivisorGpuTester).GetMethod("GetKernel", BindingFlags.NonPublic | BindingFlags.Instance) typeof(MersenneNumberDivisorGpuTester).GetMethod("GetKernel", BindingFlags.NonPublic | BindingFlags.Instance)
?? throw new InvalidOperationException("MersenneNumberDivisorGpuTester.GetKernel not found."); ?? throw new InvalidOperationException("MersenneNumberDivisorGpuTester.GetKernel not found.");
@@ -154,7 +150,6 @@ public class GpuKernelCompilationTests
yield return Loader("NttGpuMath.InverseKernel", CompileNttInverseKernel); yield return Loader("NttGpuMath.InverseKernel", CompileNttInverseKernel);
yield return Loader("MersenneNumberDivisorByDivisorGpuTester.CheckKernel", CompileDivisorByDivisorCheckKernel); yield return Loader("MersenneNumberDivisorByDivisorGpuTester.CheckKernel", CompileDivisorByDivisorCheckKernel);
yield return Loader("MersenneNumberDivisorByDivisorGpuTester.EvaluateDivisorWithStepperKernel", CompileDivisorByDivisorExponentKernel); yield return Loader("MersenneNumberDivisorByDivisorGpuTester.EvaluateDivisorWithStepperKernel", CompileDivisorByDivisorExponentKernel);
yield return Loader("MersenneNumberDivisorByDivisorGpuTester.GenerateFilteredCandidatesKernel", CompileDivisorByDivisorFilteredCandidateKernel);
yield return Loader("MersenneNumberDivisorGpuTester.Kernel", CompileDivisorTesterKernel); yield return Loader("MersenneNumberDivisorGpuTester.Kernel", CompileDivisorTesterKernel);
yield return Loader("MersenneNumberLucasLehmerGpuTester.Kernel", CompileLucasLehmerKernel); yield return Loader("MersenneNumberLucasLehmerGpuTester.Kernel", CompileLucasLehmerKernel);
yield return Loader("MersenneNumberLucasLehmerGpuTester.AddSmallKernel", CompileLucasLehmerAddSmallKernel); yield return Loader("MersenneNumberLucasLehmerGpuTester.AddSmallKernel", CompileLucasLehmerAddSmallKernel);
@@ -282,12 +277,6 @@ public class GpuKernelCompilationTests
_ = DivisorByDivisorGetExponentKernelMethod.Invoke(tester, new object[] { accelerator }); _ = DivisorByDivisorGetExponentKernelMethod.Invoke(tester, new object[] { accelerator });
} }
private static void CompileDivisorByDivisorFilteredCandidateKernel(Accelerator accelerator)
{
var tester = new MersenneNumberDivisorByDivisorGpuTester();
_ = DivisorByDivisorGetFilteredCandidateKernelMethod.Invoke(tester, new object[] { accelerator });
}
private static void CompileDivisorTesterKernel(Accelerator accelerator) private static void CompileDivisorTesterKernel(Accelerator accelerator)
{ {
var tester = new MersenneNumberDivisorGpuTester(); var tester = new MersenneNumberDivisorGpuTester();
@@ -86,105 +86,6 @@ internal static class DivisorByDivisorKernels
} }
} }
public static void GenerateFilteredCandidatesKernel(
Index1D index,
ArrayView<ulong> candidates,
ArrayView<int> filteredCount,
ArrayView<GpuUInt128> nextStarts,
GpuUInt128 startValue,
GpuUInt128 stride,
byte lastIsSevenFlag)
{
int globalIndex = index;
int localIndex = Group.IdxX;
int groupSize = Group.Dimension.X;
ulong candidateOffset = (ulong)globalIndex;
GpuUInt128 candidateValue = stride;
candidateValue.Mul(candidateOffset);
candidateValue.Add(startValue);
ulong candidate = candidateValue.Low;
candidates[globalIndex] = candidate;
if (globalIndex == 0)
{
ulong candidateCount = (ulong)groupSize;
GpuUInt128 nextValue = stride;
nextValue.Mul(candidateCount);
nextValue.Add(startValue);
nextStarts[0] = nextValue;
}
bool lastIsSeven = lastIsSevenFlag != 0;
byte remainder10 = (byte)(candidate % 10UL);
bool acceptSeven = remainder10 == 3 || remainder10 == 7 || remainder10 == 9;
bool acceptNonSeven = remainder10 == 1 || remainder10 == 3 || remainder10 == 7 || remainder10 == 9;
bool accept10 = lastIsSeven ? acceptSeven : acceptNonSeven;
byte remainder8 = (byte)(candidate & 7UL);
bool accept8 = remainder8 == 1 || remainder8 == 7;
byte remainder5 = (byte)(candidate % 5UL);
bool accept5 = remainder5 != 0;
byte remainder3 = (byte)(candidate % 3UL);
bool accept3 = remainder3 != 0;
int accepted = (accept10 && accept8 && accept3 && accept5) ? 1 : 0;
var shared = SharedMemory.GetDynamic<int>();
int length = groupSize;
int prefixBase = 0;
int mappingBase = length;
int fallbackBase = length * 2;
shared[prefixBase + localIndex] = accepted;
shared[fallbackBase + localIndex] = globalIndex;
Group.Barrier();
int scanOffset = 1;
while (scanOffset < groupSize)
{
int addendIndex = prefixBase + localIndex - scanOffset;
int addend = localIndex >= scanOffset ? shared[addendIndex] : 0;
Group.Barrier();
int currentIndex = prefixBase + localIndex;
int current = shared[currentIndex];
int sum = current + addend;
int shouldUpdate = localIndex >= scanOffset ? 1 : 0;
shared[currentIndex] = shouldUpdate != 0 ? sum : current;
Group.Barrier();
scanOffset <<= 1;
}
int inclusivePrefix = shared[prefixBase + localIndex];
int exclusiveIndex = inclusivePrefix - accepted;
int targetBase = accepted != 0 ? mappingBase : fallbackBase;
int targetOffset = accepted != 0 ? exclusiveIndex : localIndex;
shared[targetBase + targetOffset] = globalIndex;
Group.Barrier();
int totalAccepted = shared[prefixBase + length - 1];
int writerMask = localIndex < totalAccepted ? 1 : 0;
int lookupBase = writerMask != 0 ? mappingBase : fallbackBase;
int sourceIndex = shared[lookupBase + localIndex];
ulong candidateValueToStore = candidates[sourceIndex];
if (writerMask != 0)
{
candidates[localIndex] = candidateValueToStore;
}
int lastLaneMask = globalIndex == length - 1 ? 1 : 0;
int countValue = shared[prefixBase + localIndex];
if (lastLaneMask != 0)
{
filteredCount[0] = countValue;
}
}
public static void ConvertMontgomeryResultsToHitsKernel( public static void ConvertMontgomeryResultsToHitsKernel(
Index1D index, Index1D index,
ArrayView<ulong> results, ArrayView<ulong> results,
@@ -25,7 +25,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
private readonly ConcurrentDictionary<Accelerator, Action<Index1D, ArrayView<MontgomeryDivisorData>, ArrayView<ulong>, ArrayView<byte>, ArrayView<int>>> _kernelCache = new(); private readonly ConcurrentDictionary<Accelerator, Action<Index1D, ArrayView<MontgomeryDivisorData>, ArrayView<ulong>, ArrayView<byte>, ArrayView<int>>> _kernelCache = new();
private readonly ConcurrentDictionary<Accelerator, Action<Index1D, MontgomeryDivisorData, ulong, ulong, ArrayView<ulong>, ArrayView<byte>>> _stepperKernelCache = new(AcceleratorReferenceComparer.Instance); private readonly ConcurrentDictionary<Accelerator, Action<Index1D, MontgomeryDivisorData, ulong, ulong, ArrayView<ulong>, ArrayView<byte>>> _stepperKernelCache = new(AcceleratorReferenceComparer.Instance);
private readonly ConcurrentDictionary<Accelerator, Action<KernelConfig, Index1D, ArrayView<ulong>, ArrayView<int>, ArrayView<GpuUInt128>, GpuUInt128, GpuUInt128, byte>> _filteredCandidateKernelCache = new(AcceleratorReferenceComparer.Instance);
private readonly ConcurrentDictionary<Accelerator, ConcurrentBag<BatchResources>> _resourcePools = new(AcceleratorReferenceComparer.Instance); private readonly ConcurrentDictionary<Accelerator, ConcurrentBag<BatchResources>> _resourcePools = new(AcceleratorReferenceComparer.Instance);
private readonly ConcurrentBag<GpuContextPool.GpuContextLease> _acceleratorPool = new(); private readonly ConcurrentBag<GpuContextPool.GpuContextLease> _acceleratorPool = new();
private readonly ConcurrentBag<DivisorScanSession> _sessionPool = new(); private readonly ConcurrentBag<DivisorScanSession> _sessionPool = new();
@@ -36,10 +35,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
private Action<Index1D, MontgomeryDivisorData, ulong, ulong, ArrayView<ulong>, ArrayView<byte>> GetStepperKernel(Accelerator accelerator) => private Action<Index1D, MontgomeryDivisorData, ulong, ulong, ArrayView<ulong>, ArrayView<byte>> GetStepperKernel(Accelerator accelerator) =>
_stepperKernelCache.GetOrAdd(accelerator, acc => acc.LoadAutoGroupedStreamKernel<Index1D, MontgomeryDivisorData, ulong, ulong, ArrayView<ulong>, ArrayView<byte>>(DivisorByDivisorKernels.EvaluateDivisorWithStepperKernel)); _stepperKernelCache.GetOrAdd(accelerator, acc => acc.LoadAutoGroupedStreamKernel<Index1D, MontgomeryDivisorData, ulong, ulong, ArrayView<ulong>, ArrayView<byte>>(DivisorByDivisorKernels.EvaluateDivisorWithStepperKernel));
private Action<KernelConfig, Index1D, ArrayView<ulong>, ArrayView<int>, ArrayView<GpuUInt128>, GpuUInt128, GpuUInt128, byte> GetFilteredCandidateKernel(Accelerator accelerator) =>
_filteredCandidateKernelCache.GetOrAdd(
accelerator,
acc => acc.LoadStreamKernel<Index1D, ArrayView<ulong>, ArrayView<int>, ArrayView<GpuUInt128>, GpuUInt128, GpuUInt128, byte>(DivisorByDivisorKernels.GenerateFilteredCandidatesKernel));
public int GpuBatchSize public int GpuBatchSize
{ {
@@ -110,16 +105,11 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
composite = CheckDivisors( composite = CheckDivisors(
prime, prime,
allowedMax, allowedMax,
accelerator,
kernel, kernel,
resources.DivisorsBuffer, resources.DivisorsBuffer,
resources.ExponentBuffer, resources.ExponentBuffer,
resources.HitsBuffer, resources.HitsBuffer,
resources.HitIndexBuffer, resources.HitIndexBuffer,
resources.CandidateBuffer,
resources.NextStartBuffer,
resources.FilterCountBuffer,
resources.FilteredCandidateKernel,
resources.Divisors, resources.Divisors,
resources.Exponents, resources.Exponents,
resources.DivisorData, resources.DivisorData,
@@ -175,16 +165,11 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
private static bool CheckDivisors( private static bool CheckDivisors(
ulong prime, ulong prime,
ulong allowedMax, ulong allowedMax,
Accelerator accelerator,
Action<Index1D, ArrayView<MontgomeryDivisorData>, ArrayView<ulong>, ArrayView<byte>, ArrayView<int>> kernel, Action<Index1D, ArrayView<MontgomeryDivisorData>, ArrayView<ulong>, ArrayView<byte>, ArrayView<int>> kernel,
MemoryBuffer1D<MontgomeryDivisorData, Stride1D.Dense> divisorsBuffer, MemoryBuffer1D<MontgomeryDivisorData, Stride1D.Dense> divisorsBuffer,
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer, MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer,
MemoryBuffer1D<byte, Stride1D.Dense> hitsBuffer, MemoryBuffer1D<byte, Stride1D.Dense> hitsBuffer,
MemoryBuffer1D<int, Stride1D.Dense> hitIndexBuffer, MemoryBuffer1D<int, Stride1D.Dense> hitIndexBuffer,
MemoryBuffer1D<ulong, Stride1D.Dense> candidateBuffer,
MemoryBuffer1D<GpuUInt128, Stride1D.Dense> nextStartBuffer,
MemoryBuffer1D<int, Stride1D.Dense> filterCountBuffer,
Action<KernelConfig, Index1D, ArrayView<ulong>, ArrayView<int>, ArrayView<GpuUInt128>, GpuUInt128, GpuUInt128, byte> filteredCandidateKernel,
in ulong[] divisors, in ulong[] divisors,
ulong[] exponents, ulong[] exponents,
MontgomeryDivisorData[] divisorData, MontgomeryDivisorData[] divisorData,
@@ -202,10 +187,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
cycleCapacity = Math.Max(1, cycleCapacity); cycleCapacity = Math.Max(1, cycleCapacity);
int chunkCapacity = Math.Min(batchCapacity, cycleCapacity); int chunkCapacity = Math.Min(batchCapacity, cycleCapacity);
int maxThreadsPerGroup = (int)accelerator.MaxNumThreadsPerGroup;
bool clampThreads = maxThreadsPerGroup > 0;
chunkCapacity = clampThreads && chunkCapacity > maxThreadsPerGroup ? maxThreadsPerGroup : chunkCapacity;
chunkCapacity = chunkCapacity <= 0 ? cycleCapacity : chunkCapacity;
UInt128 twoP128 = (UInt128)prime << 1; UInt128 twoP128 = (UInt128)prime << 1;
UInt128 allowedMax128 = allowedMax; UInt128 allowedMax128 = allowedMax;
@@ -226,7 +207,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
UInt128 currentDivisor128 = firstDivisor128; UInt128 currentDivisor128 = firstDivisor128;
bool lastIsSeven = (prime & 3UL) == 3UL; bool lastIsSeven = (prime & 3UL) == 3UL;
byte lastIsSevenFlag = lastIsSeven ? (byte)1 : (byte)0;
DivisorCycleCache cycleCache = DivisorCycleCache.Shared; DivisorCycleCache cycleCache = DivisorCycleCache.Shared;
ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool; ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool;
@@ -236,56 +216,43 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
Span<MontgomeryDivisorData> divisorDataStorage = divisorData.AsSpan(); Span<MontgomeryDivisorData> divisorDataStorage = divisorData.AsSpan();
Span<ulong> divisorStorage = divisors.AsSpan(); Span<ulong> divisorStorage = divisors.AsSpan();
Span<ulong> exponentStorage = exponents.AsSpan(); Span<ulong> exponentStorage = exponents.AsSpan();
ArrayView1D<int, Stride1D.Dense> filteredCountView = filterCountBuffer.View;
while (currentK <= maxK && !composite) while (currentK <= maxK && !composite)
{ {
int chunkCount = Math.Min(chunkCapacity, batchCapacity); int chunkCount = Math.Min(chunkCapacity, batchCapacity);
ulong remainingK = maxK - currentK + 1UL; ulong remainingK = maxK - currentK + 1UL;
chunkCount = (ulong)chunkCount > remainingK ? (int)remainingK : chunkCount; if ((ulong)chunkCount > remainingK)
bool hasChunk = chunkCount > 0; {
int effectiveCount = hasChunk ? chunkCount : 0; chunkCount = (int)remainingK;
if (!hasChunk) }
if (chunkCount <= 0)
{ {
processedAll = true; processedAll = true;
break; break;
} }
ArrayView1D<ulong, Stride1D.Dense> candidateView = candidateBuffer.View.SubView(0, effectiveCount); int filteredCount = 0;
ArrayView1D<GpuUInt128, Stride1D.Dense> nextStartView = nextStartBuffer.View.SubView(0, 1); UInt128 nextDivisor128 = currentDivisor128;
ArrayView1D<int, Stride1D.Dense> filteredCountSubView = filteredCountView.SubView(0, 1);
GpuUInt128 gpuStartValue = new GpuUInt128(currentDivisor128);
GpuUInt128 gpuStride = new GpuUInt128(twoP128);
GpuUInt128 nextDivisorGpu = default;
int filteredCount = GenerateFilteredCandidatesOnGpu(
effectiveCount,
gpuStartValue,
gpuStride,
lastIsSevenFlag,
candidateView,
filteredCountSubView,
nextStartView,
filteredCandidateKernel,
out nextDivisorGpu);
if (effectiveCount > 0) for (int i = 0; i < chunkCount; i++)
{ {
processedCount += (ulong)effectiveCount; ulong candidate = (ulong)nextDivisor128;
UInt128 nextDivisor128 = (UInt128)nextDivisorGpu; nextDivisor128 += twoP128;
UInt128 stride128 = (UInt128)gpuStride;
UInt128 lastDivisor128 = nextDivisor128 - stride128; if (CandidatePassesHeuristics(candidate, lastIsSeven))
lastProcessed = (ulong)lastDivisor128; {
currentDivisor128 = nextDivisor128; filteredStorage[filteredCount++] = candidate;
}
} }
if (filteredCount > 0) processedCount += (ulong)chunkCount;
{
Span<ulong> filteredSlice = filteredStorage[..filteredCount];
ArrayView1D<ulong, Stride1D.Dense> filteredView = candidateView.SubView(0, filteredCount);
filteredView.CopyToCPU(ref MemoryMarshal.GetReference(filteredSlice), filteredCount);
}
currentK += (ulong)effectiveCount; UInt128 lastDivisor128 = nextDivisor128 - twoP128;
lastProcessed = (ulong)lastDivisor128;
currentDivisor128 = nextDivisor128;
currentK += (ulong)chunkCount;
processedAll = currentK > maxK; processedAll = currentK > maxK;
if (filteredCount == 0) if (filteredCount == 0)
@@ -300,9 +267,15 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
int admissibleCount = 0; int admissibleCount = 0;
for (int i = 0; i < filteredCount; i++) for (int i = 0; i < filteredCount; i++)
{ {
int add = cycleSpan[i] == prime ? 1 : 0; ulong candidate = filteredDivisorsSpan[i];
filteredDivisorsSpan[admissibleCount] = filteredDivisorsSpan[i]; ulong candidateCycle = cycleSpan[i];
admissibleCount += add; if (candidateCycle != prime)
{
continue;
}
filteredDivisorsSpan[admissibleCount] = candidate;
admissibleCount++;
} }
if (admissibleCount == 0) if (admissibleCount == 0)
@@ -348,47 +321,36 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
return composite; return composite;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int GenerateFilteredCandidatesOnGpu( private static bool CandidatePassesHeuristics(ulong candidate, bool lastIsSeven)
int count,
GpuUInt128 startValue,
GpuUInt128 stride,
byte lastIsSevenFlag,
ArrayView1D<ulong, Stride1D.Dense> candidateView,
ArrayView1D<int, Stride1D.Dense> filteredCountView,
ArrayView1D<GpuUInt128, Stride1D.Dense> nextStartView,
Action<KernelConfig, Index1D, ArrayView<ulong>, ArrayView<int>, ArrayView<GpuUInt128>, GpuUInt128, GpuUInt128, byte> kernel,
out GpuUInt128 nextStart)
{ {
// EvenPerfectBitScanner always launches this helper with a positive count, ulong remainder10 = candidate % 10UL;
// so the guard stays commented out to keep the hot path branch-free. bool accept10 = lastIsSeven
// if (count <= 0) ? (remainder10 == 3UL || remainder10 == 7UL || remainder10 == 9UL)
// { : (remainder10 == 1UL || remainder10 == 3UL || remainder10 == 7UL || remainder10 == 9UL);
// nextStart = GpuUInt128.Zero; if (!accept10)
// return 0; {
// } return false;
}
SharedMemoryConfig sharedMemoryConfig = SharedMemoryConfig.RequestDynamic<int>(count * 3); ulong remainder8 = candidate & 7UL;
Index1D gridDim = new Index1D(1); if (remainder8 != 1UL && remainder8 != 7UL)
Index1D groupDim = new Index1D(count); {
KernelConfig kernelConfig = new KernelConfig(gridDim, groupDim, sharedMemoryConfig); return false;
}
kernel(kernelConfig, new Index1D(count), candidateView, filteredCountView, nextStartView, startValue, stride, lastIsSevenFlag); if (candidate % 5UL == 0UL)
{
return false;
}
int filteredCount = 0; return candidate % 3UL != 0UL;
filteredCountView.SubView(0, 1).CopyToCPU(ref filteredCount, 1);
nextStart = default;
nextStartView.SubView(0, 1).CopyToCPU(ref nextStart, 1);
return filteredCount;
} }
private static ulong ComputeDivisorLimitFromMaxPrimeGpu(ulong maxPrime) private static ulong ComputeDivisorLimitFromMaxPrimeGpu(ulong maxPrime)
{ {
// The --mersenne=bydivisor flow in EvenPerfectBitScanner only calls ConfigureFromMaxPrime with primes greater than 1, // The --mersenne=bydivisor flow in EvenPerfectBitScanner only calls ConfigureFromMaxPrime with primes greater than 1,
@@ -601,14 +563,14 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
return resources; return resources;
} }
return new BatchResources(this, accelerator, capacity); return new BatchResources(accelerator, capacity);
} }
private void ReturnBatchResources(Accelerator accelerator, BatchResources resources) => _resourcePools.GetOrAdd(accelerator, static _ => []).Add(resources); private void ReturnBatchResources(Accelerator accelerator, BatchResources resources) => _resourcePools.GetOrAdd(accelerator, static _ => []).Add(resources);
private sealed class BatchResources : IDisposable private sealed class BatchResources : IDisposable
{ {
internal BatchResources(MersenneNumberDivisorByDivisorGpuTester owner, Accelerator accelerator, int capacity) internal BatchResources(Accelerator accelerator, int capacity)
{ {
int cycleCapacity = DivisorCycleCache.Shared.PreferredBatchSize; int cycleCapacity = DivisorCycleCache.Shared.PreferredBatchSize;
if (cycleCapacity <= 0) if (cycleCapacity <= 0)
@@ -622,15 +584,11 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
ExponentBuffer = accelerator.Allocate1D<ulong>(actualCapacity); ExponentBuffer = accelerator.Allocate1D<ulong>(actualCapacity);
HitsBuffer = accelerator.Allocate1D<byte>(actualCapacity); HitsBuffer = accelerator.Allocate1D<byte>(actualCapacity);
HitIndexBuffer = accelerator.Allocate1D<int>(1); HitIndexBuffer = accelerator.Allocate1D<int>(1);
CandidateBuffer = accelerator.Allocate1D<ulong>(actualCapacity);
NextStartBuffer = accelerator.Allocate1D<GpuUInt128>(1);
FilterCountBuffer = accelerator.Allocate1D<int>(1);
ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool; ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool;
Divisors = ulongPool.Rent(actualCapacity); Divisors = ulongPool.Rent(actualCapacity);
Exponents = ulongPool.Rent(actualCapacity); Exponents = ulongPool.Rent(actualCapacity);
DivisorData = ThreadStaticPools.MontgomeryDivisorDataPool.Rent(actualCapacity); DivisorData = ThreadStaticPools.MontgomeryDivisorDataPool.Rent(actualCapacity);
CycleLengths = ulongPool.Rent(cycleCapacity); CycleLengths = ulongPool.Rent(cycleCapacity);
FilteredCandidateKernel = owner.GetFilteredCandidateKernel(accelerator);
Capacity = actualCapacity; Capacity = actualCapacity;
CycleCapacity = cycleCapacity; CycleCapacity = cycleCapacity;
} }
@@ -643,12 +601,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
internal readonly MemoryBuffer1D<int, Stride1D.Dense> HitIndexBuffer; internal readonly MemoryBuffer1D<int, Stride1D.Dense> HitIndexBuffer;
internal readonly MemoryBuffer1D<ulong, Stride1D.Dense> CandidateBuffer;
internal readonly MemoryBuffer1D<GpuUInt128, Stride1D.Dense> NextStartBuffer;
internal readonly MemoryBuffer1D<int, Stride1D.Dense> FilterCountBuffer;
internal readonly ulong[] Divisors; internal readonly ulong[] Divisors;
internal readonly ulong[] Exponents; internal readonly ulong[] Exponents;
@@ -657,8 +609,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
internal readonly ulong[] CycleLengths; internal readonly ulong[] CycleLengths;
internal readonly Action<KernelConfig, Index1D, ArrayView<ulong>, ArrayView<int>, ArrayView<GpuUInt128>, GpuUInt128, GpuUInt128, byte> FilteredCandidateKernel;
internal readonly int Capacity; internal readonly int Capacity;
internal readonly int CycleCapacity; internal readonly int CycleCapacity;
@@ -669,9 +619,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
ExponentBuffer.Dispose(); ExponentBuffer.Dispose();
HitsBuffer.Dispose(); HitsBuffer.Dispose();
HitIndexBuffer.Dispose(); HitIndexBuffer.Dispose();
CandidateBuffer.Dispose();
NextStartBuffer.Dispose();
FilterCountBuffer.Dispose();
ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool; ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool;
ArrayPool<MontgomeryDivisorData> divisorPool = ThreadStaticPools.MontgomeryDivisorDataPool; ArrayPool<MontgomeryDivisorData> divisorPool = ThreadStaticPools.MontgomeryDivisorDataPool;
ulongPool.Return(Divisors, clearArray: false); ulongPool.Return(Divisors, clearArray: false);