From fc5700f82ccc727f657d6c9bea9d62325090d15a Mon Sep 17 00:00:00 2001 From: mlemanczyk Date: Wed, 29 Oct 2025 22:31:28 +0100 Subject: [PATCH] IsPrime with cancellation token removed. --- .../PrimeTesterBenchmarks.cs | 14 +- EvenPerfectBitScanner.Tests/ProgramTests.cs | 2 +- EvenPerfectBitScanner/Program.cs | 4 +- .../Gpu/PrimeTesterGpuTests.cs | 4 +- .../PrimeTester/PrimeTesterIsPrimeTests.cs | 12 +- PerfectNumbers.Core/HeuristicPrimeTester.cs | 9 +- PerfectNumbers.Core/MersenneDivisorCycles.cs | 14 +- .../MersennePrimeFactorTester.cs | 4 +- .../PrimeOrderCalculator.Cpu.cs | 20 +- .../PrimeOrderCalculator.Shared.cs | 2 +- PerfectNumbers.Core/PrimeTester.cs | 516 +++++++++--------- 11 files changed, 287 insertions(+), 314 deletions(-) diff --git a/EvenPerfectBitScanner.Benchmarks/PrimeTesterBenchmarks.cs b/EvenPerfectBitScanner.Benchmarks/PrimeTesterBenchmarks.cs index f63e315..db1c2fb 100644 --- a/EvenPerfectBitScanner.Benchmarks/PrimeTesterBenchmarks.cs +++ b/EvenPerfectBitScanner.Benchmarks/PrimeTesterBenchmarks.cs @@ -29,8 +29,7 @@ public class PrimeTesterBenchmarks return; } - CancellationToken cancellationToken = CancellationToken.None; - _ = _heuristicTester.IsPrimeCpu(_candidates[0], cancellationToken); + _ = _heuristicTester.IsPrimeCpu(_candidates[0]); _ = _heuristicTester.IsPrimeGpu(_candidates[0]); _ = Prime.Numbers.IsPrime(_candidates[0]); } @@ -40,12 +39,11 @@ public class PrimeTesterBenchmarks { HeuristicPrimeTester tester = _heuristicTester; ulong[] values = _candidates; - CancellationToken cancellationToken = CancellationToken.None; int primeCount = 0; for (int i = 0; i < values.Length; i++) { - if (tester.IsPrimeCpu(values[i], cancellationToken)) + if (tester.IsPrimeCpu(values[i])) { primeCount++; } @@ -75,7 +73,6 @@ public class PrimeTesterBenchmarks [Benchmark] public int HeuristicCombinedGpu() { - HeuristicCombinedPrimeTester tester = _heuristicCombinedTester; ulong[] values = _candidates; int primeCount = 0; @@ -93,7 +90,6 @@ public class PrimeTesterBenchmarks [Benchmark] public int HeuristicCombinedCpu() { - HeuristicCombinedPrimeTester tester = _heuristicCombinedTester; ulong[] values = _candidates; int primeCount = 0; @@ -115,12 +111,11 @@ public class PrimeTesterBenchmarks { PrimeTester tester = _nonHeuristicTester; ulong[] values = _candidates; - CancellationToken cancellationToken = CancellationToken.None; int primeCount = 0; for (int i = 0; i < values.Length; i++) { - if (tester.IsPrimeGpu(values[i], cancellationToken)) + if (tester.IsPrimeGpu(values[i])) { primeCount++; } @@ -133,12 +128,11 @@ public class PrimeTesterBenchmarks public int NonHeuristicCpu() { ulong[] values = _candidates; - CancellationToken cancellationToken = CancellationToken.None; int primeCount = 0; for (int i = 0; i < values.Length; i++) { - if (PrimeTester.IsPrimeCpu(values[i], cancellationToken)) + if (PrimeTester.IsPrime(values[i])) { primeCount++; } diff --git a/EvenPerfectBitScanner.Tests/ProgramTests.cs b/EvenPerfectBitScanner.Tests/ProgramTests.cs index f08a676..cf16bdb 100644 --- a/EvenPerfectBitScanner.Tests/ProgramTests.cs +++ b/EvenPerfectBitScanner.Tests/ProgramTests.cs @@ -55,7 +55,7 @@ public class ProgramTests [InlineData(81UL, false)] public void IsPrime_identifies_primes_correctly(ulong n, bool expected) { - PrimeTester.IsPrime(n, CancellationToken.None).Should().Be(expected); + PrimeTester.IsPrime(n).Should().Be(expected); } [Fact] diff --git a/EvenPerfectBitScanner/Program.cs b/EvenPerfectBitScanner/Program.cs index 86b4c20..bf755d4 100644 --- a/EvenPerfectBitScanner/Program.cs +++ b/EvenPerfectBitScanner/Program.cs @@ -622,8 +622,8 @@ internal static class Program if (!_cliArguments.UseByDivisor) { if (!(GpuContextPool.ForceCpu - ? PrimeTester.IsPrime(p, CancellationToken.None) - : PrimeTesters.Value!.IsPrimeGpu(p, CancellationToken.None))) + ? PrimeTester.IsPrime(p) + : PrimeTesters.Value!.IsPrimeGpu(p))) { _lastCompositeP = true; return false; diff --git a/PerfectNumbers.Core.Tests/Gpu/PrimeTesterGpuTests.cs b/PerfectNumbers.Core.Tests/Gpu/PrimeTesterGpuTests.cs index 5e8faf9..6213b07 100644 --- a/PerfectNumbers.Core.Tests/Gpu/PrimeTesterGpuTests.cs +++ b/PerfectNumbers.Core.Tests/Gpu/PrimeTesterGpuTests.cs @@ -17,7 +17,7 @@ public class PrimeTesterGpuTests ulong[] primes = [31UL, 61UL, 89UL, 107UL, 127UL, 521UL]; foreach (ulong prime in primes) { - tester.IsPrimeGpu(prime, CancellationToken.None).Should().BeTrue(); + tester.IsPrimeGpu(prime).Should().BeTrue(); } } finally @@ -37,7 +37,7 @@ public class PrimeTesterGpuTests ulong[] composites = [33UL, 39UL, 51UL, 77UL, 91UL]; foreach (ulong composite in composites) { - tester.IsPrimeGpu(composite, CancellationToken.None).Should().BeFalse(); + tester.IsPrimeGpu(composite).Should().BeFalse(); } } finally diff --git a/PerfectNumbers.Core.Tests/PrimeTester/PrimeTesterIsPrimeTests.cs b/PerfectNumbers.Core.Tests/PrimeTester/PrimeTesterIsPrimeTests.cs index e86e1db..f7dd5b7 100644 --- a/PerfectNumbers.Core.Tests/PrimeTester/PrimeTesterIsPrimeTests.cs +++ b/PerfectNumbers.Core.Tests/PrimeTester/PrimeTesterIsPrimeTests.cs @@ -26,7 +26,7 @@ public class PrimeTesterIsPrimeTests { var tester = new PrimeTester(); - PrimeTester.IsPrime(n, CancellationToken.None).Should().Be(expected); + PrimeTester.IsPrime(n).Should().Be(expected); } [Theory] @@ -40,7 +40,7 @@ public class PrimeTesterIsPrimeTests GpuContextPool.ForceCpu = false; var tester = new PrimeTester(); - tester.IsPrimeGpu(n, CancellationToken.None).Should().Be(expected); + tester.IsPrimeGpu(n).Should().Be(expected); } [Fact] @@ -50,9 +50,9 @@ public class PrimeTesterIsPrimeTests var tester = new PrimeTester(); GpuContextPool.ForceCpu = true; - tester.IsPrimeGpu(137UL, CancellationToken.None).Should().BeTrue(); + tester.IsPrimeGpu(137UL).Should().BeTrue(); - tester.IsPrimeGpu(341UL, CancellationToken.None).Should().BeFalse(); + tester.IsPrimeGpu(341UL).Should().BeFalse(); GpuContextPool.ForceCpu = false; } @@ -71,7 +71,7 @@ public class PrimeTesterIsPrimeTests var testers = new ThreadLocal(() => new PrimeTester(), trackAllValues: true); Parallel.For(0, primes.Length, i => { - results[i] = testers.Value!.IsPrimeGpu(primes[i], CancellationToken.None); + results[i] = testers.Value!.IsPrimeGpu(primes[i]); }); results.Should().AllBeEquivalentTo(true); @@ -80,7 +80,7 @@ public class PrimeTesterIsPrimeTests { foreach (ulong prime in primes) { - testers.Value!.IsPrimeGpu(prime, CancellationToken.None).Should().BeTrue(); + testers.Value!.IsPrimeGpu(prime).Should().BeTrue(); } }); } diff --git a/PerfectNumbers.Core/HeuristicPrimeTester.cs b/PerfectNumbers.Core/HeuristicPrimeTester.cs index 5d91856..2f491df 100644 --- a/PerfectNumbers.Core/HeuristicPrimeTester.cs +++ b/PerfectNumbers.Core/HeuristicPrimeTester.cs @@ -77,10 +77,8 @@ public sealed class HeuristicPrimeTester public static HeuristicPrimeTester Exclusive => _tester ??= new(); - public bool IsPrimeCpu(ulong n, CancellationToken ct) + public bool IsPrimeCpu(ulong n) { - ct.ThrowIfCancellationRequested(); - byte nMod10 = (byte)n.Mod10(); ulong maxDivisorSquare = ComputeHeuristicDivisorSquareLimit(n); @@ -93,11 +91,6 @@ public sealed class HeuristicPrimeTester return HeuristicTrialDivisionCpu(n, maxDivisorSquare, nMod10, includeGroupB); } - public bool IsPrimeCpu(ulong n) - { - return IsPrimeCpu(n, CancellationToken.None); - } - public bool IsPrimeGpu(ulong n) { byte nMod10 = (byte)n.Mod10(); diff --git a/PerfectNumbers.Core/MersenneDivisorCycles.cs b/PerfectNumbers.Core/MersenneDivisorCycles.cs index 851473c..149bc77 100644 --- a/PerfectNumbers.Core/MersenneDivisorCycles.cs +++ b/PerfectNumbers.Core/MersenneDivisorCycles.cs @@ -411,8 +411,8 @@ public class MersenneDivisorCycles // Atomic.Add(ref _tryFactorIntoCountsInternalHits, 1UL); // Console.WriteLine($"MersenneDivisorCycles.TryFactorIntoCountsInternal hits {Volatile.Read(ref _tryFactorIntoCountsInternalHits)}"); - HeuristicPrimeTester primeTester = _primeTester ??= new(); - if (primeTester.IsPrimeGpu(remaining)) + // HeuristicPrimeTester primeTester = _primeTester ??= new(); + if (PrimeTester.IsPrime(remaining)) // if (PrimeTester.IsPrimeCpu(remaining, CancellationToken.None)) { AddFactor(counts, remaining); @@ -917,8 +917,8 @@ public class MersenneDivisorCycles return CalculateCycleLengthFallback(divisor); } - [ThreadStatic] - private static HeuristicPrimeTester? _primeTester; + // [ThreadStatic] + // private static HeuristicPrimeTester? _primeTester; internal static bool TryCalculateCycleLengthHeuristic(ulong divisor, in MontgomeryDivisorData divisorData, out ulong cycleLength, bool skipPrimeOrderHeuristic = false) { @@ -940,10 +940,10 @@ public class MersenneDivisorCycles // Console.WriteLine($"MersenneDivisorCycles.CalculateCycleLengthFallback hits {Volatile.Read(ref _tryCalculateCycleLengthHeuristicHits)}"); // } - HeuristicPrimeTester primeTester = _primeTester ??= new(); + // HeuristicPrimeTester primeTester = _primeTester ??= new(); // if (!skipPrimeOrderHeuristic && HeuristicPrimeTester.Exclusive.IsPrimeCpu(divisor, CancellationToken.None)) - if (!skipPrimeOrderHeuristic && primeTester.IsPrimeGpu(divisor)) - // if (!skipPrimeOrderHeuristic && PrimeTester.IsPrimeCpu(divisor, CancellationToken.None)) + // if (!skipPrimeOrderHeuristic && primeTester.IsPrimeGpu(divisor)) + if (!skipPrimeOrderHeuristic && PrimeTester.IsPrime(divisor)) { ulong computedOrder = PrimeOrderCalculator.Calculate( divisor, diff --git a/PerfectNumbers.Core/MersennePrimeFactorTester.cs b/PerfectNumbers.Core/MersennePrimeFactorTester.cs index a160a3b..93dcb58 100644 --- a/PerfectNumbers.Core/MersennePrimeFactorTester.cs +++ b/PerfectNumbers.Core/MersennePrimeFactorTester.cs @@ -34,7 +34,7 @@ public static class MersennePrimeFactorTester // Atomic.Add(ref _isPrimeFactorHits, 1UL); // Console.WriteLine($"MersennePrimeFactorTester.IsPrimeFactor hits {Volatile.Read(ref _isPrimeFactorHits)}"); - if (!PrimeTester.IsPrimeCpu(q, ct)) + if (!PrimeTester.IsPrime(q)) { return false; } @@ -247,7 +247,7 @@ public static class MersennePrimeFactorTester // Console.WriteLine($"MersennePrimeFactorTester.Factor64 hits {Volatile.Read(ref _factor64Hits)}"); // if (HeuristicPrimeTester.Exclusive.IsPrime(m, ct)) - if (PrimeTester.IsPrimeCpu(m, ct)) + if (PrimeTester.IsPrime(m)) { dict[m] = 1; continue; diff --git a/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs b/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs index 1be9074..3f5773e 100644 --- a/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs +++ b/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs @@ -1079,7 +1079,7 @@ internal static partial class PrimeOrderCalculator PartialFactorResult result; PrimeTester primeTester = PrimeTester.Exclusive; CancellationToken ct = CancellationToken.None; - HeuristicPrimeTester? tester = _tester ??= new(); + // HeuristicPrimeTester? tester = _tester ??= new(); if (!gpuFactored) { @@ -1152,7 +1152,7 @@ internal static partial class PrimeOrderCalculator // Console.WriteLine($"Partial factor hits {Volatile.Read(ref _partialFactorHits)}"); // bool isPrime = PrimeTester.IsPrimeCpu(composite, CancellationToken.None); - bool isPrime = tester.IsPrimeGpu(composite); + bool isPrime = PrimeTester.IsPrime(composite); // bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite); if (isPrime) @@ -1220,7 +1220,7 @@ internal static partial class PrimeOrderCalculator // Console.WriteLine($"Partial factor pending hits {Volatile.Read(ref _partialFactorPendingHits)}"); // bool isPrime = PrimeTester.IsPrimeCpu(composite, CancellationToken.None); - bool isPrime = tester.IsPrimeGpu(composite); + bool isPrime = PrimeTester.IsPrime(composite); // bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite); entry = entry.WithPrimality(isPrime); @@ -1257,7 +1257,7 @@ internal static partial class PrimeOrderCalculator // Atomic.Add(ref _partialFactorCofactorHits, 1UL); // Console.WriteLine($"Partial factor cofactor hits {Volatile.Read(ref _partialFactorCofactorHits)}"); - cofactorIsPrime = tester.IsPrimeGpu(cofactor); + cofactorIsPrime = PrimeTester.IsPrime(cofactor); // cofactorIsPrime = PrimeTester.IsPrimeGpu(cofactor); // cofactorIsPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(cofactor); } @@ -1782,8 +1782,8 @@ internal static partial class PrimeOrderCalculator // private static ulong _factorCompletelyHits; // private static ulong _factorCompletelyPollardRhoHits; - [ThreadStatic] - private static HeuristicPrimeTester? _tester; + // [ThreadStatic] + // private static HeuristicPrimeTester? _tester; private static void FactorCompletely(ulong value, Dictionary counts, bool knownComposite) { @@ -1794,10 +1794,10 @@ internal static partial class PrimeOrderCalculator // Atomic.Add(ref _factorCompletelyHits, 1UL); // Console.WriteLine($"Factor completely hits {Volatile.Read(ref _factorCompletelyHits)}"); - HeuristicPrimeTester tester = _tester ??= new(); + // HeuristicPrimeTester tester = _tester ??= new(); // bool isPrime = primeTester.HeuristicIsPrimeGpu(value); - bool isPrime = tester.IsPrimeGpu(value); + bool isPrime = PrimeTester.IsPrime(value); // bool isPrime = PrimeTester.IsPrimeGpu(value); // bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(value); if (!knownComposite && isPrime) @@ -1813,7 +1813,7 @@ internal static partial class PrimeOrderCalculator // Console.WriteLine($"Factor completely after PollardRho hits {Volatile.Read(ref _factorCompletelyPollardRhoHits)}"); // isPrime = primeTester.HeuristicIsPrimeGpu(factor); - isPrime = tester.IsPrimeGpu(factor); + isPrime = PrimeTester.IsPrime(factor); // isPrime = PrimeTester.IsPrimeGpu(factor); // isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(factor); if (isPrime) @@ -1850,7 +1850,7 @@ internal static partial class PrimeOrderCalculator // Atomic.Add(ref _partialFactorCofactorHits, 1UL); // Console.WriteLine($"Partial factor cofactor hits {Volatile.Read(ref _partialFactorCofactorHits)}"); - isPrime = tester.IsPrimeGpu(quotient); + isPrime = PrimeTester.IsPrime(quotient); // isPrime = PrimeTester.IsPrimeGpu(quotient); // isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(quotient); } diff --git a/PerfectNumbers.Core/PrimeOrderCalculator.Shared.cs b/PerfectNumbers.Core/PrimeOrderCalculator.Shared.cs index 2f923c6..2fe2791 100644 --- a/PerfectNumbers.Core/PrimeOrderCalculator.Shared.cs +++ b/PerfectNumbers.Core/PrimeOrderCalculator.Shared.cs @@ -950,7 +950,7 @@ internal static partial class PrimeOrderCalculator if (value <= ulong.MaxValue) { // return HeuristicPrimeTester.Exclusive.IsPrimeCpu((ulong)value, CancellationToken.None); - return PrimeTester.IsPrimeCpu((ulong)value, CancellationToken.None); + return PrimeTester.IsPrime((ulong)value); } if ((value & UInt128.One) == UInt128.Zero) diff --git a/PerfectNumbers.Core/PrimeTester.cs b/PerfectNumbers.Core/PrimeTester.cs index f18ca71..52bb5bf 100644 --- a/PerfectNumbers.Core/PrimeTester.cs +++ b/PerfectNumbers.Core/PrimeTester.cs @@ -1,7 +1,5 @@ -using System; using System.Buffers; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -22,7 +20,7 @@ public sealed class PrimeTester public static PrimeTester Exclusive => _tester ??= new(); - public static bool IsPrime(ulong n, CancellationToken ct) + public static bool IsPrime(ulong n) { if (n <= 1UL) { @@ -92,310 +90,298 @@ public sealed class PrimeTester return result; } - public static bool IsPrimeGpu(ulong n) - { - return Exclusive.IsPrimeGpu(n, CancellationToken.None); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsPrimeGpu(ulong n, CancellationToken ct) - { - bool forceCpu = GpuContextPool.ForceCpu; - bool belowGpuRange = n < 31UL; - - if (forceCpu || belowGpuRange) - { - return IsPrimeCpu(n, ct); - } - - var limiter = GpuPrimeWorkLimiter.Acquire(); - var gpu = PrimeTesterGpuContextPool.Rent(1); - var accelerator = gpu.Accelerator; - var kernel = gpu.Kernel; - - ulong value = n; - byte flag = 0; - - var input = gpu.Input; - var output = gpu.Output; - var inputView = input.View; - var outputView = output.View; - - inputView.CopyFromCPU(ref value, 1); - kernel( - 1, - inputView, - gpu.DevicePrimesDefault.View, - gpu.DevicePrimesLastOne.View, - gpu.DevicePrimesLastSeven.View, - gpu.DevicePrimesLastThree.View, - gpu.DevicePrimesLastNine.View, - gpu.DevicePrimesPow2Default.View, - gpu.DevicePrimesPow2LastOne.View, - gpu.DevicePrimesPow2LastSeven.View, - gpu.DevicePrimesPow2LastThree.View, - gpu.DevicePrimesPow2LastNine.View, - outputView); - accelerator.Synchronize(); - outputView.CopyToCPU(ref flag, 1); - - gpu.Dispose(); - limiter.Dispose(); - - return flag != 0; - } - -public static bool IsPrimeCpu(ulong n, CancellationToken ct) + public bool IsPrimeGpu(ulong n) { - // Preserve the legacy entry point for callers that bypass the thread-local caches. - return IsPrime(n, ct); - } + bool forceCpu = GpuContextPool.ForceCpu; + bool belowGpuRange = n < 31UL; + if (forceCpu || belowGpuRange) + { + return IsPrime(n); + } + + var limiter = GpuPrimeWorkLimiter.Acquire(); + var gpu = PrimeTesterGpuContextPool.Rent(1); + var accelerator = gpu.Accelerator; + var kernel = gpu.Kernel; + + ulong value = n; + byte flag = 0; + + var input = gpu.Input; + var output = gpu.Output; + var inputView = input.View; + var outputView = output.View; + + inputView.CopyFromCPU(ref value, 1); + kernel( + 1, + inputView, + gpu.DevicePrimesDefault.View, + gpu.DevicePrimesLastOne.View, + gpu.DevicePrimesLastSeven.View, + gpu.DevicePrimesLastThree.View, + gpu.DevicePrimesLastNine.View, + gpu.DevicePrimesPow2Default.View, + gpu.DevicePrimesPow2LastOne.View, + gpu.DevicePrimesPow2LastSeven.View, + gpu.DevicePrimesPow2LastThree.View, + gpu.DevicePrimesPow2LastNine.View, + outputView); + accelerator.Synchronize(); + outputView.CopyToCPU(ref flag, 1); + + gpu.Dispose(); + limiter.Dispose(); + + return flag != 0; + } public static int GpuBatchSize { get; set; } = 262_144; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void IsPrimeBatchGpu(ReadOnlySpan values, Span results) - { - var limiter = GpuPrimeWorkLimiter.Acquire(); - var gpu = PrimeTesterGpuContextPool.Rent(GpuBatchSize); - var accelerator = gpu.Accelerator; - var kernel = gpu.Kernel; - int totalLength = values.Length; - int batchSize = GpuBatchSize; + { + var limiter = GpuPrimeWorkLimiter.Acquire(); + var gpu = PrimeTesterGpuContextPool.Rent(GpuBatchSize); + var accelerator = gpu.Accelerator; + var kernel = gpu.Kernel; + int totalLength = values.Length; + int batchSize = GpuBatchSize; - var input = gpu.Input; - var output = gpu.Output; - var inputView = input.View; - var outputView = output.View; + var input = gpu.Input; + var output = gpu.Output; + var inputView = input.View; + var outputView = output.View; - int pos = 0; - while (pos < totalLength) - { - int remaining = totalLength - pos; - int count = remaining > batchSize ? batchSize : remaining; + int pos = 0; + while (pos < totalLength) + { + int remaining = totalLength - pos; + int count = remaining > batchSize ? batchSize : remaining; - var valueSlice = values.Slice(pos, count); - ref ulong valueRef = ref MemoryMarshal.GetReference(valueSlice); - inputView.CopyFromCPU(ref valueRef, count); + var valueSlice = values.Slice(pos, count); + ref ulong valueRef = ref MemoryMarshal.GetReference(valueSlice); + inputView.CopyFromCPU(ref valueRef, count); - kernel( - count, - inputView, - gpu.DevicePrimesDefault.View, - gpu.DevicePrimesLastOne.View, - gpu.DevicePrimesLastSeven.View, - gpu.DevicePrimesLastThree.View, - gpu.DevicePrimesLastNine.View, - gpu.DevicePrimesPow2Default.View, - gpu.DevicePrimesPow2LastOne.View, - gpu.DevicePrimesPow2LastSeven.View, - gpu.DevicePrimesPow2LastThree.View, - gpu.DevicePrimesPow2LastNine.View, - outputView); - accelerator.Synchronize(); - var resultSlice = results.Slice(pos, count); - ref byte resultRef = ref MemoryMarshal.GetReference(resultSlice); - outputView.CopyToCPU(ref resultRef, count); + kernel( + count, + inputView, + gpu.DevicePrimesDefault.View, + gpu.DevicePrimesLastOne.View, + gpu.DevicePrimesLastSeven.View, + gpu.DevicePrimesLastThree.View, + gpu.DevicePrimesLastNine.View, + gpu.DevicePrimesPow2Default.View, + gpu.DevicePrimesPow2LastOne.View, + gpu.DevicePrimesPow2LastSeven.View, + gpu.DevicePrimesPow2LastThree.View, + gpu.DevicePrimesPow2LastNine.View, + outputView); + accelerator.Synchronize(); + var resultSlice = results.Slice(pos, count); + ref byte resultRef = ref MemoryMarshal.GetReference(resultSlice); + outputView.CopyToCPU(ref resultRef, count); - pos += count; - } + pos += count; + } - gpu.Dispose(); - limiter.Dispose(); - } + gpu.Dispose(); + limiter.Dispose(); + } - internal static class PrimeTesterGpuContextPool - { - private static readonly ConcurrentQueue Pool = new(); + internal static class PrimeTesterGpuContextPool + { + private static readonly ConcurrentQueue Pool = new(); - internal static PrimeTesterGpuContextLease Rent(int minBufferCapacity = 1) - { - if (!Pool.TryDequeue(out var lease)) - { - lease = new PrimeTesterGpuContextLease(minBufferCapacity); - } - else - { - lease.EnsureCapacity(minBufferCapacity); - } + internal static PrimeTesterGpuContextLease Rent(int minBufferCapacity = 1) + { + if (!Pool.TryDequeue(out var lease)) + { + lease = new PrimeTesterGpuContextLease(minBufferCapacity); + } + else + { + lease.EnsureCapacity(minBufferCapacity); + } - lease.ResetReturnFlag(); - return lease; - } + lease.ResetReturnFlag(); + return lease; + } - internal static void Return(PrimeTesterGpuContextLease lease) - { - lease.Accelerator.Synchronize(); - Pool.Enqueue(lease); - } + internal static void Return(PrimeTesterGpuContextLease lease) + { + lease.Accelerator.Synchronize(); + Pool.Enqueue(lease); + } - internal static void DisposeAll() - { - while (Pool.TryDequeue(out var lease)) - { - lease.DisposeResources(); - } - } + internal static void DisposeAll() + { + while (Pool.TryDequeue(out var lease)) + { + lease.DisposeResources(); + } + } - internal static void Clear(Accelerator accelerator) - { - if (accelerator is null) - { - return; - } + internal static void Clear(Accelerator accelerator) + { + if (accelerator is null) + { + return; + } - var retained = new List(); - while (Pool.TryDequeue(out var lease)) - { - if (lease.Accelerator == accelerator) - { - lease.DisposeResources(); - } - else - { - retained.Add(lease); - } - } + var retained = new List(); + while (Pool.TryDequeue(out var lease)) + { + if (lease.Accelerator == accelerator) + { + lease.DisposeResources(); + } + else + { + retained.Add(lease); + } + } - int retainedCount = retained.Count; - for (int i = 0; i < retainedCount; i++) - { - Pool.Enqueue(retained[i]); - } - } + int retainedCount = retained.Count; + for (int i = 0; i < retainedCount; i++) + { + Pool.Enqueue(retained[i]); + } + } - internal sealed class PrimeTesterGpuContextLease : IDisposable - { - private bool _returned; + internal sealed class PrimeTesterGpuContextLease : IDisposable + { + private bool _returned; - internal readonly Context AcceleratorContext; - public readonly Accelerator Accelerator; - public readonly Action, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView> Kernel; - public readonly Action, ulong, ArrayView> HeuristicTrialDivisionKernel; - public readonly MemoryBuffer1D DevicePrimesDefault; - public readonly MemoryBuffer1D DevicePrimesLastOne; - public readonly MemoryBuffer1D DevicePrimesLastSeven; - public readonly MemoryBuffer1D DevicePrimesLastThree; - public readonly MemoryBuffer1D DevicePrimesLastNine; - public readonly MemoryBuffer1D DevicePrimesPow2Default; - public readonly MemoryBuffer1D DevicePrimesPow2LastOne; - public readonly MemoryBuffer1D DevicePrimesPow2LastSeven; - public readonly MemoryBuffer1D DevicePrimesPow2LastThree; - public readonly MemoryBuffer1D DevicePrimesPow2LastNine; - public MemoryBuffer1D Input; - public MemoryBuffer1D Output; - public MemoryBuffer1D HeuristicFlag; - public int BufferCapacity; + internal readonly Context AcceleratorContext; + public readonly Accelerator Accelerator; + public readonly Action, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView> Kernel; + public readonly Action, ulong, ArrayView> HeuristicTrialDivisionKernel; + public readonly MemoryBuffer1D DevicePrimesDefault; + public readonly MemoryBuffer1D DevicePrimesLastOne; + public readonly MemoryBuffer1D DevicePrimesLastSeven; + public readonly MemoryBuffer1D DevicePrimesLastThree; + public readonly MemoryBuffer1D DevicePrimesLastNine; + public readonly MemoryBuffer1D DevicePrimesPow2Default; + public readonly MemoryBuffer1D DevicePrimesPow2LastOne; + public readonly MemoryBuffer1D DevicePrimesPow2LastSeven; + public readonly MemoryBuffer1D DevicePrimesPow2LastThree; + public readonly MemoryBuffer1D DevicePrimesPow2LastNine; + public MemoryBuffer1D Input; + public MemoryBuffer1D Output; + public MemoryBuffer1D HeuristicFlag; + public int BufferCapacity; - internal PrimeTesterGpuContextLease(int minBufferCapacity) - { - AcceleratorContext = Context.CreateDefault(); - Accelerator = AcceleratorContext.GetPreferredDevice(false).CreateAccelerator(AcceleratorContext); - Kernel = Accelerator.LoadAutoGroupedStreamKernel, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView>(PrimeTesterKernels.SmallPrimeSieveKernel); - HeuristicTrialDivisionKernel = Accelerator.LoadAutoGroupedStreamKernel, ulong, ArrayView>(PrimeTesterKernels.HeuristicTrialDivisionKernel); + internal PrimeTesterGpuContextLease(int minBufferCapacity) + { + AcceleratorContext = Context.CreateDefault(); + Accelerator = AcceleratorContext.GetPreferredDevice(false).CreateAccelerator(AcceleratorContext); + Kernel = Accelerator.LoadAutoGroupedStreamKernel, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView, ArrayView>(PrimeTesterKernels.SmallPrimeSieveKernel); + HeuristicTrialDivisionKernel = Accelerator.LoadAutoGroupedStreamKernel, ulong, ArrayView>(PrimeTesterKernels.HeuristicTrialDivisionKernel); - var primesDefault = DivisorGenerator.SmallPrimes; - DevicePrimesDefault = Accelerator.Allocate1D(primesDefault.Length); - DevicePrimesDefault.View.CopyFromCPU(primesDefault); + var primesDefault = DivisorGenerator.SmallPrimes; + DevicePrimesDefault = Accelerator.Allocate1D(primesDefault.Length); + DevicePrimesDefault.View.CopyFromCPU(primesDefault); - var primesLastOne = DivisorGenerator.SmallPrimesLastOne; - DevicePrimesLastOne = Accelerator.Allocate1D(primesLastOne.Length); - DevicePrimesLastOne.View.CopyFromCPU(primesLastOne); + var primesLastOne = DivisorGenerator.SmallPrimesLastOne; + DevicePrimesLastOne = Accelerator.Allocate1D(primesLastOne.Length); + DevicePrimesLastOne.View.CopyFromCPU(primesLastOne); - var primesLastSeven = DivisorGenerator.SmallPrimesLastSeven; - DevicePrimesLastSeven = Accelerator.Allocate1D(primesLastSeven.Length); - DevicePrimesLastSeven.View.CopyFromCPU(primesLastSeven); + var primesLastSeven = DivisorGenerator.SmallPrimesLastSeven; + DevicePrimesLastSeven = Accelerator.Allocate1D(primesLastSeven.Length); + DevicePrimesLastSeven.View.CopyFromCPU(primesLastSeven); - var primesLastThree = DivisorGenerator.SmallPrimesLastThree; - DevicePrimesLastThree = Accelerator.Allocate1D(primesLastThree.Length); - DevicePrimesLastThree.View.CopyFromCPU(primesLastThree); + var primesLastThree = DivisorGenerator.SmallPrimesLastThree; + DevicePrimesLastThree = Accelerator.Allocate1D(primesLastThree.Length); + DevicePrimesLastThree.View.CopyFromCPU(primesLastThree); - var primesLastNine = DivisorGenerator.SmallPrimesLastNine; - DevicePrimesLastNine = Accelerator.Allocate1D(primesLastNine.Length); - DevicePrimesLastNine.View.CopyFromCPU(primesLastNine); + var primesLastNine = DivisorGenerator.SmallPrimesLastNine; + DevicePrimesLastNine = Accelerator.Allocate1D(primesLastNine.Length); + DevicePrimesLastNine.View.CopyFromCPU(primesLastNine); - var primesPow2Default = DivisorGenerator.SmallPrimesPow2; - DevicePrimesPow2Default = Accelerator.Allocate1D(primesPow2Default.Length); - DevicePrimesPow2Default.View.CopyFromCPU(primesPow2Default); + var primesPow2Default = DivisorGenerator.SmallPrimesPow2; + DevicePrimesPow2Default = Accelerator.Allocate1D(primesPow2Default.Length); + DevicePrimesPow2Default.View.CopyFromCPU(primesPow2Default); - var primesPow2LastOne = DivisorGenerator.SmallPrimesPow2LastOne; - DevicePrimesPow2LastOne = Accelerator.Allocate1D(primesPow2LastOne.Length); - DevicePrimesPow2LastOne.View.CopyFromCPU(primesPow2LastOne); + var primesPow2LastOne = DivisorGenerator.SmallPrimesPow2LastOne; + DevicePrimesPow2LastOne = Accelerator.Allocate1D(primesPow2LastOne.Length); + DevicePrimesPow2LastOne.View.CopyFromCPU(primesPow2LastOne); - var primesPow2LastSeven = DivisorGenerator.SmallPrimesPow2LastSeven; - DevicePrimesPow2LastSeven = Accelerator.Allocate1D(primesPow2LastSeven.Length); - DevicePrimesPow2LastSeven.View.CopyFromCPU(primesPow2LastSeven); + var primesPow2LastSeven = DivisorGenerator.SmallPrimesPow2LastSeven; + DevicePrimesPow2LastSeven = Accelerator.Allocate1D(primesPow2LastSeven.Length); + DevicePrimesPow2LastSeven.View.CopyFromCPU(primesPow2LastSeven); - var primesPow2LastThree = DivisorGenerator.SmallPrimesPow2LastThree; - DevicePrimesPow2LastThree = Accelerator.Allocate1D(primesPow2LastThree.Length); - DevicePrimesPow2LastThree.View.CopyFromCPU(primesPow2LastThree); + var primesPow2LastThree = DivisorGenerator.SmallPrimesPow2LastThree; + DevicePrimesPow2LastThree = Accelerator.Allocate1D(primesPow2LastThree.Length); + DevicePrimesPow2LastThree.View.CopyFromCPU(primesPow2LastThree); - var primesPow2LastNine = DivisorGenerator.SmallPrimesPow2LastNine; - DevicePrimesPow2LastNine = Accelerator.Allocate1D(primesPow2LastNine.Length); - DevicePrimesPow2LastNine.View.CopyFromCPU(primesPow2LastNine); + var primesPow2LastNine = DivisorGenerator.SmallPrimesPow2LastNine; + DevicePrimesPow2LastNine = Accelerator.Allocate1D(primesPow2LastNine.Length); + DevicePrimesPow2LastNine.View.CopyFromCPU(primesPow2LastNine); - BufferCapacity = minBufferCapacity < 1 ? 1 : minBufferCapacity; - Input = Accelerator.Allocate1D(BufferCapacity); - Output = Accelerator.Allocate1D(BufferCapacity); - HeuristicFlag = Accelerator.Allocate1D(BufferCapacity); - _returned = false; - } + BufferCapacity = minBufferCapacity < 1 ? 1 : minBufferCapacity; + Input = Accelerator.Allocate1D(BufferCapacity); + Output = Accelerator.Allocate1D(BufferCapacity); + HeuristicFlag = Accelerator.Allocate1D(BufferCapacity); + _returned = false; + } - public void EnsureCapacity(int minCapacity) - { - int required = minCapacity < 1 ? 1 : minCapacity; - if (required <= BufferCapacity) - { - return; - } + public void EnsureCapacity(int minCapacity) + { + int required = minCapacity < 1 ? 1 : minCapacity; + if (required <= BufferCapacity) + { + return; + } - Input.Dispose(); - Output.Dispose(); - HeuristicFlag.Dispose(); - Input = Accelerator.Allocate1D(required); - Output = Accelerator.Allocate1D(required); - HeuristicFlag = Accelerator.Allocate1D(required); - BufferCapacity = required; - } + Input.Dispose(); + Output.Dispose(); + HeuristicFlag.Dispose(); + Input = Accelerator.Allocate1D(required); + Output = Accelerator.Allocate1D(required); + HeuristicFlag = Accelerator.Allocate1D(required); + BufferCapacity = required; + } - internal void ResetReturnFlag() - { - _returned = false; - } + internal void ResetReturnFlag() + { + _returned = false; + } - public void Dispose() - { - if (_returned) - { - return; - } + public void Dispose() + { + if (_returned) + { + return; + } - _returned = true; - PrimeTesterGpuContextPool.Return(this); - } + _returned = true; + PrimeTesterGpuContextPool.Return(this); + } - internal void DisposeResources() - { - Input.Dispose(); - Output.Dispose(); - HeuristicFlag.Dispose(); - DevicePrimesDefault.Dispose(); - DevicePrimesLastOne.Dispose(); - DevicePrimesLastSeven.Dispose(); - DevicePrimesLastThree.Dispose(); - DevicePrimesLastNine.Dispose(); - DevicePrimesPow2Default.Dispose(); - DevicePrimesPow2LastOne.Dispose(); - DevicePrimesPow2LastSeven.Dispose(); - DevicePrimesPow2LastThree.Dispose(); - DevicePrimesPow2LastNine.Dispose(); - Accelerator.Dispose(); - AcceleratorContext.Dispose(); - } - } - } - // Expose cache clearing for accelerator disposal coordination + internal void DisposeResources() + { + Input.Dispose(); + Output.Dispose(); + HeuristicFlag.Dispose(); + DevicePrimesDefault.Dispose(); + DevicePrimesLastOne.Dispose(); + DevicePrimesLastSeven.Dispose(); + DevicePrimesLastThree.Dispose(); + DevicePrimesLastNine.Dispose(); + DevicePrimesPow2Default.Dispose(); + DevicePrimesPow2LastOne.Dispose(); + DevicePrimesPow2LastSeven.Dispose(); + DevicePrimesPow2LastThree.Dispose(); + DevicePrimesPow2LastNine.Dispose(); + Accelerator.Dispose(); + AcceleratorContext.Dispose(); + } + } + } + // Expose cache clearing for accelerator disposal coordination public static void ClearGpuCaches(Accelerator accelerator) { PrimeTesterGpuContextPool.Clear(accelerator);