GpuPrimeWorkLimiter.Acquire() / .Release() removed to save time on the hot-path with billions of calls. We'll rely on AcceleratorStreamPool limits and synchronization.

This commit is contained in:
mlemanczyk committed 2025-11-13 17:52:13 +01:00
1 parent 1552e10ff0
commit 0d2a88c45f
17 files changed
+108 -124

No files matched your search

+15 -19
View File
@@ -41,8 +41,9 @@ public sealed class DivisorCycleCache
private DivisorCycleCache(int divisorCyclesBatchSize)
{
_divisorCyclesBatchSize = Math.Max(1, divisorCyclesBatchSize);
_accelerator = SharedGpuContext.Device.CreateAccelerator(SharedGpuContext.Context);
_gpuKernel = LoadKernel(_accelerator);
var accelerator = AcceleratorPool.Shared.Rent();
_accelerator = accelerator;
_gpuKernel = LoadKernel(accelerator);
_snapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot();
}
@@ -83,7 +84,6 @@ public sealed class DivisorCycleCache
throw new InvalidDataException($"Divisor cycle is missing for {divisor}");
}
// ObserveCycleCacheDivisor(divisor);
return cached;
}
@@ -118,7 +118,6 @@ public sealed class DivisorCycleCache
throw new InvalidDataException($"Divisor cycle is missing for {divisor}");
}
// ObserveCycleCacheDivisor(divisor);
cycles[i] = cached;
}
else
@@ -257,18 +256,15 @@ public sealed class DivisorCycleCache
powBuffer!.Dispose();
orderBuffer!.Dispose();
resultBuffer!.Dispose();
statusBuffer!.Dispose();
statusBuffer!.Dispose();
}
Accelerator accelerator = _accelerator;
// 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);
}
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)
@@ -312,8 +308,10 @@ public sealed class DivisorCycleCache
statusSpan[i] = ByteZero;
}
GpuPrimeWorkLimiter.Acquire();
var stream = AcceleratorStreamPool.Rent(_accelerator);// accelerator.CreateStream();
// GpuPrimeWorkLimiter.Acquire();
int pending;
var kernel = _gpuKernel;
var stream = AcceleratorStreamPool.Rent(_accelerator);
divisorBuffer!.View.CopyFromCPU(stream, divisors);
powBuffer!.View.CopyFromCPU(stream, powSpan);
@@ -321,8 +319,6 @@ public sealed class DivisorCycleCache
resultBuffer!.View.CopyFromCPU(stream, resultSpan);
statusBuffer!.View.CopyFromCPU(stream, statusSpan);
int pending;
var kernel = _gpuKernel;
do
{
kernel(stream, length, _divisorCyclesBatchSize, divisorBuffer.View, powBuffer.View, orderBuffer.View, resultBuffer.View, statusBuffer.View);
@@ -341,7 +337,7 @@ public sealed class DivisorCycleCache
}
while (pending > 0);
resultBuffer.View.CopyToCPU(stream,resultSpan);
resultBuffer.View.CopyToCPU(stream, resultSpan);
stream.Synchronize();
AcceleratorStreamPool.Return(stream);
@@ -354,7 +350,7 @@ public sealed class DivisorCycleCache
ThreadStaticPools.BytePool.Return(rentedStatus!, clearArray: false);
}
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
}
private static Action<AcceleratorStream, Index1D, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>> LoadKernel(Accelerator accelerator)
+2 -2
View File
@@ -280,13 +280,13 @@ public class GpuKernelPool
/// <param name="action">Action to run with (Accelerator, Stream).</param>
public static void Run(Action<Accelerator, AcceleratorStream> action)
{
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
var accelerator = SharedGpuContext.CreateAccelerator();
var stream = accelerator.CreateStream();
action(accelerator, stream);
stream.Synchronize();
stream.Dispose();
accelerator.Dispose();
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
}
}
@@ -103,7 +103,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
ulong processedCount;
ulong lastProcessed;
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter();
var accelerator = AcceleratorPool.Shared.Rent();
var stream = accelerator.CreateStream();
@@ -137,7 +137,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
stream.Dispose();
ReturnBatchResources(resources);
// Monitor.Exit(gpuLease.ExecutionLock);
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
if (composite)
{
@@ -509,7 +509,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
internal DivisorScanSession(MersenneNumberDivisorByDivisorGpuTester owner)
{
_owner = owner;
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
Accelerator accelerator = AcceleratorPool.Shared.Rent();
_accelerator = accelerator;
_stream = accelerator.CreateStream();
@@ -16,7 +16,7 @@ public class MersenneNumberIncrementalGpuTester(GpuKernelType kernelType, bool u
{
throw new NotImplementedException($"GPU incremental scanning requires the device cycle heuristics implementation (kernel: {_kernelType}, GPU order: {_useGpuOrder}).");
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
var accelerator = AcceleratorPool.Shared.Rent();
var stream = accelerator.CreateStream();
int batchSize = GpuConstants.ScanBatchSize; // large batch improves GPU occupancy
@@ -125,6 +125,6 @@ public class MersenneNumberIncrementalGpuTester(GpuKernelType kernelType, bool u
stream.Dispose();
ulongPool.Return(orderArray);
orderBuffer.Dispose();
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
}
}
@@ -159,7 +159,7 @@ public class MersenneNumberLucasLehmerGpuTester
}
else
{
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
var accelerator = AcceleratorPool.Shared.Rent();
var stream = accelerator.CreateStream();
var modulus = new GpuUInt128(((UInt128)1 << (int)exponent) - 1UL); // TODO: Cache these Mersenne moduli per exponent so LL GPU runs skip rebuilding them every launch.
@@ -173,7 +173,7 @@ public class MersenneNumberLucasLehmerGpuTester
stream.Dispose();
}
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
return result;
}
@@ -9,7 +9,7 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
public void Scan(ulong exponent, UInt128 twoP, LastDigit lastDigit, UInt128 maxK, ref bool isPrime)
{
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
// var accelerator = SharedGpuContext.Accelerator;
var accelerator = AcceleratorPool.Shared.Rent();
var stream = accelerator.CreateStream();
@@ -71,6 +71,6 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
stream.Dispose();
foundBuffer.Dispose();
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
}
}
@@ -25,7 +25,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
// GPU residue variant: check 2^p % q == 1 for q = 2*p*k + 1.
public void Scan(ulong exponent, UInt128 twoP, LastDigit lastDigit, UInt128 maxK, ref bool isPrime)
{
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
var accelerator = AcceleratorPool.Shared.Rent();
// Monitor.Enter(gpuLease.ExecutionLock);
@@ -110,7 +110,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
stream.Dispose();
// Monitor.Exit(gpuLease.ExecutionLock);
gpuKernels.Dispose();
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
}
private static Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<ulong>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> GetPow2ModKernel(Accelerator accelerator)
@@ -10,28 +10,29 @@ public static class Pow2MontgomeryGpuCalculator
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong CalculateKeep(ulong exponent, in MontgomeryDivisorData divisor)
{
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
ulong result = 0UL;
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
Accelerator? accelerator = gpu.Accelerator;
AcceleratorStream stream = AcceleratorStreamPool.Rent(accelerator);
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.OutputUlong;
var kernel = gpu.KeepMontgomeryKernel;
AcceleratorStream stream = AcceleratorStreamPool.Rent(accelerator);
exponentBuffer.View.CopyFromCPU(stream, ref exponent, 1);
// We don't need to worry about any left-overs here.
// resultBuffer.MemSetToZero(stream);
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.OutputUlong;
var kernel = gpu.KeepMontgomeryKernel;
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
kernelLauncher(stream, 1, exponentBuffer.View, divisor, resultBuffer.View);
ulong result = 0UL;
resultBuffer.View.CopyToCPU(stream, ref result, 1);
stream.Synchronize();
AcceleratorStreamPool.Return(stream);
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
PrimeOrderCalculatorAccelerator.Return(gpu);
return result;
@@ -40,50 +41,48 @@ public static class Pow2MontgomeryGpuCalculator
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong CalculateConvert(ulong exponent, in MontgomeryDivisorData divisor)
{
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
ulong result = 0UL;
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.OutputUlong;
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
exponentBuffer.View.CopyFromCPU(stream, ref exponent, 1);
// We don't need to worry about any left-overs here.
// resultBuffer.MemSetToZero(stream);
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.OutputUlong;
var kernel = gpu.ConvertToStandardKernel;
kernel.Launch(stream, 1, 1, exponentBuffer.View, divisor, resultBuffer.View);
ulong result = 0UL;
resultBuffer.View.CopyToCPU(stream, ref result, 1);
stream.Synchronize();
AcceleratorStreamPool.Return(stream);
GpuPrimeWorkLimiter.Release();
AcceleratorStreamPool.Return(stream);
// GpuPrimeWorkLimiter.Release();
PrimeOrderCalculatorAccelerator.Return(gpu);
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong CalculateConvert(PrimeOrderCalculatorAccelerator gpu, ulong exponent, in MontgomeryDivisorData divisor)
{
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
ulong result = 0UL;
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.OutputUlong;
var kernel = gpu.ConvertToStandardKernel;
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
exponentBuffer.View.CopyFromCPU(stream, ref exponent, 1);
// We don't need to worry about any left-overs here.
// resultBuffer.MemSetToZero(stream);
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.OutputUlong;
var kernel = gpu.ConvertToStandardKernel;
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
kernelLauncher(stream, 1,exponentBuffer.View, divisor, resultBuffer.View);
ulong result = 0UL;
resultBuffer.View.CopyToCPU(stream, ref result, 1);
stream.Synchronize();
AcceleratorStreamPool.Return(stream);
return result;
@@ -225,7 +225,7 @@ internal static partial class PrimeOrderGpuHeuristics
try
{
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
Accelerator accelerator = AcceleratorPool.Shared.Rent();
AcceleratorStream stream = accelerator.CreateStream();
@@ -290,7 +290,7 @@ internal static partial class PrimeOrderGpuHeuristics
countBuffer.Dispose();
remainingBuffer.Dispose();
fullyFactoredBuffer.Dispose();
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
return true;
}
catch (CLException ex)
@@ -402,7 +402,7 @@ internal static partial class PrimeOrderGpuHeuristics
{
order = 0UL;
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
Accelerator accelerator = AcceleratorPool.Shared.Rent();
AcceleratorStream stream = accelerator.CreateStream();
@@ -494,7 +494,7 @@ internal static partial class PrimeOrderGpuHeuristics
stackProductBuffer.Dispose();
resultBuffer.Dispose();
statusBuffer.Dispose();
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
PrimeOrderKernelStatus kernelStatus = (PrimeOrderKernelStatus)status;
if (kernelStatus == PrimeOrderKernelStatus.Fallback)
@@ -574,7 +574,7 @@ internal static partial class PrimeOrderGpuHeuristics
private static bool TryComputeOnGpu(ReadOnlySpan<ulong> exponents, ulong prime, in MontgomeryDivisorData divisorData, Span<ulong> results)
{
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
Accelerator accelerator = AcceleratorPool.Shared.Rent();
AcceleratorStream? stream = accelerator.CreateStream();
// TODO: These buffers should be allocated once per accelerator and only reallocated when the new length exceeds capacity.
@@ -604,7 +604,7 @@ internal static partial class PrimeOrderGpuHeuristics
stream = null;
exponentBuffer.Dispose();
remainderBuffer.Dispose();
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
}
catch (Exception)
{
@@ -612,7 +612,7 @@ internal static partial class PrimeOrderGpuHeuristics
stream?.Dispose();
exponentBuffer.Dispose();
remainderBuffer.Dispose();
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
throw;
}
@@ -638,7 +638,7 @@ internal static partial class PrimeOrderGpuHeuristics
GpuUInt128[]? rentedExponents = null;
GpuUInt128[]? rentedResults = null;
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
ArrayPool<GpuUInt128> gpuUInt128Pool = ThreadStaticPools.GpuUInt128Pool;
try
@@ -704,7 +704,7 @@ internal static partial class PrimeOrderGpuHeuristics
gpuUInt128Pool.Return(rentedResults!, clearArray: false);
}
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
}
}
@@ -224,11 +224,11 @@ public sealed class HeuristicCombinedPrimeTester
private static bool HeuristicTrialDivisionGpuDetectsDivisor(ulong n, ulong maxDivisorSquare, byte nMod10)
{
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
var gpu = HeuristicPrimeTesterAccelerator.Rent(1);
var accelerator = gpu.Accelerator;
var stream = gpu.Stream;
var kernel = HeuristicPrimeTesterAccelerator.GetHeuristicTrialDivisionKernel(accelerator);
var kernel = HeuristicPrimeTesterAccelerator.HeuristicTrialDivisionKernel;
var flagView1D = gpu.HeuristicFlag.View;
var flagView = flagView1D.AsContiguous();
@@ -251,7 +251,7 @@ public sealed class HeuristicCombinedPrimeTester
flagView1D.CopyToCPU(stream, ref compositeFlag, 1);
stream.Synchronize();
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
compositeDetected = compositeFlag != 0;
HeuristicPrimeTesterAccelerator.Return(gpu);
+2 -2
View File
@@ -241,7 +241,7 @@ public sealed class HeuristicPrimeTester
private bool HeuristicTrialDivisionGpuDetectsDivisor(ulong n, ulong maxDivisorSquare, byte nMod10)
{
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
var gpu = HeuristicPrimeTesterAccelerator.Rent(1);
var accelerator = gpu.Accelerator;
var stream = gpu.Stream;
@@ -307,7 +307,7 @@ public sealed class HeuristicPrimeTester
}
gpu.Dispose();
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
return compositeDetected;
}
+2 -2
View File
@@ -804,7 +804,7 @@ public class MersenneDivisorCycles
divisors = pool.Rent(count);
outCycles = pool.Rent(count);
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
var accelerator = AcceleratorPool.Shared.Rent();
var stream = accelerator.CreateStream();
@@ -897,7 +897,7 @@ public class MersenneDivisorCycles
pool.Return(divisors, clearArray: false);
pool.Return(outCycles, clearArray: false);
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
}
private static Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> GetDivisorCycleKernel(Accelerator accelerator)
+4 -7
View File
@@ -147,7 +147,7 @@ public sealed class MersenneNumberTester(
UInt128[] qs = qsBuffer;
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
var accelerator = AcceleratorPool.Shared.Rent();
var stream = accelerator.CreateStream();
var orderKernel = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.OrderKernelScan).Order!;
@@ -164,11 +164,8 @@ public sealed class MersenneNumberTester(
while (offset < idx)
{
int count = Math.Min(batchSize, idx - offset);
// lock (accelerator)
{
qBuffer = accelerator.Allocate1D<GpuUInt128>(count);
orderBuffer = accelerator.Allocate1D<ulong>(count);
}
qBuffer = accelerator.Allocate1D<GpuUInt128>(count);
orderBuffer = accelerator.Allocate1D<ulong>(count);
// Convert to device-friendly GpuUInt128 on the fly
var tmp = gpuUInt128Pool.Rent(count);
@@ -204,7 +201,7 @@ public sealed class MersenneNumberTester(
}
stream.Dispose();
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
uInt128Pool.Return(qs);
}
+12 -17
View File
@@ -91,30 +91,30 @@ internal static partial class PrimeOrderCalculator
return phi;
}
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
ulong candidateOrder = InitializeStartingOrderCpu(gpu, prime, phi, divisorData);
candidateOrder = ExponentLoweringCpu(candidateOrder, prime, phiFactors, divisorData);
if (TryConfirmOrderCpu(gpu, prime, candidateOrder, divisorData, config, out PartialFactorResult? orderFactors))
{
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
return candidateOrder;
}
if (config.Mode == PrimeOrderMode.Strict)
{
orderFactors?.Dispose();
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
return CalculateByFactorizationGpu(gpu, prime, divisorData);
}
if (TryHeuristicFinishCpu(gpu, prime, candidateOrder, previousOrder, divisorData, config, phiFactors, orderFactors, out ulong order))
{
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
return order;
}
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
return candidateOrder;
}
@@ -1148,7 +1148,7 @@ internal static partial class PrimeOrderCalculator
bool pollardRhoDeadlineReached = Stopwatch.GetTimestamp() > deadlineTimestamp;
if (!pollardRhoDeadlineReached)
{
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
while (compositeStack.Count > 0)
{
@@ -1200,7 +1200,7 @@ internal static partial class PrimeOrderCalculator
pollardRhoDeadlineReached = Stopwatch.GetTimestamp() > deadlineTimestamp;
}
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
}
if (pollardRhoDeadlineReached)
@@ -1216,7 +1216,7 @@ internal static partial class PrimeOrderCalculator
bool cofactorContainsComposite = false;
int pendingCount = pending.Count;
int index = 0;
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
for (; index < pendingCount; index++)
{
PendingEntry entry = pending[index];
@@ -1280,7 +1280,7 @@ internal static partial class PrimeOrderCalculator
// cofactorIsPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(cofactor);
}
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
// ArrayPool<FactorEntry> pool = ThreadStaticPools.FactorEntryPool;
bool temp;
@@ -1331,19 +1331,14 @@ internal static partial class PrimeOrderCalculator
// continue;
// }
// factorsArray[arrayIndex] = new FactorEntry(primeValue, exponentValue, true);
factorsArray[arrayIndex] = primeValue;
exponentsArray[arrayIndex] = exponentValue;
// cofactorIsPrimesArray[arrayIndex] = true;
arrayIndex++;
}
// Span<FactorEntry> arraySpan = factorsArray.AsSpan(0, arrayIndex);
// Span<ulong> arraySpan = factorsArray.AsSpan(0, arrayIndex);
// arraySpan.Sort(static (a, b) => a.CompareTo(b));
Array.Sort(factorsArray, exponentsArray, 0, arrayIndex);
temp = cofactor == 1UL;
// result = PartialFactorResult.Rent(factorsArray, exponentsArray, cofactorIsPrimesArray, cofactor, temp, arrayIndex, cofactorIsPrime);
result = PartialFactorResult.Rent(factorsArray, exponentsArray, cofactor, temp, arrayIndex, cofactorIsPrime);
ReturnResult:
@@ -1716,7 +1711,7 @@ internal static partial class PrimeOrderCalculator
ulong order = phi;
int entryCount = entries.Length;
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
for (int i = 0; i < entryCount; i++)
{
ulong primeFactor = entries[i].Key;
@@ -1744,7 +1739,7 @@ internal static partial class PrimeOrderCalculator
}
}
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
return order;
}
@@ -39,7 +39,7 @@ internal static partial class PrimeOrderCalculator
var kernel = gpu.CheckFactorsKernel;
gpu.EnsureCapacity(entryCount, 1);
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
gpu.Pow2ModEntriesToTestOnDevice.View.CopyFromCPU(stream, entries);
@@ -51,7 +51,7 @@ internal static partial class PrimeOrderCalculator
stream.Synchronize();
AcceleratorStreamPool.Return(stream);
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
return order;
}
@@ -66,7 +66,7 @@ internal static partial class PrimeOrderCalculator
gpu.EnsureSmallPrimeFactorSlotsCapacity(GpuSmallPrimeFactorSlots);
var accelerator = gpu.Accelerator;
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
var stream = AcceleratorStreamPool.Rent(accelerator);
KernelContainer kernels = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.SmallPrimeFactorKernelScan);
SmallPrimeFactorViews tables = GpuKernelPool.GetSmallPrimeFactorTables(kernels);
@@ -113,7 +113,7 @@ internal static partial class PrimeOrderCalculator
stream.Synchronize();
AcceleratorStreamPool.Return(stream);
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
for (int i = 0; i < factorCount; i++)
{
@@ -136,7 +136,7 @@ internal static partial class PrimeOrderCalculator
gpu.EnsureSpecialMaxFactorsCapacity(factorCount);
Accelerator accelerator = gpu.Accelerator;
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
var stream = AcceleratorStreamPool.Rent(accelerator);
var kernels = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.EvaluateSpecialMaxCandidatesKernel);
@@ -162,7 +162,7 @@ internal static partial class PrimeOrderCalculator
stream.Synchronize();
AcceleratorStreamPool.Return(stream);
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
return result != 0;
}
@@ -171,11 +171,12 @@ internal static partial class PrimeOrderCalculator
Span<ulong> randomStateSpan = stackalloc ulong[1];
randomStateSpan[0] = ThreadStaticDeterministicRandomGpu.Exclusive.State;
Span<byte> factoredSpan = stackalloc byte[1];
Span<ulong> factorSpan = stackalloc ulong[1];
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
gpu.Input.View.CopyFromCPU(stream, randomStateSpan);
Span<byte> factoredSpan = stackalloc byte[1];
Span<ulong> factorSpan = stackalloc ulong[1];
var kernelLauncher = gpu.PollardRhoKernel.CreateLauncherDelegate<Action<AcceleratorStream, ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>();
kernelLauncher(stream, n, 1, gpu.Input.View, gpu.OutputByte.View, gpu.OutputUlong.View);
+18 -22
View File
@@ -1,7 +1,6 @@
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using ILGPU;
using ILGPU.Runtime;
using PerfectNumbers.Core.Gpu;
@@ -93,15 +92,15 @@ public sealed class PrimeTester
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsPrimeGpu(ulong n)
{
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
byte flag = 0;
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
var inputView = gpu.PrimeTestInput.View;
var outputView = gpu.OutputByte.View;
var kernel = gpu.SmallPrimeSieveKernel!;
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
// var stream = gpu.Stream!;
inputView.CopyFromCPU(stream, ref n, 1);
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>>>();
@@ -120,13 +119,12 @@ public sealed class PrimeTester
gpu.DevicePrimesPow2LastNine.View,
outputView);
byte flag = 0;
outputView.CopyToCPU(stream, ref flag, 1);
stream.Synchronize();
AcceleratorStreamPool.Return(stream);
PrimeOrderCalculatorAccelerator.Return(gpu);
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
return flag != 0;
}
@@ -134,6 +132,7 @@ public sealed class PrimeTester
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsPrimeGpu(PrimeOrderCalculatorAccelerator gpu, ulong n)
{
byte flag = 0;
var input = gpu.PrimeTestInput;
var inputView = input.View;
var output = gpu.OutputByte;
@@ -159,7 +158,6 @@ public sealed class PrimeTester
gpu.DevicePrimesPow2LastNine.View,
outputView);
byte flag = 0;
outputView.CopyToCPU(stream, ref flag, 1);
stream.Synchronize();
AcceleratorStreamPool.Return(stream);
@@ -195,7 +193,7 @@ public sealed class PrimeTester
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsPrimeBatchGpu(ReadOnlySpan<ulong> values, Span<byte> results)
{
GpuPrimeWorkLimiter.Acquire();
// GpuPrimeWorkLimiter.Acquire();
var gpu = PrimeOrderCalculatorAccelerator.Rent(GpuBatchSize);
var accelerator = gpu.Accelerator;
var kernel = gpu.SmallPrimeSieveKernel!;
@@ -240,7 +238,7 @@ public sealed class PrimeTester
stream.Synchronize();
AcceleratorStreamPool.Return(stream);
PrimeOrderCalculatorAccelerator.Return(gpu);
GpuPrimeWorkLimiter.Release();
// GpuPrimeWorkLimiter.Release();
}
// Expose cache clearing for accelerator disposal coordination
@@ -276,31 +274,27 @@ public sealed class PrimeTester
// TODO: Route this batch helper through the shared GPU kernel pool from
// GpuUInt128BinaryGcdBenchmarks so we reuse cached kernels, pinned host buffers,
// and divisor-cycle staging instead of allocating new device buffers per call.
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
var accelerator = gpu.Accelerator;
// Check in benchmarks, which implementation was the fastest, is compatible with GPU,
// and implement it.
int length = values.Length;
ArrayPool<ulong> pool = ThreadStaticPools.UlongPool;
ulong[] temp = pool.Rent(length);
values.CopyTo(temp);
MemoryBuffer1D<ulong, Stride1D.Dense>? inputBuffer;
MemoryBuffer1D<byte, Stride1D.Dense>? resultBuffer;
inputBuffer = accelerator.Allocate1D<ulong>(length);
resultBuffer = accelerator.Allocate1D<byte>(length);
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
var accelerator = gpu.Accelerator;
gpu.EnsureCapacity(0, length);
MemoryBuffer1D<ulong, Stride1D.Dense>? inputBuffer = gpu.PrimeTestInput;
MemoryBuffer1D<byte, Stride1D.Dense>? resultBuffer = gpu.OutputByte;
AcceleratorStream stream = AcceleratorStreamPool.Rent(accelerator);
inputBuffer.View.CopyFromCPU(stream, ref temp[0], length);
inputBuffer.View.CopyFromCPU(stream, values);
var kernel = GetSharesFactorKernel(accelerator);
kernel(stream, length, inputBuffer.View, resultBuffer.View);
resultBuffer.View.CopyToCPU(stream, in results);
stream.Synchronize();
AcceleratorStreamPool.Return(stream);
pool.Return(temp, clearArray: false);
resultBuffer.Dispose();
inputBuffer.Dispose();
PrimeOrderCalculatorAccelerator.Return(gpu);
}
@@ -323,6 +317,8 @@ public sealed class PrimeTester
// TODO: Swap this handwritten binary GCD for the optimized helper measured in
// GpuUInt128BinaryGcdBenchmarks so CPU callers share the faster subtract-less
// ladder once the common implementation is promoted into PerfectNumbers.Core.
// You have an example in the benchmarks and you already implemented it in
// GpuUInt128, iirc.
if (u == 0UL)
{
return v;