GpuScratchBuffer / -Pool naively integrated with PriemOrderCalculatorAccelerator (formerly Pow2MontgomeryAccelerator). FactorEntry replaced with 2 arrays - unused field removed. Small cleanup.
This commit is contained in:
1 parent
43863d03fb
commit
c53aa517f7
14 files changed
+295
-420
No files matched your search
@@ -6,21 +6,20 @@ namespace PerfectNumbers.Core.Gpu.Accelerators;
|
||||
|
||||
public static class AcceleratorStreamPool
|
||||
{
|
||||
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 Dictionary<Accelerator, ConcurrentQueue<AcceleratorStream>> _streams = new(PerfectNumberConstants .RollingAccelerators << 1);
|
||||
|
||||
private static SemaphoreSlim CreateLock() => new(PerfectNumberConstants.ThreadsByStream);
|
||||
private static AcceleratorStream CreateStream(Accelerator accelerator) => accelerator.CreateStream();
|
||||
|
||||
private static readonly Dictionary<Accelerator, SemaphoreSlim> _locks = new(AcceleratorPool.Shared.Accelerators.ToDictionary(x => x, static x => CreateLock()));
|
||||
private static readonly Dictionary<Accelerator, SemaphoreSlim> _locks = new(PerfectNumberConstants.RollingAccelerators << 1);
|
||||
|
||||
// private static int _rented;
|
||||
|
||||
public static AcceleratorStream Rent(Accelerator accelerator)
|
||||
{
|
||||
var streamLock = _locks[accelerator];
|
||||
// var streamLock = _locks.GetOrAdd(accelerator, static _ => CreateLock());
|
||||
var queue = _streams[accelerator];
|
||||
|
||||
streamLock.Wait();
|
||||
var queue = _streams[accelerator];
|
||||
|
||||
return queue.TryDequeue(out var stream)
|
||||
? stream
|
||||
@@ -40,13 +39,5 @@ public static class AcceleratorStreamPool
|
||||
{
|
||||
_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();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Runtime.CompilerServices;
|
||||
using ILGPU;
|
||||
using ILGPU.Runtime;
|
||||
|
||||
@@ -6,10 +6,13 @@ namespace PerfectNumbers.Core.Gpu.Accelerators;
|
||||
|
||||
internal sealed class LastDigitGpuTables
|
||||
{
|
||||
private static readonly ConcurrentDictionary<Accelerator, LastDigitGpuTables> _sharedTables = new(20_480, PerfectNumberConstants.RollingAccelerators * 2);
|
||||
private static readonly Dictionary<Accelerator, LastDigitGpuTables> _sharedTables = new(PerfectNumberConstants.RollingAccelerators);
|
||||
|
||||
internal static LastDigitGpuTables EnsureStaticTables(Accelerator accelerator, AcceleratorStream stream)
|
||||
=> _sharedTables.GetOrAdd(accelerator, _ => new LastDigitGpuTables(accelerator, stream));
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static LastDigitGpuTables EnsureStaticTables(Accelerator accelerator) => _sharedTables[accelerator];
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void WarmUp(Accelerator accelerator, AcceleratorStream stream) => _sharedTables[accelerator] = new LastDigitGpuTables(accelerator, stream);
|
||||
|
||||
internal LastDigitGpuTables(Accelerator accelerator, AcceleratorStream stream)
|
||||
{
|
||||
@@ -21,18 +24,14 @@ internal sealed class LastDigitGpuTables
|
||||
var primesPow2LastSeven = DivisorGenerator.SmallPrimesPow2LastSeven;
|
||||
var primesPow2LastThree = DivisorGenerator.SmallPrimesPow2LastThree;
|
||||
var primesPow2LastNine = DivisorGenerator.SmallPrimesPow2LastNine;
|
||||
|
||||
// lock (accelerator)
|
||||
{
|
||||
DevicePrimesLastOne = accelerator.Allocate1D(stream, primesLastOne);
|
||||
DevicePrimesLastSeven = accelerator.Allocate1D(stream, primesLastSeven);
|
||||
DevicePrimesLastThree = accelerator.Allocate1D(stream, primesLastThree);
|
||||
DevicePrimesLastNine = accelerator.Allocate1D(stream, primesLastNine);
|
||||
DevicePrimesPow2LastOne = accelerator.Allocate1D(stream, primesPow2LastOne);
|
||||
DevicePrimesPow2LastSeven = accelerator.Allocate1D(stream, primesPow2LastSeven);
|
||||
DevicePrimesPow2LastThree = accelerator.Allocate1D(stream, primesPow2LastThree);
|
||||
DevicePrimesPow2LastNine = accelerator.Allocate1D(stream, primesPow2LastNine);
|
||||
}
|
||||
DevicePrimesLastOne = accelerator.Allocate1D(stream, primesLastOne);
|
||||
DevicePrimesLastSeven = accelerator.Allocate1D(stream, primesLastSeven);
|
||||
DevicePrimesLastThree = accelerator.Allocate1D(stream, primesLastThree);
|
||||
DevicePrimesLastNine = accelerator.Allocate1D(stream, primesLastNine);
|
||||
DevicePrimesPow2LastOne = accelerator.Allocate1D(stream, primesPow2LastOne);
|
||||
DevicePrimesPow2LastSeven = accelerator.Allocate1D(stream, primesPow2LastSeven);
|
||||
DevicePrimesPow2LastThree = accelerator.Allocate1D(stream, primesPow2LastThree);
|
||||
DevicePrimesPow2LastNine = accelerator.Allocate1D(stream, primesPow2LastNine);
|
||||
}
|
||||
|
||||
internal readonly MemoryBuffer1D<uint, Stride1D.Dense> DevicePrimesLastOne;
|
||||
|
||||
+76
-68
@@ -5,27 +5,26 @@ using PerfectNumbers.Core.Gpu.Kernels;
|
||||
|
||||
namespace PerfectNumbers.Core.Gpu.Accelerators;
|
||||
|
||||
public sealed class Pow2MontgomeryAccelerator
|
||||
public sealed class PrimeOrderCalculatorAccelerator
|
||||
{
|
||||
#region Pool
|
||||
|
||||
[ThreadStatic]
|
||||
private static Queue<Pow2MontgomeryAccelerator>? _pool;
|
||||
private static Queue<PrimeOrderCalculatorAccelerator>? _pool;
|
||||
|
||||
private static AcceleratorPool _accelerators = new(PerfectNumberConstants.RollingAccelerators);
|
||||
private static readonly AcceleratorPool _accelerators = new(PerfectNumberConstants.RollingAccelerators);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Pow2MontgomeryAccelerator Rent(int primeTesterCapacity)
|
||||
public static PrimeOrderCalculatorAccelerator Rent(int primeTesterCapacity)
|
||||
{
|
||||
var pool = _pool ??= [];
|
||||
if (!pool.TryDequeue(out var gpu))
|
||||
{
|
||||
Accelerator accelerator = _accelerators.Rent();
|
||||
gpu = new(accelerator, PerfectNumberConstants.DefaultFactorsBuffer, primeTesterCapacity);
|
||||
gpu = new(accelerator, PerfectNumberConstants.DefaultFactorsBuffer, primeTesterCapacity, PerfectNumberConstants.DefaultSmallPrimeFactorSlotCount, PerfectNumberConstants.DefaultSpecialMaxFactorCapacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
// gpu.Stream = gpu.Accelerator.CreateStream();
|
||||
gpu.EnsureCapacity(PerfectNumberConstants.DefaultFactorsBuffer, primeTesterCapacity);
|
||||
}
|
||||
|
||||
@@ -33,33 +32,28 @@ public sealed class Pow2MontgomeryAccelerator
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Return(Pow2MontgomeryAccelerator gpu)
|
||||
{
|
||||
// gpu.Stream!.Dispose();
|
||||
// gpu.Stream = null;
|
||||
_pool!.Enqueue(gpu);
|
||||
}
|
||||
public static void Return(PrimeOrderCalculatorAccelerator gpu) => _pool!.Enqueue(gpu);
|
||||
|
||||
internal static void Clear()
|
||||
{
|
||||
Queue<Pow2MontgomeryAccelerator>? pool = _pool;
|
||||
Queue<PrimeOrderCalculatorAccelerator>? pool = _pool;
|
||||
if (pool != null)
|
||||
{
|
||||
while (pool.TryDequeue(out var lease))
|
||||
while (pool.TryDequeue(out var gpu))
|
||||
{
|
||||
lease.Dispose();
|
||||
gpu.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DisposeAll()
|
||||
{
|
||||
Queue<Pow2MontgomeryAccelerator>? pool = _pool;
|
||||
Queue<PrimeOrderCalculatorAccelerator>? pool = _pool;
|
||||
if (pool != null)
|
||||
{
|
||||
while (pool.TryDequeue(out var lease))
|
||||
while (pool.TryDequeue(out var gpu))
|
||||
{
|
||||
lease.Dispose();
|
||||
gpu.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,17 +67,15 @@ public sealed class Pow2MontgomeryAccelerator
|
||||
Console.WriteLine($"Preparing accelerator {i}...");
|
||||
var accelerator = accelerators[i];
|
||||
AcceleratorStreamPool.WarmUp(accelerator);
|
||||
// AcceleratorStream stream = AcceleratorStreamPool.Rent(accelerator);
|
||||
// Don't take this from the pool as quick uploads of data to the accelerator consumes much of GPU's memory and throws.
|
||||
AcceleratorStream stream = accelerator.CreateStream();
|
||||
LastDigitGpuTables.EnsureStaticTables(accelerator, stream);
|
||||
LastDigitGpuTables.WarmUp(accelerator, stream);
|
||||
// SharedHeuristicGpuTables.EnsureStaticTables(accelerator, stream);
|
||||
// _ = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.None);
|
||||
// KernelContainer kernels = GpuKernelPool.GetOrAddKernels(accelerator, stream);
|
||||
// GpuStaticTableInitializer.EnsureStaticTables(accelerator, kernels, stream);
|
||||
stream.Synchronize();
|
||||
stream.Dispose();
|
||||
|
||||
// AcceleratorStreamPool.Return(stream);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,31 +97,20 @@ public sealed class Pow2MontgomeryAccelerator
|
||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> DevicePrimesPow2LastSeven;
|
||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> DevicePrimesPow2LastThree;
|
||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> DevicePrimesPow2LastNine;
|
||||
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 readonly Kernel SmallPrimeSieveKernel;
|
||||
|
||||
// public AcceleratorStream? Stream;
|
||||
|
||||
public readonly Kernel CheckFactorsKernel;
|
||||
public readonly Kernel ConvertToStandardKernel;
|
||||
public readonly Kernel KeepMontgomeryKernel;
|
||||
public readonly Kernel PollardRhoKernel;
|
||||
|
||||
[ThreadStatic]
|
||||
private static Dictionary<Accelerator, Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>>? SmallPrimeSieveKernelPool;
|
||||
|
||||
internal static Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>> GetSmallPrimeSieveKernel(Accelerator accelerator)
|
||||
{
|
||||
var pool = SmallPrimeSieveKernelPool ??= [];
|
||||
if (pool.TryGetValue(accelerator, out var cached))
|
||||
{
|
||||
return cached;
|
||||
}
|
||||
|
||||
cached = 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)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>>();
|
||||
pool[accelerator] = cached;
|
||||
return cached;
|
||||
}
|
||||
|
||||
public void EnsureCapacity(int factorsCount, int primeTesterCapacity)
|
||||
{
|
||||
if (factorsCount > Pow2ModEntriesToTestOnDevice.Length)
|
||||
@@ -141,35 +122,62 @@ public sealed class Pow2MontgomeryAccelerator
|
||||
|
||||
if (primeTesterCapacity > PrimeTestInput.Length)
|
||||
{
|
||||
PrimeTestInput?.Dispose();
|
||||
OutputByte?.Dispose();
|
||||
HeuristicFlag?.Dispose();
|
||||
PrimeTestInput.Dispose();
|
||||
OutputByte.Dispose();
|
||||
HeuristicFlag.Dispose();
|
||||
|
||||
// lock (Accelerator)
|
||||
{
|
||||
PrimeTestInput = Accelerator.Allocate1D<ulong>(primeTesterCapacity);
|
||||
OutputByte = Accelerator.Allocate1D<byte>(primeTesterCapacity);
|
||||
HeuristicFlag = Accelerator.Allocate1D<int>(primeTesterCapacity);
|
||||
}
|
||||
PrimeTestInput = Accelerator.Allocate1D<ulong>(primeTesterCapacity);
|
||||
OutputByte = Accelerator.Allocate1D<byte>(primeTesterCapacity);
|
||||
HeuristicFlag = Accelerator.Allocate1D<int>(primeTesterCapacity);
|
||||
}
|
||||
}
|
||||
|
||||
public Pow2MontgomeryAccelerator(Accelerator accelerator, int factorsCount, int primeTesterCapacity)
|
||||
public void EnsureSmallPrimeFactorSlotsCapacity(int newSize)
|
||||
{
|
||||
// Console.WriteLine($"Resizing GPU scratch buffer from pool ({buffer.SmallPrimeFactorPrimeSlots.Length} / {smallPrimeFactorSlotCount}), ({buffer.SpecialMaxFactors.Length}/{specialMaxFactorCapacity})");
|
||||
if (SmallPrimeFactorPrimeSlots.Length < newSize)
|
||||
{
|
||||
SmallPrimeFactorPrimeSlots.Dispose();
|
||||
SmallPrimeFactorExponentSlots.Dispose();
|
||||
|
||||
var accelerator = Accelerator;
|
||||
SmallPrimeFactorPrimeSlots = accelerator.Allocate1D<ulong>(newSize);
|
||||
SmallPrimeFactorExponentSlots = accelerator.Allocate1D<int>(newSize);
|
||||
}
|
||||
}
|
||||
|
||||
public void EnsureSpecialMaxFactorsCapacity(int newSize)
|
||||
{
|
||||
if (SpecialMaxFactors.Length < newSize)
|
||||
{
|
||||
SpecialMaxFactors.Dispose();
|
||||
SpecialMaxCandidates.Dispose();
|
||||
|
||||
var accelerator = Accelerator;
|
||||
SpecialMaxFactors = accelerator.Allocate1D<ulong>(newSize);
|
||||
SpecialMaxCandidates = accelerator.Allocate1D<ulong>(newSize);
|
||||
}
|
||||
}
|
||||
|
||||
public PrimeOrderCalculatorAccelerator(Accelerator accelerator, int factorsCount, int primeTesterCapacity, int smallPrimeFactorSlotCount, int specialMaxFactorCapacity)
|
||||
{
|
||||
Accelerator = accelerator;
|
||||
AcceleratorStream stream = AcceleratorStreamPool.Rent(accelerator);
|
||||
// AcceleratorStream stream = accelerator.DefaultStream;
|
||||
// AcceleratorStream stream = accelerator.CreateStream();
|
||||
// Stream = stream;
|
||||
|
||||
Input = accelerator.Allocate1D<ulong>(1);
|
||||
OutputUlong = accelerator.Allocate1D<ulong>(1);
|
||||
Pow2ModEntriesToTestOnDevice = accelerator.Allocate1D<KeyValuePair<ulong, int>>(factorsCount);
|
||||
PrimeTestInput = Accelerator.Allocate1D<ulong>(primeTesterCapacity);
|
||||
OutputByte = Accelerator.Allocate1D<byte>(primeTesterCapacity);
|
||||
HeuristicFlag = Accelerator.Allocate1D<int>(primeTesterCapacity);
|
||||
SmallPrimeFactorPrimeSlots = accelerator.Allocate1D<ulong>(smallPrimeFactorSlotCount);
|
||||
SmallPrimeFactorExponentSlots = accelerator.Allocate1D<int>(smallPrimeFactorSlotCount);
|
||||
SmallPrimeFactorCountSlot = accelerator.Allocate1D<int>(1);
|
||||
SmallPrimeFactorRemainingSlot = accelerator.Allocate1D<ulong>(1);
|
||||
|
||||
var sharedTables = LastDigitGpuTables.EnsureStaticTables(accelerator, stream);
|
||||
SpecialMaxFactors = accelerator.Allocate1D<ulong>(specialMaxFactorCapacity);
|
||||
SpecialMaxCandidates = accelerator.Allocate1D<ulong>(specialMaxFactorCapacity);
|
||||
SpecialMaxResult = accelerator.Allocate1D<ulong>(1);
|
||||
|
||||
var sharedTables = LastDigitGpuTables.EnsureStaticTables(accelerator);
|
||||
DevicePrimesLastOne = sharedTables.DevicePrimesLastOne;
|
||||
DevicePrimesLastSeven = sharedTables.DevicePrimesLastSeven;
|
||||
DevicePrimesLastThree = sharedTables.DevicePrimesLastThree;
|
||||
@@ -191,27 +199,27 @@ public sealed class Pow2MontgomeryAccelerator
|
||||
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));
|
||||
|
||||
PollardRhoKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel<ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.TryPollardRhoKernel));
|
||||
|
||||
AcceleratorStreamPool.Return(stream);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Input.Dispose();
|
||||
OutputUlong.Dispose();
|
||||
// Stream?.Dispose();
|
||||
Pow2ModEntriesToTestOnDevice.Dispose();
|
||||
PrimeTestInput?.Dispose();
|
||||
OutputByte?.Dispose();
|
||||
HeuristicFlag?.Dispose();
|
||||
|
||||
// Stream is disposed upon return to the queue, so we don't need to dispose it here.
|
||||
// Stream.Dispose();
|
||||
PrimeTestInput.Dispose();
|
||||
OutputByte.Dispose();
|
||||
HeuristicFlag.Dispose();
|
||||
SmallPrimeFactorPrimeSlots.Dispose();
|
||||
SmallPrimeFactorExponentSlots.Dispose();
|
||||
SmallPrimeFactorCountSlot.Dispose();
|
||||
SmallPrimeFactorRemainingSlot.Dispose();
|
||||
SpecialMaxFactors.Dispose();
|
||||
SpecialMaxCandidates.Dispose();
|
||||
SpecialMaxResult.Dispose();
|
||||
|
||||
// These resources are shared between GPU leases
|
||||
// ReleaseSharedTables(_sharedTables);
|
||||
// Stream.Dispose();
|
||||
// Accelerator.Dispose();
|
||||
// Context.Dispose();
|
||||
// Accelerator.Dispose();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user