Performance improvements

This commit is contained in:
mlemanczyk committed 2025-11-13 00:51:32 +01:00
1 parent 5bc65464d0
commit 43863d03fb
11 files changed
+127 -86

No files matched your search

+13 -14
View File
@@ -7,6 +7,7 @@ using ILGPU;
using ILGPU.Algorithms; using ILGPU.Algorithms;
using ILGPU.Runtime; using ILGPU.Runtime;
using PerfectNumbers.Core.Gpu; using PerfectNumbers.Core.Gpu;
using PerfectNumbers.Core.Gpu.Accelerators;
namespace PerfectNumbers.Core; namespace PerfectNumbers.Core;
@@ -273,11 +274,7 @@ public sealed class DivisorCycleCache
private void ComputeCyclesGpuCore(ReadOnlySpan<ulong> divisors, Span<ulong> destination) private void ComputeCyclesGpuCore(ReadOnlySpan<ulong> divisors, Span<ulong> destination)
{ {
int length = divisors.Length; int length = divisors.Length;
GpuPrimeWorkLimiter.Acquire();
Accelerator accelerator = _accelerator;
var stream = accelerator.CreateStream();
var kernel = _gpuKernel;
EnsureCapacity(length); EnsureCapacity(length);
ulong[]? rentedPow = null; ulong[]? rentedPow = null;
@@ -300,9 +297,6 @@ public sealed class DivisorCycleCache
? stackalloc byte[length] ? stackalloc byte[length]
: new Span<byte>(rentedStatus = ThreadStaticPools.BytePool.Rent(length), 0, length); : new Span<byte>(rentedStatus = ThreadStaticPools.BytePool.Rent(length), 0, length);
ref ulong divisorRef = ref MemoryMarshal.GetReference(divisors);
divisorBuffer!.View.CopyFromCPU(stream, ref divisorRef, length);
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
{ {
ulong divisor = divisors[i]; ulong divisor = divisors[i];
@@ -318,17 +312,22 @@ public sealed class DivisorCycleCache
statusSpan[i] = ByteZero; statusSpan[i] = ByteZero;
} }
powBuffer!.View.CopyFromCPU(stream, ref MemoryMarshal.GetReference(powSpan), length); GpuPrimeWorkLimiter.Acquire();
orderBuffer!.View.CopyFromCPU(stream, ref MemoryMarshal.GetReference(orderSpan), length); var stream = AcceleratorStreamPool.Rent(_accelerator);// accelerator.CreateStream();
resultBuffer!.View.CopyFromCPU(stream, ref MemoryMarshal.GetReference(resultSpan), length);
statusBuffer!.View.CopyFromCPU(stream, ref MemoryMarshal.GetReference(statusSpan), length); divisorBuffer!.View.CopyFromCPU(stream, divisors);
powBuffer!.View.CopyFromCPU(stream, powSpan);
orderBuffer!.View.CopyFromCPU(stream, orderSpan);
resultBuffer!.View.CopyFromCPU(stream, resultSpan);
statusBuffer!.View.CopyFromCPU(stream, statusSpan);
int pending; int pending;
var kernel = _gpuKernel;
do do
{ {
kernel(stream, length, _divisorCyclesBatchSize, divisorBuffer.View, powBuffer.View, orderBuffer.View, resultBuffer.View, statusBuffer.View); kernel(stream, length, _divisorCyclesBatchSize, divisorBuffer.View, powBuffer.View, orderBuffer.View, resultBuffer.View, statusBuffer.View);
statusBuffer.View.CopyToCPU(stream, ref MemoryMarshal.GetReference(statusSpan), length); statusBuffer.View.CopyToCPU(stream, statusSpan);
stream.Synchronize(); stream.Synchronize();
pending = 0; pending = 0;
@@ -342,9 +341,9 @@ public sealed class DivisorCycleCache
} }
while (pending > 0); while (pending > 0);
resultBuffer.View.CopyToCPU(stream, ref MemoryMarshal.GetReference(resultSpan), length); resultBuffer.View.CopyToCPU(stream,resultSpan);
stream.Synchronize(); stream.Synchronize();
stream.Dispose(); AcceleratorStreamPool.Return(stream);
resultSpan.CopyTo(destination); resultSpan.CopyTo(destination);
if (rentedPow is not null) if (rentedPow is not null)
@@ -1,24 +1,26 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using ILGPU.Runtime; using ILGPU.Runtime;
using Open.Collections;
namespace PerfectNumbers.Core.Gpu.Accelerators; namespace PerfectNumbers.Core.Gpu.Accelerators;
public static class AcceleratorStreamPool public static class AcceleratorStreamPool
{ {
private static readonly ConcurrentDictionary<Accelerator, ConcurrentQueue<AcceleratorStream>> _streams = new(20_480, PerfectNumberConstants.RollingAccelerators); private static readonly Dictionary<Accelerator, ConcurrentQueue<AcceleratorStream>> _streams = new(PerfectNumberConstants .RollingAccelerators);
// private static readonly ConcurrentDictionary<Accelerator, AcceleratorStream> _streams = new(AcceleratorPool.Shared.Accelerators.ToDictionary(static x => x, CreateStream)); // private static readonly ConcurrentDictionary<Accelerator, AcceleratorStream> _streams = new(AcceleratorPool.Shared.Accelerators.ToDictionary(static x => x, CreateStream));
private static SemaphoreSlim CreateLock() => new(PerfectNumberConstants.ThreadsByStream); private static SemaphoreSlim CreateLock() => new(PerfectNumberConstants.ThreadsByStream);
private static AcceleratorStream CreateStream(Accelerator accelerator) => accelerator.CreateStream(); private static AcceleratorStream CreateStream(Accelerator accelerator) => accelerator.CreateStream();
private static readonly ConcurrentDictionary<Accelerator, SemaphoreSlim> _locks = new(AcceleratorPool.Shared.Accelerators.ToDictionary(x => x, static x => CreateLock())); private static readonly Dictionary<Accelerator, SemaphoreSlim> _locks = new(AcceleratorPool.Shared.Accelerators.ToDictionary(x => x, static x => CreateLock()));
public static AcceleratorStream Rent(Accelerator accelerator) public static AcceleratorStream Rent(Accelerator accelerator)
{ {
var streamLock = _locks.GetOrAdd(accelerator, static _ => new SemaphoreSlim(PerfectNumberConstants.ThreadsByStream)); var streamLock = _locks[accelerator];
// var streamLock = _locks.GetOrAdd(accelerator, static _ => CreateLock());
streamLock.Wait(); streamLock.Wait();
var queue = _streams.GetOrAdd(accelerator, static _ => new()); var queue = _streams[accelerator];
return queue.TryDequeue(out var stream) return queue.TryDequeue(out var stream)
? stream ? stream
@@ -28,9 +30,23 @@ public static class AcceleratorStreamPool
public static void Return(AcceleratorStream stream) public static void Return(AcceleratorStream stream)
{ {
Accelerator accelerator = stream.Accelerator; Accelerator accelerator = stream.Accelerator;
var streamLock = _locks.GetOrAdd(accelerator, static _ => CreateLock()); var streamLock = _locks[accelerator];
var queue = _streams.GetOrAdd(accelerator, static _ => new()); var queue = _streams[accelerator];
queue.Enqueue(stream); queue.Enqueue(stream);
streamLock.Release(); streamLock.Release();
} }
public static void WarmUp(Accelerator accelerator)
{
_streams.Add(accelerator, new());
_ = _locks.TryAdd(accelerator, CreateLock());
// ConcurrentQueue<AcceleratorStream> streamQueue = new();
// var stream = accelerator.CreateStream();
// // var stream = accelerator.CreateStream();
// streamQueue.Enqueue(stream);
// _streams[accelerator] = streamQueue;
// _locks[accelerator] = CreateLock();
// stream.Synchronize();
}
} }
@@ -72,6 +72,8 @@ public sealed class Pow2MontgomeryAccelerator
{ {
Console.WriteLine($"Preparing accelerator {i}..."); Console.WriteLine($"Preparing accelerator {i}...");
var accelerator = accelerators[i]; var accelerator = accelerators[i];
AcceleratorStreamPool.WarmUp(accelerator);
// AcceleratorStream stream = AcceleratorStreamPool.Rent(accelerator);
AcceleratorStream stream = accelerator.CreateStream(); AcceleratorStream stream = accelerator.CreateStream();
LastDigitGpuTables.EnsureStaticTables(accelerator, stream); LastDigitGpuTables.EnsureStaticTables(accelerator, stream);
// SharedHeuristicGpuTables.EnsureStaticTables(accelerator, stream); // SharedHeuristicGpuTables.EnsureStaticTables(accelerator, stream);
@@ -80,6 +82,8 @@ public sealed class Pow2MontgomeryAccelerator
// GpuStaticTableInitializer.EnsureStaticTables(accelerator, kernels, stream); // GpuStaticTableInitializer.EnsureStaticTables(accelerator, kernels, stream);
stream.Synchronize(); stream.Synchronize();
stream.Dispose(); stream.Dispose();
// AcceleratorStreamPool.Return(stream);
} }
} }
+2 -7
View File
@@ -142,14 +142,9 @@ public class GpuKernelPool
static void InitSmallPrimeFactorKernelScan(Accelerator accelerator, KernelContainer kernels) static void InitSmallPrimeFactorKernelScan(Accelerator accelerator, KernelContainer kernels)
{ {
InitOnce(ref kernels.SmallPrimeFactor, () => var loaded = 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);
{
var loaded = 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);
var kernel = KernelUtil.GetKernel(loaded); kernels.SmallPrimeFactor = KernelUtil.GetKernel(loaded);
return kernel.CreateLauncherDelegate<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>>>();
});
} }
} }
+42 -16
View File
@@ -1,23 +1,20 @@
using System.Collections.Concurrent;
using ILGPU; using ILGPU;
using ILGPU.Runtime; using ILGPU.Runtime;
namespace PerfectNumbers.Core.Gpu; namespace PerfectNumbers.Core.Gpu;
public sealed class ScratchBuffer public sealed class GpuScratchBuffer
{ {
public MemoryBuffer1D<ulong, Stride1D.Dense> SmallPrimeFactorPrimeSlots { get; private set; }
public MemoryBuffer1D<int, Stride1D.Dense> SmallPrimeFactorExponentSlots { get; private set; }
public MemoryBuffer1D<int, Stride1D.Dense> SmallPrimeFactorCountSlot { get; private set; }
public MemoryBuffer1D<ulong, Stride1D.Dense> SmallPrimeFactorRemainingSlot { get; private set; }
public MemoryBuffer1D<ulong, Stride1D.Dense> SpecialMaxFactors { get; private set; }
public MemoryBuffer1D<ulong, Stride1D.Dense> SpecialMaxCandidates { get; private set; }
public MemoryBuffer1D<ulong, Stride1D.Dense> SpecialMaxResult { get; private set; }
internal readonly Accelerator _accelerator; internal readonly Accelerator _accelerator;
public readonly MemoryBuffer1D<int, Stride1D.Dense> SmallPrimeFactorCountSlot;
public MemoryBuffer1D<int, Stride1D.Dense> SmallPrimeFactorExponentSlots;
public MemoryBuffer1D<ulong, Stride1D.Dense> SmallPrimeFactorPrimeSlots;
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> SmallPrimeFactorRemainingSlot;
public MemoryBuffer1D<ulong, Stride1D.Dense> SpecialMaxCandidates;
public MemoryBuffer1D<ulong, Stride1D.Dense> SpecialMaxFactors;
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> SpecialMaxResult;
public ScratchBuffer(Accelerator accelerator, int smallPrimeFactorSlotCount, int specialMaxFactorCapacity) public GpuScratchBuffer(Accelerator accelerator, int smallPrimeFactorSlotCount, int specialMaxFactorCapacity)
{ {
_accelerator = accelerator; _accelerator = accelerator;
@@ -63,18 +60,29 @@ public sealed class ScratchBuffer
} }
} }
} }
internal void Dispose()
{
SmallPrimeFactorPrimeSlots.Dispose();
SmallPrimeFactorExponentSlots.Dispose();
SmallPrimeFactorCountSlot.Dispose();
SmallPrimeFactorRemainingSlot.Dispose();
SpecialMaxFactors.Dispose();
SpecialMaxCandidates.Dispose();
SpecialMaxResult.Dispose();
}
} }
public static class GpuScratchBufferPool public static class GpuScratchBufferPool
{ {
[ThreadStatic] [ThreadStatic]
private static Dictionary<Accelerator, Queue<ScratchBuffer>>? _pools; private static Dictionary<Accelerator, Queue<GpuScratchBuffer>>? _pools;
// private static readonly ConcurrentDictionary<Accelerator, ConcurrentQueue<ScratchBuffer>> _pools = new(); // private static readonly ConcurrentDictionary<Accelerator, ConcurrentQueue<ScratchBuffer>> _pools = new();
private const int DefaultSmallPrimeFactorSlotCount = 64; // From PrimeOrderCalculator.Gpu.cs private const int DefaultSmallPrimeFactorSlotCount = 64; // From PrimeOrderCalculator.Gpu.cs
private const int DefaultSpecialMaxFactorCapacity = 1024; // A reasonable default, will be resized if needed private const int DefaultSpecialMaxFactorCapacity = 1024; // A reasonable default, will be resized if needed
public static ScratchBuffer Rent(Accelerator accelerator, int smallPrimeFactorSlotCount, int specialMaxFactorCapacity) public static GpuScratchBuffer Rent(Accelerator accelerator, int smallPrimeFactorSlotCount, int specialMaxFactorCapacity)
{ {
const int WarmUpCapacity = 100; const int WarmUpCapacity = 100;
// var pool = _pools.GetOrAdd(accelerator, _ => new ConcurrentQueue<ScratchBuffer>()); // var pool = _pools.GetOrAdd(accelerator, _ => new ConcurrentQueue<ScratchBuffer>());
@@ -107,10 +115,10 @@ public static class GpuScratchBufferPool
return buffer; return buffer;
} }
return new ScratchBuffer(accelerator, smallPrimeFactorSlotCount, specialMaxFactorCapacity); return new GpuScratchBuffer(accelerator, smallPrimeFactorSlotCount, specialMaxFactorCapacity);
} }
public static void Return(ScratchBuffer buffer) public static void Return(GpuScratchBuffer buffer)
{ {
if (_pools!.TryGetValue(buffer._accelerator, out var pool)) if (_pools!.TryGetValue(buffer._accelerator, out var pool))
{ {
@@ -128,4 +136,22 @@ public static class GpuScratchBufferPool
// Return(buffer); // Return(buffer);
// } // }
} }
public static void DisposeAll()
{
var pool = _pools;
if (pool is not null)
{
foreach (var queue in pool.Values)
{
while (queue.TryDequeue(out var buffer))
{
buffer.Dispose();
}
}
pool.Clear();
_pools = null;
}
}
} }
+1 -1
View File
@@ -22,7 +22,7 @@ public sealed class KernelContainer
public Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, public Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong,
ResidueAutomatonArgs, ArrayView<int>, ArrayView1D<ulong, Stride1D.Dense>>? Pow2ModOrder; ResidueAutomatonArgs, ArrayView<int>, ArrayView1D<ulong, Stride1D.Dense>>? Pow2ModOrder;
public 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>>? SmallPrimeFactor; public Kernel? SmallPrimeFactor;
public Action<AcceleratorStream, Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>? SpecialMax; public Action<AcceleratorStream, Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>? SpecialMax;
@@ -27,6 +27,7 @@ public static class Pow2MontgomeryGpuCalculator
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>(); var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
kernelLauncher(stream, 1, exponentBuffer.View, divisor, resultBuffer.View); kernelLauncher(stream, 1, exponentBuffer.View, divisor, resultBuffer.View);
// kernel.Launch(stream, 1, 1, exponentBuffer.View, divisor, resultBuffer.View);
ulong result = 0UL; ulong result = 0UL;
resultBuffer.View.CopyToCPU(stream, ref result, 1); resultBuffer.View.CopyToCPU(stream, ref result, 1);
@@ -83,6 +84,7 @@ public static class Pow2MontgomeryGpuCalculator
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>(); var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
kernelLauncher(stream, 1,exponentBuffer.View, divisor, resultBuffer.View); kernelLauncher(stream, 1,exponentBuffer.View, divisor, resultBuffer.View);
// kernel.Launch(stream, 1, 1,exponentBuffer.View, divisor, resultBuffer.View);
ulong result = 0UL; ulong result = 0UL;
resultBuffer.View.CopyToCPU(stream, ref result, 1); resultBuffer.View.CopyToCPU(stream, ref result, 1);
@@ -4,6 +4,7 @@ using System.Threading.Tasks;
using System.Globalization; using System.Globalization;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using PerfectNumbers.Core.Gpu.Accelerators; using PerfectNumbers.Core.Gpu.Accelerators;
using PerfectNumbers.Core.Gpu;
namespace PerfectNumbers.Core; namespace PerfectNumbers.Core;
@@ -304,6 +305,7 @@ public static class MersenneNumberDivisorByDivisorTester
Console.WriteLine($"Task finished for range {rangeStart}"); Console.WriteLine($"Task finished for range {rangeStart}");
Pow2MontgomeryAccelerator.DisposeAll(); Pow2MontgomeryAccelerator.DisposeAll();
GpuScratchBufferPool.DisposeAll();
}, },
CancellationToken.None, CancellationToken.None,
TaskCreationOptions.DenyChildAttach, TaskCreationOptions.DenyChildAttach,
@@ -86,7 +86,7 @@ internal static partial class PrimeOrderCalculator
ulong phi, ulong phi,
PartialFactorResult phiFactors) PartialFactorResult phiFactors)
{ {
if (phiFactors.FullyFactored && TrySpecialMaxCpu(phi, prime, phiFactors, divisorData)) if (phiFactors.FullyFactored && TrySpecialMaxCpu(gpu, phi, prime, phiFactors, divisorData))
{ {
return phi; return phi;
} }
@@ -119,7 +119,7 @@ internal static partial class PrimeOrderCalculator
} }
// private static ulong specialMaxHits; // private static ulong specialMaxHits;
private static bool TrySpecialMaxCpu(ulong phi, ulong prime, PartialFactorResult factors, in MontgomeryDivisorData divisorData) private static bool TrySpecialMaxCpu(Pow2MontgomeryAccelerator gpu, ulong phi, ulong prime, PartialFactorResult factors, in MontgomeryDivisorData divisorData)
{ {
int length = factors.Count; int length = factors.Count;
// The phi factorization on the scanner path always yields at least one entry for phi >= 2, // The phi factorization on the scanner path always yields at least one entry for phi >= 2,
@@ -140,7 +140,7 @@ internal static partial class PrimeOrderCalculator
// Atomic.Add(ref specialMaxHits, 1); // Atomic.Add(ref specialMaxHits, 1);
// Console.WriteLine($"Special max GPU hit {specialMaxHits} ({length})"); // Console.WriteLine($"Special max GPU hit {specialMaxHits} ({length})");
return EvaluateSpecialMaxCandidatesGpu(stackBuffer, factorSpan, phi, prime, divisorData); return EvaluateSpecialMaxCandidatesGpu(gpu, stackBuffer, factorSpan, phi, prime, divisorData);
} }
private static bool EvaluateSpecialMaxCandidates(Span<ulong> buffer, ReadOnlySpan<FactorEntry> factors, ulong phi, ulong prime, in MontgomeryDivisorData divisorData) private static bool EvaluateSpecialMaxCandidates(Span<ulong> buffer, ReadOnlySpan<FactorEntry> factors, ulong phi, ulong prime, in MontgomeryDivisorData divisorData)
+27 -28
View File
@@ -39,18 +39,18 @@ internal static partial class PrimeOrderCalculator
entries.Sort(entries, static (a, b) => a.Key.CompareTo(b.Key)); entries.Sort(entries, static (a, b) => a.Key.CompareTo(b.Key));
// AcceleratorStream stream = gpu.Stream!; ulong order = phi;
var kernel = gpu.CheckFactorsKernel;
gpu.EnsureCapacity(entryCount, 1); gpu.EnsureCapacity(entryCount, 1);
GpuPrimeWorkLimiter.Acquire(); GpuPrimeWorkLimiter.Acquire();
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator); AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
gpu.Pow2ModEntriesToTestOnDevice.View.CopyFromCPU(stream, entries); gpu.Pow2ModEntriesToTestOnDevice.View.CopyFromCPU(stream, entries);
ulong order = phi; var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
var kernel = gpu.CheckFactorsKernel;
stream.Synchronize(); kernelLauncher(stream, entryCount, phi, gpu.Pow2ModEntriesToTestOnDevice.View, divisorData, gpu.OutputUlong.View);
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();
AcceleratorStreamPool.Return(stream); AcceleratorStreamPool.Return(stream);
@@ -67,19 +67,16 @@ internal static partial class PrimeOrderCalculator
Span<int> exponentBuffer = exponentBufferArray.AsSpan(0, GpuSmallPrimeFactorSlots); Span<int> exponentBuffer = exponentBufferArray.AsSpan(0, GpuSmallPrimeFactorSlots);
remaining = value; remaining = value;
GpuPrimeWorkLimiter.Acquire();
Accelerator accelerator = AcceleratorPool.Shared.Rent(); Accelerator accelerator = AcceleratorPool.Shared.Rent();
var stream = accelerator.CreateStream(); GpuScratchBuffer scratch = GpuScratchBufferPool.Rent(accelerator, GpuSmallPrimeFactorSlots, 0);
GpuPrimeWorkLimiter.Acquire();
var stream = AcceleratorStreamPool.Rent(accelerator);
KernelContainer kernels = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.SmallPrimeFactorKernelScan); KernelContainer kernels = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.SmallPrimeFactorKernelScan);
ScratchBuffer scratch = GpuScratchBufferPool.Rent(accelerator, GpuSmallPrimeFactorSlots, 0);
SmallPrimeFactorViews tables = GpuKernelPool.GetSmallPrimeFactorTables(kernels); SmallPrimeFactorViews tables = GpuKernelPool.GetSmallPrimeFactorTables(kernels);
if (kernels.SmallPrimeFactorsPrimes is null) throw new NullReferenceException($"{nameof(kernels.SmallPrimeFactorsPrimes)} is null");
if (kernels.SmallPrimeFactorsSquares is null) throw new NullReferenceException($"{nameof(kernels.SmallPrimeFactorsSquares)} is null");
var kernel = kernels.SmallPrimeFactor!; var kernel = kernels.SmallPrimeFactor!;
var kernelLauncher = kernel.CreateLauncherDelegate<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>>>();
ArrayView1D<int, Stride1D.Dense> smallPrimeFactorCountSlotView = scratch.SmallPrimeFactorCountSlot.View; ArrayView1D<int, Stride1D.Dense> smallPrimeFactorCountSlotView = scratch.SmallPrimeFactorCountSlot.View;
ArrayView1D<ulong, Stride1D.Dense> smallPrimeFactorRemainingSlotView = scratch.SmallPrimeFactorRemainingSlot.View; ArrayView1D<ulong, Stride1D.Dense> smallPrimeFactorRemainingSlotView = scratch.SmallPrimeFactorRemainingSlot.View;
@@ -87,7 +84,7 @@ internal static partial class PrimeOrderCalculator
ArrayView1D<int, Stride1D.Dense> smallPrimeFactorExponentSlotsView = scratch.SmallPrimeFactorExponentSlots.View; ArrayView1D<int, Stride1D.Dense> smallPrimeFactorExponentSlotsView = scratch.SmallPrimeFactorExponentSlots.View;
ArrayView1D<uint, Stride1D.Dense> smallPrimeFactorsPrimesView = kernels.SmallPrimeFactorsPrimes!.View; ArrayView1D<uint, Stride1D.Dense> smallPrimeFactorsPrimesView = kernels.SmallPrimeFactorsPrimes!.View;
kernel( kernelLauncher(
stream, stream,
1, 1,
value, value,
@@ -101,26 +98,27 @@ internal static partial class PrimeOrderCalculator
smallPrimeFactorRemainingSlotView); smallPrimeFactorRemainingSlotView);
// Span<int> factorCountTemp = stackalloc int[1];
factorCount = 0; factorCount = 0;
smallPrimeFactorCountSlotView.CopyToCPU(stream, ref factorCount, 1); smallPrimeFactorCountSlotView.CopyToCPU(stream, ref factorCount, 1);
stream.Synchronize(); stream.Synchronize();
// factorCount = factorCountTemp[0];
factorCount = Math.Min(factorCount, GpuSmallPrimeFactorSlots); factorCount = Math.Min(factorCount, GpuSmallPrimeFactorSlots);
if (factorCount > 0) if (factorCount > 0)
{ {
smallPrimeFactorPrimeSlotsView.CopyToCPU(stream, ref MemoryMarshal.GetReference(primeBuffer), factorCount); primeBuffer = primeBuffer[..factorCount];
smallPrimeFactorPrimeSlotsView.CopyToCPU(stream, primeBuffer);
smallPrimeFactorExponentSlotsView.CopyToCPU(stream, ref MemoryMarshal.GetReference(exponentBuffer), factorCount); exponentBuffer = exponentBuffer[..factorCount];
smallPrimeFactorExponentSlotsView.CopyToCPU(stream, exponentBuffer);
} }
// Span<ulong> remainingTemp = stackalloc ulong[1];
smallPrimeFactorRemainingSlotView.CopyToCPU(stream, ref remaining, 1); smallPrimeFactorRemainingSlotView.CopyToCPU(stream, ref remaining, 1);
// remaining = remainingTemp[0];
stream.Synchronize(); stream.Synchronize();
stream.Dispose();
AcceleratorStreamPool.Return(stream);
GpuScratchBufferPool.Return(scratch);
GpuPrimeWorkLimiter.Release();
for (int i = 0; i < factorCount; i++) for (int i = 0; i < factorCount; i++)
{ {
@@ -129,12 +127,11 @@ internal static partial class PrimeOrderCalculator
counts.Add(primeValue, exponent); counts.Add(primeValue, exponent);
} }
GpuScratchBufferPool.Return(scratch);
GpuPrimeWorkLimiter.Release();
return true; return true;
} }
private static bool EvaluateSpecialMaxCandidatesGpu( private static bool EvaluateSpecialMaxCandidatesGpu(
Pow2MontgomeryAccelerator gpu,
Span<ulong> buffer, Span<ulong> buffer,
ReadOnlySpan<FactorEntry> factors, ReadOnlySpan<FactorEntry> factors,
ulong phi, ulong phi,
@@ -154,11 +151,11 @@ internal static partial class PrimeOrderCalculator
} }
GpuPrimeWorkLimiter.Acquire(); GpuPrimeWorkLimiter.Acquire();
Accelerator accelerator = AcceleratorPool.Shared.Rent(); Accelerator accelerator = gpu.Accelerator; //AcceleratorPool.Shared.Rent();
var stream = accelerator.CreateStream(); var stream = AcceleratorStreamPool.Rent(accelerator);// accelerator.CreateStream();
var kernels = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.EvaluateSpecialMaxCandidatesKernel); var kernels = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.EvaluateSpecialMaxCandidatesKernel);
ScratchBuffer scratch = GpuScratchBufferPool.Rent(accelerator, 0, factorCount); GpuScratchBuffer scratch = GpuScratchBufferPool.Rent(accelerator, 0, factorCount);
ArrayView1D<ulong, Stride1D.Dense> specialMaxFactorsView = scratch.SpecialMaxFactors.View; ArrayView1D<ulong, Stride1D.Dense> specialMaxFactorsView = scratch.SpecialMaxFactors.View;
specialMaxFactorsView.SubView(0, factorCount).CopyFromCPU(stream, ref MemoryMarshal.GetReference(factorSpan), factorCount); specialMaxFactorsView.SubView(0, factorCount).CopyFromCPU(stream, ref MemoryMarshal.GetReference(factorSpan), factorCount);
@@ -182,7 +179,9 @@ internal static partial class PrimeOrderCalculator
// specialMaxResultView.CopyToCPU(stream, ref result, 1); // specialMaxResultView.CopyToCPU(stream, ref result, 1);
specialMaxResultView.CopyToCPU(stream, ref result, 1); specialMaxResultView.CopyToCPU(stream, ref result, 1);
stream.Synchronize(); stream.Synchronize();
stream.Dispose();
AcceleratorStreamPool.Return(stream);
// stream.Dispose();
// stream.Synchronize(); // stream.Synchronize();
// return result != 0; // return result != 0;
+9 -11
View File
@@ -94,20 +94,22 @@ public sealed class PrimeTester
public static bool IsPrimeGpu(ulong n) public static bool IsPrimeGpu(ulong n)
{ {
var gpu = Pow2MontgomeryAccelerator.Rent(1); var gpu = Pow2MontgomeryAccelerator.Rent(1);
var kernel = gpu.SmallPrimeSieveKernel!;
// Span<byte> flag = stackalloc byte[1]; // Span<byte> flag = stackalloc byte[1];
var inputView = gpu.PrimeTestInput.View; var inputView = gpu.PrimeTestInput.View;
var outputView = gpu.OutputByte.View;
var kernel = gpu.SmallPrimeSieveKernel!;
GpuPrimeWorkLimiter.Acquire(); GpuPrimeWorkLimiter.Acquire();
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator); AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
// var stream = gpu.Stream!; // var stream = gpu.Stream!;
inputView.CopyFromCPU(stream, ref n, 1); inputView.CopyFromCPU(stream, ref n, 1);
var outputView = gpu.OutputByte.View; 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>>>();
kernel.Launch( kernelLauncher(
stream, stream,
1, 1,
inputView, inputView,
@@ -136,18 +138,15 @@ public sealed class PrimeTester
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsPrimeGpu(Pow2MontgomeryAccelerator gpu, ulong n) public static bool IsPrimeGpu(Pow2MontgomeryAccelerator gpu, ulong n)
{ {
// var stream = gpu.Stream!;
var input = gpu.PrimeTestInput; var input = gpu.PrimeTestInput;
var inputView = input.View; var inputView = input.View;
var output = gpu.OutputByte;
var outputView = output.View;
Kernel kernel = gpu.SmallPrimeSieveKernel!;
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator); AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
inputView.CopyFromCPU(stream, ref n, 1); inputView.CopyFromCPU(stream, ref n, 1);
// Span<byte> flag = stackalloc byte[1];
var output = gpu.OutputByte;
var outputView = output.View;
Kernel kernel = gpu.SmallPrimeSieveKernel!;
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>>>(); 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>>>();
kernelLauncher( kernelLauncher(
@@ -238,8 +237,7 @@ public sealed class PrimeTester
outputView); outputView);
var resultSlice = results.Slice(pos, count); var resultSlice = results.Slice(pos, count);
ref byte resultRef = ref MemoryMarshal.GetReference(resultSlice); outputView.CopyToCPU(stream, resultSlice);
outputView.CopyToCPU(stream, ref resultRef, count);
pos += count; pos += count;
} }