Factoring switched to PrimeTester.IsPrime for the best performance. PrimeOrderCalculator.PartialFactor switched to GPU factorization. Every so often it will send work to GPU instead of CPU. BatchedResources renamed to MersenneNumberDivisorByDivisorAccelerator for consistency and moved to its own file. It now uses array instead of dictionary for lookup free performance.

This commit is contained in:
mlemanczyk committed 2025-11-23 00:07:03 +01:00
1 parent 7b09c1fd3b
commit 6d1ff1372e
7 files changed
+201 -239

No files matched your search

@@ -0,0 +1,119 @@
using System.Buffers;
using ILGPU;
using ILGPU.Runtime;
namespace PerfectNumbers.Core.Gpu;
public sealed class MersenneNumberDivisorByDivisorAccelerator
{
internal MersenneNumberDivisorByDivisorAccelerator(Accelerator accelerator, int capacity)
{
ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool;
ArrayPool<int> intPool = ThreadStaticPools.IntPool;
ArrayPool<GpuDivisorPartialData> partialPool = ThreadStaticPools.GpuDivisorPartialDataPool;
Divisors = ulongPool.Rent(capacity);
Exponents = ulongPool.Rent(capacity);
DivisorData = partialPool.Rent(capacity);
Offsets = intPool.Rent(capacity);
Counts = intPool.Rent(capacity);
Cycles = ulongPool.Rent(capacity);
lock (accelerator)
{
DivisorDataBuffer = accelerator.Allocate1D<GpuDivisorPartialData>(capacity);
OffsetBuffer = accelerator.Allocate1D<int>(capacity);
CountBuffer = accelerator.Allocate1D<int>(capacity);
CycleBuffer = accelerator.Allocate1D<ulong>(capacity);
ExponentBuffer = accelerator.Allocate1D<ulong>(capacity);
HitsBuffer = accelerator.Allocate1D<byte>(capacity);
HitIndexBuffer = accelerator.Allocate1D<int>(1);
CheckDivisorKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<GpuDivisorPartialData>, ArrayView<int>, ArrayView<int>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>, ArrayView<int>>(DivisorByDivisorKernels.CheckKernel));
}
}
internal MemoryBuffer1D<GpuDivisorPartialData, Stride1D.Dense> DivisorDataBuffer;
internal MemoryBuffer1D<int, Stride1D.Dense> OffsetBuffer;
internal MemoryBuffer1D<int, Stride1D.Dense> CountBuffer;
internal MemoryBuffer1D<ulong, Stride1D.Dense> CycleBuffer;
internal MemoryBuffer1D<ulong, Stride1D.Dense> ExponentBuffer;
internal MemoryBuffer1D<byte, Stride1D.Dense> HitsBuffer;
internal MemoryBuffer1D<int, Stride1D.Dense> HitIndexBuffer;
internal ulong[] Divisors;
internal ulong[] Exponents;
internal GpuDivisorPartialData[] DivisorData;
internal int[] Offsets;
internal int[] Counts;
internal ulong[] Cycles;
internal readonly Kernel CheckDivisorKernel;
public void EnsureCapacity(Accelerator accelerator, int requiredCapacity)
{
if (DivisorDataBuffer.Length < requiredCapacity)
{
ReallocateBuffers(accelerator, requiredCapacity);
}
}
private void ReallocateBuffers(Accelerator accelerator, int capacity)
{
DivisorDataBuffer.Dispose();
OffsetBuffer.Dispose();
CountBuffer.Dispose();
CycleBuffer.Dispose();
ExponentBuffer.Dispose();
HitsBuffer.Dispose();
HitIndexBuffer.Dispose();
lock (accelerator)
{
DivisorDataBuffer = accelerator.Allocate1D<GpuDivisorPartialData>(capacity);
OffsetBuffer = accelerator.Allocate1D<int>(capacity);
CountBuffer = accelerator.Allocate1D<int>(capacity);
CycleBuffer = accelerator.Allocate1D<ulong>(capacity);
ExponentBuffer = accelerator.Allocate1D<ulong>(capacity);
HitsBuffer = accelerator.Allocate1D<byte>(capacity);
HitIndexBuffer = accelerator.Allocate1D<int>(1);
}
ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool;
ArrayPool<int> intPool = ThreadStaticPools.IntPool;
ArrayPool<GpuDivisorPartialData> partialPool = ThreadStaticPools.GpuDivisorPartialDataPool;
ulongPool.Return(Divisors, clearArray: false);
ulongPool.Return(Exponents, clearArray: false);
partialPool.Return(DivisorData, clearArray: false);
intPool.Return(Offsets, clearArray: false);
intPool.Return(Counts, clearArray: false);
ulongPool.Return(Cycles, clearArray: false);
Divisors = ulongPool.Rent(capacity);
Exponents = ulongPool.Rent(capacity);
DivisorData = partialPool.Rent(capacity);
Offsets = intPool.Rent(capacity);
Counts = intPool.Rent(capacity);
Cycles = ulongPool.Rent(capacity);
}
public void Dispose()
{
DivisorDataBuffer.Dispose();
OffsetBuffer.Dispose();
CountBuffer.Dispose();
CycleBuffer.Dispose();
ExponentBuffer.Dispose();
HitsBuffer.Dispose();
HitIndexBuffer.Dispose();
ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool;
ArrayPool<int> intPool = ThreadStaticPools.IntPool;
ArrayPool<GpuDivisorPartialData> partialPool = ThreadStaticPools.GpuDivisorPartialDataPool;
ulongPool.Return(Divisors, clearArray: false);
ulongPool.Return(Exponents, clearArray: false);
partialPool.Return(DivisorData, clearArray: false);
intPool.Return(Offsets, clearArray: false);
intPool.Return(Counts, clearArray: false);
ulongPool.Return(Cycles, clearArray: false);
}
}
@@ -69,7 +69,7 @@ public sealed class PrimeOrderCalculatorAccelerator
AcceleratorStream stream = accelerator.CreateStream(); AcceleratorStream stream = accelerator.CreateStream();
// TODO: Review which tables are needed when final execution path is defined. // TODO: Review which tables are needed when final execution path is defined.
LastDigitGpuTables.WarmUp(i, stream); LastDigitGpuTables.WarmUp(i, stream);
HeuristicCombinedGpuTables.WarmUp(i, stream); // HeuristicCombinedGpuTables.WarmUp(i, stream);
// SmallPrimeFactorGpuTables.WarmUp(i, stream); // SmallPrimeFactorGpuTables.WarmUp(i, stream);
// SharedHeuristicGpuTables.EnsureStaticTables(accelerator, stream); // SharedHeuristicGpuTables.EnsureStaticTables(accelerator, stream);
// _ = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.None); // _ = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.None);
@@ -115,13 +115,13 @@ public sealed class PrimeOrderCalculatorAccelerator
public Dictionary<ulong, int> Pow2ModEntriesToTestOnHost = []; public Dictionary<ulong, int> Pow2ModEntriesToTestOnHost = [];
public readonly Action<AcceleratorStream, int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>> CheckFactorsKernelLauncher; public readonly Kernel CheckFactorsKernel;
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>> ConvertToStandardKernelLauncher; public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>> ConvertToStandardKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews> HeuristicCombinedTrialDivisionKernelLauncher; public readonly Action<AcceleratorStream, Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews> HeuristicCombinedTrialDivisionKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>> KeepMontgomeryKernelLauncher; public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>> KeepMontgomeryKernelLauncher;
public readonly Action<AcceleratorStream, ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> PollardRhoKernelLauncher; public readonly Kernel PollardRhoKernel;
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>> Pow2ModWideKernelLauncher; public readonly Action<AcceleratorStream, Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>> Pow2ModWideKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<byte>> SharesFactorKernelLauncher; public readonly Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<byte>> SharesFactorKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, ulong, uint, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> SmallPrimeFactorKernelLauncher; public readonly Action<AcceleratorStream, Index1D, ulong, uint, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> SmallPrimeFactorKernelLauncher;
@@ -247,9 +247,9 @@ public sealed class PrimeOrderCalculatorAccelerator
DevicePrimesPow2LastThree = lastDigitSharedTables.DevicePrimesPow2LastThree.View; DevicePrimesPow2LastThree = lastDigitSharedTables.DevicePrimesPow2LastThree.View;
DevicePrimesPow2LastNine = lastDigitSharedTables.DevicePrimesPow2LastNine.View; DevicePrimesPow2LastNine = lastDigitSharedTables.DevicePrimesPow2LastNine.View;
DivisorTables = HeuristicCombinedGpuTables // DivisorTables = HeuristicCombinedGpuTables
.GetStaticTables(acceleratorIndex) // .GetStaticTables(acceleratorIndex)
.CreateViews(); // .CreateViews();
var smallPrimeFactorTables = SmallPrimeFactorGpuTables.GetStaticTables(acceleratorIndex); var smallPrimeFactorTables = SmallPrimeFactorGpuTables.GetStaticTables(acceleratorIndex);
@@ -260,7 +260,7 @@ public sealed class PrimeOrderCalculatorAccelerator
SmallPrimeFactorSquares = tables.Squares.View; SmallPrimeFactorSquares = tables.Squares.View;
} }
CheckFactorsKernelLauncher = KernelUtil.GetKernel(accelerator.LoadStreamKernel<int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.CheckFactorsKernel)).CreateLauncherDelegate<Action<AcceleratorStream, int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>(); CheckFactorsKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel<int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.CheckFactorsKernel));
ConvertToStandardKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelConvertToStandard)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>(); ConvertToStandardKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelConvertToStandard)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
@@ -268,7 +268,7 @@ public sealed class PrimeOrderCalculatorAccelerator
KeepMontgomeryKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelKeepMontgomery)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>(); KeepMontgomeryKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelKeepMontgomery)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
PollardRhoKernelLauncher = KernelUtil.GetKernel(accelerator.LoadStreamKernel<ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.TryPollardRhoKernel)).CreateLauncherDelegate<Action<AcceleratorStream, ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>(); PollardRhoKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel<ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.TryPollardRhoKernel));
Pow2ModWideKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>(PrimeOrderGpuHeuristics.Pow2ModKernelWide)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>>(); Pow2ModWideKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>(PrimeOrderGpuHeuristics.Pow2ModKernelWide)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>>();
@@ -1,4 +1,3 @@
using System.Buffers;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@@ -12,7 +11,7 @@ namespace PerfectNumbers.Core.Gpu;
/// Scans Mersenne divisors on the GPU for prime exponents p >= 31 using cached GPU divisor partial data. /// Scans Mersenne divisors on the GPU for prime exponents p >= 31 using cached GPU divisor partial data.
/// Consumers must call <see cref="ConfigureFromMaxPrime"/> before invoking other members so the divisor limits are populated. /// Consumers must call <see cref="ConfigureFromMaxPrime"/> before invoking other members so the divisor limits are populated.
/// </summary> /// </summary>
public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDivisorByDivisorTester public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDivisorByDivisorTester
{ {
private int _gpuBatchSize = GpuConstants.ScanBatchSize; private int _gpuBatchSize = GpuConstants.ScanBatchSize;
// EvenPerfectBitScanner configures the GPU tester once before scanning and never mutates the configuration afterwards, // EvenPerfectBitScanner configures the GPU tester once before scanning and never mutates the configuration afterwards,
@@ -21,27 +20,10 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
private ulong _divisorLimit; private ulong _divisorLimit;
// private bool _isConfigured; // private bool _isConfigured;
[ThreadStatic] private readonly ConcurrentBag<MersenneNumberDivisorByDivisorAccelerator>[] _resourcePool = [..AcceleratorPool.Shared.Accelerators.Select(x => new ConcurrentBag<MersenneNumberDivisorByDivisorAccelerator>())];
private static Dictionary<Accelerator, Action<AcceleratorStream, Index1D, ArrayView<GpuDivisorPartialData>, ArrayView<int>, ArrayView<int>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>, ArrayView<int>>>? _kernel;
private readonly ConcurrentBag<BatchResources> _resourcePool = [];
private readonly ConcurrentBag<DivisorScanSession> _sessionPool = []; private readonly ConcurrentBag<DivisorScanSession> _sessionPool = [];
private static Action<AcceleratorStream, Index1D, ArrayView<GpuDivisorPartialData>, ArrayView<int>, ArrayView<int>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>, ArrayView<int>> GetKernel(Accelerator accelerator)
{
var pool = _kernel ??= [];
if (pool.TryGetValue(accelerator, out var cached))
{
return cached;
}
var loaded = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<GpuDivisorPartialData>, ArrayView<int>, ArrayView<int>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>, ArrayView<int>>(DivisorByDivisorKernels.CheckKernel);
var kernel = KernelUtil.GetKernel(loaded);
cached = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<GpuDivisorPartialData>, ArrayView<int>, ArrayView<int>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>, ArrayView<int>>>();
pool[accelerator] = cached;
return cached;
}
public int GpuBatchSize public int GpuBatchSize
{ {
get => _gpuBatchSize; get => _gpuBatchSize;
@@ -107,20 +89,16 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
// var accelerator = _accelerators[acceleratorIndex]; // var accelerator = _accelerators[acceleratorIndex];
var gpu = PrimeOrderCalculatorAccelerator.Rent(batchCapacity); var gpu = PrimeOrderCalculatorAccelerator.Rent(batchCapacity);
var acceleratorIndex = gpu.AcceleratorIndex; var acceleratorIndex = gpu.AcceleratorIndex;
var accelerator = gpu.Accelerator;
var stream = AcceleratorStreamPool.Rent(acceleratorIndex);
// Monitor.Enter(gpuLease.ExecutionLock); // Monitor.Enter(gpuLease.ExecutionLock);
var kernel = GetKernel(accelerator); var resources = RentBatchResources(acceleratorIndex, batchCapacity);
var resources = RentBatchResources(accelerator, batchCapacity);
composite = CheckDivisors( composite = CheckDivisors(
gpu, gpu,
prime, prime,
allowedMax, allowedMax,
kernel, resources.CheckDivisorKernel,
stream,
resources.DivisorDataBuffer, resources.DivisorDataBuffer,
resources.OffsetBuffer, resources.OffsetBuffer,
resources.CountBuffer, resources.CountBuffer,
@@ -138,8 +116,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
out coveredRange, out coveredRange,
out processedCount); out processedCount);
AcceleratorStreamPool.Return(acceleratorIndex, stream); ReturnBatchResources(acceleratorIndex, resources);
ReturnBatchResources(resources);
PrimeOrderCalculatorAccelerator.Return(gpu); PrimeOrderCalculatorAccelerator.Return(gpu);
// Monitor.Exit(gpuLease.ExecutionLock); // Monitor.Exit(gpuLease.ExecutionLock);
// GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
@@ -189,8 +166,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
PrimeOrderCalculatorAccelerator gpu, PrimeOrderCalculatorAccelerator gpu,
ulong prime, ulong prime,
ulong allowedMax, ulong allowedMax,
Action<AcceleratorStream, Index1D, ArrayView<GpuDivisorPartialData>, ArrayView<int>, ArrayView<int>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>, ArrayView<int>> kernel, Kernel kernel,
AcceleratorStream stream,
MemoryBuffer1D<GpuDivisorPartialData, Stride1D.Dense> divisorDataBuffer, MemoryBuffer1D<GpuDivisorPartialData, Stride1D.Dense> divisorDataBuffer,
MemoryBuffer1D<int, Stride1D.Dense> offsetBuffer, MemoryBuffer1D<int, Stride1D.Dense> offsetBuffer,
MemoryBuffer1D<int, Stride1D.Dense> countBuffer, MemoryBuffer1D<int, Stride1D.Dense> countBuffer,
@@ -213,6 +189,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
bool processedAll; bool processedAll;
processedCount = 0UL; processedCount = 0UL;
lastProcessed = 0UL; lastProcessed = 0UL;
var acceleratorIndex = gpu.AcceleratorIndex;
// EvenPerfectBitScanner always configures non-empty GPU divisor buffers, so the defensive guard stays // EvenPerfectBitScanner always configures non-empty GPU divisor buffers, so the defensive guard stays
// commented out. Tests and benchmarks that rely on zero-capacity buffers must be updated instead of re-enabling // commented out. Tests and benchmarks that rely on zero-capacity buffers must be updated instead of re-enabling
@@ -352,6 +329,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
continue; continue;
} }
var stream = AcceleratorStreamPool.Rent(acceleratorIndex);
divisorDataView.CopyFromCPU(stream, ref divisorDataRef, admissibleCount); divisorDataView.CopyFromCPU(stream, ref divisorDataRef, admissibleCount);
offsetView.CopyFromCPU(stream, ref offsetRef, admissibleCount); offsetView.CopyFromCPU(stream, ref offsetRef, admissibleCount);
countView.CopyFromCPU(stream, ref countRef, admissibleCount); countView.CopyFromCPU(stream, ref countRef, admissibleCount);
@@ -361,11 +339,12 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
int sentinel = int.MaxValue; int sentinel = int.MaxValue;
hitIndexView.CopyFromCPU(stream, ref sentinel, 1); hitIndexView.CopyFromCPU(stream, ref sentinel, 1);
kernel(stream, new Index1D(admissibleCount), divisorDataView, offsetView, countView, exponentViewDevice, cycleView, hitsView, hitIndexView); kernel.Launch(stream, 1, new Index1D(admissibleCount), divisorDataView, offsetView, countView, exponentViewDevice, cycleView, hitsView, hitIndexView);
int firstHit = sentinel; int firstHit = sentinel;
hitIndexView.CopyToCPU(stream, ref firstHit, 1); hitIndexView.CopyToCPU(stream, ref firstHit, 1);
stream.Synchronize(); stream.Synchronize();
AcceleratorStreamPool.Return(acceleratorIndex, stream);
int hitIndex = firstHit >= admissibleCount ? -1 : firstHit; int hitIndex = firstHit >= admissibleCount ? -1 : firstHit;
bool hitFound = hitIndex >= 0; bool hitFound = hitIndex >= 0;
composite = hitFound; composite = hitFound;
@@ -537,7 +516,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
if (_kernel == null) if (_kernel == null)
{ {
_kernel = GetKernel(_accelerator); _kernel = KernelUtil.GetKernel(_accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<GpuDivisorPartialData>, ArrayView<int>, ArrayView<int>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>, ArrayView<int>>(DivisorByDivisorKernels.CheckKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<GpuDivisorPartialData>, ArrayView<int>, ArrayView<int>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>, ArrayView<int>>>();
} }
if (_divisorBuffer == null) if (_divisorBuffer == null)
@@ -694,192 +673,20 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
private BatchResources RentBatchResources(Accelerator accelerator, int capacity) private MersenneNumberDivisorByDivisorAccelerator RentBatchResources(int acceleratorIndex, int capacity)
{ {
if (!_resourcePool.TryTake(out BatchResources? resources)) var queue = _resourcePool[acceleratorIndex];
var accelerator = AcceleratorPool.Shared.Accelerators[acceleratorIndex];
if (!queue.TryTake(out MersenneNumberDivisorByDivisorAccelerator? resources))
{ {
resources = new BatchResources(Math.Max(1, capacity)); return new MersenneNumberDivisorByDivisorAccelerator(accelerator, capacity);
} }
resources.Bind(accelerator, capacity); resources.EnsureCapacity(accelerator, capacity);
return resources; return resources;
} }
private void ReturnBatchResources(BatchResources resources) => _resourcePool.Add(resources); private void ReturnBatchResources(int acceleratorIndex, MersenneNumberDivisorByDivisorAccelerator resources) => _resourcePool[acceleratorIndex].Add(resources);
private sealed class BatchResources
{
private Accelerator? _accelerator;
private MemoryBuffer1D<GpuDivisorPartialData, Stride1D.Dense>? _divisorDataBuffer;
private MemoryBuffer1D<int, Stride1D.Dense>? _offsetBuffer;
private MemoryBuffer1D<int, Stride1D.Dense>? _countBuffer;
private MemoryBuffer1D<ulong, Stride1D.Dense>? _cycleBuffer;
private MemoryBuffer1D<ulong, Stride1D.Dense>? _exponentBuffer;
private MemoryBuffer1D<byte, Stride1D.Dense>? _hitsBuffer;
private MemoryBuffer1D<int, Stride1D.Dense>? _hitIndexBuffer;
private int _deviceCapacity;
private int _hostCapacity;
internal BatchResources(int capacity)
{
int actualCapacity = Math.Max(1, capacity);
RentHostArrays(actualCapacity);
}
internal MemoryBuffer1D<GpuDivisorPartialData, Stride1D.Dense> DivisorDataBuffer => _divisorDataBuffer ?? throw new InvalidOperationException("Batch resources not bound to an accelerator.");
internal MemoryBuffer1D<int, Stride1D.Dense> OffsetBuffer => _offsetBuffer ?? throw new InvalidOperationException("Batch resources not bound to an accelerator.");
internal MemoryBuffer1D<int, Stride1D.Dense> CountBuffer => _countBuffer ?? throw new InvalidOperationException("Batch resources not bound to an accelerator.");
internal MemoryBuffer1D<ulong, Stride1D.Dense> CycleBuffer => _cycleBuffer ?? throw new InvalidOperationException("Batch resources not bound to an accelerator.");
internal MemoryBuffer1D<ulong, Stride1D.Dense> ExponentBuffer => _exponentBuffer ?? throw new InvalidOperationException("Batch resources not bound to an accelerator.");
internal MemoryBuffer1D<byte, Stride1D.Dense> HitsBuffer => _hitsBuffer ?? throw new InvalidOperationException("Batch resources not bound to an accelerator.");
internal MemoryBuffer1D<int, Stride1D.Dense> HitIndexBuffer => _hitIndexBuffer ?? throw new InvalidOperationException("Batch resources not bound to an accelerator.");
internal ulong[] Divisors { get; private set; } = null!;
internal ulong[] Exponents { get; private set; } = null!;
internal GpuDivisorPartialData[] DivisorData { get; private set; } = null!;
internal int[] Offsets { get; private set; } = null!;
internal int[] Counts { get; private set; } = null!;
internal ulong[] Cycles { get; private set; } = null!;
internal int Capacity => _hostCapacity;
internal void Bind(Accelerator accelerator, int requiredCapacity)
{
EnsureHostCapacity(requiredCapacity);
if (!ReferenceEquals(_accelerator, accelerator))
{
ReleaseDeviceBuffers();
_accelerator = accelerator;
}
EnsureDeviceCapacity(accelerator, requiredCapacity);
}
private void EnsureHostCapacity(int requiredCapacity)
{
int desiredCapacity = Math.Max(1, requiredCapacity);
if (_hostCapacity >= desiredCapacity)
{
return;
}
ReturnHostArrays();
RentHostArrays(desiredCapacity);
}
private void EnsureDeviceCapacity(Accelerator accelerator, int requiredCapacity)
{
int desiredCapacity = Math.Max(1, requiredCapacity);
if (_divisorDataBuffer is null)
{
AllocateDeviceBuffers(accelerator, desiredCapacity);
return;
}
if (_deviceCapacity >= desiredCapacity)
{
return;
}
ReleaseDeviceBuffers();
AllocateDeviceBuffers(accelerator, desiredCapacity);
}
private void AllocateDeviceBuffers(Accelerator accelerator, int capacity)
{
lock (accelerator)
{
_divisorDataBuffer = accelerator.Allocate1D<GpuDivisorPartialData>(capacity);
_offsetBuffer = accelerator.Allocate1D<int>(capacity);
_countBuffer = accelerator.Allocate1D<int>(capacity);
_cycleBuffer = accelerator.Allocate1D<ulong>(capacity);
_exponentBuffer = accelerator.Allocate1D<ulong>(capacity);
_hitsBuffer = accelerator.Allocate1D<byte>(capacity);
_hitIndexBuffer = accelerator.Allocate1D<int>(1);
}
_deviceCapacity = capacity;
}
private void RentHostArrays(int capacity)
{
ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool;
ArrayPool<int> intPool = ThreadStaticPools.IntPool;
ArrayPool<GpuDivisorPartialData> partialPool = ThreadStaticPools.GpuDivisorPartialDataPool;
Divisors = ulongPool.Rent(capacity);
Exponents = ulongPool.Rent(capacity);
DivisorData = partialPool.Rent(capacity);
Offsets = intPool.Rent(capacity);
Counts = intPool.Rent(capacity);
Cycles = ulongPool.Rent(capacity);
_hostCapacity = capacity;
}
private void ReleaseDeviceBuffers()
{
_divisorDataBuffer?.Dispose();
_offsetBuffer?.Dispose();
_countBuffer?.Dispose();
_cycleBuffer?.Dispose();
_exponentBuffer?.Dispose();
_hitsBuffer?.Dispose();
_hitIndexBuffer?.Dispose();
_divisorDataBuffer = null;
_offsetBuffer = null;
_countBuffer = null;
_cycleBuffer = null;
_exponentBuffer = null;
_hitsBuffer = null;
_hitIndexBuffer = null;
_deviceCapacity = 0;
}
private void ReturnHostArrays()
{
if (_hostCapacity == 0)
{
return;
}
ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool;
ArrayPool<int> intPool = ThreadStaticPools.IntPool;
ArrayPool<GpuDivisorPartialData> partialPool = ThreadStaticPools.GpuDivisorPartialDataPool;
ulongPool.Return(Divisors, clearArray: false);
ulongPool.Return(Exponents, clearArray: false);
partialPool.Return(DivisorData, clearArray: false);
intPool.Return(Offsets, clearArray: false);
intPool.Return(Counts, clearArray: false);
ulongPool.Return(Cycles, clearArray: false);
Divisors = Array.Empty<ulong>();
Exponents = Array.Empty<ulong>();
DivisorData = Array.Empty<GpuDivisorPartialData>();
Offsets = Array.Empty<int>();
Counts = Array.Empty<int>();
Cycles = Array.Empty<ulong>();
_hostCapacity = 0;
}
public void Dispose()
{
ReleaseDeviceBuffers();
_accelerator = null;
ReturnHostArrays();
}
}
private sealed class AcceleratorReferenceComparer : IEqualityComparer<Accelerator> private sealed class AcceleratorReferenceComparer : IEqualityComparer<Accelerator>
{ {
+4 -4
View File
@@ -412,8 +412,8 @@ public class MersenneDivisorCycles
// Console.WriteLine($"MersenneDivisorCycles.TryFactorIntoCountsInternal hits {Volatile.Read(ref _tryFactorIntoCountsInternalHits)}"); // Console.WriteLine($"MersenneDivisorCycles.TryFactorIntoCountsInternal hits {Volatile.Read(ref _tryFactorIntoCountsInternalHits)}");
// HeuristicPrimeTester primeTester = _primeTester ??= new(); // HeuristicPrimeTester primeTester = _primeTester ??= new();
if (HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, remaining)) // if (HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, remaining))
// if (PrimeTester.IsPrimeCpu(remaining, CancellationToken.None)) if (PrimeTester.IsPrime(remaining))
{ {
AddFactor(counts, remaining); AddFactor(counts, remaining);
return true; return true;
@@ -958,8 +958,8 @@ public class MersenneDivisorCycles
// HeuristicPrimeTester primeTester = _primeTester ??= new(); // HeuristicPrimeTester primeTester = _primeTester ??= new();
// if (!skipPrimeOrderHeuristic && HeuristicPrimeTester.Exclusive.IsPrimeCpu(divisor, CancellationToken.None)) // if (!skipPrimeOrderHeuristic && HeuristicPrimeTester.Exclusive.IsPrimeCpu(divisor, CancellationToken.None))
// if (!skipPrimeOrderHeuristic && primeTester.IsPrimeGpu(divisor)) if (!skipPrimeOrderHeuristic && PrimeTester.IsPrime(divisor))
if (!skipPrimeOrderHeuristic && HeuristicCombinedPrimeTester.IsPrimeGpu(divisor)) // if (!skipPrimeOrderHeuristic && HeuristicCombinedPrimeTester.IsPrimeGpu(divisor))
{ {
ulong computedOrder = PrimeOrderCalculator.Calculate( ulong computedOrder = PrimeOrderCalculator.Calculate(
divisor, divisor,
@@ -8,7 +8,7 @@ public static class PerfectNumberConstants
public const int DefaultSmallPrimeFactorSlotCount = 64; public const int DefaultSmallPrimeFactorSlotCount = 64;
public const int DefaultSpecialMaxFactorCapacity = 1024; public const int DefaultSpecialMaxFactorCapacity = 1024;
public const ulong ExtraDivisorCycleSearchLimit = 64UL; public const ulong ExtraDivisorCycleSearchLimit = 64UL;
public const int GpuFrequency = 768 - 1; public const int GpuFrequency = 16 - 1;
public const int MaxQForDivisorCycles = 4_000_000; public const int MaxQForDivisorCycles = 4_000_000;
public static readonly uint PrimesLimit = 1_000_000; //(ulong)Array.MaxLength;// 1_000_000; public static readonly uint PrimesLimit = 1_000_000; //(ulong)Array.MaxLength;// 1_000_000;
public const int MaxOddPowersCount = 128; public const int MaxOddPowersCount = 128;
+46 -11
View File
@@ -66,9 +66,11 @@ internal static partial class PrimeOrderCalculator
ulong result; ulong result;
if (phiFactors.Factors is null) if (phiFactors.Factors is null)
{ {
result = /*prime <= PerfectNumberConstants.MaxQForDivisorCycles // result = prime <= PerfectNumberConstants.MaxQForDivisorCycles
? CalculateByFactorizationGpu(gpu, prime, divisorData) // ? CalculateByFactorizationGpu(gpu, prime, divisorData)
: */CalculateByFactorizationCpu(gpu, prime, divisorData); // : CalculateByFactorizationCpu(gpu, prime, divisorData);
result = CalculateByFactorizationGpu(gpu, prime, divisorData);
// result = CalculateByFactorizationCpu(gpu, prime, divisorData);
phiFactors.Dispose(); phiFactors.Dispose();
PrimeOrderCalculatorAccelerator.Return(gpu); PrimeOrderCalculatorAccelerator.Return(gpu);
@@ -109,8 +111,8 @@ internal static partial class PrimeOrderCalculator
{ {
orderFactors?.Dispose(); orderFactors?.Dispose();
// GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
return CalculateByFactorizationCpu(gpu, prime, divisorData); // return CalculateByFactorizationCpu(gpu, prime, divisorData);
// return CalculateByFactorizationGpu(gpu, prime, divisorData); return CalculateByFactorizationGpu(gpu, prime, divisorData);
} }
if (TryHeuristicFinishCpu(gpu, prime, candidateOrder, previousOrder, divisorData, config, phiFactors, orderFactors, out ulong order)) if (TryHeuristicFinishCpu(gpu, prime, candidateOrder, previousOrder, divisorData, config, phiFactors, orderFactors, out ulong order))
@@ -138,7 +140,7 @@ internal static partial class PrimeOrderCalculator
Span<ulong> stackBuffer = stackalloc ulong[length]; Span<ulong> stackBuffer = stackalloc ulong[length];
if (length <= 9) if (length <= 8)
{ {
return EvaluateSpecialMaxCandidates(stackBuffer, factorSpan, phi, prime, divisorData); return EvaluateSpecialMaxCandidates(stackBuffer, factorSpan, phi, prime, divisorData);
} }
@@ -1174,9 +1176,10 @@ internal static partial class PrimeOrderCalculator
// bool isPrime = composite > PerfectNumberConstants.MaxQForDivisorCycles // bool isPrime = composite > PerfectNumberConstants.MaxQForDivisorCycles
// ? HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite) // ? HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite)
// : PrimeTester.IsPrime(composite); // : PrimeTester.IsPrime(composite);
// bool isPrime = PrimeTester.IsPrime(composite);
// bool isPrime = HeuristicCombinedPrimeTester.IsPrimeCpu(composite);
// bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite); // bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite);
bool runOnGpu = RunOnGpu(); bool runOnGpu = RunOnGpu();
bool isPrime = !runOnGpu ? PrimeTester.IsPrime(composite) : HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite); bool isPrime = !runOnGpu ? PrimeTester.IsPrime(composite) : HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite);
// bool isPrime = PrimeTester.IsPrime(composite); // bool isPrime = PrimeTester.IsPrime(composite);
// bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite); // bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite);
@@ -1243,13 +1246,18 @@ internal static partial class PrimeOrderCalculator
if (!entry.HasKnownPrimality) if (!entry.HasKnownPrimality)
{ {
// bool isPrime = primeTester.HeuristicIsPrimeGpu(composite); // bool isPrime = HeuristicCombinedPrimeTester.IsPrimeCpu(composite);
// bool isPrime = PrimeTester.IsPrime(composite);
// bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(composite);
// bool isPrime = PrimeTester.IsPrimeInternal(composite, CancellationToken.None); // bool isPrime = PrimeTester.IsPrimeInternal(composite, CancellationToken.None);
// Atomic.Add(ref _partialFactorPendingHits, 1UL); // Atomic.Add(ref _partialFactorPendingHits, 1UL);
// Console.WriteLine($"Partial factor pending hits {Volatile.Read(ref _partialFactorPendingHits)}"); // Console.WriteLine($"Partial factor pending hits {Volatile.Read(ref _partialFactorPendingHits)}");
bool isPrime = PrimeTester.IsPrime(composite); bool isPrime = RunOnGpu()
? HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite)
: PrimeTester.IsPrime(composite);
// bool isPrime = PrimeTester.IsPrime(composite);
// bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite); // bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite);
// bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite); // bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite);
@@ -1281,7 +1289,9 @@ internal static partial class PrimeOrderCalculator
} }
else else
{ {
// cofactorIsPrime = primeTester.HeuristicIsPrimeGpu(cofactor); // cofactorIsPrime = PrimeTester.IsPrime(cofactor);
// cofactorIsPrime = HeuristicCombinedPrimeTester.IsPrimeCpu(cofactor);
// cofactorIsPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(cofactor);
// cofactorIsPrime = PrimeTester.IsPrimeInternal(cofactor, CancellationToken.None); // cofactorIsPrime = PrimeTester.IsPrimeInternal(cofactor, CancellationToken.None);
// Atomic.Add(ref _partialFactorCofactorHits, 1UL); // Atomic.Add(ref _partialFactorCofactorHits, 1UL);
@@ -1289,7 +1299,10 @@ internal static partial class PrimeOrderCalculator
// cofactorIsPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, cofactor); // cofactorIsPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, cofactor);
// cofactorIsPrime = PrimeTester.IsPrimeGpu(gpu, cofactor); // cofactorIsPrime = PrimeTester.IsPrimeGpu(gpu, cofactor);
cofactorIsPrime = PrimeTester.IsPrime(cofactor); cofactorIsPrime = RunOnGpu()
? HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, cofactor)
: PrimeTester.IsPrime(cofactor);
// cofactorIsPrime = PrimeTester.IsPrime(cofactor);
// cofactorIsPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(cofactor); // cofactorIsPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(cofactor);
} }
@@ -1375,7 +1388,23 @@ internal static partial class PrimeOrderCalculator
private static bool RunOnGpu() private static bool RunOnGpu()
{ {
// return false;
// return true; // return true;
// int cpuCount;
// lock(_sync)
// {
// cpuCount = _cpuCount;
// cpuCount++;
// if (cpuCount == PerfectNumberConstants.GpuFrequency)
// {
// cpuCount = 0;
// }
// _cpuCount = cpuCount;
// }
// return cpuCount == 0;
int cpuCount = Atomic.Add(ref _cpuCount, 1); int cpuCount = Atomic.Add(ref _cpuCount, 1);
// return (cpuCount % GpuFrequency) == 0; // return (cpuCount % GpuFrequency) == 0;
if (cpuCount == PerfectNumberConstants.GpuFrequency) if (cpuCount == PerfectNumberConstants.GpuFrequency)
@@ -1800,6 +1829,9 @@ internal static partial class PrimeOrderCalculator
// bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, value); // bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, value);
// bool isPrime = PrimeTester.IsPrimeGpu(value); // bool isPrime = PrimeTester.IsPrimeGpu(value);
bool isPrime = PrimeTester.IsPrime(value); bool isPrime = PrimeTester.IsPrime(value);
// bool isPrime = RunOnGpu()
// ? HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, value)
// : PrimeTester.IsPrime(value);
// bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(value); // bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(value);
if (!knownComposite && isPrime) if (!knownComposite && isPrime)
{ {
@@ -1816,6 +1848,9 @@ internal static partial class PrimeOrderCalculator
// isPrime = primeTester.HeuristicIsPrimeGpu(factor); // isPrime = primeTester.HeuristicIsPrimeGpu(factor);
// isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, factor); // isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, factor);
// isPrime = PrimeTester.IsPrimeGpu(factor); // isPrime = PrimeTester.IsPrimeGpu(factor);
// isPrime = RunOnGpu()
// ? HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, factor)
// : PrimeTester.IsPrime(factor);
isPrime = PrimeTester.IsPrime(factor); isPrime = PrimeTester.IsPrime(factor);
// isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(factor); // isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(factor);
if (isPrime) if (isPrime)
@@ -42,8 +42,9 @@ internal static partial class PrimeOrderCalculator
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex); AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
gpu.Pow2ModEntriesToTestOnDevice.View.CopyFromCPU(stream, entries); gpu.Pow2ModEntriesToTestOnDevice.View.CopyFromCPU(stream, entries);
var kernelLauncher = gpu.CheckFactorsKernelLauncher; // var kernelLauncher = gpu.CheckFactorsKernelLauncher;
kernelLauncher(stream, entryCount, phi, gpu.Pow2ModEntriesToTestOnDevice.View, divisorData, gpu.OutputUlong.View); var kernel = gpu.CheckFactorsKernel;
kernel.Launch(stream, 1, entryCount, phi, gpu.Pow2ModEntriesToTestOnDevice.View, divisorData, gpu.OutputUlong.View);
gpu.OutputUlong.View.CopyToCPU(stream, ref order, 1); gpu.OutputUlong.View.CopyToCPU(stream, ref order, 1);
stream.Synchronize(); stream.Synchronize();
@@ -170,9 +171,9 @@ internal static partial class PrimeOrderCalculator
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex); AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
gpu.Input.View.CopyFromCPU(stream, randomStateSpan); gpu.Input.View.CopyFromCPU(stream, randomStateSpan);
var kernelLauncher = gpu.PollardRhoKernelLauncher; var kernel = gpu.PollardRhoKernel;
kernelLauncher(stream, n, 1, gpu.Input.View, gpu.OutputByte.View, gpu.OutputUlong.View); kernel.Launch(stream, 1, n, 1, gpu.Input.View, gpu.OutputByte.View, gpu.OutputUlong.View);
gpu.OutputByte.View.CopyToCPU(stream, factoredSpan); gpu.OutputByte.View.CopyToCPU(stream, factoredSpan);
gpu.OutputUlong.View.CopyToCPU(stream, factorSpan); gpu.OutputUlong.View.CopyToCPU(stream, factorSpan);