GpuContextPool removed, because we share context and accelerator between threads, using streams to separate.
This commit is contained in:
1 parent
7c035239b4
commit
f4e365194d
19 files changed
+92
-232
No files matched your search
@@ -269,7 +269,7 @@ public sealed class DivisorCycleCache
|
|||||||
int length = divisors.Length;
|
int length = divisors.Length;
|
||||||
var gpuLease = GpuKernelPool.Rent();
|
var gpuLease = GpuKernelPool.Rent();
|
||||||
|
|
||||||
Accelerator accelerator = gpuLease.Accelerator;
|
Accelerator accelerator = SharedGpuContext.Accelerator;
|
||||||
var stream = gpuLease.Stream;
|
var stream = gpuLease.Stream;
|
||||||
var kernel = _gpuKernel;
|
var kernel = _gpuKernel;
|
||||||
EnsureCapacity(length);
|
EnsureCapacity(length);
|
||||||
|
|||||||
@@ -1,107 +0,0 @@
|
|||||||
using System.Collections.Concurrent;
|
|
||||||
using ILGPU;
|
|
||||||
using ILGPU.Runtime;
|
|
||||||
|
|
||||||
namespace PerfectNumbers.Core.Gpu;
|
|
||||||
|
|
||||||
public sealed class GpuContextLease
|
|
||||||
{
|
|
||||||
private GpuContextPool.PooledContext? _ctx;
|
|
||||||
|
|
||||||
internal GpuContextLease(GpuContextPool.PooledContext ctx)
|
|
||||||
{
|
|
||||||
_ctx = ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Context Context => _ctx!.Context;
|
|
||||||
public Accelerator Accelerator => _ctx!.Accelerator;
|
|
||||||
|
|
||||||
public void Dispose() => GpuContextPool.Return(_ctx!);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class GpuContextPool
|
|
||||||
{
|
|
||||||
// The pool intentionally skips pre-loading ProcessEightBitWindows kernels so accelerator initialization
|
|
||||||
// stays stable; GpuKernelPool JIT-compiles them on first use alongside the small-cycle uploads.
|
|
||||||
// Default device preference for generic GPU kernels (prime scans, NTT, etc.)
|
|
||||||
internal sealed class PooledContext
|
|
||||||
{
|
|
||||||
public readonly Context Context;
|
|
||||||
public readonly Accelerator Accelerator;
|
|
||||||
|
|
||||||
public PooledContext()
|
|
||||||
{
|
|
||||||
Context = SharedGpuContext.Context;
|
|
||||||
Accelerator = SharedGpuContext.Accelerator;
|
|
||||||
// NOTE: Avoid loading/compiling any kernel here to prevent implicit
|
|
||||||
// CL stream/queue creation during accelerator construction.
|
|
||||||
// Some OpenCL drivers are fragile when a queue is created immediately
|
|
||||||
// after device init. Real kernels will be JIT-loaded at first use.
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
// Ensure all cached GPU buffers for this accelerator are released.
|
|
||||||
// Release PrimeTester GPU state for this accelerator (kernel/device primes)
|
|
||||||
// Clear any per-accelerator cached resources to avoid releasing
|
|
||||||
// after the accelerator is destroyed.
|
|
||||||
|
|
||||||
// These resources are shared between GPU leases
|
|
||||||
// Accelerator.Dispose();
|
|
||||||
// Context.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly ConcurrentQueue<PooledContext> GpuPool = new();
|
|
||||||
private static int WarmedGpuContextCount;
|
|
||||||
|
|
||||||
// Allows callers to choose CPU/GPU per use-case, decoupled from ForceCpu.
|
|
||||||
public static GpuContextLease Rent()
|
|
||||||
{
|
|
||||||
if (GpuPool.TryDequeue(out var gpu))
|
|
||||||
{
|
|
||||||
return new GpuContextLease(gpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new accelerator when the pool does not have one available.
|
|
||||||
return new GpuContextLease(new PooledContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void WarmUpPool(int threadCount)
|
|
||||||
{
|
|
||||||
if (threadCount <= WarmedGpuContextCount)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int toCreate = threadCount - WarmedGpuContextCount;
|
|
||||||
Console.WriteLine($"Warming up GPU context pool to {toCreate} contexts...");
|
|
||||||
var contexts = new PooledContext[toCreate];
|
|
||||||
var pool = GpuPool;
|
|
||||||
PooledContext context;
|
|
||||||
for (int i = 0; i < toCreate; i++)
|
|
||||||
{
|
|
||||||
context = new PooledContext();
|
|
||||||
contexts[i] = context;
|
|
||||||
pool.Enqueue(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
WarmedGpuContextCount = threadCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DisposeAll()
|
|
||||||
{
|
|
||||||
while (GpuPool.TryDequeue(out var gpu))
|
|
||||||
{
|
|
||||||
gpu.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
WarmedGpuContextCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void Return(PooledContext ctx)
|
|
||||||
{
|
|
||||||
GpuPool.Enqueue(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using ILGPU;
|
using ILGPU;
|
||||||
using ILGPU.Algorithms;
|
|
||||||
using ILGPU.Runtime;
|
using ILGPU.Runtime;
|
||||||
|
|
||||||
namespace PerfectNumbers.Core.Gpu;
|
namespace PerfectNumbers.Core.Gpu;
|
||||||
@@ -9,7 +8,6 @@ public sealed class GpuKernelLease
|
|||||||
{
|
{
|
||||||
private static readonly ConcurrentQueue<GpuKernelLease> Pool = new();
|
private static readonly ConcurrentQueue<GpuKernelLease> Pool = new();
|
||||||
|
|
||||||
private GpuContextLease _gpu;
|
|
||||||
public KernelContainer Kernels;
|
public KernelContainer Kernels;
|
||||||
public AcceleratorStream Stream;
|
public AcceleratorStream Stream;
|
||||||
|
|
||||||
@@ -20,29 +18,25 @@ public sealed class GpuKernelLease
|
|||||||
Kernels = kernels;
|
Kernels = kernels;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static GpuKernelLease Rent(GpuContextLease gpu, AcceleratorStream stream, KernelContainer kernels)
|
internal static GpuKernelLease Rent(AcceleratorStream stream, KernelContainer kernels)
|
||||||
{
|
{
|
||||||
if (!Pool.TryDequeue(out var lease))
|
if (!Pool.TryDequeue(out var lease))
|
||||||
{
|
{
|
||||||
lease = new GpuKernelLease(kernels);
|
lease = new GpuKernelLease(kernels);
|
||||||
}
|
}
|
||||||
|
|
||||||
lease._gpu = gpu;
|
|
||||||
lease.Kernels = kernels;
|
lease.Kernels = kernels;
|
||||||
lease.Stream = stream;
|
lease.Stream = stream;
|
||||||
return lease;
|
return lease;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Accelerator Accelerator => _gpu?.Accelerator ?? throw new NullReferenceException("GPU context is already released");
|
|
||||||
|
|
||||||
public Action<AcceleratorStream, Index1D, ulong, ulong, ArrayView<GpuUInt128>, ArrayView<ulong>> OrderKernel
|
public Action<AcceleratorStream, Index1D, ulong, ulong, ArrayView<GpuUInt128>, ArrayView<ulong>> OrderKernel
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var accel = Accelerator; // avoid capturing 'this' in lambda
|
|
||||||
return GpuKernelPool.InitOnce(ref Kernels!.Order, () =>
|
return GpuKernelPool.InitOnce(ref Kernels!.Order, () =>
|
||||||
{
|
{
|
||||||
var loaded = accel.LoadAutoGroupedStreamKernel<Index1D, ulong, ulong, ArrayView<GpuUInt128>, ArrayView<ulong>>(OrderKernels.OrderKernelScan);
|
var loaded = SharedGpuContext.Accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, ulong, ArrayView<GpuUInt128>, ArrayView<ulong>>(OrderKernels.OrderKernelScan);
|
||||||
var kernel = KernelUtil.GetKernel(loaded);
|
var kernel = KernelUtil.GetKernel(loaded);
|
||||||
return kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, ulong, ArrayView<GpuUInt128>, ArrayView<ulong>>>();
|
return kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, ulong, ArrayView<GpuUInt128>, ArrayView<ulong>>>();
|
||||||
});
|
});
|
||||||
@@ -53,10 +47,9 @@ public sealed class GpuKernelLease
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var accel = Accelerator;
|
|
||||||
return GpuKernelPool.InitOnce(ref Kernels!.Pow2Mod, () =>
|
return GpuKernelPool.InitOnce(ref Kernels!.Pow2Mod, () =>
|
||||||
{
|
{
|
||||||
var loaded = accel.LoadAutoGroupedStreamKernel<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>>(Pow2ModKernels.Pow2ModKernelScan);
|
var loaded = SharedGpuContext.Accelerator.LoadAutoGroupedStreamKernel<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>>(Pow2ModKernels.Pow2ModKernelScan);
|
||||||
var kernel = KernelUtil.GetKernel(loaded);
|
var kernel = KernelUtil.GetKernel(loaded);
|
||||||
return kernel.CreateLauncherDelegate<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>>>();
|
return kernel.CreateLauncherDelegate<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>>>();
|
||||||
});
|
});
|
||||||
@@ -67,10 +60,9 @@ public sealed class GpuKernelLease
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var accel = Accelerator; // avoid capturing 'this' in lambda
|
|
||||||
return GpuKernelPool.InitOnce(ref Kernels!.Incremental, () =>
|
return GpuKernelPool.InitOnce(ref Kernels!.Incremental, () =>
|
||||||
{
|
{
|
||||||
var loaded = accel.LoadAutoGroupedStreamKernel<Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ulong, ulong, ulong, ulong, ArrayView<ulong>, ArrayView1D<ulong, Stride1D.Dense>>(IncrementalKernels.IncrementalKernelScan);
|
var loaded = SharedGpuContext.Accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ulong, ulong, ulong, ulong, ArrayView<ulong>, ArrayView1D<ulong, Stride1D.Dense>>(IncrementalKernels.IncrementalKernelScan);
|
||||||
var kernel = KernelUtil.GetKernel(loaded);
|
var kernel = KernelUtil.GetKernel(loaded);
|
||||||
return kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ulong, ulong, ulong, ulong, ArrayView<ulong>, ArrayView1D<ulong, Stride1D.Dense>>>();
|
return kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ulong, ulong, ulong, ulong, ArrayView<ulong>, ArrayView1D<ulong, Stride1D.Dense>>>();
|
||||||
});
|
});
|
||||||
@@ -81,10 +73,9 @@ public sealed class GpuKernelLease
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var accel = Accelerator;
|
|
||||||
return GpuKernelPool.InitOnce(ref Kernels!.IncrementalOrder, () =>
|
return GpuKernelPool.InitOnce(ref Kernels!.IncrementalOrder, () =>
|
||||||
{
|
{
|
||||||
var loaded = accel.LoadAutoGroupedStreamKernel<Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<int>, ArrayView1D<ulong, Stride1D.Dense>>(IncrementalKernels.IncrementalOrderKernelScan);
|
var loaded = SharedGpuContext.Accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<int>, ArrayView1D<ulong, Stride1D.Dense>>(IncrementalKernels.IncrementalOrderKernelScan);
|
||||||
var kernel = KernelUtil.GetKernel(loaded);
|
var kernel = KernelUtil.GetKernel(loaded);
|
||||||
return kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<int>, ArrayView1D<ulong, Stride1D.Dense>>>();
|
return kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<int>, ArrayView1D<ulong, Stride1D.Dense>>>();
|
||||||
});
|
});
|
||||||
@@ -95,10 +86,9 @@ public sealed class GpuKernelLease
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var accel = Accelerator;
|
|
||||||
return GpuKernelPool.InitOnce(ref Kernels!.Pow2ModOrder, () =>
|
return GpuKernelPool.InitOnce(ref Kernels!.Pow2ModOrder, () =>
|
||||||
{
|
{
|
||||||
var loaded = accel.LoadAutoGroupedStreamKernel<Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<int>, ArrayView1D<ulong, Stride1D.Dense>>(Pow2ModKernels.Pow2ModOrderKernelScan);
|
var loaded = SharedGpuContext.Accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<int>, ArrayView1D<ulong, Stride1D.Dense>>(Pow2ModKernels.Pow2ModOrderKernelScan);
|
||||||
var kernel = KernelUtil.GetKernel(loaded);
|
var kernel = KernelUtil.GetKernel(loaded);
|
||||||
return kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<int>, ArrayView1D<ulong, Stride1D.Dense>>>();
|
return kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<int>, ArrayView1D<ulong, Stride1D.Dense>>>();
|
||||||
});
|
});
|
||||||
@@ -109,10 +99,9 @@ public sealed class GpuKernelLease
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var accel = Accelerator;
|
|
||||||
return GpuKernelPool.InitOnce(ref Kernels!.SpecialMax, () =>
|
return GpuKernelPool.InitOnce(ref Kernels!.SpecialMax, () =>
|
||||||
{
|
{
|
||||||
var loaded = accel.LoadAutoGroupedStreamKernel<Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.EvaluateSpecialMaxCandidatesKernel);
|
var loaded = SharedGpuContext.Accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.EvaluateSpecialMaxCandidatesKernel);
|
||||||
var kernel = KernelUtil.GetKernel(loaded);
|
var kernel = KernelUtil.GetKernel(loaded);
|
||||||
return kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>();
|
return kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>();
|
||||||
});
|
});
|
||||||
@@ -123,10 +112,9 @@ public sealed class GpuKernelLease
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var accel = Accelerator;
|
|
||||||
return GpuKernelPool.InitOnce(ref Kernels!.SmallPrimeFactor, () =>
|
return GpuKernelPool.InitOnce(ref Kernels!.SmallPrimeFactor, () =>
|
||||||
{
|
{
|
||||||
var loaded = accel.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 = SharedGpuContext.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);
|
var kernel = 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>>>();
|
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>>>();
|
||||||
});
|
});
|
||||||
@@ -136,9 +124,7 @@ public sealed class GpuKernelLease
|
|||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Stream.Dispose();
|
Stream.Dispose();
|
||||||
_gpu.Dispose();
|
|
||||||
Pool.Enqueue(this);
|
Pool.Enqueue(this);
|
||||||
GpuPrimeWorkLimiter.Release();
|
GpuPrimeWorkLimiter.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using ILGPU;
|
using ILGPU;
|
||||||
using ILGPU.Runtime;
|
using ILGPU.Runtime;
|
||||||
using static PerfectNumbers.Core.Gpu.GpuContextPool;
|
|
||||||
|
|
||||||
namespace PerfectNumbers.Core.Gpu;
|
namespace PerfectNumbers.Core.Gpu;
|
||||||
|
|
||||||
public class GpuKernelPool
|
public class GpuKernelPool
|
||||||
{
|
{
|
||||||
private static readonly ConcurrentDictionary<Accelerator, KernelContainer> _kernels = new();
|
public static readonly KernelContainer Kernels = CreateKernels();
|
||||||
|
|
||||||
public static T InitOnce<T>(ref T? target, Func<T> valueFactory) where T : class
|
public static T InitOnce<T>(ref T? target, Func<T> valueFactory) where T : class
|
||||||
{
|
{
|
||||||
@@ -20,26 +19,35 @@ public class GpuKernelPool
|
|||||||
return Interlocked.CompareExchange(ref target, newValue, null) ?? newValue;
|
return Interlocked.CompareExchange(ref target, newValue, null) ?? newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static KernelContainer GetKernels(Accelerator accelerator, AcceleratorStream stream)
|
private static KernelContainer CreateKernels()
|
||||||
{
|
|
||||||
return _kernels.GetOrAdd(accelerator, (accelerator) =>
|
|
||||||
{
|
{
|
||||||
var kernels = new KernelContainer();
|
var kernels = new KernelContainer();
|
||||||
PreloadStaticTables(kernels, accelerator, stream);
|
var stream = SharedGpuContext.Accelerator.CreateStream();
|
||||||
|
PreloadStaticTables(kernels, stream);
|
||||||
|
stream.Synchronize();
|
||||||
|
stream.Dispose();
|
||||||
return kernels;
|
return kernels;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void PreloadStaticTables(KernelContainer kernels, Accelerator accelerator, AcceleratorStream stream)
|
private static KernelContainer CreateKernels(AcceleratorStream stream)
|
||||||
{
|
{
|
||||||
EnsureSmallCyclesOnDevice(kernels, accelerator, stream);
|
KernelContainer kernels = new();
|
||||||
EnsureSmallPrimesOnDevice(kernels, accelerator, stream);
|
PreloadStaticTables(kernels, stream);
|
||||||
EnsureSmallPrimeFactorTables(kernels, accelerator, stream);
|
return Kernels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static void PreloadStaticTables(KernelContainer kernels, AcceleratorStream stream)
|
||||||
|
{
|
||||||
|
_ = EnsureSmallCyclesOnDevice(kernels, stream);
|
||||||
|
_ = EnsureSmallPrimesOnDevice(kernels, stream);
|
||||||
|
_ = EnsureSmallPrimeFactorTables(kernels, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ArrayView1D<ulong, Stride1D.Dense> GetSmallCyclesOnDevice() => Kernels.SmallCycles!;
|
||||||
|
|
||||||
// Ensures the small cycles table is uploaded to the device for the given accelerator.
|
// Ensures the small cycles table is uploaded to the device for the given accelerator.
|
||||||
// Returns the ArrayView to pass into kernels (when kernels are extended to accept it).
|
// Returns the ArrayView to pass into kernels (when kernels are extended to accept it).
|
||||||
public static ArrayView1D<ulong, Stride1D.Dense> EnsureSmallCyclesOnDevice(KernelContainer kernels, Accelerator accelerator, AcceleratorStream stream)
|
private static ArrayView1D<ulong, Stride1D.Dense> EnsureSmallCyclesOnDevice(KernelContainer kernels, AcceleratorStream stream)
|
||||||
{
|
{
|
||||||
if (kernels.SmallCycles is { } buffer)
|
if (kernels.SmallCycles is { } buffer)
|
||||||
{
|
{
|
||||||
@@ -47,13 +55,20 @@ public class GpuKernelPool
|
|||||||
}
|
}
|
||||||
|
|
||||||
var host = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot(); // TODO: Preload this device buffer during startup and keep it immutable so we can delete the lock above in favor of the preloaded snapshot.
|
var host = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot(); // TODO: Preload this device buffer during startup and keep it immutable so we can delete the lock above in favor of the preloaded snapshot.
|
||||||
var device = accelerator.Allocate1D<ulong>(host.Length);
|
var device = SharedGpuContext.Accelerator.Allocate1D<ulong>(host.Length);
|
||||||
device.View.CopyFromCPU(stream, host);
|
device.View.CopyFromCPU(stream, host);
|
||||||
kernels.SmallCycles = device;
|
kernels.SmallCycles = device;
|
||||||
return device.View;
|
return device.View;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ResiduePrimeViews EnsureSmallPrimesOnDevice(KernelContainer kernels, Accelerator accelerator, AcceleratorStream stream)
|
public static ResiduePrimeViews GetSmallPrimesOnDevice() => new(
|
||||||
|
Kernels.SmallPrimesLastOne!,
|
||||||
|
Kernels.SmallPrimesLastSeven!,
|
||||||
|
Kernels.SmallPrimesPow2LastOne!,
|
||||||
|
Kernels.SmallPrimesPow2LastSeven!
|
||||||
|
);
|
||||||
|
|
||||||
|
private static ResiduePrimeViews EnsureSmallPrimesOnDevice(KernelContainer kernels, AcceleratorStream stream)
|
||||||
{
|
{
|
||||||
if (kernels.SmallPrimesLastOne is { } lastOne &&
|
if (kernels.SmallPrimesLastOne is { } lastOne &&
|
||||||
kernels.SmallPrimesLastSeven is { } lastSeven &&
|
kernels.SmallPrimesLastSeven is { } lastSeven &&
|
||||||
@@ -71,6 +86,7 @@ public class GpuKernelPool
|
|||||||
return new ResiduePrimeViews(existingLastOne.View, existingLastSeven.View, existingLastOnePow2.View, existingLastSevenPow2.View);
|
return new ResiduePrimeViews(existingLastOne.View, existingLastSeven.View, existingLastOnePow2.View, existingLastSevenPow2.View);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Accelerator accelerator = SharedGpuContext.Accelerator;
|
||||||
var hostLastOne = PrimesGenerator.SmallPrimesLastOne;
|
var hostLastOne = PrimesGenerator.SmallPrimesLastOne;
|
||||||
var hostLastSeven = PrimesGenerator.SmallPrimesLastSeven;
|
var hostLastSeven = PrimesGenerator.SmallPrimesLastSeven;
|
||||||
var hostLastOnePow2 = PrimesGenerator.SmallPrimesPow2LastOne;
|
var hostLastOnePow2 = PrimesGenerator.SmallPrimesPow2LastOne;
|
||||||
@@ -93,34 +109,39 @@ public class GpuKernelPool
|
|||||||
return new ResiduePrimeViews(deviceLastOne.View, deviceLastSeven.View, deviceLastOnePow2.View, deviceLastSevenPow2.View);
|
return new ResiduePrimeViews(deviceLastOne.View, deviceLastSeven.View, deviceLastOnePow2.View, deviceLastSevenPow2.View);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SmallPrimeFactorViews EnsureSmallPrimeFactorTables(KernelContainer kernels, Accelerator accelerator, AcceleratorStream stream)
|
public static SmallPrimeFactorViews GetSmallPrimeFactorTables() => new(
|
||||||
|
Kernels.SmallPrimeFactorsPrimes!,
|
||||||
|
Kernels.SmallPrimeFactorsSquares!
|
||||||
|
);
|
||||||
|
|
||||||
|
private static SmallPrimeFactorViews EnsureSmallPrimeFactorTables(KernelContainer kernels, AcceleratorStream stream)
|
||||||
{
|
{
|
||||||
if (kernels.SmallPrimeFactorsPrimes is { } primeBuffer && kernels.SmallPrimeFactorsSquares is { } squareBuffer)
|
if (kernels.SmallPrimeFactorsPrimes is { } primeBuffer && kernels.SmallPrimeFactorsSquares is { } squareBuffer)
|
||||||
{
|
{
|
||||||
return new SmallPrimeFactorViews(primeBuffer, squareBuffer, (int)primeBuffer.Length);
|
return new SmallPrimeFactorViews(primeBuffer, squareBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Accelerator accelerator = SharedGpuContext.Accelerator;
|
||||||
var hostPrimes = PrimesGenerator.SmallPrimes;
|
var hostPrimes = PrimesGenerator.SmallPrimes;
|
||||||
var hostSquares = PrimesGenerator.SmallPrimesPow2;
|
var hostSquares = PrimesGenerator.SmallPrimesPow2;
|
||||||
|
|
||||||
var devicePrimes = accelerator.Allocate1D<uint>(hostPrimes.Length);
|
int length = hostPrimes.Length;
|
||||||
|
var devicePrimes = accelerator.Allocate1D<uint>(length);
|
||||||
devicePrimes.View.CopyFromCPU(stream, hostPrimes);
|
devicePrimes.View.CopyFromCPU(stream, hostPrimes);
|
||||||
var deviceSquares = accelerator.Allocate1D<ulong>(hostSquares.Length);
|
var deviceSquares = accelerator.Allocate1D<ulong>(length);
|
||||||
deviceSquares.View.CopyFromCPU(stream, hostSquares);
|
deviceSquares.View.CopyFromCPU(stream, hostSquares);
|
||||||
|
|
||||||
kernels.SmallPrimeFactorsPrimes = devicePrimes;
|
kernels.SmallPrimeFactorsPrimes = devicePrimes;
|
||||||
kernels.SmallPrimeFactorsSquares = deviceSquares;
|
kernels.SmallPrimeFactorsSquares = deviceSquares;
|
||||||
|
|
||||||
return new SmallPrimeFactorViews(devicePrimes, deviceSquares, hostPrimes.Length);
|
return new SmallPrimeFactorViews(devicePrimes, deviceSquares);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GpuKernelLease Rent()
|
public static GpuKernelLease Rent()
|
||||||
{
|
{
|
||||||
GpuPrimeWorkLimiter.Acquire();
|
GpuPrimeWorkLimiter.Acquire();
|
||||||
var gpu = GpuContextPool.Rent();
|
var stream = SharedGpuContext.Accelerator.CreateStream();
|
||||||
var stream = gpu.Accelerator.CreateStream();
|
return GpuKernelLease.Rent(stream, Kernels);
|
||||||
var kernels = GetKernels(gpu.Accelerator, stream);
|
|
||||||
return GpuKernelLease.Rent(gpu, stream, kernels);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -130,7 +151,7 @@ public class GpuKernelPool
|
|||||||
public static void Run(Action<Accelerator, AcceleratorStream> action)
|
public static void Run(Action<Accelerator, AcceleratorStream> action)
|
||||||
{
|
{
|
||||||
var lease = Rent();
|
var lease = Rent();
|
||||||
var accelerator = lease.Accelerator;
|
var accelerator = SharedGpuContext.Accelerator;
|
||||||
var stream = lease.Stream;
|
var stream = lease.Stream;
|
||||||
action(accelerator, stream);
|
action(accelerator, stream);
|
||||||
lease.Dispose();
|
lease.Dispose();
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ internal static class GpuStaticTableInitializer
|
|||||||
Initialized.GetOrAdd(accelerator, acc =>
|
Initialized.GetOrAdd(accelerator, acc =>
|
||||||
{
|
{
|
||||||
PrimeTester.PrimeTesterGpuContextPool.EnsureStaticTables(kernels, acc, stream);
|
PrimeTester.PrimeTesterGpuContextPool.EnsureStaticTables(kernels, acc, stream);
|
||||||
GpuKernelPool.PreloadStaticTables(kernels, acc, stream);
|
GpuKernelPool.PreloadStaticTables(kernels, stream);
|
||||||
PrimeOrderGpuHeuristics.PreloadStaticTables( acc, stream);
|
PrimeOrderGpuHeuristics.PreloadStaticTables( acc, stream);
|
||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
ulong lastProcessed;
|
ulong lastProcessed;
|
||||||
|
|
||||||
var gpuLease = GpuKernelPool.Rent();
|
var gpuLease = GpuKernelPool.Rent();
|
||||||
var accelerator = gpuLease.Accelerator;
|
var accelerator = SharedGpuContext.Accelerator;
|
||||||
var stream = gpuLease.Stream;
|
var stream = gpuLease.Stream;
|
||||||
|
|
||||||
// Monitor.Enter(gpuLease.ExecutionLock);
|
// Monitor.Enter(gpuLease.ExecutionLock);
|
||||||
@@ -502,7 +502,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
{
|
{
|
||||||
_owner = owner;
|
_owner = owner;
|
||||||
_lease = GpuKernelPool.Rent();
|
_lease = GpuKernelPool.Rent();
|
||||||
_accelerator = _lease.Accelerator;
|
_accelerator = SharedGpuContext.Accelerator;
|
||||||
_stream = _lease.Stream;
|
_stream = _lease.Stream;
|
||||||
_capacity = Math.Max(1, owner._gpuBatchSize);
|
_capacity = Math.Max(1, owner._gpuBatchSize);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ public sealed class MersenneNumberDivisorGpuTester
|
|||||||
|
|
||||||
public bool IsDivisible(ulong exponent, in ReadOnlyGpuUInt128 divisor)
|
public bool IsDivisible(ulong exponent, in ReadOnlyGpuUInt128 divisor)
|
||||||
{
|
{
|
||||||
var gpu = GpuContextPool.Rent();
|
var accelerator = SharedGpuContext.Accelerator;
|
||||||
var accelerator = gpu.Accelerator;
|
|
||||||
var stream = accelerator.CreateStream();
|
var stream = accelerator.CreateStream();
|
||||||
var kernel = GetKernel(accelerator);
|
var kernel = GetKernel(accelerator);
|
||||||
var resultBuffer = _resultBuffers.GetOrAdd(accelerator, acc => acc.Allocate1D<byte>(1));
|
var resultBuffer = _resultBuffers.GetOrAdd(accelerator, acc => acc.Allocate1D<byte>(1));
|
||||||
@@ -56,11 +55,10 @@ public sealed class MersenneNumberDivisorGpuTester
|
|||||||
stream.Synchronize();
|
stream.Synchronize();
|
||||||
bool divisible = result[0] != 0;
|
bool divisible = result[0] != 0;
|
||||||
stream.Dispose();
|
stream.Dispose();
|
||||||
gpu.Dispose();
|
|
||||||
return divisible;
|
return divisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (ulong divisor, uint cycle)[]? _divisorCandidates = Array.Empty<(ulong divisor, uint cycle)>();
|
private static (ulong divisor, uint cycle)[]? _divisorCandidates = [];
|
||||||
|
|
||||||
public bool IsPrime(ulong p, UInt128 d, ulong divisorCyclesSearchLimit, out bool divisorsExhausted)
|
public bool IsPrime(ulong p, UInt128 d, ulong divisorCyclesSearchLimit, out bool divisorsExhausted)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,7 +17,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}).");
|
throw new NotImplementedException($"GPU incremental scanning requires the device cycle heuristics implementation (kernel: {_kernelType}, GPU order: {_useGpuOrder}).");
|
||||||
|
|
||||||
var gpuLease = GpuKernelPool.Rent();
|
var gpuLease = GpuKernelPool.Rent();
|
||||||
var accelerator = gpuLease.Accelerator;
|
var accelerator = SharedGpuContext.Accelerator;
|
||||||
var stream = gpuLease.Stream;
|
var stream = gpuLease.Stream;
|
||||||
int batchSize = GpuConstants.ScanBatchSize; // large batch improves GPU occupancy
|
int batchSize = GpuConstants.ScanBatchSize; // large batch improves GPU occupancy
|
||||||
UInt128 kStart = 1UL;
|
UInt128 kStart = 1UL;
|
||||||
@@ -31,11 +31,11 @@ public class MersenneNumberIncrementalGpuTester(GpuKernelType kernelType, bool u
|
|||||||
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
||||||
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
||||||
GpuUInt128 twoPGpu = (GpuUInt128)twoP;
|
GpuUInt128 twoPGpu = (GpuUInt128)twoP;
|
||||||
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(gpuLease.Kernels, accelerator, stream);
|
var smallCyclesView = GpuKernelPool.GetSmallCyclesOnDevice();
|
||||||
ResiduePrimeViews primeViews = default;
|
ResiduePrimeViews primeViews = default;
|
||||||
if (_kernelType == GpuKernelType.Pow2Mod)
|
if (_kernelType == GpuKernelType.Pow2Mod)
|
||||||
{
|
{
|
||||||
primeViews = GpuKernelPool.EnsureSmallPrimesOnDevice(gpuLease.Kernels, accelerator, stream);
|
primeViews = GpuKernelPool.GetSmallPrimesOnDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
var orderBuffer = accelerator.Allocate1D<ulong>(batchSize);
|
var orderBuffer = accelerator.Allocate1D<ulong>(batchSize);
|
||||||
|
|||||||
@@ -97,8 +97,7 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var gpu = GpuContextPool.Rent();
|
var accelerator = SharedGpuContext.Accelerator;
|
||||||
var accelerator = gpu.Accelerator;
|
|
||||||
var stream = accelerator.CreateStream();
|
var stream = accelerator.CreateStream();
|
||||||
var kernel = GetKernel(accelerator);
|
var kernel = GetKernel(accelerator);
|
||||||
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.
|
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.
|
||||||
@@ -109,7 +108,6 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
result = buffer.GetAsArray1D()[0].IsZero;
|
result = buffer.GetAsArray1D()[0].IsZero;
|
||||||
buffer.Dispose();
|
buffer.Dispose();
|
||||||
stream.Dispose();
|
stream.Dispose();
|
||||||
gpu.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GpuPrimeWorkLimiter.Release();
|
GpuPrimeWorkLimiter.Release();
|
||||||
@@ -132,8 +130,7 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var gpu = GpuContextPool.Rent();
|
var accelerator = SharedGpuContext.Accelerator;
|
||||||
var accelerator = gpu.Accelerator;
|
|
||||||
var stream = accelerator.CreateStream();
|
var stream = accelerator.CreateStream();
|
||||||
var kernel = GetBatchKernel(accelerator);
|
var kernel = GetBatchKernel(accelerator);
|
||||||
|
|
||||||
@@ -166,7 +163,6 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
gpuUInt128Pool.Return(modulusArray);
|
gpuUInt128Pool.Return(modulusArray);
|
||||||
ulongPool.Return(expArray);
|
ulongPool.Return(expArray);
|
||||||
stream.Dispose();
|
stream.Dispose();
|
||||||
gpu.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void IsMersennePrimeBatch(ReadOnlySpan<ulong> exponents, Span<bool> results)
|
public void IsMersennePrimeBatch(ReadOnlySpan<ulong> exponents, Span<bool> results)
|
||||||
@@ -189,9 +185,9 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
|
|
||||||
private bool IsMersennePrimeNtt(ulong exponent, GpuUInt128 nttMod, GpuUInt128 primitiveRoot, bool runOnGpu)
|
private bool IsMersennePrimeNtt(ulong exponent, GpuUInt128 nttMod, GpuUInt128 primitiveRoot, bool runOnGpu)
|
||||||
{
|
{
|
||||||
var gpu = GpuContextPool.Rent();
|
var accelerator = SharedGpuContext.Accelerator;
|
||||||
var accelerator = gpu.Accelerator;
|
|
||||||
var stream = accelerator.CreateStream();
|
var stream = accelerator.CreateStream();
|
||||||
|
|
||||||
var addKernel = GetAddSmallKernel(accelerator);
|
var addKernel = GetAddSmallKernel(accelerator);
|
||||||
var subKernel = GetSubSmallKernel(accelerator);
|
var subKernel = GetSubSmallKernel(accelerator);
|
||||||
var reduceKernel = GetReduceKernel(accelerator);
|
var reduceKernel = GetReduceKernel(accelerator);
|
||||||
@@ -240,7 +236,6 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
resultBuffer.Dispose();
|
resultBuffer.Dispose();
|
||||||
stateBuffer.Dispose();
|
stateBuffer.Dispose();
|
||||||
stream.Dispose();
|
stream.Dispose();
|
||||||
gpu.Dispose();
|
|
||||||
return isPrime;
|
return isPrime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
|
|||||||
public void Scan(ulong exponent, UInt128 twoP, LastDigit lastDigit, UInt128 maxK, ref bool isPrime)
|
public void Scan(ulong exponent, UInt128 twoP, LastDigit lastDigit, UInt128 maxK, ref bool isPrime)
|
||||||
{
|
{
|
||||||
var gpuLease = GpuKernelPool.Rent();
|
var gpuLease = GpuKernelPool.Rent();
|
||||||
var accelerator = gpuLease.Accelerator;
|
var accelerator = SharedGpuContext.Accelerator;
|
||||||
var stream = gpuLease.Stream;
|
var stream = gpuLease.Stream;
|
||||||
int batchSize = GpuConstants.ScanBatchSize; // large batch improves GPU occupancy and avoids TDR
|
int batchSize = GpuConstants.ScanBatchSize; // large batch improves GPU occupancy and avoids TDR
|
||||||
UInt128 kStart = UInt128.One;
|
UInt128 kStart = UInt128.One;
|
||||||
@@ -30,7 +30,7 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
|
|||||||
int currentSize;
|
int currentSize;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
|
|
||||||
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(gpuLease.Kernels, accelerator, stream);
|
var smallCyclesView = GpuKernelPool.GetSmallCyclesOnDevice();
|
||||||
while (kStart <= maxK && Volatile.Read(ref isPrime))
|
while (kStart <= maxK && Volatile.Read(ref isPrime))
|
||||||
{
|
{
|
||||||
remaining = maxK - kStart + 1UL;
|
remaining = maxK - kStart + 1UL;
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ namespace PerfectNumbers.Core.Gpu;
|
|||||||
public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
||||||
{
|
{
|
||||||
private readonly bool _useGpuOrder = useGpuOrder;
|
private readonly bool _useGpuOrder = useGpuOrder;
|
||||||
private readonly ConcurrentBag<GpuContextLease> _acceleratorPool = new();
|
|
||||||
private readonly ConcurrentDictionary<Accelerator, 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>>> _pow2ModKernelCache = new(AcceleratorReferenceComparer.Instance);
|
private readonly ConcurrentDictionary<Accelerator, 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>>> _pow2ModKernelCache = new(AcceleratorReferenceComparer.Instance);
|
||||||
private readonly ConcurrentDictionary<Accelerator, ConcurrentBag<ResidueResources>> _resourcePools = new(AcceleratorReferenceComparer.Instance);
|
private readonly ConcurrentDictionary<Accelerator, ConcurrentBag<ResidueResources>> _resourcePools = new(AcceleratorReferenceComparer.Instance);
|
||||||
|
|
||||||
@@ -28,15 +27,14 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
|||||||
public void Scan(ulong exponent, UInt128 twoP, LastDigit lastDigit, UInt128 maxK, ref bool isPrime)
|
public void Scan(ulong exponent, UInt128 twoP, LastDigit lastDigit, UInt128 maxK, ref bool isPrime)
|
||||||
{
|
{
|
||||||
GpuPrimeWorkLimiter.Acquire();
|
GpuPrimeWorkLimiter.Acquire();
|
||||||
var gpuLease = RentAccelerator();
|
var accelerator = SharedGpuContext.Accelerator;
|
||||||
var accelerator = gpuLease.Accelerator;
|
|
||||||
|
|
||||||
// Monitor.Enter(gpuLease.ExecutionLock);
|
// Monitor.Enter(gpuLease.ExecutionLock);
|
||||||
|
|
||||||
var stream = accelerator.CreateStream();
|
var stream = accelerator.CreateStream();
|
||||||
var kernel = GetPow2ModKernel(accelerator);
|
var kernel = GetPow2ModKernel(accelerator);
|
||||||
var resources = RentResources(accelerator, GpuConstants.ScanBatchSize);
|
var resources = RentResources(accelerator, GpuConstants.ScanBatchSize);
|
||||||
var gpuKernels = GpuKernelPool.GetKernels(accelerator, stream);
|
var gpuKernels = GpuKernelPool.Kernels;
|
||||||
|
|
||||||
var orderBuffer = resources.OrderBuffer;
|
var orderBuffer = resources.OrderBuffer;
|
||||||
ulong[] orderArray = resources.OrderArray;
|
ulong[] orderArray = resources.OrderArray;
|
||||||
@@ -44,8 +42,8 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
|||||||
|
|
||||||
// Ensure device has small cycles and primes tables for in-kernel lookup
|
// Ensure device has small cycles and primes tables for in-kernel lookup
|
||||||
// TODO: Pass-in the stream down the path
|
// TODO: Pass-in the stream down the path
|
||||||
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(gpuKernels, accelerator, stream);
|
var smallCyclesView = GpuKernelPool.GetSmallCyclesOnDevice();
|
||||||
ResiduePrimeViews primeViews = GpuKernelPool.EnsureSmallPrimesOnDevice(gpuKernels, accelerator, stream);
|
ResiduePrimeViews primeViews = GpuKernelPool.GetSmallPrimesOnDevice();
|
||||||
|
|
||||||
UInt128 kStart = 1UL;
|
UInt128 kStart = 1UL;
|
||||||
UInt128 limit = maxK + UInt128.One;
|
UInt128 limit = maxK + UInt128.One;
|
||||||
@@ -114,7 +112,6 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
|||||||
stream.Dispose();
|
stream.Dispose();
|
||||||
// Monitor.Exit(gpuLease.ExecutionLock);
|
// Monitor.Exit(gpuLease.ExecutionLock);
|
||||||
gpuKernels.Dispose();
|
gpuKernels.Dispose();
|
||||||
ReturnAccelerator(gpuLease);
|
|
||||||
GpuPrimeWorkLimiter.Release();
|
GpuPrimeWorkLimiter.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,18 +127,6 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
|||||||
loaded.Method);
|
loaded.Method);
|
||||||
});
|
});
|
||||||
|
|
||||||
private GpuContextLease RentAccelerator()
|
|
||||||
{
|
|
||||||
if (_acceleratorPool.TryTake(out var lease))
|
|
||||||
{
|
|
||||||
return lease;
|
|
||||||
}
|
|
||||||
|
|
||||||
return GpuContextPool.Rent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ReturnAccelerator(GpuContextLease lease) => _acceleratorPool.Add(lease);
|
|
||||||
|
|
||||||
private ResidueResources RentResources(Accelerator accelerator, int capacity)
|
private ResidueResources RentResources(Accelerator accelerator, int capacity)
|
||||||
{
|
{
|
||||||
var bag = _resourcePools.GetOrAdd(accelerator, static _ => []);
|
var bag = _resourcePools.GetOrAdd(accelerator, static _ => []);
|
||||||
|
|||||||
@@ -504,8 +504,7 @@ public static class NttGpuMath
|
|||||||
{
|
{
|
||||||
int n = values.Length;
|
int n = values.Length;
|
||||||
int bits = (int)Math.Log2(n);
|
int bits = (int)Math.Log2(n);
|
||||||
var gpu = GpuContextPool.Rent();
|
var accelerator = SharedGpuContext.Accelerator;
|
||||||
var accelerator = gpu.Accelerator;
|
|
||||||
var kernel = GetBitReverseKernel(accelerator);
|
var kernel = GetBitReverseKernel(accelerator);
|
||||||
var pool = ThreadStaticPools.GpuUInt128Pool;
|
var pool = ThreadStaticPools.GpuUInt128Pool;
|
||||||
var array = pool.Rent(n);
|
var array = pool.Rent(n);
|
||||||
@@ -520,7 +519,6 @@ public static class NttGpuMath
|
|||||||
pool.Return(array, clearArray: true);
|
pool.Return(array, clearArray: true);
|
||||||
buffer.Dispose();
|
buffer.Dispose();
|
||||||
stream.Dispose();
|
stream.Dispose();
|
||||||
gpu.Dispose();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -568,8 +566,7 @@ public static class NttGpuMath
|
|||||||
private static void ForwardGpuReference(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
private static void ForwardGpuReference(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
||||||
{
|
{
|
||||||
int n = (int)values.Length;
|
int n = (int)values.Length;
|
||||||
var gpu = GpuContextPool.Rent();
|
var accelerator = SharedGpuContext.Accelerator;
|
||||||
var accelerator = gpu.Accelerator;
|
|
||||||
var stream = accelerator.CreateStream();
|
var stream = accelerator.CreateStream();
|
||||||
var kernel = GetForwardKernel(accelerator);
|
var kernel = GetForwardKernel(accelerator);
|
||||||
var pool = ThreadStaticPools.GpuUInt128Pool;
|
var pool = ThreadStaticPools.GpuUInt128Pool;
|
||||||
@@ -592,8 +589,6 @@ public static class NttGpuMath
|
|||||||
outputBuffer.Dispose();
|
outputBuffer.Dispose();
|
||||||
inputBuffer.Dispose();
|
inputBuffer.Dispose();
|
||||||
stream.Dispose();
|
stream.Dispose();
|
||||||
gpu.Dispose();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Inverse(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
public static void Inverse(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
||||||
@@ -667,8 +662,7 @@ public static class NttGpuMath
|
|||||||
private static void InverseGpuReference(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
private static void InverseGpuReference(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
||||||
{
|
{
|
||||||
int n = values.Length;
|
int n = values.Length;
|
||||||
var gpu = GpuContextPool.Rent();
|
var accelerator = SharedGpuContext.Accelerator;
|
||||||
var accelerator = gpu.Accelerator;
|
|
||||||
var stream = accelerator.CreateStream();
|
var stream = accelerator.CreateStream();
|
||||||
var kernel = GetInverseKernel(accelerator);
|
var kernel = GetInverseKernel(accelerator);
|
||||||
var pool = ThreadStaticPools.GpuUInt128Pool;
|
var pool = ThreadStaticPools.GpuUInt128Pool;
|
||||||
@@ -710,15 +704,12 @@ public static class NttGpuMath
|
|||||||
outputBuffer.Dispose();
|
outputBuffer.Dispose();
|
||||||
inputBuffer.Dispose();
|
inputBuffer.Dispose();
|
||||||
stream.Dispose();
|
stream.Dispose();
|
||||||
gpu.Dispose();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ForwardGpuStaged(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
private static void ForwardGpuStaged(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
||||||
{
|
{
|
||||||
int n = values.Length;
|
int n = values.Length;
|
||||||
var gpu = GpuContextPool.Rent();
|
var accelerator = SharedGpuContext.Accelerator;
|
||||||
var accelerator = gpu.Accelerator;
|
|
||||||
var stream = accelerator.CreateStream();
|
var stream = accelerator.CreateStream();
|
||||||
var buffer = accelerator.Allocate1D<GpuUInt128>(n);
|
var buffer = accelerator.Allocate1D<GpuUInt128>(n);
|
||||||
buffer.View.CopyFromCPU(stream, ref values[0], n);
|
buffer.View.CopyFromCPU(stream, ref values[0], n);
|
||||||
@@ -728,15 +719,12 @@ public static class NttGpuMath
|
|||||||
stream.Synchronize();
|
stream.Synchronize();
|
||||||
stream.Dispose();
|
stream.Dispose();
|
||||||
buffer.Dispose();
|
buffer.Dispose();
|
||||||
gpu.Dispose();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void InverseGpuStaged(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
private static void InverseGpuStaged(Span<GpuUInt128> values, GpuUInt128 modulus, GpuUInt128 primitiveRoot)
|
||||||
{
|
{
|
||||||
int n = values.Length;
|
int n = values.Length;
|
||||||
var gpu = GpuContextPool.Rent();
|
var accelerator = SharedGpuContext.Accelerator;
|
||||||
var accelerator = gpu.Accelerator;
|
|
||||||
var stream = accelerator.CreateStream();
|
var stream = accelerator.CreateStream();
|
||||||
var buffer = accelerator.Allocate1D<GpuUInt128>(n);
|
var buffer = accelerator.Allocate1D<GpuUInt128>(n);
|
||||||
buffer.View.CopyFromCPU(stream, ref values[0], n);
|
buffer.View.CopyFromCPU(stream, ref values[0], n);
|
||||||
@@ -746,8 +734,6 @@ public static class NttGpuMath
|
|||||||
stream.Synchronize();
|
stream.Synchronize();
|
||||||
stream.Dispose();
|
stream.Dispose();
|
||||||
buffer.Dispose();
|
buffer.Dispose();
|
||||||
gpu.Dispose();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ForwardDevice(Accelerator accelerator, AcceleratorStream stream, ArrayView<GpuUInt128> data, int length, GpuUInt128 modulus, SquareCacheEntry cache)
|
private static void ForwardDevice(Accelerator accelerator, AcceleratorStream stream, ArrayView<GpuUInt128> data, int length, GpuUInt128 modulus, SquareCacheEntry cache)
|
||||||
@@ -939,8 +925,7 @@ public static class NttGpuMath
|
|||||||
|
|
||||||
public static void PointwiseMultiply(Span<GpuUInt128> left, Span<GpuUInt128> right, GpuUInt128 modulus)
|
public static void PointwiseMultiply(Span<GpuUInt128> left, Span<GpuUInt128> right, GpuUInt128 modulus)
|
||||||
{
|
{
|
||||||
var gpu = GpuContextPool.Rent();
|
var accelerator = SharedGpuContext.Accelerator;
|
||||||
var accelerator = gpu.Accelerator;
|
|
||||||
var stream = accelerator.CreateStream();
|
var stream = accelerator.CreateStream();
|
||||||
var kernel = GetMulKernel(accelerator);
|
var kernel = GetMulKernel(accelerator);
|
||||||
var pool = ThreadStaticPools.GpuUInt128Pool;
|
var pool = ThreadStaticPools.GpuUInt128Pool;
|
||||||
@@ -963,8 +948,6 @@ public static class NttGpuMath
|
|||||||
rightBuffer.Dispose();
|
rightBuffer.Dispose();
|
||||||
leftBuffer.Dispose();
|
leftBuffer.Dispose();
|
||||||
stream.Dispose();
|
stream.Dispose();
|
||||||
gpu.Dispose();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ulong[] GenerateSmallPrimes(int limit)
|
private static ulong[] GenerateSmallPrimes(int limit)
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ internal static partial class PrimeOrderGpuHeuristics
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var lease = GpuKernelPool.Rent();
|
var lease = GpuKernelPool.Rent();
|
||||||
Accelerator accelerator = lease.Accelerator;
|
Accelerator accelerator = SharedGpuContext.Accelerator;
|
||||||
AcceleratorStream stream = lease.Stream;
|
AcceleratorStream stream = lease.Stream;
|
||||||
|
|
||||||
var kernel = GetPartialFactorKernel(accelerator);
|
var kernel = GetPartialFactorKernel(accelerator);
|
||||||
@@ -366,7 +366,7 @@ internal static partial class PrimeOrderGpuHeuristics
|
|||||||
order = 0UL;
|
order = 0UL;
|
||||||
|
|
||||||
var lease = GpuKernelPool.Rent();
|
var lease = GpuKernelPool.Rent();
|
||||||
Accelerator accelerator = lease.Accelerator;
|
Accelerator accelerator = SharedGpuContext.Accelerator;
|
||||||
AcceleratorStream stream = lease.Stream;
|
AcceleratorStream stream = lease.Stream;
|
||||||
|
|
||||||
var kernel = GetOrderKernel(accelerator);
|
var kernel = GetOrderKernel(accelerator);
|
||||||
@@ -527,7 +527,7 @@ internal static partial class PrimeOrderGpuHeuristics
|
|||||||
private static bool TryComputeOnGpu(ReadOnlySpan<ulong> exponents, ulong prime, in MontgomeryDivisorData divisorData, Span<ulong> results)
|
private static bool TryComputeOnGpu(ReadOnlySpan<ulong> exponents, ulong prime, in MontgomeryDivisorData divisorData, Span<ulong> results)
|
||||||
{
|
{
|
||||||
var lease = GpuKernelPool.Rent();
|
var lease = GpuKernelPool.Rent();
|
||||||
Accelerator accelerator = lease.Accelerator;
|
Accelerator accelerator = SharedGpuContext.Accelerator;
|
||||||
AcceleratorStream stream = lease.Stream;
|
AcceleratorStream stream = lease.Stream;
|
||||||
var kernel = GetPow2ModKernel(accelerator);
|
var kernel = GetPow2ModKernel(accelerator);
|
||||||
// TODO: These buffers should be allocated once per accelerator and only reallocated when the new length exceeds capacity.
|
// TODO: These buffers should be allocated once per accelerator and only reallocated when the new length exceeds capacity.
|
||||||
@@ -586,7 +586,7 @@ internal static partial class PrimeOrderGpuHeuristics
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Accelerator accelerator = lease.Accelerator;
|
Accelerator accelerator = SharedGpuContext.Accelerator;
|
||||||
AcceleratorStream stream = lease.Stream;
|
AcceleratorStream stream = lease.Stream;
|
||||||
var kernel = GetPow2ModWideKernel(accelerator);
|
var kernel = GetPow2ModWideKernel(accelerator);
|
||||||
// TODO: These buffers should be allocated once per accelerator and only reallocated when the new length exceeds capacity.
|
// TODO: These buffers should be allocated once per accelerator and only reallocated when the new length exceeds capacity.
|
||||||
|
|||||||
@@ -6,12 +6,11 @@ namespace PerfectNumbers.Core.Gpu;
|
|||||||
|
|
||||||
public readonly struct SmallPrimeFactorViews(
|
public readonly struct SmallPrimeFactorViews(
|
||||||
MemoryBuffer1D<uint, Stride1D.Dense> primes,
|
MemoryBuffer1D<uint, Stride1D.Dense> primes,
|
||||||
MemoryBuffer1D<ulong, Stride1D.Dense> squares,
|
MemoryBuffer1D<ulong, Stride1D.Dense> squares)
|
||||||
int count)
|
|
||||||
{
|
{
|
||||||
public readonly MemoryBuffer1D<uint, Stride1D.Dense> Primes = primes;
|
public readonly MemoryBuffer1D<uint, Stride1D.Dense> Primes = primes;
|
||||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> Squares = squares;
|
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> Squares = squares;
|
||||||
public readonly int Count = count;
|
public readonly int Count = (int)primes.Length;
|
||||||
|
|
||||||
public ArrayView1D<uint, Stride1D.Dense> PrimesView
|
public ArrayView1D<uint, Stride1D.Dense> PrimesView
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -805,7 +805,7 @@ public class MersenneDivisorCycles
|
|||||||
divisors = pool.Rent(count);
|
divisors = pool.Rent(count);
|
||||||
outCycles = pool.Rent(count);
|
outCycles = pool.Rent(count);
|
||||||
var lease = GpuKernelPool.Rent();
|
var lease = GpuKernelPool.Rent();
|
||||||
var accelerator = lease.Accelerator;
|
var accelerator = SharedGpuContext.Accelerator;
|
||||||
var stream = lease.Stream;
|
var stream = lease.Stream;
|
||||||
var loaded = accelerator.LoadAutoGroupedStreamKernel<
|
var loaded = accelerator.LoadAutoGroupedStreamKernel<
|
||||||
Index1D,
|
Index1D,
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ public sealed class MersenneNumberTester(
|
|||||||
UInt128[] qs = qsBuffer;
|
UInt128[] qs = qsBuffer;
|
||||||
|
|
||||||
var gpuLease = GpuKernelPool.Rent();
|
var gpuLease = GpuKernelPool.Rent();
|
||||||
var accelerator = gpuLease.Accelerator;
|
var accelerator = SharedGpuContext.Accelerator;
|
||||||
var stream = gpuLease.Stream;
|
var stream = gpuLease.Stream;
|
||||||
var orderKernel = gpuLease.OrderKernel!;
|
var orderKernel = gpuLease.OrderKernel!;
|
||||||
|
|
||||||
|
|||||||
@@ -20,13 +20,13 @@ internal static partial class PrimeOrderCalculator
|
|||||||
remaining = value;
|
remaining = value;
|
||||||
|
|
||||||
var lease = GpuKernelPool.Rent();
|
var lease = GpuKernelPool.Rent();
|
||||||
Accelerator accelerator = lease.Accelerator;
|
Accelerator accelerator = SharedGpuContext.Accelerator;
|
||||||
var stream = lease.Stream;
|
var stream = lease.Stream;
|
||||||
KernelContainer kernels = lease.Kernels;
|
KernelContainer kernels = lease.Kernels;
|
||||||
|
|
||||||
ScratchBuffer scratch = GpuScratchBufferPool.Rent(accelerator, GpuSmallPrimeFactorSlots, 0);
|
ScratchBuffer scratch = GpuScratchBufferPool.Rent(accelerator, GpuSmallPrimeFactorSlots, 0);
|
||||||
|
|
||||||
SmallPrimeFactorViews tables = GpuKernelPool.EnsureSmallPrimeFactorTables(kernels, accelerator, stream);
|
SmallPrimeFactorViews tables = GpuKernelPool.GetSmallPrimeFactorTables();
|
||||||
|
|
||||||
if (kernels.SmallPrimeFactorsPrimes is null) throw new NullReferenceException($"{nameof(kernels.SmallPrimeFactorsPrimes)} is null");
|
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");
|
if (kernels.SmallPrimeFactorsSquares is null) throw new NullReferenceException($"{nameof(kernels.SmallPrimeFactorsSquares)} is null");
|
||||||
@@ -101,7 +101,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
}
|
}
|
||||||
|
|
||||||
GpuKernelLease lease = GpuKernelPool.Rent();
|
GpuKernelLease lease = GpuKernelPool.Rent();
|
||||||
Accelerator accelerator = lease.Accelerator;
|
Accelerator accelerator = SharedGpuContext.Accelerator;
|
||||||
|
|
||||||
var stream = lease.Stream;
|
var stream = lease.Stream;
|
||||||
|
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ public sealed class PrimeTester
|
|||||||
|
|
||||||
Accelerator accelerator = SharedGpuContext.Accelerator;
|
Accelerator accelerator = SharedGpuContext.Accelerator;
|
||||||
AcceleratorStream stream = accelerator.CreateStream();
|
AcceleratorStream stream = accelerator.CreateStream();
|
||||||
KernelContainer kernels = GpuKernelPool.GetKernels(accelerator, stream);
|
KernelContainer kernels = GpuKernelPool.Kernels;
|
||||||
|
|
||||||
GpuStaticTableInitializer.EnsureStaticTables(kernels, accelerator, stream);
|
GpuStaticTableInitializer.EnsureStaticTables(kernels, accelerator, stream);
|
||||||
|
|
||||||
@@ -433,7 +433,7 @@ public sealed class PrimeTester
|
|||||||
AcceleratorContext = SharedGpuContext.Context;
|
AcceleratorContext = SharedGpuContext.Context;
|
||||||
Accelerator = SharedGpuContext.Accelerator;
|
Accelerator = SharedGpuContext.Accelerator;
|
||||||
AcceleratorStream stream = SharedGpuContext.Accelerator.CreateStream();
|
AcceleratorStream stream = SharedGpuContext.Accelerator.CreateStream();
|
||||||
var kernels = GpuKernelPool.GetKernels(Accelerator, stream);
|
var kernels = GpuKernelPool.Kernels;
|
||||||
GpuStaticTableInitializer.EnsureStaticTables(kernels, Accelerator, stream);
|
GpuStaticTableInitializer.EnsureStaticTables(kernels, Accelerator, stream);
|
||||||
|
|
||||||
_sharedTables = RentSharedTables(Accelerator, stream);
|
_sharedTables = RentSharedTables(Accelerator, stream);
|
||||||
|
|||||||
@@ -463,7 +463,7 @@ public static partial class ULongExtensions
|
|||||||
|
|
||||||
GpuKernelLease lease = GpuKernelPool.Rent();
|
GpuKernelLease lease = GpuKernelPool.Rent();
|
||||||
|
|
||||||
Accelerator accelerator = lease.Accelerator;
|
Accelerator accelerator = SharedGpuContext.Accelerator;
|
||||||
AcceleratorStream stream = lease.Stream;
|
AcceleratorStream stream = lease.Stream;
|
||||||
var kernelGroup = Kernel;
|
var kernelGroup = Kernel;
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user