GPU memory allocations protected with lock to prevent shared memory access issues. GPU usage limited for the best performance.

This commit is contained in:
mlemanczyk committed 2025-11-19 16:49:01 +01:00
1 parent 02d16bf05c
commit 5cac51479e
12 files changed
+236 -148

No files matched your search

+8 -5
View File
@@ -260,11 +260,14 @@ public sealed class DivisorCycleCache
}
Accelerator accelerator = _accelerator;
divisorBuffer = accelerator.Allocate1D<ulong>(requiredCapacity);
powBuffer = accelerator.Allocate1D<ulong>(requiredCapacity);
orderBuffer = accelerator.Allocate1D<ulong>(requiredCapacity);
resultBuffer = accelerator.Allocate1D<ulong>(requiredCapacity);
statusBuffer = accelerator.Allocate1D<byte>(requiredCapacity);
lock(accelerator)
{
divisorBuffer = accelerator.Allocate1D<ulong>(requiredCapacity);
powBuffer = accelerator.Allocate1D<ulong>(requiredCapacity);
orderBuffer = accelerator.Allocate1D<ulong>(requiredCapacity);
resultBuffer = accelerator.Allocate1D<ulong>(requiredCapacity);
statusBuffer = accelerator.Allocate1D<byte>(requiredCapacity);
}
}
private void ComputeCyclesGpuCore(ReadOnlySpan<ulong> divisors, Span<ulong> destination)
@@ -117,7 +117,11 @@ public sealed class PrimeOrderCalculatorAccelerator
public readonly Kernel CheckFactorsKernel;
public readonly Kernel ConvertToStandardKernel;
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>> ConvertToStandardKernelLauncher;
public readonly Kernel HeuristicCombinedTrialDivisionKernel;
public readonly Action<AcceleratorStream, Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews> HeuristicCombinedTrialDivisionKernelLauncher;
public readonly Kernel KeepMontgomeryKernel;
public readonly Kernel PollardRhoKernel;
public readonly Kernel Pow2ModWideKernel;
@@ -133,29 +137,41 @@ public sealed class PrimeOrderCalculatorAccelerator
MemoryBuffer1D<KeyValuePair<ulong, int>, Stride1D.Dense> pow2ModEntriesToTestOnDevice = Pow2ModEntriesToTestOnDevice;
if (pow2ModEntriesToTestOnDevice.Length < factorsCount)
{
pow2ModEntriesToTestOnDevice.Dispose();
Pow2ModEntriesToTestOnDevice = accelerator.Allocate1D<KeyValuePair<ulong, int>>(factorsCount);
lock (accelerator)
{
pow2ModEntriesToTestOnDevice.Dispose();
Pow2ModEntriesToTestOnDevice = accelerator.Allocate1D<KeyValuePair<ulong, int>>(factorsCount);
}
}
MemoryBuffer1D<ulong, Stride1D.Dense> input = Input;
if (input.Length < primeTesterCapacity)
{
input.Dispose();
Input = accelerator.Allocate1D<ulong>(primeTesterCapacity);
lock (accelerator)
{
input.Dispose();
Input = accelerator.Allocate1D<ulong>(primeTesterCapacity);
}
}
MemoryBuffer1D<byte, Stride1D.Dense> outputByte = OutputByte;
if (outputByte.Length < primeTesterCapacity)
{
outputByte.Dispose();
OutputByte = accelerator.Allocate1D<byte>(primeTesterCapacity);
lock (accelerator)
{
outputByte.Dispose();
OutputByte = accelerator.Allocate1D<byte>(primeTesterCapacity);
}
}
MemoryBuffer1D<int, Stride1D.Dense> outputInt = OutputInt;
if (outputInt.Length < primeTesterCapacity)
{
outputInt.Dispose();
OutputInt = accelerator.Allocate1D<int>(primeTesterCapacity);
lock (accelerator)
{
outputInt.Dispose();
OutputInt = accelerator.Allocate1D<int>(primeTesterCapacity);
}
}
}
@@ -166,15 +182,21 @@ public sealed class PrimeOrderCalculatorAccelerator
MemoryBuffer1D<ulong, Stride1D.Dense> outputUlong = OutputUlong;
if (outputUlong.Length < newSize)
{
outputUlong.Dispose();
OutputUlong = accelerator.Allocate1D<ulong>(newSize);
lock (accelerator)
{
outputUlong.Dispose();
OutputUlong = accelerator.Allocate1D<ulong>(newSize);
}
}
MemoryBuffer1D<int, Stride1D.Dense> outputInt = OutputInt;
if (outputInt.Length < newSize)
{
outputInt.Dispose();
OutputInt = accelerator.Allocate1D<int>(newSize);
lock (accelerator)
{
outputInt.Dispose();
OutputInt = accelerator.Allocate1D<int>(newSize);
}
}
}
@@ -184,15 +206,21 @@ public sealed class PrimeOrderCalculatorAccelerator
MemoryBuffer1D<ulong, Stride1D.Dense> input = Input;
if (input.Length < newSize)
{
input.Dispose();
Input = accelerator.Allocate1D<ulong>(newSize);
lock (accelerator)
{
input.Dispose();
Input = accelerator.Allocate1D<ulong>(newSize);
}
}
MemoryBuffer1D<ulong, Stride1D.Dense> outputUlong = OutputUlong;
if (outputUlong.Length < newSize)
{
outputUlong.Dispose();
OutputUlong = accelerator.Allocate1D<ulong>(newSize);
lock (accelerator)
{
outputUlong.Dispose();
OutputUlong = accelerator.Allocate1D<ulong>(newSize);
}
}
}
@@ -201,57 +229,65 @@ public sealed class PrimeOrderCalculatorAccelerator
var accelerator = _accelerators[acceleratorIndex];
Accelerator = accelerator;
AcceleratorIndex = acceleratorIndex;
Input = accelerator.Allocate1D<ulong>(Math.Max(specialMaxFactorCapacity, primeTesterCapacity));
OutputByte = Accelerator.Allocate1D<byte>(primeTesterCapacity);
OutputInt = Accelerator.Allocate1D<int>(Math.Max(primeTesterCapacity, smallPrimeFactorSlotCount));
OutputUlong = accelerator.Allocate1D<ulong>(Math.Max(specialMaxFactorCapacity, smallPrimeFactorSlotCount));
Pow2ModEntriesToTestOnDevice = accelerator.Allocate1D<KeyValuePair<ulong, int>>(factorsCount);
SmallPrimeFactorCountSlot = accelerator.Allocate1D<int>(1);
SpecialMaxResult = accelerator.Allocate1D<ulong>(1);
LastDigitGpuTables lastDigitSharedTables = LastDigitGpuTables.GetStaticTables(acceleratorIndex);
DevicePrimesLastOne = lastDigitSharedTables.DevicePrimesLastOne.View;
DevicePrimesLastSeven = lastDigitSharedTables.DevicePrimesLastSeven.View;
DevicePrimesLastThree = lastDigitSharedTables.DevicePrimesLastThree.View;
DevicePrimesLastNine = lastDigitSharedTables.DevicePrimesLastNine.View;
DevicePrimesPow2LastOne = lastDigitSharedTables.DevicePrimesPow2LastOne.View;
DevicePrimesPow2LastSeven = lastDigitSharedTables.DevicePrimesPow2LastSeven.View;
DevicePrimesPow2LastThree = lastDigitSharedTables.DevicePrimesPow2LastThree.View;
DevicePrimesPow2LastNine = lastDigitSharedTables.DevicePrimesPow2LastNine.View;
DivisorTables = HeuristicCombinedGpuTables
.GetStaticTables(acceleratorIndex)
.CreateViews();
var smallPrimeFactorTables = SmallPrimeFactorGpuTables.GetStaticTables(acceleratorIndex);
if (smallPrimeFactorTables.HasValue)
lock (accelerator)
{
SmallPrimeFactorGpuTables tables = smallPrimeFactorTables.Value;
SmallPrimeFactorPrimes = tables.Primes.View;
SmallPrimeFactorSquares = tables.Squares.View;
Input = accelerator.Allocate1D<ulong>(Math.Max(specialMaxFactorCapacity, primeTesterCapacity));
OutputByte = Accelerator.Allocate1D<byte>(primeTesterCapacity);
OutputInt = Accelerator.Allocate1D<int>(Math.Max(primeTesterCapacity, smallPrimeFactorSlotCount));
OutputUlong = accelerator.Allocate1D<ulong>(Math.Max(specialMaxFactorCapacity, smallPrimeFactorSlotCount));
Pow2ModEntriesToTestOnDevice = accelerator.Allocate1D<KeyValuePair<ulong, int>>(factorsCount);
SmallPrimeFactorCountSlot = accelerator.Allocate1D<int>(1);
SpecialMaxResult = accelerator.Allocate1D<ulong>(1);
LastDigitGpuTables lastDigitSharedTables = LastDigitGpuTables.GetStaticTables(acceleratorIndex);
DevicePrimesLastOne = lastDigitSharedTables.DevicePrimesLastOne.View;
DevicePrimesLastSeven = lastDigitSharedTables.DevicePrimesLastSeven.View;
DevicePrimesLastThree = lastDigitSharedTables.DevicePrimesLastThree.View;
DevicePrimesLastNine = lastDigitSharedTables.DevicePrimesLastNine.View;
DevicePrimesPow2LastOne = lastDigitSharedTables.DevicePrimesPow2LastOne.View;
DevicePrimesPow2LastSeven = lastDigitSharedTables.DevicePrimesPow2LastSeven.View;
DevicePrimesPow2LastThree = lastDigitSharedTables.DevicePrimesPow2LastThree.View;
DevicePrimesPow2LastNine = lastDigitSharedTables.DevicePrimesPow2LastNine.View;
DivisorTables = HeuristicCombinedGpuTables
.GetStaticTables(acceleratorIndex)
.CreateViews();
var smallPrimeFactorTables = SmallPrimeFactorGpuTables.GetStaticTables(acceleratorIndex);
if (smallPrimeFactorTables.HasValue)
{
SmallPrimeFactorGpuTables tables = smallPrimeFactorTables.Value;
SmallPrimeFactorPrimes = tables.Primes.View;
SmallPrimeFactorSquares = tables.Squares.View;
}
CheckFactorsKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel<int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.CheckFactorsKernel));
Kernel convertToStandardKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelConvertToStandard));
ConvertToStandardKernel = convertToStandardKernel;
ConvertToStandardKernelLauncher = convertToStandardKernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
var heuristicCombinedTrialDivisionKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews>(PrimeTesterKernels.HeuristicTrialCombinedDivisionKernel));
HeuristicCombinedTrialDivisionKernel = heuristicCombinedTrialDivisionKernel;
HeuristicCombinedTrialDivisionKernelLauncher = heuristicCombinedTrialDivisionKernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews>>();
KeepMontgomeryKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelKeepMontgomery));
PollardRhoKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel<ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.TryPollardRhoKernel));
Pow2ModWideKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>(PrimeOrderGpuHeuristics.Pow2ModKernelWide));
SharesFactorKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<byte>>(PrimeTesterKernels.SharesFactorKernel));
SmallPrimeFactorKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<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>>(SmallPrimeFactorKernels.SmallPrimeFactorKernelScan));
SmallPrimeSieveKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>(PrimeTesterKernels.SmallPrimeSieveKernel));
SpecialMaxKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.EvaluateSpecialMaxCandidatesKernel));
}
CheckFactorsKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel<int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.CheckFactorsKernel));
ConvertToStandardKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelConvertToStandard));
HeuristicCombinedTrialDivisionKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews>(PrimeTesterKernels.HeuristicTrialCombinedDivisionKernel));
KeepMontgomeryKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelKeepMontgomery));
PollardRhoKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel<ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.TryPollardRhoKernel));
Pow2ModWideKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>(PrimeOrderGpuHeuristics.Pow2ModKernelWide));
SharesFactorKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<byte>>(PrimeTesterKernels.SharesFactorKernel));
SmallPrimeFactorKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<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>>(SmallPrimeFactorKernels.SmallPrimeFactorKernelScan));
SmallPrimeSieveKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>(PrimeTesterKernels.SmallPrimeSieveKernel));
SpecialMaxKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.EvaluateSpecialMaxCandidatesKernel));
}
public void Dispose()
+9 -9
View File
@@ -26,7 +26,7 @@ public class GpuKernelPool
internal static KernelContainer GetOrAddKernels(int acceleratorIndex, AcceleratorStream stream, KernelType kernelType)
{
var pool = _pool ??= [];
if (pool[acceleratorIndex] is not {} kernels)
if (pool[acceleratorIndex] is not { } kernels)
{
kernels = new();
}
@@ -151,7 +151,7 @@ public class GpuKernelPool
var host = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot();
MemoryBuffer1D<ulong, Stride1D.Dense>? device;
// lock (accelerator)
lock (accelerator)
{
device = accelerator.Allocate1D<ulong>(host.Length);
}
@@ -195,13 +195,13 @@ public class GpuKernelPool
MemoryBuffer1D<ulong, Stride1D.Dense>? deviceLastOnePow2;
MemoryBuffer1D<ulong, Stride1D.Dense>? deviceLastSevenPow2;
// lock (accelerator)
// {
deviceLastOne = accelerator.Allocate1D<uint>(hostLastOne.Length);
deviceLastSeven = accelerator.Allocate1D<uint>(hostLastSeven.Length);
deviceLastOnePow2 = accelerator.Allocate1D<ulong>(hostLastOnePow2.Length);
deviceLastSevenPow2 = accelerator.Allocate1D<ulong>(hostLastSevenPow2.Length);
// }
lock (accelerator)
{
deviceLastOne = accelerator.Allocate1D<uint>(hostLastOne.Length);
deviceLastSeven = accelerator.Allocate1D<uint>(hostLastSeven.Length);
deviceLastOnePow2 = accelerator.Allocate1D<ulong>(hostLastOnePow2.Length);
deviceLastSevenPow2 = accelerator.Allocate1D<ulong>(hostLastSevenPow2.Length);
}
deviceLastOne.View.CopyFromCPU(stream, hostLastOne);
deviceLastSeven.View.CopyFromCPU(stream, hostLastSeven);
@@ -540,7 +540,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
if (_divisorBuffer == null)
{
// lock(accelerator)
lock(accelerator)
{
_divisorBuffer = accelerator.Allocate1D<GpuDivisorPartialData>(1);
_offsetBuffer = accelerator.Allocate1D<int>(1);
@@ -570,7 +570,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
{
int desiredCapacity = requiredCapacity > _capacity ? requiredCapacity : _capacity;
_capacity = desiredCapacity;
// lock (accelerator)
lock (accelerator)
{
_exponentsBuffer = accelerator.Allocate1D<ulong>(desiredCapacity);
_hitBuffer = accelerator.Allocate1D<byte>(desiredCapacity);
@@ -798,7 +798,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
private void AllocateDeviceBuffers(Accelerator accelerator, int capacity)
{
// lock (accelerator)
lock (accelerator)
{
_divisorDataBuffer = accelerator.Allocate1D<GpuDivisorPartialData>(capacity);
_offsetBuffer = accelerator.Allocate1D<int>(capacity);
@@ -55,8 +55,10 @@ public static class Pow2MontgomeryGpuCalculator
// We don't need to worry about any left-overs here.
// resultBuffer.MemSetToZero(stream);
var kernel = gpu.ConvertToStandardKernel;
kernel.Launch(stream, 1, 1, exponentBuffer.View, divisor, resultBuffer.View);
var kernelLauncher = gpu.ConvertToStandardKernelLauncher!;
kernelLauncher(stream, 1, exponentBuffer.View, divisor, resultBuffer.View);
resultBuffer.View.CopyToCPU(stream, ref result, 1);
stream.Synchronize();
@@ -73,7 +75,6 @@ public static class Pow2MontgomeryGpuCalculator
ulong result = 0UL;
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.OutputUlong;
var kernel = gpu.ConvertToStandardKernel;
int acceleratorIndex = gpu.AcceleratorIndex;
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
@@ -81,8 +82,11 @@ public static class Pow2MontgomeryGpuCalculator
// We don't need to worry about any left-overs here.
// resultBuffer.MemSetToZero(stream);
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
kernelLauncher(stream, 1,exponentBuffer.View, divisor, resultBuffer.View);
var accelerator = gpu.Accelerator;
var kernelLauncher = gpu.ConvertToStandardKernelLauncher;
kernelLauncher(stream, 1, exponentBuffer.View, divisor, resultBuffer.View);
resultBuffer.View.CopyToCPU(stream, ref result, 1);
stream.Synchronize();
@@ -190,14 +190,14 @@ internal static partial class PrimeOrderGpuHeuristics
// fullyFactoredBuffer.MemSetToZero(stream);
var partialFactorKernel = GetPartialFactorKernel(acceleratorIndex);
var kernelLauncher = partialFactorKernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, int, ulong, uint, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>>>();
partialFactorKernel.Launch(
kernelLauncher(
stream,
1,
1,
smallPrimesView,
smallSquaresView,
smallPrimesView.Length,
(int)smallPrimesView.Length,
primeTargets.Length,
value,
limit,
@@ -354,7 +354,7 @@ internal static partial class PrimeOrderGpuHeuristics
MemoryBuffer1D<ulong, Stride1D.Dense>? resultBuffer;
MemoryBuffer1D<byte, Stride1D.Dense>? statusBuffer;
// lock(accelerator)
lock(accelerator)
{
phiFactorBuffer = accelerator.Allocate1D<ulong>(GpuSmallPrimeFactorSlots);
phiExponentBuffer = accelerator.Allocate1D<int>(GpuSmallPrimeFactorSlots);
@@ -398,16 +398,17 @@ internal static partial class PrimeOrderGpuHeuristics
statusBuffer.View);
var orderKernel = GetOrderKernel(acceleratorIndex);
orderKernel.Launch(
var kernelLauncher = orderKernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, OrderKernelConfig, MontgomeryDivisorData, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, OrderKernelBuffers>>();
kernelLauncher(
stream,
1,
1,
prime,
kernelConfig,
divisorData,
smallPrimesView,
smallSquaresView,
smallPrimesView.Length,
(int)smallPrimesView.Length,
buffers);
@@ -517,7 +518,7 @@ internal static partial class PrimeOrderGpuHeuristics
// with out preallocated buffers. Share the pool with Pow2ModWide kernel.
MemoryBuffer1D<ulong, Stride1D.Dense>? exponentBuffer;
MemoryBuffer1D<ulong, Stride1D.Dense>? remainderBuffer;
// lock(accelerator)
lock(accelerator)
{
exponentBuffer = accelerator.Allocate1D<ulong>(exponents.Length);
remainderBuffer = accelerator.Allocate1D<ulong>(exponents.Length);
@@ -529,9 +530,11 @@ internal static partial class PrimeOrderGpuHeuristics
// remainderBuffer.MemSetToZero(stream);
var pow2ModKernel = GetPow2ModKernel(acceleratorIndex);
var kernelLauncher = pow2ModKernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
try
{
pow2ModKernel.Launch(stream, 1, exponents.Length, exponentBuffer.View, divisorData, remainderBuffer.View);
kernelLauncher(stream, exponents.Length, exponentBuffer.View, divisorData, remainderBuffer.View);
remainderBuffer.View.CopyToCPU(stream, ref MemoryMarshal.GetReference(results), exponents.Length);
stream.Synchronize();
@@ -590,13 +593,20 @@ internal static partial class PrimeOrderGpuHeuristics
int acceleratorIndex = gpu.AcceleratorIndex;
Accelerator accelerator = gpu.Accelerator;
MemoryBuffer1D<GpuUInt128, Stride1D.Dense> exponentBuffer = accelerator.Allocate1D<GpuUInt128>(length);
MemoryBuffer1D<GpuUInt128, Stride1D.Dense> remainderBuffer = accelerator.Allocate1D<GpuUInt128>(length);
AcceleratorStream? stream = AcceleratorStreamPool.Rent(acceleratorIndex);
exponentBuffer.View.CopyFromCPU(stream, exponentSpan);
MemoryBuffer1D<GpuUInt128, Stride1D.Dense> exponentBuffer;
MemoryBuffer1D<GpuUInt128, Stride1D.Dense> remainderBuffer;
gpu.Pow2ModWideKernel.Launch(stream, length, exponentBuffer.View, modulus, remainderBuffer.View);
lock(accelerator)
{
exponentBuffer = accelerator.Allocate1D<GpuUInt128>(length);
remainderBuffer = accelerator.Allocate1D<GpuUInt128>(length);
}
exponentBuffer.View.CopyFromCPU(stream, exponentSpan);
var kernelLauncher = gpu.Pow2ModWideKernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>>();
kernelLauncher(stream, length, exponentBuffer.View, modulus, remainderBuffer.View);
remainderBuffer.View.CopyToCPU(stream, ref MemoryMarshal.GetReference(resultSpan), length);
stream.Synchronize();
@@ -240,13 +240,12 @@ public sealed class HeuristicCombinedPrimeTester
var kernel = gpu.HeuristicCombinedTrialDivisionKernel;
var flagView1D = gpu.OutputInt!.View;
bool compositeDetected = false;
int divisorLength = GetCombinedDivisors(nMod10).Length;
bool compositeDetected;
// int compositeFlag = 0;
Span<int> compositeFlag = stackalloc int[1];
flagView1D.MemSetToZero(stream);
int compositeFlag = 0;
flagView1D.CopyFromCPU(stream, ref compositeFlag, 1);
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews>>();
var kernelLauncher = gpu.HeuristicCombinedTrialDivisionKernelLauncher;
kernelLauncher(
stream,
1,
@@ -255,13 +254,13 @@ public sealed class HeuristicCombinedPrimeTester
n,
maxDivisorSquare,
gpu.DivisorTables);
flagView1D.CopyToCPU(stream, ref compositeFlag, 1);
flagView1D.CopyToCPU(stream, compositeFlag);
stream.Synchronize();
AcceleratorStreamPool.Return(acceleratorIndex, stream);
// GpuPrimeWorkLimiter.Release();
compositeDetected = compositeFlag != 0;
compositeDetected = compositeFlag[0] != 0;
return compositeDetected;
}
+4 -3
View File
@@ -840,6 +840,8 @@ public class MersenneDivisorCycles
}
var divisorCycleKernel = GetDivisorCycleKernel(acceleratorIndex);
var kernelLauncher = divisorCycleKernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>();
while (start <= maxDivisor)
{
end = Math.Min(start + batchSizeUL - 1UL, maxDivisor);
@@ -860,15 +862,14 @@ public class MersenneDivisorCycles
// GpuKernelPool.Run((accelerator, stream) =>
MemoryBuffer1D<ulong, Stride1D.Dense>? bufferDiv;
MemoryBuffer1D<ulong, Stride1D.Dense>? bufferCycle;
// lock(accelerator)
lock(accelerator)
{
bufferDiv = accelerator.Allocate1D(validDivisors);
bufferCycle = accelerator.Allocate1D<ulong>(idx);
}
divisorCycleKernel.Launch(
kernelLauncher(
stream,
1,
idx,
bufferDiv.View,
bufferCycle.View);
@@ -13,7 +13,7 @@ public static class PerfectNumberConstants
public const int MaxOddPowersCount = 128;
public const int PooledArrayThreshold = 64;
public static readonly int RollingAccelerators = 298; //SharedGpuContext.Device.MaxNumThreadsPerGroup;
public const int ThreadsByAccelerator = 4096;
public const int ThreadsByAccelerator = 1;
// TODO: Load these limits from the benchmark-driven configuration so CPU and GPU scans stay aligned with the optimal
// divisor-cycle datasets we generate offline.
// TODO: Promote these magic numbers into a runtime profile derived from EvenPerfectBitScanner.Benchmarks so we can retune
+62 -31
View File
@@ -3,6 +3,7 @@ using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using ILGPU;
using PerfectNumbers.Core.Cpu;
using PerfectNumbers.Core.Gpu;
using PerfectNumbers.Core.Gpu.Accelerators;
@@ -65,9 +66,9 @@ internal static partial class PrimeOrderCalculator
ulong result;
if (phiFactors.Factors is null)
{
result = prime <= PerfectNumberConstants.MaxQForDivisorCycles
result = /*prime <= PerfectNumberConstants.MaxQForDivisorCycles
? CalculateByFactorizationGpu(gpu, prime, divisorData)
: CalculateByFactorizationCpu(gpu, prime, divisorData);
: */CalculateByFactorizationCpu(gpu, prime, divisorData);
phiFactors.Dispose();
PrimeOrderCalculatorAccelerator.Return(gpu);
@@ -108,7 +109,8 @@ internal static partial class PrimeOrderCalculator
{
orderFactors?.Dispose();
// GpuPrimeWorkLimiter.Release();
return CalculateByFactorizationGpu(gpu, prime, divisorData);
return CalculateByFactorizationCpu(gpu, prime, divisorData);
// return CalculateByFactorizationGpu(gpu, prime, divisorData);
}
if (TryHeuristicFinishCpu(gpu, prime, candidateOrder, previousOrder, divisorData, config, phiFactors, orderFactors, out ulong order))
@@ -136,7 +138,7 @@ internal static partial class PrimeOrderCalculator
Span<ulong> stackBuffer = stackalloc ulong[length];
if (length <= 7)
if (length <= 9)
{
return EvaluateSpecialMaxCandidates(stackBuffer, factorSpan, phi, prime, divisorData);
}
@@ -1055,17 +1057,17 @@ internal static partial class PrimeOrderCalculator
private static ulong _pow2CpuHits;
private static bool Pow2EqualsOneCpu(PrimeOrderCalculatorAccelerator gpu, ulong exponent, ulong prime, in MontgomeryDivisorData divisorData)
{
if (exponent <= (PerfectNumberConstants.MaxQForDivisorCycles) || prime <= (PerfectNumberConstants.MaxQForDivisorCycles))
{
// Atomic.Add(ref _pow2GpuHits, 1);
// Console.WriteLine($"pow2 GPU Hits {_pow2GpuHits}");
ulong remainder = exponent.Pow2MontgomeryModWindowedConvertGpu(gpu, divisorData);
// GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(exponent, prime, out ulong remainder, divisorData);
// if (status == GpuPow2ModStatus.Success)
// {
return remainder == 1UL;
// }
}
// if (exponent >= PerfectNumberConstants.MaxQForDivisorCycles || prime >= PerfectNumberConstants.MaxQForDivisorCycles)
// {
// // Atomic.Add(ref _pow2GpuHits, 1);
// // Console.WriteLine($"pow2 GPU Hits {_pow2GpuHits}");
// ulong remainder = exponent.Pow2MontgomeryModWindowedConvertGpu(gpu, divisorData);
// // GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(exponent, prime, out ulong remainder, divisorData);
// // if (status == GpuPow2ModStatus.Success)
// // {
// return remainder == 1UL;
// // }
// }
// Atomic.Add(ref _pow2CpuHits, 1);
// Console.WriteLine($"pow2 CPU Hits {_pow2CpuHits}");
@@ -1077,6 +1079,7 @@ internal static partial class PrimeOrderCalculator
// private static ulong _partialFactorCofactorHits;
private static bool _goToGpu = true;
private static int _cpuCount;
private static PartialFactorResult PartialFactor(PrimeOrderCalculatorAccelerator gpu, ulong value, in PrimeOrderSearchConfig config)
{
@@ -1163,11 +1166,19 @@ internal static partial class PrimeOrderCalculator
// Console.WriteLine($"Partial factor hits {Volatile.Read(ref _partialFactorHits)}");
// bool isPrime = PrimeTester.IsPrimeCpu(composite, CancellationToken.None);
bool goToGpu = Volatile.Read(ref _goToGpu);
Volatile.Write(ref _goToGpu, !goToGpu);
bool isPrime = goToGpu
? HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite)
: PrimeTester.IsPrime(composite);
// bool goToGpu = Volatile.Read(ref _goToGpu);
// Volatile.Write(ref _goToGpu, !goToGpu);
// bool isPrime = goToGpu
// ? HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite)
// : PrimeTester.IsPrime(composite);
// bool isPrime = composite > PerfectNumberConstants.MaxQForDivisorCycles
// ? HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite)
// : PrimeTester.IsPrime(composite);
// bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite);
bool runOnGpu = RunOnGpu();
bool isPrime = runOnGpu ? PrimeTester.IsPrime(composite) : HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite);
// bool isPrime = PrimeTester.IsPrime(composite);
// bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite);
if (isPrime)
@@ -1184,8 +1195,8 @@ internal static partial class PrimeOrderCalculator
continue;
}
if (!TryPollardRhoGpu(gpu, composite, out ulong factor))
// if (!TryPollardRhoCpu(composite, deadlineTimestamp, out ulong factor))
// if (!TryPollardRhoGpu(gpu, composite, out ulong factor))
if (!TryPollardRhoCpu(composite, deadlineTimestamp, out ulong factor))
{
pending.Add(new PendingEntry(composite, knownComposite: true));
continue;
@@ -1238,8 +1249,8 @@ internal static partial class PrimeOrderCalculator
// Atomic.Add(ref _partialFactorPendingHits, 1UL);
// Console.WriteLine($"Partial factor pending hits {Volatile.Read(ref _partialFactorPendingHits)}");
// bool isPrime = PrimeTester.IsPrimeCpu(composite, CancellationToken.None);
bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite);
bool isPrime = PrimeTester.IsPrime(composite);
// bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite);
// bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite);
entry = entry.WithPrimality(isPrime);
@@ -1276,9 +1287,9 @@ internal static partial class PrimeOrderCalculator
// Atomic.Add(ref _partialFactorCofactorHits, 1UL);
// Console.WriteLine($"Partial factor cofactor hits {Volatile.Read(ref _partialFactorCofactorHits)}");
cofactorIsPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, cofactor);
// cofactorIsPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, cofactor);
// cofactorIsPrime = PrimeTester.IsPrimeGpu(gpu, cofactor);
// cofactorIsPrime = PrimeTester.IsPrimeGpu(cofactor);
cofactorIsPrime = PrimeTester.IsPrime(cofactor);
// cofactorIsPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(cofactor);
}
@@ -1362,6 +1373,23 @@ internal static partial class PrimeOrderCalculator
return result;
}
private static bool RunOnGpu()
{
const int GpuFrequency = 1024 - 1;
int cpuCount = Atomic.Add(target: ref _cpuCount, 1);
if (cpuCount == GpuFrequency)
{
Atomic.Add(ref _cpuCount, -GpuFrequency);
}
else if (cpuCount > GpuFrequency)
{
cpuCount -= GpuFrequency;
}
return cpuCount != GpuFrequency;
}
private static void PopulateSmallPrimeFactorsCpu(
ulong value,
uint limit,
@@ -1731,7 +1759,8 @@ internal static partial class PrimeOrderCalculator
// ulong candidate = order / primeFactor;
// if (candidate.Pow2MontgomeryModWindowedCpu(divisorData, keepMontgomery: false) == 1UL)
if (candidate.Pow2MontgomeryModWindowedConvertGpu(gpu, divisorData) == 1UL)
if (candidate.Pow2MontgomeryModWindowedCpu(divisorData, keepMontgomery: false) == 1UL)
// if (candidate.Pow2MontgomeryModWindowedConvertGpu(gpu, divisorData) == 1UL)
// if (Pow2EqualsOneCpu(candidate, prime, divisorData))
{
order = candidate;
@@ -1768,9 +1797,9 @@ internal static partial class PrimeOrderCalculator
// HeuristicPrimeTester tester = _tester ??= new();
// bool isPrime = primeTester.HeuristicIsPrimeGpu(value);
bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, value);
// bool isPrime = PrimeTester.IsPrimeGpu(value);
// bool isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, value);
// bool isPrime = PrimeTester.IsPrimeGpu(value);
bool isPrime = PrimeTester.IsPrime(value);
// bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(value);
if (!knownComposite && isPrime)
{
@@ -1785,8 +1814,9 @@ internal static partial class PrimeOrderCalculator
// Console.WriteLine($"Factor completely after PollardRho hits {Volatile.Read(ref _factorCompletelyPollardRhoHits)}");
// isPrime = primeTester.HeuristicIsPrimeGpu(factor);
isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, factor);
// isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, factor);
// isPrime = PrimeTester.IsPrimeGpu(factor);
isPrime = PrimeTester.IsPrime(factor);
// isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(factor);
if (isPrime)
{
@@ -1822,7 +1852,8 @@ internal static partial class PrimeOrderCalculator
// Atomic.Add(ref _partialFactorCofactorHits, 1UL);
// Console.WriteLine($"Partial factor cofactor hits {Volatile.Read(ref _partialFactorCofactorHits)}");
isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, quotient);
// isPrime = HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, quotient);
isPrime = PrimeTester.IsPrime(quotient);
// isPrime = PrimeTester.IsPrimeGpu(quotient);
// isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(quotient);
}
@@ -145,10 +145,11 @@ internal static partial class PrimeOrderCalculator
ArrayView1D<ulong, Stride1D.Dense> specialMaxResultView = gpu.SpecialMaxResult.View;
kernel.Launch(
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>();
kernelLauncher(
stream,
1,
1,
phi,
specialMaxFactorsView,
factorCount,
+5 -2
View File
@@ -207,6 +207,8 @@ public sealed class PrimeTester
int pos = 0;
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>>();
while (pos < totalLength)
{
int remaining = totalLength - pos;
@@ -215,7 +217,7 @@ public sealed class PrimeTester
var valueSlice = values.Slice(pos, count);
inputView.CopyFromCPU(stream, valueSlice);
kernel.Launch(
kernelLauncher(
stream,
count,
inputView,
@@ -285,8 +287,9 @@ public sealed class PrimeTester
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
inputBuffer.View.CopyFromCPU(stream, values);
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<byte>>>();
kernel.Launch(stream, length, inputBuffer.View, resultBuffer.View);
kernelLauncher(stream, length, inputBuffer.View, resultBuffer.View);
resultBuffer.View.CopyToCPU(stream, in results);
stream.Synchronize();