diff --git a/EvenPerfectBitScanner.Tests/ProgramTests.cs b/EvenPerfectBitScanner.Tests/ProgramTests.cs index cf16bdb..9be802b 100644 --- a/EvenPerfectBitScanner.Tests/ProgramTests.cs +++ b/EvenPerfectBitScanner.Tests/ProgramTests.cs @@ -102,13 +102,11 @@ public class ProgramTests var testerField = typeof(Program).GetField("_divisorTester", BindingFlags.NonPublic | BindingFlags.Static)!; var candidatesField = typeof(MersenneNumberDivisorGpuTester).GetField("_divisorCandidates", BindingFlags.NonPublic | BindingFlags.Static)!; var primeField = typeof(Program).GetField("PrimeTesters", BindingFlags.NonPublic | BindingFlags.Static)!; - var forceCpuProp = typeof(GpuContextPool).GetProperty("ForceCpu"); testerField.SetValue(null, new MersenneNumberDivisorGpuTester()); primeField.SetValue(null, new ThreadLocal(() => new PrimeTester(), trackAllValues: true)); CandidatesCalculator.OverrideResidueTrackers(new ThreadLocal(() => new ModResidueTracker(ResidueModel.Identity, 2UL, true), trackAllValues: true)); candidatesField.SetValue(null, new (ulong, uint)[] { (7UL, 3U), (23UL, 11U) }); - forceCpuProp!.SetValue(null, true); try { @@ -122,7 +120,6 @@ public class ProgramTests candidatesField.SetValue(null, null); primeField.SetValue(null, null); CandidatesCalculator.ResetResidueTrackers(); - forceCpuProp!.SetValue(null, false); ResetCliArguments(); } } @@ -135,13 +132,11 @@ public class ProgramTests var testerField = typeof(Program).GetField("_divisorTester", BindingFlags.NonPublic | BindingFlags.Static)!; var candidatesField = typeof(MersenneNumberDivisorGpuTester).GetField("_divisorCandidates", BindingFlags.NonPublic | BindingFlags.Static)!; var primeField = typeof(Program).GetField("PrimeTesters", BindingFlags.NonPublic | BindingFlags.Static)!; - var forceCpuProp = typeof(GpuContextPool).GetProperty("ForceCpu"); testerField.SetValue(null, new MersenneNumberDivisorGpuTester()); primeField.SetValue(null, new ThreadLocal(() => new PrimeTester(), trackAllValues: true)); CandidatesCalculator.OverrideResidueTrackers(new ThreadLocal(() => new ModResidueTracker(ResidueModel.Identity, 2UL, true), trackAllValues: true)); candidatesField.SetValue(null, Array.Empty<(ulong, uint)>()); - forceCpuProp!.SetValue(null, true); try { @@ -155,7 +150,6 @@ public class ProgramTests candidatesField.SetValue(null, null); primeField.SetValue(null, null); CandidatesCalculator.ResetResidueTrackers(); - forceCpuProp!.SetValue(null, false); ResetCliArguments(); } } @@ -168,12 +162,10 @@ public class ProgramTests var testerField = typeof(Program).GetField("_divisorTester", BindingFlags.NonPublic | BindingFlags.Static)!; var primeField = typeof(Program).GetField("PrimeTesters", BindingFlags.NonPublic | BindingFlags.Static)!; - var forceCpuProp = typeof(GpuContextPool).GetProperty("ForceCpu"); testerField.SetValue(null, new MersenneNumberDivisorGpuTester()); primeField.SetValue(null, new ThreadLocal(() => new PrimeTester(), trackAllValues: true)); CandidatesCalculator.OverrideResidueTrackers(new ThreadLocal(() => new ModResidueTracker(ResidueModel.Identity, 2UL, true), trackAllValues: true)); - forceCpuProp!.SetValue(null, true); try { @@ -186,7 +178,6 @@ public class ProgramTests testerField.SetValue(null, null); primeField.SetValue(null, null); CandidatesCalculator.ResetResidueTrackers(); - forceCpuProp!.SetValue(null, false); ResetCliArguments(); } } @@ -199,12 +190,10 @@ public class ProgramTests var testerField = typeof(Program).GetField("_divisorTester", BindingFlags.NonPublic | BindingFlags.Static)!; var primeField = typeof(Program).GetField("PrimeTesters", BindingFlags.NonPublic | BindingFlags.Static)!; - var forceCpuProp = typeof(GpuContextPool).GetProperty("ForceCpu"); testerField.SetValue(null, new MersenneNumberDivisorGpuTester()); primeField.SetValue(null, new ThreadLocal(() => new PrimeTester(), trackAllValues: true)); CandidatesCalculator.OverrideResidueTrackers(new ThreadLocal(() => new ModResidueTracker(ResidueModel.Identity, 2UL, true), trackAllValues: true)); - forceCpuProp!.SetValue(null, false); try { @@ -221,7 +210,6 @@ public class ProgramTests testerField.SetValue(null, null); primeField.SetValue(null, null); CandidatesCalculator.ResetResidueTrackers(); - forceCpuProp!.SetValue(null, false); ResetCliArguments(); } } @@ -233,12 +221,10 @@ public class ProgramTests var mersenneField = typeof(Program).GetField("MersenneTesters", BindingFlags.NonPublic | BindingFlags.Static)!; var primeField = typeof(Program).GetField("PrimeTesters", BindingFlags.NonPublic | BindingFlags.Static)!; - var forceCpuProp = typeof(GpuContextPool).GetProperty("ForceCpu"); mersenneField.SetValue(null, new ThreadLocal(() => new MersenneNumberTester(useIncremental: true, useResidue: true, maxK: 1_000UL), trackAllValues: true)); primeField.SetValue(null, new ThreadLocal(() => new PrimeTester(), trackAllValues: true)); CandidatesCalculator.OverrideResidueTrackers(new ThreadLocal(() => new ModResidueTracker(ResidueModel.Identity, 2UL, true), trackAllValues: true)); - forceCpuProp!.SetValue(null, false); try { @@ -255,7 +241,6 @@ public class ProgramTests mersenneField.SetValue(null, null); primeField.SetValue(null, null); CandidatesCalculator.ResetResidueTrackers(); - forceCpuProp!.SetValue(null, false); ResetCliArguments(); } } @@ -267,7 +252,6 @@ public class ProgramTests var mersenneField = typeof(Program).GetField("MersenneTesters", BindingFlags.NonPublic | BindingFlags.Static)!; var primeField = typeof(Program).GetField("PrimeTesters", BindingFlags.NonPublic | BindingFlags.Static)!; - var forceCpuProp = typeof(GpuContextPool).GetProperty("ForceCpu"); mersenneField.SetValue(null, new ThreadLocal(() => new MersenneNumberTester( useIncremental: true, @@ -275,7 +259,6 @@ public class ProgramTests maxK: 1_024UL), trackAllValues: true)); primeField.SetValue(null, new ThreadLocal(() => new PrimeTester(), trackAllValues: true)); CandidatesCalculator.OverrideResidueTrackers(new ThreadLocal(() => new ModResidueTracker(ResidueModel.Identity, 2UL, true), trackAllValues: true)); - forceCpuProp!.SetValue(null, false); try { @@ -292,7 +275,6 @@ public class ProgramTests mersenneField.SetValue(null, null); primeField.SetValue(null, null); CandidatesCalculator.ResetResidueTrackers(); - forceCpuProp!.SetValue(null, false); ResetCliArguments(); } } @@ -305,7 +287,6 @@ public class ProgramTests var mersenneField = typeof(Program).GetField("MersenneTesters", BindingFlags.NonPublic | BindingFlags.Static)!; var primeField = typeof(Program).GetField("PrimeTesters", BindingFlags.NonPublic | BindingFlags.Static)!; - var forceCpuProp = typeof(GpuContextPool).GetProperty("ForceCpu"); mersenneField.SetValue(null, new ThreadLocal(() => new MersenneNumberTester( useIncremental: true, @@ -313,7 +294,6 @@ public class ProgramTests maxK: 5_000_000UL), trackAllValues: true)); primeField.SetValue(null, new ThreadLocal(() => new PrimeTester(), trackAllValues: true)); CandidatesCalculator.OverrideResidueTrackers(new ThreadLocal(() => new ModResidueTracker(ResidueModel.Identity, 2UL, true), trackAllValues: true)); - forceCpuProp!.SetValue(null, false); try { @@ -330,7 +310,6 @@ public class ProgramTests mersenneField.SetValue(null, null); primeField.SetValue(null, null); CandidatesCalculator.ResetResidueTrackers(); - forceCpuProp!.SetValue(null, false); ResetCliArguments(); } } @@ -342,7 +321,6 @@ public class ProgramTests var mersenneField = typeof(Program).GetField("MersenneTesters", BindingFlags.NonPublic | BindingFlags.Static)!; var primeField = typeof(Program).GetField("PrimeTesters", BindingFlags.NonPublic | BindingFlags.Static)!; - var forceCpuProp = typeof(GpuContextPool).GetProperty("ForceCpu"); mersenneField.SetValue(null, new ThreadLocal(() => new MersenneNumberTester( useIncremental: true, @@ -350,7 +328,6 @@ public class ProgramTests maxK: 5_000_000UL), trackAllValues: true)); primeField.SetValue(null, new ThreadLocal(() => new PrimeTester(), trackAllValues: true)); CandidatesCalculator.OverrideResidueTrackers(new ThreadLocal(() => new ModResidueTracker(ResidueModel.Identity, 2UL, true), trackAllValues: true)); - forceCpuProp!.SetValue(null, false); try { @@ -367,7 +344,6 @@ public class ProgramTests mersenneField.SetValue(null, null); primeField.SetValue(null, null); CandidatesCalculator.ResetResidueTrackers(); - forceCpuProp!.SetValue(null, false); ResetCliArguments(); } } @@ -380,7 +356,6 @@ public class ProgramTests var mersenneField = typeof(Program).GetField("MersenneTesters", BindingFlags.NonPublic | BindingFlags.Static)!; var primeField = typeof(Program).GetField("PrimeTesters", BindingFlags.NonPublic | BindingFlags.Static)!; - var forceCpuProp = typeof(GpuContextPool).GetProperty("ForceCpu"); mersenneField.SetValue(null, new ThreadLocal(() => new MersenneNumberTester( useIncremental: true, @@ -390,7 +365,6 @@ public class ProgramTests maxK: 1_024UL), trackAllValues: true)); primeField.SetValue(null, new ThreadLocal(() => new PrimeTester(), trackAllValues: true)); CandidatesCalculator.OverrideResidueTrackers(new ThreadLocal(() => new ModResidueTracker(ResidueModel.Identity, exponent, true), trackAllValues: true)); - forceCpuProp!.SetValue(null, true); try { @@ -402,7 +376,6 @@ public class ProgramTests mersenneField.SetValue(null, null); primeField.SetValue(null, null); CandidatesCalculator.ResetResidueTrackers(); - forceCpuProp!.SetValue(null, false); ResetCliArguments(); } } @@ -417,7 +390,6 @@ public class ProgramTests var mersenneField = typeof(Program).GetField("MersenneTesters", BindingFlags.NonPublic | BindingFlags.Static)!; var primeField = typeof(Program).GetField("PrimeTesters", BindingFlags.NonPublic | BindingFlags.Static)!; - var forceCpuProp = typeof(GpuContextPool).GetProperty("ForceCpu"); mersenneField.SetValue(null, new ThreadLocal(() => new MersenneNumberTester( useIncremental: false, @@ -428,7 +400,6 @@ public class ProgramTests maxK: configuration.ResidueMaxK), trackAllValues: true)); primeField.SetValue(null, new ThreadLocal(() => new PrimeTester(), trackAllValues: true)); CandidatesCalculator.OverrideResidueTrackers(new ThreadLocal(() => new ModResidueTracker(ResidueModel.Identity, exponent, true), trackAllValues: true)); - forceCpuProp!.SetValue(null, false); try { @@ -440,9 +411,7 @@ public class ProgramTests mersenneField.SetValue(null, null); primeField.SetValue(null, null); CandidatesCalculator.ResetResidueTrackers(); - forceCpuProp!.SetValue(null, false); ResetCliArguments(); - GpuContextPool.DisposeAll(); } } @@ -506,12 +475,10 @@ public class ProgramTests var mersenneField = typeof(Program).GetField("MersenneTesters", BindingFlags.NonPublic | BindingFlags.Static)!; var primeField = typeof(Program).GetField("PrimeTesters", BindingFlags.NonPublic | BindingFlags.Static)!; var compositeField = typeof(Program).GetField("_lastCompositeP", BindingFlags.NonPublic | BindingFlags.Static)!; - var forceCpuProp = typeof(GpuContextPool).GetProperty("ForceCpu"); mersenneField.SetValue(null, new ThreadLocal(() => new MersenneNumberTester(useIncremental: true, useResidue: false, maxK: 1_000UL), trackAllValues: true)); primeField.SetValue(null, new ThreadLocal(() => new PrimeTester(), trackAllValues: true)); CandidatesCalculator.OverrideResidueTrackers(new ThreadLocal(() => new ModResidueTracker(ResidueModel.Identity, 2UL, true), trackAllValues: true)); - forceCpuProp!.SetValue(null, true); try { @@ -532,7 +499,6 @@ public class ProgramTests primeField.SetValue(null, null); CandidatesCalculator.ResetResidueTrackers(); compositeField.SetValue(null, false); - forceCpuProp!.SetValue(null, false); ResetCliArguments(); } } diff --git a/EvenPerfectBitScanner/Program.cs b/EvenPerfectBitScanner/Program.cs index 5240b52..26a5b9d 100644 --- a/EvenPerfectBitScanner/Program.cs +++ b/EvenPerfectBitScanner/Program.cs @@ -62,7 +62,6 @@ internal static class Program UnboundedTaskScheduler.ConfigureThreadCount(threadCount); PrimeTester.GpuBatchSize = gpuPrimeBatch; GpuPrimeWorkLimiter.SetLimit(gpuPrimeThreads); - GpuContextPool.WarmUpPool(threadCount); PrimeTester.WarmUpGpuKernels(gpuPrimeThreads); GpuScratchBufferPool.WarmUp(gpuPrimeThreads << 4, 64, 1024); Console.WriteLine("Starting up threads..."); diff --git a/PerfectNumbers.Core.Tests/Gpu/GpuKernelCompilationTests.cs b/PerfectNumbers.Core.Tests/Gpu/GpuKernelCompilationTests.cs index df1c528..0f94715 100644 --- a/PerfectNumbers.Core.Tests/Gpu/GpuKernelCompilationTests.cs +++ b/PerfectNumbers.Core.Tests/Gpu/GpuKernelCompilationTests.cs @@ -352,11 +352,11 @@ public class GpuKernelCompilationTests var lease = GpuKernelPool.Rent(); try { - _ = lease.OrderKernel; - _ = lease.IncrementalKernel; - _ = lease.Pow2ModKernel; - _ = lease.IncrementalOrderKernel; - _ = lease.Pow2ModOrderKernel; + _ = GpuKernelLease.OrderKernel; + _ = GpuKernelLease.IncrementalKernel; + _ = GpuKernelLease.Pow2ModKernel; + _ = GpuKernelLease.IncrementalOrderKernel; + _ = GpuKernelLease.Pow2ModOrderKernel; } finally { @@ -366,11 +366,11 @@ public class GpuKernelCompilationTests var orderLease = GpuKernelPool.Rent(); try { - _ = orderLease.OrderKernel; - _ = orderLease.IncrementalKernel; - _ = orderLease.Pow2ModKernel; - _ = orderLease.IncrementalOrderKernel; - _ = orderLease.Pow2ModOrderKernel; + _ = GpuKernelLease.OrderKernel; + _ = GpuKernelLease.IncrementalKernel; + _ = GpuKernelLease.Pow2ModKernel; + _ = GpuKernelLease.IncrementalOrderKernel; + _ = GpuKernelLease.Pow2ModOrderKernel; } finally { diff --git a/PerfectNumbers.Core.Tests/Gpu/NttGpuMathTests.cs b/PerfectNumbers.Core.Tests/Gpu/NttGpuMathTests.cs index a8b4ae4..3e83968 100644 --- a/PerfectNumbers.Core.Tests/Gpu/NttGpuMathTests.cs +++ b/PerfectNumbers.Core.Tests/Gpu/NttGpuMathTests.cs @@ -150,39 +150,31 @@ public class NttGpuMathTests var modulus = new GpuUInt128(0UL, 17UL); var primitiveRoot = new GpuUInt128(0UL, 3UL); - GpuContextLease gpu = GpuContextPool.Rent(); - try + var accelerator = SharedGpuContext.Accelerator; + var stream = accelerator.CreateStream(); + + var method = typeof(NttGpuMath).GetMethod("GetSquareCache", BindingFlags.NonPublic | BindingFlags.Static); + method.Should().NotBeNull(); + var cache = method!.Invoke(null, new object[] { accelerator, 8, modulus, primitiveRoot })!; + var cacheType = cache.GetType(); + + var twiddlesMont = (MemoryBuffer1D)cacheType.GetProperty("TwiddlesMont")!.GetValue(cache)!; + var twiddlesInvMont = (MemoryBuffer1D)cacheType.GetProperty("TwiddlesInvMont")!.GetValue(cache)!; + var r2 = (ulong)cacheType.GetProperty("MontR2Mod64")!.GetValue(cache)!; + var mod = (ulong)cacheType.GetProperty("ModulusLow")!.GetValue(cache)!; + + int count = 7; // length 8 -> 7 twiddles + var forward = new GpuUInt128[count]; + var inverse = new GpuUInt128[count]; + twiddlesMont.CopyToCPU(stream, forward); + twiddlesInvMont.CopyToCPU(stream, inverse); + stream.Synchronize(); + stream.Dispose(); + + for (int i = 0; i < count; i++) { - var accelerator = gpu.Accelerator; - var stream = accelerator.CreateStream(); - - var method = typeof(NttGpuMath).GetMethod("GetSquareCache", BindingFlags.NonPublic | BindingFlags.Static); - method.Should().NotBeNull(); - var cache = method!.Invoke(null, new object[] { accelerator, 8, modulus, primitiveRoot })!; - var cacheType = cache.GetType(); - - var twiddlesMont = (MemoryBuffer1D)cacheType.GetProperty("TwiddlesMont")!.GetValue(cache)!; - var twiddlesInvMont = (MemoryBuffer1D)cacheType.GetProperty("TwiddlesInvMont")!.GetValue(cache)!; - var r2 = (ulong)cacheType.GetProperty("MontR2Mod64")!.GetValue(cache)!; - var mod = (ulong)cacheType.GetProperty("ModulusLow")!.GetValue(cache)!; - - int count = 7; // length 8 -> 7 twiddles - var forward = new GpuUInt128[count]; - var inverse = new GpuUInt128[count]; - twiddlesMont.CopyToCPU(stream, forward); - twiddlesInvMont.CopyToCPU(stream, inverse); - stream.Synchronize(); - stream.Dispose(); - - for (int i = 0; i < count; i++) - { - ulong prod = (ulong)((((BigInteger)forward[i].Low) * inverse[i].Low) % mod); - prod.Should().Be(r2); - } - } - finally - { - gpu.Dispose(); + ulong prod = (ulong)((((BigInteger)forward[i].Low) * inverse[i].Low) % mod); + prod.Should().Be(r2); } } @@ -348,15 +340,14 @@ public class NttGpuMathTests values[1] = new GpuUInt128(0UL, 2UL); var modulus = new GpuUInt128(0UL, 17UL); var primitiveRoot = new GpuUInt128(0UL, 3UL); - GpuContextLease gpu = GpuContextPool.Rent(); - var stream = gpu.Accelerator.CreateStream(); - var buffer = gpu.Accelerator.Allocate1D(values.Length); + Accelerator accelerator = SharedGpuContext.Accelerator; + var stream = accelerator.CreateStream(); + var buffer = accelerator.Allocate1D(values.Length); buffer.View.CopyFromCPU(stream, ref values[0], values.Length); - NttGpuMath.SquareDevice(gpu.Accelerator, stream, buffer.View, modulus, primitiveRoot); + NttGpuMath.SquareDevice(accelerator, stream, buffer.View, modulus, primitiveRoot); stream.Synchronize(); - buffer.Dispose(); stream.Dispose(); - gpu.Dispose(); + buffer.Dispose(); // Verify that the square cache now holds entries for the accelerator. var field = typeof(NttGpuMath).GetField("SquareCache", BindingFlags.NonPublic | BindingFlags.Static)!; @@ -364,8 +355,6 @@ public class NttGpuMathTests int count = (int)cacheObj.GetType().GetProperty("Count")!.GetValue(cacheObj)!; count.Should().BeGreaterThan(0); - GpuContextPool.DisposeAll(); - count = (int)cacheObj.GetType().GetProperty("Count")!.GetValue(cacheObj)!; count.Should().Be(0); } diff --git a/PerfectNumbers.Core.Tests/Gpu/NttMontgomeryTests.cs b/PerfectNumbers.Core.Tests/Gpu/NttMontgomeryTests.cs index 5a1ec02..2348296 100644 --- a/PerfectNumbers.Core.Tests/Gpu/NttMontgomeryTests.cs +++ b/PerfectNumbers.Core.Tests/Gpu/NttMontgomeryTests.cs @@ -33,8 +33,7 @@ public class NttMontgomeryTests NttGpuMath.Square(cpu, modulus, primitiveRoot); // Device execution - GpuContextLease context = GpuContextPool.Rent(); - var accelerator = context.Accelerator; + var accelerator = SharedGpuContext.Accelerator; var stream = accelerator.CreateStream(); using var buffer = accelerator.Allocate1D(gpu.Length); buffer.View.CopyFromCPU(stream, ref gpu[0], gpu.Length); @@ -48,7 +47,6 @@ public class NttMontgomeryTests } stream.Dispose(); - context.Dispose(); } [Fact] diff --git a/PerfectNumbers.Core.Tests/Gpu/PrimeTesterGpuTests.cs b/PerfectNumbers.Core.Tests/Gpu/PrimeTesterGpuTests.cs index 8f6ed46..19a9984 100644 --- a/PerfectNumbers.Core.Tests/Gpu/PrimeTesterGpuTests.cs +++ b/PerfectNumbers.Core.Tests/Gpu/PrimeTesterGpuTests.cs @@ -10,37 +10,23 @@ public class PrimeTesterGpuTests [Fact] public void IsPrimeGpu_accepts_known_primes() { - try - { - var tester = new PrimeTester(); - ulong[] primes = [31UL, 61UL, 89UL, 107UL, 127UL, 521UL]; - foreach (ulong prime in primes) - { - PrimeTester.IsPrimeGpu(prime).Should().BeTrue(); - } - } - finally - { - GpuContextPool.DisposeAll(); - } + var tester = new PrimeTester(); + ulong[] primes = [31UL, 61UL, 89UL, 107UL, 127UL, 521UL]; + foreach (ulong prime in primes) + { + PrimeTester.IsPrimeGpu(prime).Should().BeTrue(); + } } [Fact] public void IsPrimeGpu_rejects_composites() { - try - { - var tester = new PrimeTester(); - ulong[] composites = [33UL, 39UL, 51UL, 77UL, 91UL]; - foreach (ulong composite in composites) - { - PrimeTester.IsPrimeGpu(composite).Should().BeFalse(); - } - } - finally - { - GpuContextPool.DisposeAll(); - } + var tester = new PrimeTester(); + ulong[] composites = [33UL, 39UL, 51UL, 77UL, 91UL]; + foreach (ulong composite in composites) + { + PrimeTester.IsPrimeGpu(composite).Should().BeFalse(); + } } } diff --git a/PerfectNumbers.Core.Tests/MersenneNumberDivisorGpuTesterTests.cs b/PerfectNumbers.Core.Tests/MersenneNumberDivisorGpuTesterTests.cs index 44d820c..2ec1744 100644 --- a/PerfectNumbers.Core.Tests/MersenneNumberDivisorGpuTesterTests.cs +++ b/PerfectNumbers.Core.Tests/MersenneNumberDivisorGpuTesterTests.cs @@ -317,7 +317,6 @@ public class MersenneNumberDivisorGpuTesterTests tableField.SetValue(cycles, originalTable); smallCyclesField.SetValue(cycles, originalSmall); DivisorCycleCache.Shared.RefreshSnapshot(); - GpuContextPool.DisposeAll(); } } diff --git a/PerfectNumbers.Core.Tests/MersenneNumberOrderGpuTesterTests.cs b/PerfectNumbers.Core.Tests/MersenneNumberOrderGpuTesterTests.cs index 2063482..108a218 100644 --- a/PerfectNumbers.Core.Tests/MersenneNumberOrderGpuTesterTests.cs +++ b/PerfectNumbers.Core.Tests/MersenneNumberOrderGpuTesterTests.cs @@ -55,7 +55,6 @@ public class MersenneNumberOrderGpuTesterTests ulong[]? backupSmall = originalSmall is null ? null : (ulong[])originalSmall.Clone(); cycles.LoadFrom(tempPath); - GpuContextPool.DisposeAll(); try { @@ -75,7 +74,6 @@ public class MersenneNumberOrderGpuTesterTests { tableField.SetValue(cycles, originalTable); smallCyclesField.SetValue(cycles, backupSmall); - GpuContextPool.DisposeAll(); } } finally diff --git a/PerfectNumbers.Core/DivisorCycleCache.cs b/PerfectNumbers.Core/DivisorCycleCache.cs index a701b2c..4b3abc4 100644 --- a/PerfectNumbers.Core/DivisorCycleCache.cs +++ b/PerfectNumbers.Core/DivisorCycleCache.cs @@ -270,7 +270,7 @@ public sealed class DivisorCycleCache var gpuLease = GpuKernelPool.Rent(); Accelerator accelerator = SharedGpuContext.Accelerator; - var stream = gpuLease.Stream; + var stream = accelerator.CreateStream(); var kernel = _gpuKernel; EnsureCapacity(length); @@ -338,6 +338,7 @@ public sealed class DivisorCycleCache resultBuffer.View.CopyToCPU(stream, ref MemoryMarshal.GetReference(resultSpan), length); stream.Synchronize(); + stream.Dispose(); resultSpan.CopyTo(destination); if (rentedPow is not null) diff --git a/PerfectNumbers.Core/Gpu/GpuKernelLease.cs b/PerfectNumbers.Core/Gpu/GpuKernelLease.cs index a21c745..a66dc5b 100644 --- a/PerfectNumbers.Core/Gpu/GpuKernelLease.cs +++ b/PerfectNumbers.Core/Gpu/GpuKernelLease.cs @@ -8,122 +8,32 @@ public sealed class GpuKernelLease { private static readonly ConcurrentQueue Pool = new(); - public KernelContainer Kernels; - public AcceleratorStream Stream; - -#pragma warning disable CS8618 // _gpu and Stream will be set by Rent method - private GpuKernelLease(KernelContainer kernels) -#pragma warning restore CS8618 - { - Kernels = kernels; - } - - internal static GpuKernelLease Rent(AcceleratorStream stream, KernelContainer kernels) + internal static GpuKernelLease Rent() { if (!Pool.TryDequeue(out var lease)) { - lease = new GpuKernelLease(kernels); + lease = new GpuKernelLease(); } - lease.Kernels = kernels; - lease.Stream = stream; return lease; } - 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 static readonly Action, ArrayView> OrderKernel = GpuKernelPool.Kernels.Order!; - 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 static readonly Action, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D> Pow2ModKernel = GpuKernelPool.Kernels.Pow2Mod!; - 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 static readonly Action, ArrayView1D> IncrementalKernel = GpuKernelPool.Kernels.Incremental!; - 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 static readonly Action, ArrayView1D> IncrementalOrderKernel = GpuKernelPool.Kernels.IncrementalOrder!; - 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 static readonly Action, ArrayView1D> Pow2ModOrderKernel = GpuKernelPool.Kernels.Pow2ModOrder!; - 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 static readonly Action, int, MontgomeryDivisorData, ArrayView1D, ArrayView1D> SpecialMaxKernel = GpuKernelPool.Kernels.SpecialMax!; - 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 static readonly Action, ArrayView1D, int, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D> SmallPrimeFactorKernel = GpuKernelPool.Kernels.SmallPrimeFactor!; 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 662ff12..2ae5777 100644 --- a/PerfectNumbers.Core/Gpu/GpuKernelPool.cs +++ b/PerfectNumbers.Core/Gpu/GpuKernelPool.cs @@ -1,4 +1,3 @@ -using System.Collections.Concurrent; using ILGPU; using ILGPU.Runtime; @@ -24,6 +23,71 @@ public class GpuKernelPool var kernels = new KernelContainer(); var stream = SharedGpuContext.Accelerator.CreateStream(); PreloadStaticTables(kernels, stream); + + InitOnce(ref kernels.Order, () => + { + var loaded = SharedGpuContext.Accelerator.LoadAutoGroupedStreamKernel, ArrayView>(OrderKernels.OrderKernelScan); + + var kernel = KernelUtil.GetKernel(loaded); + + return kernel.CreateLauncherDelegate, ArrayView>>(); + }); + + 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>>(); + }); + + InitOnce(ref kernels.Incremental, () => + { + var loaded = SharedGpuContext.Accelerator.LoadAutoGroupedStreamKernel, ArrayView1D>(IncrementalKernels.IncrementalKernelScan); + + var kernel = KernelUtil.GetKernel(loaded); + + return kernel.CreateLauncherDelegate, ArrayView1D>>(); + }); + + InitOnce(ref kernels.IncrementalOrder, () => + { + var loaded = SharedGpuContext.Accelerator.LoadAutoGroupedStreamKernel, ArrayView1D>(IncrementalKernels.IncrementalOrderKernelScan); + + var kernel = KernelUtil.GetKernel(loaded); + + return kernel.CreateLauncherDelegate, ArrayView1D>>(); + }); + + InitOnce(ref kernels.Pow2ModOrder, () => + { + var loaded = SharedGpuContext.Accelerator.LoadAutoGroupedStreamKernel, ArrayView1D>(Pow2ModKernels.Pow2ModOrderKernelScan); + + var kernel = KernelUtil.GetKernel(loaded); + + return kernel.CreateLauncherDelegate, ArrayView1D>>(); + }); + + 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>>(); + }); + + 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>>(); + }); + stream.Synchronize(); stream.Dispose(); return kernels; @@ -141,7 +205,7 @@ public class GpuKernelPool { GpuPrimeWorkLimiter.Acquire(); var stream = SharedGpuContext.Accelerator.CreateStream(); - return GpuKernelLease.Rent(stream, Kernels); + return GpuKernelLease.Rent(); } /// @@ -152,8 +216,10 @@ public class GpuKernelPool { var lease = Rent(); var accelerator = SharedGpuContext.Accelerator; - var stream = lease.Stream; + var stream = accelerator.CreateStream(); action(accelerator, stream); + stream.Synchronize(); + stream.Dispose(); lease.Dispose(); } } diff --git a/PerfectNumbers.Core/Gpu/KernelContainer.cs b/PerfectNumbers.Core/Gpu/KernelContainer.cs index 6feda20..12f8c60 100644 --- a/PerfectNumbers.Core/Gpu/KernelContainer.cs +++ b/PerfectNumbers.Core/Gpu/KernelContainer.cs @@ -7,17 +7,23 @@ public sealed class KernelContainer { // Serializes first-time initialization of kernels/buffers per accelerator. public Action, ArrayView>? Order; + public Action, ArrayView1D>? Incremental; + public Action, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D>? Pow2Mod; + public Action, ArrayView1D>? IncrementalOrder; + public Action, ArrayView1D>? Pow2ModOrder; + public Action, ArrayView1D, int, ArrayView1D, ArrayView1D, ArrayView1D, ArrayView1D>? SmallPrimeFactor; + public Action, int, MontgomeryDivisorData, ArrayView1D, ArrayView1D>? SpecialMax; // Optional device buffer with small divisor cycles (<= 4M). Index = divisor, value = cycle length. diff --git a/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs b/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs index 801b3ed..f682be8 100644 --- a/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs +++ b/PerfectNumbers.Core/Gpu/MersenneNumberDivisorByDivisorGpuTester.cs @@ -97,7 +97,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv var gpuLease = GpuKernelPool.Rent(); var accelerator = SharedGpuContext.Accelerator; - var stream = gpuLease.Stream; + var stream = accelerator.CreateStream(); // Monitor.Enter(gpuLease.ExecutionLock); @@ -126,6 +126,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv out coveredRange, out processedCount); + stream.Dispose(); ReturnBatchResources(resources); // Monitor.Exit(gpuLease.ExecutionLock); gpuLease.Dispose(); @@ -502,8 +503,9 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv { _owner = owner; _lease = GpuKernelPool.Rent(); - _accelerator = SharedGpuContext.Accelerator; - _stream = _lease.Stream; + Accelerator accelerator = SharedGpuContext.Accelerator; + _accelerator = accelerator; + _stream = accelerator.CreateStream(); _capacity = Math.Max(1, owner._gpuBatchSize); } diff --git a/PerfectNumbers.Core/Gpu/MersenneNumberIncrementalGpuTester.cs b/PerfectNumbers.Core/Gpu/MersenneNumberIncrementalGpuTester.cs index f79718b..f7570d7 100644 --- a/PerfectNumbers.Core/Gpu/MersenneNumberIncrementalGpuTester.cs +++ b/PerfectNumbers.Core/Gpu/MersenneNumberIncrementalGpuTester.cs @@ -18,14 +18,14 @@ public class MersenneNumberIncrementalGpuTester(GpuKernelType kernelType, bool u var gpuLease = GpuKernelPool.Rent(); var accelerator = SharedGpuContext.Accelerator; - var stream = gpuLease.Stream; + var stream = accelerator.CreateStream(); int batchSize = GpuConstants.ScanBatchSize; // large batch improves GPU occupancy UInt128 kStart = 1UL; ulong divMul = (ulong)((((UInt128)1 << 64) - UInt128.One) / exponent) + 1UL; byte last = lastDigit == LastDigit.Seven ? (byte)1 : (byte)0; // ILGPU kernels do not support bool parameters - var pow2Kernel = gpuLease.Pow2ModKernel; - var incKernel = gpuLease.IncrementalKernel; + var pow2Kernel = GpuKernelLease.Pow2ModKernel; + var incKernel = GpuKernelLease.IncrementalKernel; ulong step10 = (exponent.Mod10() << 1).Mod10(); ulong step8 = ((exponent & 7UL) << 1) & 7UL; ulong step3 = ((exponent % 3UL) << 1) % 3UL; @@ -121,6 +121,7 @@ public class MersenneNumberIncrementalGpuTester(GpuKernelType kernelType, bool u kStart += (UInt128)currentSize; } + stream.Dispose(); ulongPool.Return(orderArray); orderBuffer.Dispose(); gpuLease.Dispose(); diff --git a/PerfectNumbers.Core/Gpu/MersenneNumberOrderGpuTester.cs b/PerfectNumbers.Core/Gpu/MersenneNumberOrderGpuTester.cs index a767aae..afe290b 100644 --- a/PerfectNumbers.Core/Gpu/MersenneNumberOrderGpuTester.cs +++ b/PerfectNumbers.Core/Gpu/MersenneNumberOrderGpuTester.cs @@ -11,7 +11,7 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO { var gpuLease = GpuKernelPool.Rent(); var accelerator = SharedGpuContext.Accelerator; - var stream = gpuLease.Stream; + var stream = accelerator.CreateStream(); int batchSize = GpuConstants.ScanBatchSize; // large batch improves GPU occupancy and avoids TDR UInt128 kStart = UInt128.One; ulong divMul = (ulong)((((UInt128)1 << 64) - UInt128.One) / exponent) + 1UL; @@ -19,8 +19,8 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO var kernel = _kernelType switch { - GpuKernelType.Pow2Mod => gpuLease.Pow2ModOrderKernel, - _ => gpuLease.IncrementalOrderKernel, + GpuKernelType.Pow2Mod => GpuKernelLease.Pow2ModOrderKernel, + _ => GpuKernelLease.IncrementalOrderKernel, }; var foundBuffer = accelerator.Allocate1D(1); // TODO: Replace this allocation with the pooled device buffer from GpuOrderKernelBenchmarks so repeated scans reuse the pinned staging memory instead of allocating per run. @@ -60,6 +60,7 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO kStart += (UInt128)currentSize; } + stream.Dispose(); foundBuffer.Dispose(); gpuLease.Dispose(); } diff --git a/PerfectNumbers.Core/Gpu/PrimeOrderGpuHeuristics.cs b/PerfectNumbers.Core/Gpu/PrimeOrderGpuHeuristics.cs index 4c004f8..3aad7a8 100644 --- a/PerfectNumbers.Core/Gpu/PrimeOrderGpuHeuristics.cs +++ b/PerfectNumbers.Core/Gpu/PrimeOrderGpuHeuristics.cs @@ -200,7 +200,7 @@ internal static partial class PrimeOrderGpuHeuristics { var lease = GpuKernelPool.Rent(); Accelerator accelerator = SharedGpuContext.Accelerator; - AcceleratorStream stream = lease.Stream; + AcceleratorStream stream = accelerator.CreateStream(); var kernel = GetPartialFactorKernel(accelerator); SmallPrimeDeviceCache cache = GetSmallPrimeDeviceCache(accelerator, stream); @@ -243,6 +243,7 @@ internal static partial class PrimeOrderGpuHeuristics byte fullyFactoredFlag = 0; fullyFactoredBuffer.View.CopyToCPU(stream, ref fullyFactoredFlag, 1); stream.Synchronize(); + stream.Dispose(); fullyFactored = fullyFactoredFlag != 0; factorCount = Math.Min(factorCount, primeTargets.Length); @@ -252,7 +253,7 @@ internal static partial class PrimeOrderGpuHeuristics exponentBuffer.Dispose(); countBuffer.Dispose(); remainingBuffer.Dispose(); - fullyFactoredBuffer.Dispose(); + fullyFactoredBuffer.Dispose(); lease.Dispose(); return true; } @@ -367,7 +368,7 @@ internal static partial class PrimeOrderGpuHeuristics var lease = GpuKernelPool.Rent(); Accelerator accelerator = SharedGpuContext.Accelerator; - AcceleratorStream stream = lease.Stream; + AcceleratorStream stream = accelerator.CreateStream(); var kernel = GetOrderKernel(accelerator); SmallPrimeDeviceCache cache = GetSmallPrimeDeviceCache(accelerator, stream); @@ -430,20 +431,29 @@ internal static partial class PrimeOrderGpuHeuristics byte status = 0; statusBuffer.View.CopyToCPU(stream, ref status, 1); resultBuffer.View.CopyToCPU(stream, ref order, 1); - stream.Synchronize(); + stream.Synchronize(); + + stream.Dispose(); + phiFactorBuffer.Dispose(); + phiExponentBuffer.Dispose(); + workFactorBuffer.Dispose(); + workExponentBuffer.Dispose(); + candidateBuffer.Dispose(); + stackIndexBuffer.Dispose(); + stackExponentBuffer.Dispose(); + stackProductBuffer.Dispose(); + resultBuffer.Dispose(); + statusBuffer.Dispose(); + lease.Dispose(); PrimeOrderKernelStatus kernelStatus = (PrimeOrderKernelStatus)status; if (kernelStatus == PrimeOrderKernelStatus.Fallback) { - DisposeResources(); - lease.Dispose(); return false; } if (kernelStatus == PrimeOrderKernelStatus.PollardOverflow) { - DisposeResources(); - lease.Dispose(); throw new InvalidOperationException("GPU Pollard Rho stack overflow; increase HeuristicStackCapacity."); } @@ -452,24 +462,7 @@ internal static partial class PrimeOrderGpuHeuristics order = 0UL; } - DisposeResources(); - lease.Dispose(); - return order != 0UL; - - void DisposeResources() - { - phiFactorBuffer.Dispose(); - phiExponentBuffer.Dispose(); - workFactorBuffer.Dispose(); - workExponentBuffer.Dispose(); - candidateBuffer.Dispose(); - stackIndexBuffer.Dispose(); - stackExponentBuffer.Dispose(); - stackProductBuffer.Dispose(); - resultBuffer.Dispose(); - statusBuffer.Dispose(); - } } private static OrderKernelLauncher GetOrderKernel(Accelerator accelerator) @@ -528,7 +521,7 @@ internal static partial class PrimeOrderGpuHeuristics { var lease = GpuKernelPool.Rent(); Accelerator accelerator = SharedGpuContext.Accelerator; - AcceleratorStream stream = lease.Stream; + AcceleratorStream? stream = accelerator.CreateStream(); var kernel = GetPow2ModKernel(accelerator); // TODO: These buffers should be allocated once per accelerator and only reallocated when the new length exceeds capacity. // Modify the callers to use their own pool of buffers per accelerator, so that other threads don't use the accelerators @@ -546,6 +539,9 @@ internal static partial class PrimeOrderGpuHeuristics kernel(stream, exponents.Length, exponentBuffer.View, divisorData, remainderBuffer.View); remainderBuffer.View.CopyToCPU(stream, ref MemoryMarshal.GetReference(results), exponents.Length); stream.Synchronize(); + + stream.Dispose(); + stream = null; exponentBuffer.Dispose(); remainderBuffer.Dispose(); lease.Dispose(); @@ -553,6 +549,7 @@ internal static partial class PrimeOrderGpuHeuristics catch (Exception) { Console.WriteLine($"Exception for {prime} and exponents: {string.Join(",", exponents.ToArray())}."); + stream?.Dispose(); exponentBuffer.Dispose(); remainderBuffer.Dispose(); lease.Dispose(); @@ -587,7 +584,7 @@ internal static partial class PrimeOrderGpuHeuristics try { Accelerator accelerator = SharedGpuContext.Accelerator; - AcceleratorStream stream = lease.Stream; + AcceleratorStream stream = accelerator.CreateStream(); var kernel = GetPow2ModWideKernel(accelerator); // TODO: These buffers should be allocated once per accelerator and only reallocated when the new length exceeds capacity. // Modify the callers to use their own pool of buffers per accelerator, so that other threads don't use the accelerators @@ -618,6 +615,7 @@ internal static partial class PrimeOrderGpuHeuristics remainderBuffer.View.CopyToCPU(stream, ref MemoryMarshal.GetReference(resultSpan), length); stream.Synchronize(); + stream.Dispose(); for (int i = 0; i < length; i++) { @@ -641,7 +639,7 @@ internal static partial class PrimeOrderGpuHeuristics gpuUInt128Pool.Return(rentedResults!, clearArray: false); } - lease.Dispose(); + lease.Dispose(); } } diff --git a/PerfectNumbers.Core/MersenneDivisorCycles.cs b/PerfectNumbers.Core/MersenneDivisorCycles.cs index b21b8c4..1fc36d3 100644 --- a/PerfectNumbers.Core/MersenneDivisorCycles.cs +++ b/PerfectNumbers.Core/MersenneDivisorCycles.cs @@ -806,7 +806,7 @@ public class MersenneDivisorCycles outCycles = pool.Rent(count); var lease = GpuKernelPool.Rent(); var accelerator = SharedGpuContext.Accelerator; - var stream = lease.Stream; + var stream = accelerator.CreateStream(); var loaded = accelerator.LoadAutoGroupedStreamKernel< Index1D, ArrayView1D, @@ -894,6 +894,7 @@ public class MersenneDivisorCycles start = end + 1UL; } + stream.Dispose(); pool.Return(divisors, clearArray: false); pool.Return(outCycles, clearArray: false); diff --git a/PerfectNumbers.Core/MersenneNumberTester.cs b/PerfectNumbers.Core/MersenneNumberTester.cs index 45616b1..c42695c 100644 --- a/PerfectNumbers.Core/MersenneNumberTester.cs +++ b/PerfectNumbers.Core/MersenneNumberTester.cs @@ -149,8 +149,8 @@ public sealed class MersenneNumberTester( var gpuLease = GpuKernelPool.Rent(); var accelerator = SharedGpuContext.Accelerator; - var stream = gpuLease.Stream; - var orderKernel = gpuLease.OrderKernel!; + var stream = accelerator.CreateStream(); + var orderKernel = GpuKernelLease.OrderKernel!; // Guard long-running kernels by chunking the warm-up across batches. // Reuse the same ScanBatchSize knob used for scanning. @@ -196,6 +196,7 @@ public sealed class MersenneNumberTester( qBuffer.Dispose(); } + stream.Dispose(); gpuLease.Dispose(); uInt128Pool.Return(qs); } diff --git a/PerfectNumbers.Core/PrimeOrderCalculator.Gpu.cs b/PerfectNumbers.Core/PrimeOrderCalculator.Gpu.cs index cb496b0..4c5c504 100644 --- a/PerfectNumbers.Core/PrimeOrderCalculator.Gpu.cs +++ b/PerfectNumbers.Core/PrimeOrderCalculator.Gpu.cs @@ -21,8 +21,8 @@ internal static partial class PrimeOrderCalculator var lease = GpuKernelPool.Rent(); Accelerator accelerator = SharedGpuContext.Accelerator; - var stream = lease.Stream; - KernelContainer kernels = lease.Kernels; + var stream = accelerator.CreateStream(); + KernelContainer kernels = GpuKernelPool.Kernels; ScratchBuffer scratch = GpuScratchBufferPool.Rent(accelerator, GpuSmallPrimeFactorSlots, 0); @@ -31,7 +31,7 @@ internal static partial class PrimeOrderCalculator if (kernels.SmallPrimeFactorsPrimes is null) throw new NullReferenceException($"{nameof(kernels.SmallPrimeFactorsPrimes)} is null"); if (kernels.SmallPrimeFactorsSquares is null) throw new NullReferenceException($"{nameof(kernels.SmallPrimeFactorsSquares)} is null"); - var kernel = lease.SmallPrimeFactorKernel; + var kernel = GpuKernelLease.SmallPrimeFactorKernel; ArrayView1D smallPrimeFactorCountSlotView = scratch.SmallPrimeFactorCountSlot.View; ArrayView1D smallPrimeFactorRemainingSlotView = scratch.SmallPrimeFactorRemainingSlot.View; @@ -68,6 +68,7 @@ internal static partial class PrimeOrderCalculator smallPrimeFactorRemainingSlotView.CopyToCPU(stream, ref remaining, 1); stream.Synchronize(); + stream.Dispose(); for (int i = 0; i < factorCount; i++) { @@ -103,14 +104,14 @@ internal static partial class PrimeOrderCalculator GpuKernelLease lease = GpuKernelPool.Rent(); Accelerator accelerator = SharedGpuContext.Accelerator; - var stream = lease.Stream; + var stream = accelerator.CreateStream(); ScratchBuffer scratch = GpuScratchBufferPool.Rent(accelerator, 0, factorCount); ArrayView1D specialMaxFactorsView = scratch.SpecialMaxFactors.View; specialMaxFactorsView.SubView(0, factorCount).CopyFromCPU(stream, ref MemoryMarshal.GetReference(factorSpan), factorCount); - var kernel = lease.SpecialMaxKernel; + var kernel = GpuKernelLease.SpecialMaxKernel; ArrayView1D specialMaxResultView = scratch.SpecialMaxResult.View; @@ -128,6 +129,7 @@ internal static partial class PrimeOrderCalculator // specialMaxResultView.CopyToCPU(stream, ref result, 1); specialMaxResultView.CopyToCPU(stream, in result); stream.Synchronize(); + stream.Dispose(); // stream.Synchronize(); // return result != 0; diff --git a/PerfectNumbers.Core/ULongExtensions.Gpu.cs b/PerfectNumbers.Core/ULongExtensions.Gpu.cs index d195b52..fc2ee8f 100644 --- a/PerfectNumbers.Core/ULongExtensions.Gpu.cs +++ b/PerfectNumbers.Core/ULongExtensions.Gpu.cs @@ -464,7 +464,7 @@ public static partial class ULongExtensions GpuKernelLease lease = GpuKernelPool.Rent(); Accelerator accelerator = SharedGpuContext.Accelerator; - AcceleratorStream stream = lease.Stream; + AcceleratorStream stream = accelerator.CreateStream(); var kernelGroup = Kernel; EnsureCapacity(); @@ -480,7 +480,8 @@ public static partial class ULongExtensions kernel(stream, 1, exponentBuffer.View, divisor, resultBuffer.View); resultBuffer.View.CopyToCPU(stream, ref result, 1); stream.Synchronize(); - + + stream.Dispose(); resultBuffer.Dispose(); exponentBuffer.Dispose(); lease.Dispose();