From f4e365194d18459fe65b9805b85a542763057606 Mon Sep 17 00:00:00 2001 From: mlemanczyk Date: Fri, 7 Nov 2025 12:52:20 +0100 Subject: [PATCH] GpuContextPool removed, because we share context and accelerator between threads, using streams to separate. --- PerfectNumbers.Core/DivisorCycleCache.cs | 2 +- PerfectNumbers.Core/Gpu/GpuContextPool.cs | 107 --------- PerfectNumbers.Core/Gpu/GpuKernelLease.cs | 214 ++++++++---------- PerfectNumbers.Core/Gpu/GpuKernelPool.cs | 73 +++--- .../Gpu/GpuStaticTableInitializer.cs | 2 +- ...MersenneNumberDivisorByDivisorGpuTester.cs | 4 +- .../Gpu/MersenneNumberDivisorGpuTester.cs | 202 ++++++++--------- .../Gpu/MersenneNumberIncrementalGpuTester.cs | 6 +- .../Gpu/MersenneNumberLucasLehmerGpuTester.cs | 15 +- .../Gpu/MersenneNumberOrderGpuTester.cs | 4 +- .../Gpu/MersenneNumberResidueGpuTester.cs | 23 +- PerfectNumbers.Core/Gpu/NttGpuMath.cs | 29 +-- .../Gpu/PrimeOrderGpuHeuristics.cs | 8 +- .../Gpu/SmallPrimeFactorViews.cs | 5 +- PerfectNumbers.Core/MersenneDivisorCycles.cs | 2 +- PerfectNumbers.Core/MersenneNumberTester.cs | 2 +- .../PrimeOrderCalculator.Gpu.cs | 6 +- PerfectNumbers.Core/PrimeTester.cs | 4 +- PerfectNumbers.Core/ULongExtensions.Gpu.cs | 2 +- 19 files changed, 285 insertions(+), 425 deletions(-) delete mode 100644 PerfectNumbers.Core/Gpu/GpuContextPool.cs diff --git a/PerfectNumbers.Core/DivisorCycleCache.cs b/PerfectNumbers.Core/DivisorCycleCache.cs index 38188d2..a701b2c 100644 --- a/PerfectNumbers.Core/DivisorCycleCache.cs +++ b/PerfectNumbers.Core/DivisorCycleCache.cs @@ -269,7 +269,7 @@ public sealed class DivisorCycleCache int length = divisors.Length; var gpuLease = GpuKernelPool.Rent(); - Accelerator accelerator = gpuLease.Accelerator; + Accelerator accelerator = SharedGpuContext.Accelerator; var stream = gpuLease.Stream; var kernel = _gpuKernel; EnsureCapacity(length); diff --git a/PerfectNumbers.Core/Gpu/GpuContextPool.cs b/PerfectNumbers.Core/Gpu/GpuContextPool.cs deleted file mode 100644 index ec73eeb..0000000 --- a/PerfectNumbers.Core/Gpu/GpuContextPool.cs +++ /dev/null @@ -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 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); - } -} \ No newline at end of file diff --git a/PerfectNumbers.Core/Gpu/GpuKernelLease.cs b/PerfectNumbers.Core/Gpu/GpuKernelLease.cs index 1a6465c..a21c745 100644 --- a/PerfectNumbers.Core/Gpu/GpuKernelLease.cs +++ b/PerfectNumbers.Core/Gpu/GpuKernelLease.cs @@ -1,17 +1,15 @@ using System.Collections.Concurrent; using ILGPU; -using ILGPU.Algorithms; using ILGPU.Runtime; namespace PerfectNumbers.Core.Gpu; public sealed class GpuKernelLease { - private static readonly ConcurrentQueue Pool = new(); + private static readonly ConcurrentQueue Pool = new(); - private GpuContextLease _gpu; - public KernelContainer Kernels; - public AcceleratorStream Stream; + public KernelContainer Kernels; + public AcceleratorStream Stream; #pragma warning disable CS8618 // _gpu and Stream will be set by Rent method private GpuKernelLease(KernelContainer kernels) @@ -20,125 +18,113 @@ public sealed class GpuKernelLease Kernels = kernels; } - internal static GpuKernelLease Rent(GpuContextLease gpu, AcceleratorStream stream, KernelContainer kernels) - { - if (!Pool.TryDequeue(out var lease)) - { - lease = new GpuKernelLease(kernels); - } + internal static GpuKernelLease Rent(AcceleratorStream stream, KernelContainer kernels) + { + if (!Pool.TryDequeue(out var lease)) + { + lease = new GpuKernelLease(kernels); + } - lease._gpu = gpu; lease.Kernels = kernels; lease.Stream = stream; - return lease; - } + return lease; + } - public Accelerator Accelerator => _gpu?.Accelerator ?? throw new NullReferenceException("GPU context is already released"); + public Action, ArrayView> OrderKernel + { + get + { + return GpuKernelPool.InitOnce(ref Kernels!.Order, () => + { + var loaded = SharedGpuContext.Accelerator.LoadAutoGroupedStreamKernel, ArrayView>(OrderKernels.OrderKernelScan); + var kernel = KernelUtil.GetKernel(loaded); + return kernel.CreateLauncherDelegate, ArrayView>>(); + }); + } + } - public Action, ArrayView> OrderKernel - { - get - { - var accel = Accelerator; // avoid capturing 'this' in lambda - return GpuKernelPool.InitOnce(ref Kernels!.Order, () => - { - var loaded = accel.LoadAutoGroupedStreamKernel, ArrayView>(OrderKernels.OrderKernelScan); - var kernel = KernelUtil.GetKernel(loaded); - return kernel.CreateLauncherDelegate, ArrayView>>(); - }); - } - } + public Action, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D> Pow2ModKernel + { + get + { + return GpuKernelPool.InitOnce(ref Kernels!.Pow2Mod, () => + { + var loaded = SharedGpuContext.Accelerator.LoadAutoGroupedStreamKernel, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D>(Pow2ModKernels.Pow2ModKernelScan); + var kernel = KernelUtil.GetKernel(loaded); + return kernel.CreateLauncherDelegate, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D>>(); + }); + } + } - public Action, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D> Pow2ModKernel - { - get - { - var accel = Accelerator; - return GpuKernelPool.InitOnce(ref Kernels!.Pow2Mod, () => - { - var loaded = accel.LoadAutoGroupedStreamKernel, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D>(Pow2ModKernels.Pow2ModKernelScan); - var kernel = KernelUtil.GetKernel(loaded); - return kernel.CreateLauncherDelegate, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D>>(); - }); - } - } + public Action, ArrayView1D> IncrementalKernel + { + get + { + return GpuKernelPool.InitOnce(ref Kernels!.Incremental, () => + { + var loaded = SharedGpuContext.Accelerator.LoadAutoGroupedStreamKernel, ArrayView1D>(IncrementalKernels.IncrementalKernelScan); + var kernel = KernelUtil.GetKernel(loaded); + return kernel.CreateLauncherDelegate, ArrayView1D>>(); + }); + } + } - public Action, ArrayView1D> IncrementalKernel - { - get - { - var accel = Accelerator; // avoid capturing 'this' in lambda - return GpuKernelPool.InitOnce(ref Kernels!.Incremental, () => - { - var loaded = accel.LoadAutoGroupedStreamKernel, ArrayView1D>(IncrementalKernels.IncrementalKernelScan); - var kernel = KernelUtil.GetKernel(loaded); - return kernel.CreateLauncherDelegate, ArrayView1D>>(); - }); - } - } + public Action, ArrayView1D> IncrementalOrderKernel + { + get + { + return GpuKernelPool.InitOnce(ref Kernels!.IncrementalOrder, () => + { + var loaded = SharedGpuContext.Accelerator.LoadAutoGroupedStreamKernel, ArrayView1D>(IncrementalKernels.IncrementalOrderKernelScan); + var kernel = KernelUtil.GetKernel(loaded); + return kernel.CreateLauncherDelegate, ArrayView1D>>(); + }); + } + } - public Action, ArrayView1D> IncrementalOrderKernel - { - get - { - var accel = Accelerator; - return GpuKernelPool.InitOnce(ref Kernels!.IncrementalOrder, () => - { - var loaded = accel.LoadAutoGroupedStreamKernel, ArrayView1D>(IncrementalKernels.IncrementalOrderKernelScan); - var kernel = KernelUtil.GetKernel(loaded); - return kernel.CreateLauncherDelegate, ArrayView1D>>(); - }); - } - } + public Action, ArrayView1D> Pow2ModOrderKernel + { + get + { + return GpuKernelPool.InitOnce(ref Kernels!.Pow2ModOrder, () => + { + var loaded = SharedGpuContext.Accelerator.LoadAutoGroupedStreamKernel, ArrayView1D>(Pow2ModKernels.Pow2ModOrderKernelScan); + var kernel = KernelUtil.GetKernel(loaded); + return kernel.CreateLauncherDelegate, ArrayView1D>>(); + }); + } + } - public Action, ArrayView1D> Pow2ModOrderKernel - { - get - { - var accel = Accelerator; - return GpuKernelPool.InitOnce(ref Kernels!.Pow2ModOrder, () => - { - var loaded = accel.LoadAutoGroupedStreamKernel, ArrayView1D>(Pow2ModKernels.Pow2ModOrderKernelScan); - var kernel = KernelUtil.GetKernel(loaded); - return kernel.CreateLauncherDelegate, ArrayView1D>>(); - }); - } - } + public Action, int, MontgomeryDivisorData, ArrayView1D, ArrayView1D> SpecialMaxKernel + { + get + { + return GpuKernelPool.InitOnce(ref Kernels!.SpecialMax, () => + { + var loaded = SharedGpuContext.Accelerator.LoadAutoGroupedStreamKernel, int, MontgomeryDivisorData, ArrayView1D, ArrayView1D>(PrimeOrderGpuHeuristics.EvaluateSpecialMaxCandidatesKernel); + var kernel = KernelUtil.GetKernel(loaded); + return kernel.CreateLauncherDelegate, int, MontgomeryDivisorData, ArrayView1D, ArrayView1D>>(); + }); + } + } - public Action, int, MontgomeryDivisorData, ArrayView1D, ArrayView1D> SpecialMaxKernel - { - get - { - var accel = Accelerator; - return GpuKernelPool.InitOnce(ref Kernels!.SpecialMax, () => - { - var loaded = accel.LoadAutoGroupedStreamKernel, int, MontgomeryDivisorData, ArrayView1D, ArrayView1D>(PrimeOrderGpuHeuristics.EvaluateSpecialMaxCandidatesKernel); - var kernel = KernelUtil.GetKernel(loaded); - return kernel.CreateLauncherDelegate, int, MontgomeryDivisorData, ArrayView1D, ArrayView1D>>(); - }); - } - } + public Action, ArrayView1D, int, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D> SmallPrimeFactorKernel + { + get + { + return GpuKernelPool.InitOnce(ref Kernels!.SmallPrimeFactor, () => + { + var loaded = SharedGpuContext.Accelerator.LoadAutoGroupedStreamKernel, ArrayView1D, int, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D>(SmallPrimeFactorKernels.SmallPrimeFactorKernelScan); + var kernel = KernelUtil.GetKernel(loaded); + return kernel.CreateLauncherDelegate, ArrayView1D, int, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D>>(); + }); + } + } - public Action, ArrayView1D, int, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D> SmallPrimeFactorKernel - { - get - { - var accel = Accelerator; - return GpuKernelPool.InitOnce(ref Kernels!.SmallPrimeFactor, () => - { - var loaded = accel.LoadAutoGroupedStreamKernel, ArrayView1D, int, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D>(SmallPrimeFactorKernels.SmallPrimeFactorKernelScan); - var kernel = KernelUtil.GetKernel(loaded); - return kernel.CreateLauncherDelegate, ArrayView1D, int, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D>>(); - }); - } - } - - public void Dispose() - { - Stream.Dispose(); - _gpu.Dispose(); - Pool.Enqueue(this); + public void Dispose() + { + Stream.Dispose(); + Pool.Enqueue(this); GpuPrimeWorkLimiter.Release(); - } - + } } diff --git a/PerfectNumbers.Core/Gpu/GpuKernelPool.cs b/PerfectNumbers.Core/Gpu/GpuKernelPool.cs index a1ddcbe..662ff12 100644 --- a/PerfectNumbers.Core/Gpu/GpuKernelPool.cs +++ b/PerfectNumbers.Core/Gpu/GpuKernelPool.cs @@ -1,13 +1,12 @@ using System.Collections.Concurrent; using ILGPU; using ILGPU.Runtime; -using static PerfectNumbers.Core.Gpu.GpuContextPool; namespace PerfectNumbers.Core.Gpu; public class GpuKernelPool { - private static readonly ConcurrentDictionary _kernels = new(); + public static readonly KernelContainer Kernels = CreateKernels(); public static T InitOnce(ref T? target, Func valueFactory) where T : class { @@ -20,26 +19,35 @@ public class GpuKernelPool 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(); - PreloadStaticTables(kernels, accelerator, stream); - return kernels; - }); + var kernels = new KernelContainer(); + var stream = SharedGpuContext.Accelerator.CreateStream(); + PreloadStaticTables(kernels, stream); + stream.Synchronize(); + stream.Dispose(); + return kernels; } - internal static void PreloadStaticTables(KernelContainer kernels, Accelerator accelerator, AcceleratorStream stream) + private static KernelContainer CreateKernels(AcceleratorStream stream) { - EnsureSmallCyclesOnDevice(kernels, accelerator, stream); - EnsureSmallPrimesOnDevice(kernels, accelerator, stream); - EnsureSmallPrimeFactorTables(kernels, accelerator, stream); + KernelContainer kernels = new(); + PreloadStaticTables(kernels, stream); + return Kernels; } + internal static void PreloadStaticTables(KernelContainer kernels, AcceleratorStream stream) + { + _ = EnsureSmallCyclesOnDevice(kernels, stream); + _ = EnsureSmallPrimesOnDevice(kernels, stream); + _ = EnsureSmallPrimeFactorTables(kernels, stream); + } + + public static ArrayView1D GetSmallCyclesOnDevice() => Kernels.SmallCycles!; + // 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). - public static ArrayView1D EnsureSmallCyclesOnDevice(KernelContainer kernels, Accelerator accelerator, AcceleratorStream stream) + private static ArrayView1D EnsureSmallCyclesOnDevice(KernelContainer kernels, AcceleratorStream stream) { 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 device = accelerator.Allocate1D(host.Length); + var device = SharedGpuContext.Accelerator.Allocate1D(host.Length); device.View.CopyFromCPU(stream, host); kernels.SmallCycles = device; 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 && kernels.SmallPrimesLastSeven is { } lastSeven && @@ -71,6 +86,7 @@ public class GpuKernelPool return new ResiduePrimeViews(existingLastOne.View, existingLastSeven.View, existingLastOnePow2.View, existingLastSevenPow2.View); } + Accelerator accelerator = SharedGpuContext.Accelerator; var hostLastOne = PrimesGenerator.SmallPrimesLastOne; var hostLastSeven = PrimesGenerator.SmallPrimesLastSeven; var hostLastOnePow2 = PrimesGenerator.SmallPrimesPow2LastOne; @@ -93,34 +109,39 @@ public class GpuKernelPool 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) { - return new SmallPrimeFactorViews(primeBuffer, squareBuffer, (int)primeBuffer.Length); + return new SmallPrimeFactorViews(primeBuffer, squareBuffer); } + Accelerator accelerator = SharedGpuContext.Accelerator; var hostPrimes = PrimesGenerator.SmallPrimes; var hostSquares = PrimesGenerator.SmallPrimesPow2; - var devicePrimes = accelerator.Allocate1D(hostPrimes.Length); + int length = hostPrimes.Length; + var devicePrimes = accelerator.Allocate1D(length); devicePrimes.View.CopyFromCPU(stream, hostPrimes); - var deviceSquares = accelerator.Allocate1D(hostSquares.Length); + var deviceSquares = accelerator.Allocate1D(length); deviceSquares.View.CopyFromCPU(stream, hostSquares); kernels.SmallPrimeFactorsPrimes = devicePrimes; kernels.SmallPrimeFactorsSquares = deviceSquares; - return new SmallPrimeFactorViews(devicePrimes, deviceSquares, hostPrimes.Length); + return new SmallPrimeFactorViews(devicePrimes, deviceSquares); } public static GpuKernelLease Rent() { GpuPrimeWorkLimiter.Acquire(); - var gpu = GpuContextPool.Rent(); - var stream = gpu.Accelerator.CreateStream(); - var kernels = GetKernels(gpu.Accelerator, stream); - return GpuKernelLease.Rent(gpu, stream, kernels); + var stream = SharedGpuContext.Accelerator.CreateStream(); + return GpuKernelLease.Rent(stream, Kernels); } /// @@ -130,7 +151,7 @@ public class GpuKernelPool public static void Run(Action action) { var lease = Rent(); - var accelerator = lease.Accelerator; + var accelerator = SharedGpuContext.Accelerator; var stream = lease.Stream; action(accelerator, stream); lease.Dispose(); diff --git a/PerfectNumbers.Core/Gpu/GpuStaticTableInitializer.cs b/PerfectNumbers.Core/Gpu/GpuStaticTableInitializer.cs index fdc8603..4922a11 100644 --- a/PerfectNumbers.Core/Gpu/GpuStaticTableInitializer.cs +++ b/PerfectNumbers.Core/Gpu/GpuStaticTableInitializer.cs @@ -16,7 +16,7 @@ internal static class GpuStaticTableInitializer Initialized.GetOrAdd(accelerator, acc => { PrimeTester.PrimeTesterGpuContextPool.EnsureStaticTables(kernels, acc, stream); - GpuKernelPool.PreloadStaticTables(kernels, acc, stream); + GpuKernelPool.PreloadStaticTables(kernels, stream); PrimeOrderGpuHeuristics.PreloadStaticTables( acc, stream); return 0; }); diff --git a/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs b/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs index b1e6510..801b3ed 100644 --- a/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs +++ b/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs @@ -96,7 +96,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv ulong lastProcessed; var gpuLease = GpuKernelPool.Rent(); - var accelerator = gpuLease.Accelerator; + var accelerator = SharedGpuContext.Accelerator; var stream = gpuLease.Stream; // Monitor.Enter(gpuLease.ExecutionLock); @@ -502,7 +502,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv { _owner = owner; _lease = GpuKernelPool.Rent(); - _accelerator = _lease.Accelerator; + _accelerator = SharedGpuContext.Accelerator; _stream = _lease.Stream; _capacity = Math.Max(1, owner._gpuBatchSize); } diff --git a/PerfectNumbers.Core/Gpu/MersenneNumberDivisorGpuTester.cs b/PerfectNumbers.Core/Gpu/MersenneNumberDivisorGpuTester.cs index c5f2079..fb233dc 100644 --- a/PerfectNumbers.Core/Gpu/MersenneNumberDivisorGpuTester.cs +++ b/PerfectNumbers.Core/Gpu/MersenneNumberDivisorGpuTester.cs @@ -15,126 +15,124 @@ public sealed class MersenneNumberDivisorGpuTester private Action> GetKernel(Accelerator accelerator) => _kernelCache.GetOrAdd(accelerator, acc => - { - var loaded = acc.LoadAutoGroupedStreamKernel>(DivisorKernels.Kernel); - var kernel = KernelUtil.GetKernel(loaded); - return kernel.CreateLauncherDelegate>>(); - }); + { + var loaded = acc.LoadAutoGroupedStreamKernel>(DivisorKernels.Kernel); + var kernel = KernelUtil.GetKernel(loaded); + return kernel.CreateLauncherDelegate>>(); + }); - public static void BuildDivisorCandidates() - { - ulong[] snapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot(); - (ulong divisor, uint cycle)[] list = new (ulong divisor, uint cycle)[snapshot.Length / 2]; - ulong cycle; - int count = 0, i, snapshotLength = snapshot.Length; - for (i = 3; i < snapshotLength; i += 2) - { - cycle = snapshot[i]; - if (cycle == 0U) - { - continue; - } + public static void BuildDivisorCandidates() + { + ulong[] snapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot(); + (ulong divisor, uint cycle)[] list = new (ulong divisor, uint cycle)[snapshot.Length / 2]; + ulong cycle; + int count = 0, i, snapshotLength = snapshot.Length; + for (i = 3; i < snapshotLength; i += 2) + { + cycle = snapshot[i]; + if (cycle == 0U) + { + continue; + } - list[count++] = ((ulong)i, (uint)cycle); - } + list[count++] = ((ulong)i, (uint)cycle); + } - _divisorCandidates = count == 0 ? [] : list[..count]; - } + _divisorCandidates = count == 0 ? [] : list[..count]; + } - public bool IsDivisible(ulong exponent, in ReadOnlyGpuUInt128 divisor) - { - var gpu = GpuContextPool.Rent(); - var accelerator = gpu.Accelerator; + public bool IsDivisible(ulong exponent, in ReadOnlyGpuUInt128 divisor) + { + var accelerator = SharedGpuContext.Accelerator; var stream = accelerator.CreateStream(); - var kernel = GetKernel(accelerator); - var resultBuffer = _resultBuffers.GetOrAdd(accelerator, acc => acc.Allocate1D(1)); + var kernel = GetKernel(accelerator); + var resultBuffer = _resultBuffers.GetOrAdd(accelerator, acc => acc.Allocate1D(1)); // There is no point in clearing this buffer. We always override item [0] and never use it beyond item [0] - // resultBuffer.MemSetToZero(stream); - kernel(stream, 1, exponent, divisor, resultBuffer.View); - Span result = stackalloc byte[1]; - resultBuffer.View.CopyToCPU(stream, ref result[0], 1); - stream.Synchronize(); - bool divisible = result[0] != 0; + // resultBuffer.MemSetToZero(stream); + kernel(stream, 1, exponent, divisor, resultBuffer.View); + Span result = stackalloc byte[1]; + resultBuffer.View.CopyToCPU(stream, ref result[0], 1); + stream.Synchronize(); + bool divisible = result[0] != 0; 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) - { - ReadOnlyGpuUInt128 readOnlyDivisor; + public bool IsPrime(ulong p, UInt128 d, ulong divisorCyclesSearchLimit, out bool divisorsExhausted) + { + ReadOnlyGpuUInt128 readOnlyDivisor; - if (d != UInt128.Zero) - { - readOnlyDivisor = new ReadOnlyGpuUInt128(d); - if (IsDivisible(p, in readOnlyDivisor)) - { - divisorsExhausted = true; - return false; - } + if (d != UInt128.Zero) + { + readOnlyDivisor = new ReadOnlyGpuUInt128(d); + if (IsDivisible(p, in readOnlyDivisor)) + { + divisorsExhausted = true; + return false; + } - divisorsExhausted = false; - return true; - } + divisorsExhausted = false; + return true; + } - if (_divisorCandidates is { Length: > 0 } candidates) - { - int candidateCount = candidates.Length; - for (int index = 0; index < candidateCount; index++) - { - (ulong candidateDivisor, uint cycle) = candidates[index]; - if (p % cycle != 0UL) - { - continue; - } + if (_divisorCandidates is { Length: > 0 } candidates) + { + int candidateCount = candidates.Length; + for (int index = 0; index < candidateCount; index++) + { + (ulong candidateDivisor, uint cycle) = candidates[index]; + if (p % cycle != 0UL) + { + continue; + } - readOnlyDivisor = new ReadOnlyGpuUInt128(candidateDivisor); // Reusing readOnlyDivisor for candidate divisors. - if (IsDivisible(p, in readOnlyDivisor)) - { - divisorsExhausted = true; - return false; - } - } - } + readOnlyDivisor = new ReadOnlyGpuUInt128(candidateDivisor); // Reusing readOnlyDivisor for candidate divisors. + if (IsDivisible(p, in readOnlyDivisor)) + { + divisorsExhausted = true; + return false; + } + } + } - UInt128 kMul2; - var divisorCycles = MersenneDivisorCycles.Shared; - UInt128 maxK2 = UInt128.MaxValue / ((UInt128)p << 1); - ulong limit = divisorCyclesSearchLimit; - if ((UInt128)limit > maxK2) - { - limit = (ulong)maxK2; - } + UInt128 kMul2; + var divisorCycles = MersenneDivisorCycles.Shared; + UInt128 maxK2 = UInt128.MaxValue / ((UInt128)p << 1); + ulong limit = divisorCyclesSearchLimit; + if ((UInt128)limit > maxK2) + { + limit = (ulong)maxK2; + } - for (ulong k2 = 1UL; k2 <= limit; k2++) - { - kMul2 = (UInt128)k2 << 1; - UInt128 candidate = checked(kMul2 * p); - d = checked(candidate + UInt128.One); - if (p < 64UL && d == ((UInt128)1 << (int)p) - UInt128.One) - { - continue; - } + for (ulong k2 = 1UL; k2 <= limit; k2++) + { + kMul2 = (UInt128)k2 << 1; + UInt128 candidate = checked(kMul2 * p); + d = checked(candidate + UInt128.One); + if (p < 64UL && d == ((UInt128)1 << (int)p) - UInt128.One) + { + continue; + } - UInt128 cycle128 = MersenneDivisorCycles.GetCycle(d); - if ((UInt128)p % cycle128 != UInt128.Zero) - { - continue; - } + UInt128 cycle128 = MersenneDivisorCycles.GetCycle(d); + if ((UInt128)p % cycle128 != UInt128.Zero) + { + continue; + } - readOnlyDivisor = new ReadOnlyGpuUInt128(d); // Reusing readOnlyDivisor for generated divisors. - if (IsDivisible(p, in readOnlyDivisor)) - { - divisorsExhausted = true; - return false; - } - } + readOnlyDivisor = new ReadOnlyGpuUInt128(d); // Reusing readOnlyDivisor for generated divisors. + if (IsDivisible(p, in readOnlyDivisor)) + { + divisorsExhausted = true; + return false; + } + } - divisorsExhausted = (UInt128)divisorCyclesSearchLimit >= maxK2; - return true; - } + divisorsExhausted = (UInt128)divisorCyclesSearchLimit >= maxK2; + return true; + } } diff --git a/PerfectNumbers.Core/Gpu/MersenneNumberIncrementalGpuTester.cs b/PerfectNumbers.Core/Gpu/MersenneNumberIncrementalGpuTester.cs index 5aead82..f79718b 100644 --- a/PerfectNumbers.Core/Gpu/MersenneNumberIncrementalGpuTester.cs +++ b/PerfectNumbers.Core/Gpu/MersenneNumberIncrementalGpuTester.cs @@ -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})."); var gpuLease = GpuKernelPool.Rent(); - var accelerator = gpuLease.Accelerator; + var accelerator = SharedGpuContext.Accelerator; var stream = gpuLease.Stream; int batchSize = GpuConstants.ScanBatchSize; // large batch improves GPU occupancy UInt128 kStart = 1UL; @@ -31,11 +31,11 @@ public class MersenneNumberIncrementalGpuTester(GpuKernelType kernelType, bool u ulong step3 = ((exponent % 3UL) << 1) % 3UL; ulong step5 = ((exponent % 5UL) << 1) % 5UL; GpuUInt128 twoPGpu = (GpuUInt128)twoP; - var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(gpuLease.Kernels, accelerator, stream); + var smallCyclesView = GpuKernelPool.GetSmallCyclesOnDevice(); ResiduePrimeViews primeViews = default; if (_kernelType == GpuKernelType.Pow2Mod) { - primeViews = GpuKernelPool.EnsureSmallPrimesOnDevice(gpuLease.Kernels, accelerator, stream); + primeViews = GpuKernelPool.GetSmallPrimesOnDevice(); } var orderBuffer = accelerator.Allocate1D(batchSize); diff --git a/PerfectNumbers.Core/Gpu/MersenneNumberLucasLehmerGpuTester.cs b/PerfectNumbers.Core/Gpu/MersenneNumberLucasLehmerGpuTester.cs index a4f40e5..57b6add 100644 --- a/PerfectNumbers.Core/Gpu/MersenneNumberLucasLehmerGpuTester.cs +++ b/PerfectNumbers.Core/Gpu/MersenneNumberLucasLehmerGpuTester.cs @@ -97,8 +97,7 @@ public class MersenneNumberLucasLehmerGpuTester } else { - var gpu = GpuContextPool.Rent(); - var accelerator = gpu.Accelerator; + var accelerator = SharedGpuContext.Accelerator; var stream = accelerator.CreateStream(); 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. @@ -109,7 +108,6 @@ public class MersenneNumberLucasLehmerGpuTester result = buffer.GetAsArray1D()[0].IsZero; buffer.Dispose(); stream.Dispose(); - gpu.Dispose(); } GpuPrimeWorkLimiter.Release(); @@ -132,8 +130,7 @@ public class MersenneNumberLucasLehmerGpuTester } } - var gpu = GpuContextPool.Rent(); - var accelerator = gpu.Accelerator; + var accelerator = SharedGpuContext.Accelerator; var stream = accelerator.CreateStream(); var kernel = GetBatchKernel(accelerator); @@ -166,7 +163,6 @@ public class MersenneNumberLucasLehmerGpuTester gpuUInt128Pool.Return(modulusArray); ulongPool.Return(expArray); stream.Dispose(); - gpu.Dispose(); } public void IsMersennePrimeBatch(ReadOnlySpan exponents, Span results) @@ -189,10 +185,10 @@ public class MersenneNumberLucasLehmerGpuTester private bool IsMersennePrimeNtt(ulong exponent, GpuUInt128 nttMod, GpuUInt128 primitiveRoot, bool runOnGpu) { - var gpu = GpuContextPool.Rent(); - var accelerator = gpu.Accelerator; + var accelerator = SharedGpuContext.Accelerator; var stream = accelerator.CreateStream(); - var addKernel = GetAddSmallKernel(accelerator); + + var addKernel = GetAddSmallKernel(accelerator); var subKernel = GetSubSmallKernel(accelerator); var reduceKernel = GetReduceKernel(accelerator); var zeroKernel = GetIsZeroKernel(accelerator); @@ -240,7 +236,6 @@ public class MersenneNumberLucasLehmerGpuTester resultBuffer.Dispose(); stateBuffer.Dispose(); stream.Dispose(); - gpu.Dispose(); return isPrime; } diff --git a/PerfectNumbers.Core/Gpu/MersenneNumberOrderGpuTester.cs b/PerfectNumbers.Core/Gpu/MersenneNumberOrderGpuTester.cs index 613bdbf..a767aae 100644 --- a/PerfectNumbers.Core/Gpu/MersenneNumberOrderGpuTester.cs +++ b/PerfectNumbers.Core/Gpu/MersenneNumberOrderGpuTester.cs @@ -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) { var gpuLease = GpuKernelPool.Rent(); - var accelerator = gpuLease.Accelerator; + var accelerator = SharedGpuContext.Accelerator; var stream = gpuLease.Stream; int batchSize = GpuConstants.ScanBatchSize; // large batch improves GPU occupancy and avoids TDR UInt128 kStart = UInt128.One; @@ -30,7 +30,7 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO int currentSize; int found = 0; - var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(gpuLease.Kernels, accelerator, stream); + var smallCyclesView = GpuKernelPool.GetSmallCyclesOnDevice(); while (kStart <= maxK && Volatile.Read(ref isPrime)) { remaining = maxK - kStart + 1UL; diff --git a/PerfectNumbers.Core/Gpu/MersenneNumberResidueGpuTester.cs b/PerfectNumbers.Core/Gpu/MersenneNumberResidueGpuTester.cs index 8582066..1c2f5ea 100644 --- a/PerfectNumbers.Core/Gpu/MersenneNumberResidueGpuTester.cs +++ b/PerfectNumbers.Core/Gpu/MersenneNumberResidueGpuTester.cs @@ -14,7 +14,6 @@ namespace PerfectNumbers.Core.Gpu; public class MersenneNumberResidueGpuTester(bool useGpuOrder) { private readonly bool _useGpuOrder = useGpuOrder; - private readonly ConcurrentBag _acceleratorPool = new(); private readonly ConcurrentDictionary, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D>> _pow2ModKernelCache = new(AcceleratorReferenceComparer.Instance); private readonly ConcurrentDictionary> _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) { GpuPrimeWorkLimiter.Acquire(); - var gpuLease = RentAccelerator(); - var accelerator = gpuLease.Accelerator; + var accelerator = SharedGpuContext.Accelerator; // Monitor.Enter(gpuLease.ExecutionLock); var stream = accelerator.CreateStream(); var kernel = GetPow2ModKernel(accelerator); var resources = RentResources(accelerator, GpuConstants.ScanBatchSize); - var gpuKernels = GpuKernelPool.GetKernels(accelerator, stream); + var gpuKernels = GpuKernelPool.Kernels; var orderBuffer = resources.OrderBuffer; 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 // TODO: Pass-in the stream down the path - var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(gpuKernels, accelerator, stream); - ResiduePrimeViews primeViews = GpuKernelPool.EnsureSmallPrimesOnDevice(gpuKernels, accelerator, stream); + var smallCyclesView = GpuKernelPool.GetSmallCyclesOnDevice(); + ResiduePrimeViews primeViews = GpuKernelPool.GetSmallPrimesOnDevice(); UInt128 kStart = 1UL; UInt128 limit = maxK + UInt128.One; @@ -114,7 +112,6 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder) stream.Dispose(); // Monitor.Exit(gpuLease.ExecutionLock); gpuKernels.Dispose(); - ReturnAccelerator(gpuLease); GpuPrimeWorkLimiter.Release(); } @@ -130,18 +127,6 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder) 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) { var bag = _resourcePools.GetOrAdd(accelerator, static _ => []); diff --git a/PerfectNumbers.Core/Gpu/NttGpuMath.cs b/PerfectNumbers.Core/Gpu/NttGpuMath.cs index c2a5c97..0f4b167 100644 --- a/PerfectNumbers.Core/Gpu/NttGpuMath.cs +++ b/PerfectNumbers.Core/Gpu/NttGpuMath.cs @@ -504,8 +504,7 @@ public static class NttGpuMath { int n = values.Length; int bits = (int)Math.Log2(n); - var gpu = GpuContextPool.Rent(); - var accelerator = gpu.Accelerator; + var accelerator = SharedGpuContext.Accelerator; var kernel = GetBitReverseKernel(accelerator); var pool = ThreadStaticPools.GpuUInt128Pool; var array = pool.Rent(n); @@ -520,7 +519,6 @@ public static class NttGpuMath pool.Return(array, clearArray: true); buffer.Dispose(); stream.Dispose(); - gpu.Dispose(); } @@ -568,8 +566,7 @@ public static class NttGpuMath private static void ForwardGpuReference(Span values, GpuUInt128 modulus, GpuUInt128 primitiveRoot) { int n = (int)values.Length; - var gpu = GpuContextPool.Rent(); - var accelerator = gpu.Accelerator; + var accelerator = SharedGpuContext.Accelerator; var stream = accelerator.CreateStream(); var kernel = GetForwardKernel(accelerator); var pool = ThreadStaticPools.GpuUInt128Pool; @@ -592,8 +589,6 @@ public static class NttGpuMath outputBuffer.Dispose(); inputBuffer.Dispose(); stream.Dispose(); - gpu.Dispose(); - } public static void Inverse(Span values, GpuUInt128 modulus, GpuUInt128 primitiveRoot) @@ -667,8 +662,7 @@ public static class NttGpuMath private static void InverseGpuReference(Span values, GpuUInt128 modulus, GpuUInt128 primitiveRoot) { int n = values.Length; - var gpu = GpuContextPool.Rent(); - var accelerator = gpu.Accelerator; + var accelerator = SharedGpuContext.Accelerator; var stream = accelerator.CreateStream(); var kernel = GetInverseKernel(accelerator); var pool = ThreadStaticPools.GpuUInt128Pool; @@ -710,15 +704,12 @@ public static class NttGpuMath outputBuffer.Dispose(); inputBuffer.Dispose(); stream.Dispose(); - gpu.Dispose(); - } private static void ForwardGpuStaged(Span values, GpuUInt128 modulus, GpuUInt128 primitiveRoot) { int n = values.Length; - var gpu = GpuContextPool.Rent(); - var accelerator = gpu.Accelerator; + var accelerator = SharedGpuContext.Accelerator; var stream = accelerator.CreateStream(); var buffer = accelerator.Allocate1D(n); buffer.View.CopyFromCPU(stream, ref values[0], n); @@ -728,15 +719,12 @@ public static class NttGpuMath stream.Synchronize(); stream.Dispose(); buffer.Dispose(); - gpu.Dispose(); - } private static void InverseGpuStaged(Span values, GpuUInt128 modulus, GpuUInt128 primitiveRoot) { int n = values.Length; - var gpu = GpuContextPool.Rent(); - var accelerator = gpu.Accelerator; + var accelerator = SharedGpuContext.Accelerator; var stream = accelerator.CreateStream(); var buffer = accelerator.Allocate1D(n); buffer.View.CopyFromCPU(stream, ref values[0], n); @@ -746,8 +734,6 @@ public static class NttGpuMath stream.Synchronize(); stream.Dispose(); buffer.Dispose(); - gpu.Dispose(); - } private static void ForwardDevice(Accelerator accelerator, AcceleratorStream stream, ArrayView data, int length, GpuUInt128 modulus, SquareCacheEntry cache) @@ -939,8 +925,7 @@ public static class NttGpuMath public static void PointwiseMultiply(Span left, Span right, GpuUInt128 modulus) { - var gpu = GpuContextPool.Rent(); - var accelerator = gpu.Accelerator; + var accelerator = SharedGpuContext.Accelerator; var stream = accelerator.CreateStream(); var kernel = GetMulKernel(accelerator); var pool = ThreadStaticPools.GpuUInt128Pool; @@ -963,8 +948,6 @@ public static class NttGpuMath rightBuffer.Dispose(); leftBuffer.Dispose(); stream.Dispose(); - gpu.Dispose(); - } private static ulong[] GenerateSmallPrimes(int limit) diff --git a/PerfectNumbers.Core/Gpu/PrimeOrderGpuHeuristics.cs b/PerfectNumbers.Core/Gpu/PrimeOrderGpuHeuristics.cs index 682c8a9..4c004f8 100644 --- a/PerfectNumbers.Core/Gpu/PrimeOrderGpuHeuristics.cs +++ b/PerfectNumbers.Core/Gpu/PrimeOrderGpuHeuristics.cs @@ -199,7 +199,7 @@ internal static partial class PrimeOrderGpuHeuristics try { var lease = GpuKernelPool.Rent(); - Accelerator accelerator = lease.Accelerator; + Accelerator accelerator = SharedGpuContext.Accelerator; AcceleratorStream stream = lease.Stream; var kernel = GetPartialFactorKernel(accelerator); @@ -366,7 +366,7 @@ internal static partial class PrimeOrderGpuHeuristics order = 0UL; var lease = GpuKernelPool.Rent(); - Accelerator accelerator = lease.Accelerator; + Accelerator accelerator = SharedGpuContext.Accelerator; AcceleratorStream stream = lease.Stream; var kernel = GetOrderKernel(accelerator); @@ -527,7 +527,7 @@ internal static partial class PrimeOrderGpuHeuristics private static bool TryComputeOnGpu(ReadOnlySpan exponents, ulong prime, in MontgomeryDivisorData divisorData, Span results) { var lease = GpuKernelPool.Rent(); - Accelerator accelerator = lease.Accelerator; + Accelerator accelerator = SharedGpuContext.Accelerator; AcceleratorStream stream = lease.Stream; var kernel = GetPow2ModKernel(accelerator); // 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 { - Accelerator accelerator = lease.Accelerator; + Accelerator accelerator = SharedGpuContext.Accelerator; AcceleratorStream stream = lease.Stream; var kernel = GetPow2ModWideKernel(accelerator); // TODO: These buffers should be allocated once per accelerator and only reallocated when the new length exceeds capacity. diff --git a/PerfectNumbers.Core/Gpu/SmallPrimeFactorViews.cs b/PerfectNumbers.Core/Gpu/SmallPrimeFactorViews.cs index 0fb1765..7fb62ba 100644 --- a/PerfectNumbers.Core/Gpu/SmallPrimeFactorViews.cs +++ b/PerfectNumbers.Core/Gpu/SmallPrimeFactorViews.cs @@ -6,12 +6,11 @@ namespace PerfectNumbers.Core.Gpu; public readonly struct SmallPrimeFactorViews( MemoryBuffer1D primes, - MemoryBuffer1D squares, - int count) + MemoryBuffer1D squares) { public readonly MemoryBuffer1D Primes = primes; public readonly MemoryBuffer1D Squares = squares; - public readonly int Count = count; + public readonly int Count = (int)primes.Length; public ArrayView1D PrimesView { diff --git a/PerfectNumbers.Core/MersenneDivisorCycles.cs b/PerfectNumbers.Core/MersenneDivisorCycles.cs index cc0f29c..b21b8c4 100644 --- a/PerfectNumbers.Core/MersenneDivisorCycles.cs +++ b/PerfectNumbers.Core/MersenneDivisorCycles.cs @@ -805,7 +805,7 @@ public class MersenneDivisorCycles divisors = pool.Rent(count); outCycles = pool.Rent(count); var lease = GpuKernelPool.Rent(); - var accelerator = lease.Accelerator; + var accelerator = SharedGpuContext.Accelerator; var stream = lease.Stream; var loaded = accelerator.LoadAutoGroupedStreamKernel< Index1D, diff --git a/PerfectNumbers.Core/MersenneNumberTester.cs b/PerfectNumbers.Core/MersenneNumberTester.cs index 43af29e..45616b1 100644 --- a/PerfectNumbers.Core/MersenneNumberTester.cs +++ b/PerfectNumbers.Core/MersenneNumberTester.cs @@ -148,7 +148,7 @@ public sealed class MersenneNumberTester( UInt128[] qs = qsBuffer; var gpuLease = GpuKernelPool.Rent(); - var accelerator = gpuLease.Accelerator; + var accelerator = SharedGpuContext.Accelerator; var stream = gpuLease.Stream; var orderKernel = gpuLease.OrderKernel!; diff --git a/PerfectNumbers.Core/PrimeOrderCalculator.Gpu.cs b/PerfectNumbers.Core/PrimeOrderCalculator.Gpu.cs index 7e3057f..cb496b0 100644 --- a/PerfectNumbers.Core/PrimeOrderCalculator.Gpu.cs +++ b/PerfectNumbers.Core/PrimeOrderCalculator.Gpu.cs @@ -20,13 +20,13 @@ internal static partial class PrimeOrderCalculator remaining = value; var lease = GpuKernelPool.Rent(); - Accelerator accelerator = lease.Accelerator; + Accelerator accelerator = SharedGpuContext.Accelerator; var stream = lease.Stream; KernelContainer kernels = lease.Kernels; 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.SmallPrimeFactorsSquares is null) throw new NullReferenceException($"{nameof(kernels.SmallPrimeFactorsSquares)} is null"); @@ -101,7 +101,7 @@ internal static partial class PrimeOrderCalculator } GpuKernelLease lease = GpuKernelPool.Rent(); - Accelerator accelerator = lease.Accelerator; + Accelerator accelerator = SharedGpuContext.Accelerator; var stream = lease.Stream; diff --git a/PerfectNumbers.Core/PrimeTester.cs b/PerfectNumbers.Core/PrimeTester.cs index 895f9f2..3b49dcb 100644 --- a/PerfectNumbers.Core/PrimeTester.cs +++ b/PerfectNumbers.Core/PrimeTester.cs @@ -273,7 +273,7 @@ public sealed class PrimeTester Accelerator accelerator = SharedGpuContext.Accelerator; AcceleratorStream stream = accelerator.CreateStream(); - KernelContainer kernels = GpuKernelPool.GetKernels(accelerator, stream); + KernelContainer kernels = GpuKernelPool.Kernels; GpuStaticTableInitializer.EnsureStaticTables(kernels, accelerator, stream); @@ -433,7 +433,7 @@ public sealed class PrimeTester AcceleratorContext = SharedGpuContext.Context; Accelerator = SharedGpuContext.Accelerator; AcceleratorStream stream = SharedGpuContext.Accelerator.CreateStream(); - var kernels = GpuKernelPool.GetKernels(Accelerator, stream); + var kernels = GpuKernelPool.Kernels; GpuStaticTableInitializer.EnsureStaticTables(kernels, Accelerator, stream); _sharedTables = RentSharedTables(Accelerator, stream); diff --git a/PerfectNumbers.Core/ULongExtensions.Gpu.cs b/PerfectNumbers.Core/ULongExtensions.Gpu.cs index 3ec6872..d195b52 100644 --- a/PerfectNumbers.Core/ULongExtensions.Gpu.cs +++ b/PerfectNumbers.Core/ULongExtensions.Gpu.cs @@ -463,7 +463,7 @@ public static partial class ULongExtensions GpuKernelLease lease = GpuKernelPool.Rent(); - Accelerator accelerator = lease.Accelerator; + Accelerator accelerator = SharedGpuContext.Accelerator; AcceleratorStream stream = lease.Stream; var kernelGroup = Kernel;