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
+202 -240

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();
// TODO: Review which tables are needed when final execution path is defined.
LastDigitGpuTables.WarmUp(i, stream);
HeuristicCombinedGpuTables.WarmUp(i, stream);
// HeuristicCombinedGpuTables.WarmUp(i, stream);
// SmallPrimeFactorGpuTables.WarmUp(i, stream);
// SharedHeuristicGpuTables.EnsureStaticTables(accelerator, stream);
// _ = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.None);
@@ -115,13 +115,13 @@ public sealed class PrimeOrderCalculatorAccelerator
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, 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, 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, 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;
@@ -247,9 +247,9 @@ public sealed class PrimeOrderCalculatorAccelerator
DevicePrimesPow2LastThree = lastDigitSharedTables.DevicePrimesPow2LastThree.View;
DevicePrimesPow2LastNine = lastDigitSharedTables.DevicePrimesPow2LastNine.View;
DivisorTables = HeuristicCombinedGpuTables
.GetStaticTables(acceleratorIndex)
.CreateViews();
// DivisorTables = HeuristicCombinedGpuTables
// .GetStaticTables(acceleratorIndex)
// .CreateViews();
var smallPrimeFactorTables = SmallPrimeFactorGpuTables.GetStaticTables(acceleratorIndex);
@@ -260,7 +260,7 @@ public sealed class PrimeOrderCalculatorAccelerator
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>>>();
@@ -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>>>();
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>>>();