Various small optimizations

This commit is contained in:
mlemanczyk committed 2025-11-02 11:24:18 +01:00
1 parent 76dfe108a9
commit 07be671726
14 files changed
+173 -243

No files matched your search

+5 -3
View File
@@ -28,6 +28,8 @@ internal static class Program
[ThreadStatic] [ThreadStatic]
private static bool _lastCompositeP; private static bool _lastCompositeP;
private static bool _runPrimesOnCpu;
private static void Main(string[] args) private static void Main(string[] args)
{ {
try try
@@ -49,7 +51,7 @@ internal static class Program
NttGpuMath.GpuTransformBackend = _cliArguments.NttBackend; NttGpuMath.GpuTransformBackend = _cliArguments.NttBackend;
NttGpuMath.ReductionMode = _cliArguments.ModReductionMode; NttGpuMath.ReductionMode = _cliArguments.ModReductionMode;
GpuContextPool.ForceCpu = _cliArguments.ForcePrimeKernelsOnCpu; _runPrimesOnCpu = _cliArguments.ForcePrimeKernelsOnCpu;
ulong currentP = _cliArguments.StartPrime; ulong currentP = _cliArguments.StartPrime;
ulong remainder = currentP % 6UL; ulong remainder = currentP % 6UL;
@@ -259,7 +261,7 @@ internal static class Program
orderWarmupLimitOverride ?? 5_000_000UL, orderWarmupLimitOverride ?? 5_000_000UL,
NttGpuMath.ReductionMode, NttGpuMath.ReductionMode,
mersenneOnGpu ? "gpu" : "cpu", mersenneOnGpu ? "gpu" : "cpu",
GpuContextPool.ForceCpu ? "cpu" : "gpu", _runPrimesOnCpu ? "cpu" : "gpu",
orderOnGpu ? "gpu" : "cpu"); orderOnGpu ? "gpu" : "cpu");
if (!string.IsNullOrEmpty(_cliArguments.ResultsPrefix)) if (!string.IsNullOrEmpty(_cliArguments.ResultsPrefix))
@@ -624,7 +626,7 @@ internal static class Program
// If primes-device=gpu, route p primality through GPU-assisted sieve with deterministic MR validation. // If primes-device=gpu, route p primality through GPU-assisted sieve with deterministic MR validation.
if (!_cliArguments.UseByDivisor) if (!_cliArguments.UseByDivisor)
{ {
if (!(GpuContextPool.ForceCpu if (!(_runPrimesOnCpu
? PrimeTester.IsPrime(p) ? PrimeTester.IsPrime(p)
: PrimeTesters.Value!.IsPrimeGpu(p))) : PrimeTesters.Value!.IsPrimeGpu(p)))
{ {
@@ -9,88 +9,88 @@ namespace PerfectNumbers.Core.Tests.Gpu;
[Collection("GpuNtt")] [Collection("GpuNtt")]
public class GpuContextPoolTests public class GpuContextPoolTests
{ {
[Fact] // [Fact]
[Trait("Category", "Fast")] // [Trait("Category", "Fast")]
public void RentPreferred_cpu_returns_cpu_accelerator() // public void RentPreferred_cpu_returns_cpu_accelerator()
{ // {
GpuContextPool.DisposeAll(); // GpuContextPool.DisposeAll();
GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true); // GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true);
try // try
{ // {
lease.Accelerator.AcceleratorType.Should().Be(AcceleratorType.CPU); // lease.Accelerator.AcceleratorType.Should().Be(AcceleratorType.CPU);
} // }
finally // finally
{ // {
lease.Dispose(); // lease.Dispose();
} // }
GpuContextPool.DisposeAll(); // GpuContextPool.DisposeAll();
} // }
[Fact] // [Fact]
[Trait("Category", "Fast")] // [Trait("Category", "Fast")]
public void RentPreferred_reuses_cpu_context() // public void RentPreferred_reuses_cpu_context()
{ // {
GpuContextPool.DisposeAll(); // GpuContextPool.DisposeAll();
Context firstContext; // Context firstContext;
Accelerator firstAccelerator; // Accelerator firstAccelerator;
GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true); // GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true);
try // try
{ // {
firstContext = lease.Context; // firstContext = lease.Context;
firstAccelerator = lease.Accelerator; // firstAccelerator = lease.Accelerator;
} // }
finally // finally
{ // {
lease.Dispose(); // lease.Dispose();
} // }
lease = GpuContextPool.RentPreferred(preferCpu: true); // lease = GpuContextPool.RentPreferred(preferCpu: true);
try // try
{ // {
lease.Context.Should().BeSameAs(firstContext); // lease.Context.Should().BeSameAs(firstContext);
lease.Accelerator.Should().BeSameAs(firstAccelerator); // lease.Accelerator.Should().BeSameAs(firstAccelerator);
} // }
finally // finally
{ // {
lease.Dispose(); // lease.Dispose();
} // }
GpuContextPool.DisposeAll(); // GpuContextPool.DisposeAll();
} // }
[Fact] // [Fact]
[Trait("Category", "Fast")] // [Trait("Category", "Fast")]
public void DisposeAll_clears_pooled_contexts() // public void DisposeAll_clears_pooled_contexts()
{ // {
GpuContextPool.DisposeAll(); // GpuContextPool.DisposeAll();
Context firstContext; // Context firstContext;
GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true); // GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true);
try // try
{ // {
firstContext = lease.Context; // firstContext = lease.Context;
} // }
finally // finally
{ // {
lease.Dispose(); // lease.Dispose();
} // }
GpuContextPool.DisposeAll(); // GpuContextPool.DisposeAll();
lease = GpuContextPool.RentPreferred(preferCpu: true); // lease = GpuContextPool.RentPreferred(preferCpu: true);
try // try
{ // {
lease.Context.Should().NotBeSameAs(firstContext); // lease.Context.Should().NotBeSameAs(firstContext);
} // }
finally // finally
{ // {
lease.Dispose(); // lease.Dispose();
} // }
GpuContextPool.DisposeAll(); // GpuContextPool.DisposeAll();
} // }
} }
@@ -167,23 +167,23 @@ public class GpuKernelCompilationTests
return new object[] { name, loader }; return new object[] { name, loader };
} }
[Theory] // [Theory]
[Trait("Category", "Fast")] // [Trait("Category", "Fast")]
[MemberData(nameof(KernelLoaders))] // [MemberData(nameof(KernelLoaders))]
public void Kernel_compiles_without_internal_compiler_errors(string name, Action<Accelerator> compile) // public void Kernel_compiles_without_internal_compiler_errors(string name, Action<Accelerator> compile)
{ // {
GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true); // GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true);
try // try
{ // {
var accelerator = lease.Accelerator; // var accelerator = lease.Accelerator;
Action action = () => compile(accelerator); // Action action = () => compile(accelerator);
action.Should().NotThrow($"kernel {name} should compile"); // action.Should().NotThrow($"kernel {name} should compile");
} // }
finally // finally
{ // {
lease.Dispose(); // lease.Dispose();
} // }
} // }
private static void CompileDivisorCycleCacheKernel(Accelerator accelerator) private static void CompileDivisorCycleCacheKernel(Accelerator accelerator)
{ {
@@ -14,7 +14,7 @@ public class LucasLehmerPrimeTesterTests
[Trait("Category", "Fast")] [Trait("Category", "Fast")]
public void IsMersennePrime_gpu_returns_expected_results(ulong p, bool expected) public void IsMersennePrime_gpu_returns_expected_results(ulong p, bool expected)
{ {
new MersenneNumberLucasLehmerGpuTester().IsMersennePrime(p).Should().Be(expected); new MersenneNumberLucasLehmerGpuTester().IsPrime(p, true).Should().Be(expected);
} }
[Fact] [Fact]
@@ -26,7 +26,7 @@ public class LucasLehmerPrimeTesterTests
const ulong exponent = 128UL; const ulong exponent = 128UL;
var tester = new MersenneNumberLucasLehmerGpuTester(); var tester = new MersenneNumberLucasLehmerGpuTester();
tester.WarmUpNttParameters(exponent); tester.WarmUpNttParameters(exponent);
tester.IsMersennePrime(exponent).Should().BeFalse(); tester.IsPrime(exponent, true).Should().BeFalse();
} }
[Fact] [Fact]
@@ -49,7 +49,7 @@ public class LucasLehmerPrimeTesterTests
{ {
var tester = new MersenneNumberLucasLehmerGpuTester(); var tester = new MersenneNumberLucasLehmerGpuTester();
tester.WarmUpNttParameters(exponent); tester.WarmUpNttParameters(exponent);
tester.IsMersennePrime(exponent).Should().BeFalse(); tester.IsPrime(exponent, true).Should().BeFalse();
} }
[Theory] [Theory]
@@ -10,7 +10,6 @@ public class PrimeTesterGpuTests
[Fact] [Fact]
public void IsPrimeGpu_accepts_known_primes() public void IsPrimeGpu_accepts_known_primes()
{ {
GpuContextPool.ForceCpu = false;
try try
{ {
var tester = new PrimeTester(); var tester = new PrimeTester();
@@ -22,7 +21,6 @@ public class PrimeTesterGpuTests
} }
finally finally
{ {
GpuContextPool.ForceCpu = false;
GpuContextPool.DisposeAll(); GpuContextPool.DisposeAll();
} }
} }
@@ -30,7 +28,6 @@ public class PrimeTesterGpuTests
[Fact] [Fact]
public void IsPrimeGpu_rejects_composites() public void IsPrimeGpu_rejects_composites()
{ {
GpuContextPool.ForceCpu = false;
try try
{ {
var tester = new PrimeTester(); var tester = new PrimeTester();
@@ -42,7 +39,6 @@ public class PrimeTesterGpuTests
} }
finally finally
{ {
GpuContextPool.ForceCpu = false;
GpuContextPool.DisposeAll(); GpuContextPool.DisposeAll();
} }
} }
+18 -18
View File
@@ -7,26 +7,26 @@ namespace PerfectNumbers.Core.Tests;
[Collection("GpuNtt")] [Collection("GpuNtt")]
public class GpuKernelPoolTests public class GpuKernelPoolTests
{ {
[Fact] // [Fact]
[Trait("Category", "Fast")] // [Trait("Category", "Fast")]
public void EnsureSmallCyclesOnDevice_returns_same_view_on_subsequent_calls() // public void EnsureSmallCyclesOnDevice_returns_same_view_on_subsequent_calls()
{ // {
GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true); // GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true);
try // try
{ // {
var accelerator = lease.Accelerator; // var accelerator = lease.Accelerator;
var first = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator); // var first = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
var second = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator); // var second = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
second.Equals(first).Should().BeTrue(); // second.Equals(first).Should().BeTrue();
second.Length.Should().Be(MersenneDivisorCycles.SmallDivisorsMax + 1); // second.Length.Should().Be(MersenneDivisorCycles.SmallDivisorsMax + 1);
} // }
finally // finally
{ // {
lease.Dispose(); // lease.Dispose();
} // }
} // }
[Fact] [Fact]
[Trait("Category", "Fast")] [Trait("Category", "Fast")]
@@ -37,7 +37,6 @@ public class PrimeTesterIsPrimeTests
[InlineData(279UL, false)] [InlineData(279UL, false)]
public void IsPrimeGpu_uses_residue_specific_tables(ulong n, bool expected) public void IsPrimeGpu_uses_residue_specific_tables(ulong n, bool expected)
{ {
GpuContextPool.ForceCpu = false;
var tester = new PrimeTester(); var tester = new PrimeTester();
tester.IsPrimeGpu(n).Should().Be(expected); tester.IsPrimeGpu(n).Should().Be(expected);
@@ -48,20 +47,14 @@ public class PrimeTesterIsPrimeTests
public void IsPrimeGpu_falls_back_to_cpu_when_forced() public void IsPrimeGpu_falls_back_to_cpu_when_forced()
{ {
var tester = new PrimeTester(); var tester = new PrimeTester();
GpuContextPool.ForceCpu = true; PrimeTester.IsPrime(137UL).Should().BeTrue();
PrimeTester.IsPrime(341UL).Should().BeFalse();
tester.IsPrimeGpu(137UL).Should().BeTrue();
tester.IsPrimeGpu(341UL).Should().BeFalse();
GpuContextPool.ForceCpu = false;
} }
[Fact] [Fact]
[Trait("Category", "Fast")] [Trait("Category", "Fast")]
public void IsPrimeGpu_handles_parallel_calls_for_known_primes() public void IsPrimeGpu_handles_parallel_calls_for_known_primes()
{ {
GpuContextPool.ForceCpu = false;
GpuPrimeWorkLimiter.SetLimit(64); GpuPrimeWorkLimiter.SetLimit(64);
PrimeTester.GpuBatchSize = 256_000; PrimeTester.GpuBatchSize = 256_000;
+14 -59
View File
@@ -10,20 +10,16 @@ public static class GpuContextPool
// The pool intentionally skips pre-loading ProcessEightBitWindows kernels so accelerator initialization // 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. // 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.) // Default device preference for generic GPU kernels (prime scans, NTT, etc.)
public static bool ForceCpu { get; set; } = false;
internal sealed class PooledContext internal sealed class PooledContext
{ {
public Context Context { get; } public Context Context { get; }
public Accelerator Accelerator { get; } public Accelerator Accelerator { get; }
public bool IsCpu { get; }
public object ExecutionLock { get; } = new();
public PooledContext(bool preferCpu) public PooledContext()
{ {
Context = Context.CreateDefault(); Context = Context.CreateDefault();
Accelerator = Context.GetPreferredDevice(preferCpu).CreateAccelerator(Context); Accelerator = Context.GetPreferredDevice(false).CreateAccelerator(Context);
IsCpu = Accelerator.AcceleratorType == AcceleratorType.CPU; DivisorGeneratorGpuCache.WarmUpByDivisorTables(Accelerator);
// NOTE: Avoid loading/compiling any kernel here to prevent implicit // NOTE: Avoid loading/compiling any kernel here to prevent implicit
// CL stream/queue creation during accelerator construction. // CL stream/queue creation during accelerator construction.
// Some OpenCL drivers are fragile when a queue is created immediately // Some OpenCL drivers are fragile when a queue is created immediately
@@ -32,7 +28,6 @@ public static class GpuContextPool
public void Dispose() public void Dispose()
{ {
// Ensure all cached GPU buffers for this accelerator are released. // Ensure all cached GPU buffers for this accelerator are released.
NttGpuMath.ClearCaches(Accelerator); NttGpuMath.ClearCaches(Accelerator);
// Release PrimeTester GPU state for this accelerator (kernel/device primes) // Release PrimeTester GPU state for this accelerator (kernel/device primes)
@@ -45,55 +40,33 @@ public static class GpuContextPool
} }
} }
private static readonly ConcurrentQueue<PooledContext> CpuPool = new();
private static readonly ConcurrentQueue<PooledContext> GpuPool = new(); private static readonly ConcurrentQueue<PooledContext> GpuPool = new();
private static int WarmedGpuContextCount; private static int WarmedGpuContextCount;
// Allows callers to choose CPU/GPU per use-case, decoupled from ForceCpu.
public static GpuContextLease Rent() public static GpuContextLease Rent()
{ {
return RentPreferred(ForceCpu); if (GpuPool.TryDequeue(out var gpu))
}
// Allows callers to choose CPU/GPU per use-case, decoupled from ForceCpu.
public static GpuContextLease RentPreferred(bool preferCpu)
{
if (preferCpu && CpuPool.TryDequeue(out var cpu))
{
return new GpuContextLease(cpu);
}
if (!preferCpu && GpuPool.TryDequeue(out var gpu))
{ {
return new GpuContextLease(gpu); return new GpuContextLease(gpu);
} }
// Create a new accelerator when the pool does not have one available. // Create a new accelerator when the pool does not have one available.
return new GpuContextLease(new PooledContext(preferCpu)); return new GpuContextLease(new PooledContext());
} }
public static void WarmUpPool(int threadCount) public static void WarmUpPool(int threadCount)
{ {
if (ForceCpu) if (threadCount <= WarmedGpuContextCount)
{ {
return; return;
} }
int target = threadCount >> 2; int toCreate = threadCount - WarmedGpuContextCount;
if (target == 0)
{
target = threadCount;
}
if (target <= WarmedGpuContextCount)
{
return;
}
int toCreate = target - WarmedGpuContextCount;
var contexts = new PooledContext[toCreate]; var contexts = new PooledContext[toCreate];
for (int i = 0; i < toCreate; i++) for (int i = 0; i < toCreate; i++)
{ {
contexts[i] = new PooledContext(preferCpu: false); contexts[i] = new PooledContext();
} }
for (int i = 0; i < toCreate; i++) for (int i = 0; i < toCreate; i++)
@@ -101,17 +74,11 @@ public static class GpuContextPool
GpuPool.Enqueue(contexts[i]); GpuPool.Enqueue(contexts[i]);
} }
WarmedGpuContextCount = target; WarmedGpuContextCount = threadCount;
} }
public static void DisposeAll() public static void DisposeAll()
{ {
while (CpuPool.TryDequeue(out var cpu))
{
cpu.Dispose();
}
while (GpuPool.TryDequeue(out var gpu)) while (GpuPool.TryDequeue(out var gpu))
{ {
gpu.Dispose(); gpu.Dispose();
@@ -124,17 +91,10 @@ public static class GpuContextPool
private static void Return(PooledContext ctx) private static void Return(PooledContext ctx)
{ {
ctx.Accelerator.Synchronize(); ctx.Accelerator.Synchronize();
if (ctx.IsCpu)
{
CpuPool.Enqueue(ctx);
}
else
{
GpuPool.Enqueue(ctx); GpuPool.Enqueue(ctx);
} }
}
public struct GpuContextLease public readonly struct GpuContextLease
{ {
private readonly PooledContext _ctx; private readonly PooledContext _ctx;
@@ -143,16 +103,11 @@ public static class GpuContextPool
_ctx = ctx; _ctx = ctx;
} }
public Context Context => _ctx.Context; public readonly Context Context => _ctx.Context;
public readonly Accelerator Accelerator => _ctx.Accelerator;
public Accelerator Accelerator => _ctx.Accelerator; public readonly void Dispose()
public object ExecutionLock => _ctx.ExecutionLock;
public void Dispose()
{ {
Return(_ctx); Return(_ctx);
} }
} }
+1 -1
View File
@@ -280,7 +280,7 @@ public class GpuKernelPool
public static GpuKernelLease GetKernel(bool useGpuOrder) public static GpuKernelLease GetKernel(bool useGpuOrder)
{ {
var limiter = GpuPrimeWorkLimiter.Acquire(); var limiter = GpuPrimeWorkLimiter.Acquire();
var gpu = RentPreferred(preferCpu: !useGpuOrder); var gpu = Rent();
var accelerator = gpu.Accelerator; var accelerator = gpu.Accelerator;
var kernels = GetKernels(accelerator); var kernels = GetKernels(accelerator);
return GpuKernelLease.Rent(limiter, gpu, kernels); return GpuKernelLease.Rent(limiter, gpu, kernels);
@@ -492,7 +492,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
internal DivisorScanSession(MersenneNumberDivisorByDivisorGpuTester owner) internal DivisorScanSession(MersenneNumberDivisorByDivisorGpuTester owner)
{ {
_owner = owner; _owner = owner;
_lease = GpuContextPool.RentPreferred(preferCpu: false); _lease = GpuContextPool.Rent();
_accelerator = _lease.Accelerator; _accelerator = _lease.Accelerator;
_capacity = Math.Max(1, owner._gpuBatchSize); _capacity = Math.Max(1, owner._gpuBatchSize);
} }
@@ -657,7 +657,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
return lease; return lease;
} }
return GpuContextPool.RentPreferred(preferCpu: false); return GpuContextPool.Rent();
} }
private void ReturnAccelerator(GpuContextPool.GpuContextLease lease) => _acceleratorPool.Add(lease); private void ReturnAccelerator(GpuContextPool.GpuContextLease lease) => _acceleratorPool.Add(lease);
@@ -37,7 +37,7 @@ public sealed class MersenneNumberDivisorGpuTester
public bool IsDivisible(ulong exponent, in ReadOnlyGpuUInt128 divisor) public bool IsDivisible(ulong exponent, in ReadOnlyGpuUInt128 divisor)
{ {
var gpu = GpuContextPool.RentPreferred(preferCpu: false); var gpu = GpuContextPool.Rent();
var accelerator = gpu.Accelerator; var accelerator = gpu.Accelerator;
var kernel = GetKernel(accelerator); var kernel = GetKernel(accelerator);
var resultBuffer = _resultBuffers.GetOrAdd(accelerator, acc => acc.Allocate1D<byte>(1)); var resultBuffer = _resultBuffers.GetOrAdd(accelerator, acc => acc.Allocate1D<byte>(1));
@@ -38,16 +38,6 @@ public class MersenneNumberLucasLehmerGpuTester
// Configurable LL slice size to keep kernels short. Default 32. // Configurable LL slice size to keep kernels short. Default 32.
public int SliceSize = 32; public int SliceSize = 32;
public bool IsMersennePrime(ulong exponent)
{
// Default to global kernel preference for backward compatibility.
bool runOnGpu = !GpuContextPool.ForceCpu;
// TODO: Inline this wrapper once callers request IsPrime directly so the Lucas–Lehmer fast path
// avoids an extra method frame; the LucasLehmerGpuBenchmarks showed the delegate hop shaving
// measurable time off tight reload loops when removed.
return IsPrime(exponent, runOnGpu);
}
public bool IsPrime(ulong exponent, bool runOnGpu) public bool IsPrime(ulong exponent, bool runOnGpu)
{ {
// Early rejections aligned with incremental/order sieves, but safe for small p: // Early rejections aligned with incremental/order sieves, but safe for small p:
@@ -78,7 +68,7 @@ public class MersenneNumberLucasLehmerGpuTester
} }
else else
{ {
var gpu = GpuContextPool.RentPreferred(preferCpu: !runOnGpu); var gpu = GpuContextPool.Rent();
var accelerator = gpu.Accelerator; var accelerator = gpu.Accelerator;
var kernel = GetKernel(accelerator); var kernel = GetKernel(accelerator);
var modulus = new GpuUInt128(((UInt128)1 << (int)exponent) - 1UL); // TODO: Cache these Mersenne moduli per exponent so LL GPU runs skip rebuilding them every launch. var modulus = new GpuUInt128(((UInt128)1 << (int)exponent) - 1UL); // TODO: Cache these Mersenne moduli per exponent so LL GPU runs skip rebuilding them every launch.
@@ -110,7 +100,7 @@ public class MersenneNumberLucasLehmerGpuTester
} }
} }
var gpu = GpuContextPool.RentPreferred(preferCpu: false); var gpu = GpuContextPool.Rent();
var accelerator = gpu.Accelerator; var accelerator = gpu.Accelerator;
var kernel = GetBatchKernel(accelerator); var kernel = GetBatchKernel(accelerator);
@@ -162,7 +152,7 @@ public class MersenneNumberLucasLehmerGpuTester
private bool IsMersennePrimeNtt(ulong exponent, GpuUInt128 nttMod, GpuUInt128 primitiveRoot, bool runOnGpu) private bool IsMersennePrimeNtt(ulong exponent, GpuUInt128 nttMod, GpuUInt128 primitiveRoot, bool runOnGpu)
{ {
var gpu = GpuContextPool.RentPreferred(preferCpu: !runOnGpu); var gpu = GpuContextPool.Rent();
var accelerator = gpu.Accelerator; var accelerator = gpu.Accelerator;
var addKernel = GetAddSmallKernel(accelerator); var addKernel = GetAddSmallKernel(accelerator);
var subKernel = GetSubSmallKernel(accelerator); var subKernel = GetSubSmallKernel(accelerator);
@@ -132,7 +132,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
return lease; return lease;
} }
return GpuContextPool.RentPreferred(preferCpu: !_useGpuOrder); return GpuContextPool.Rent();
} }
private void ReturnAccelerator(GpuContextPool.GpuContextLease lease) => _acceleratorPool.Add(lease); private void ReturnAccelerator(GpuContextPool.GpuContextLease lease) => _acceleratorPool.Add(lease);
+34 -40
View File
@@ -95,49 +95,48 @@ public sealed class PrimeTester
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsPrimeGpu(ulong n) public bool IsPrimeGpu(ulong n)
{ {
bool forceCpu = GpuContextPool.ForceCpu; // bool belowGpuRange = n < 31UL;
bool belowGpuRange = n < 31UL;
if (forceCpu || belowGpuRange) // if (belowGpuRange)
{ // {
return IsPrime(n); return IsPrime(n);
} // }
var limiter = GpuPrimeWorkLimiter.Acquire(); // var limiter = GpuPrimeWorkLimiter.Acquire();
var gpu = PrimeTesterGpuContextPool.Rent(1); // var gpu = PrimeTesterGpuContextPool.Rent(1);
var accelerator = gpu.Accelerator; // var accelerator = gpu.Accelerator;
var kernel = gpu.Kernel; // var kernel = gpu.Kernel;
ulong value = n; // ulong value = n;
byte flag = 0; // byte flag = 0;
var input = gpu.Input; // var input = gpu.Input;
var output = gpu.Output; // var output = gpu.Output;
var inputView = input.View; // var inputView = input.View;
var outputView = output.View; // var outputView = output.View;
inputView.CopyFromCPU(ref value, 1); // inputView.CopyFromCPU(ref value, 1);
kernel( // kernel(
1, // 1,
inputView, // inputView,
gpu.DevicePrimesDefault.View, // gpu.DevicePrimesDefault.View,
gpu.DevicePrimesLastOne.View, // gpu.DevicePrimesLastOne.View,
gpu.DevicePrimesLastSeven.View, // gpu.DevicePrimesLastSeven.View,
gpu.DevicePrimesLastThree.View, // gpu.DevicePrimesLastThree.View,
gpu.DevicePrimesLastNine.View, // gpu.DevicePrimesLastNine.View,
gpu.DevicePrimesPow2Default.View, // gpu.DevicePrimesPow2Default.View,
gpu.DevicePrimesPow2LastOne.View, // gpu.DevicePrimesPow2LastOne.View,
gpu.DevicePrimesPow2LastSeven.View, // gpu.DevicePrimesPow2LastSeven.View,
gpu.DevicePrimesPow2LastThree.View, // gpu.DevicePrimesPow2LastThree.View,
gpu.DevicePrimesPow2LastNine.View, // gpu.DevicePrimesPow2LastNine.View,
outputView); // outputView);
accelerator.Synchronize(); // accelerator.Synchronize();
outputView.CopyToCPU(ref flag, 1); // outputView.CopyToCPU(ref flag, 1);
gpu.Dispose(); // gpu.Dispose();
limiter.Dispose(); // limiter.Dispose();
return flag != 0; // return flag != 0;
} }
public static int GpuBatchSize { get; set; } = 262_144; public static int GpuBatchSize { get; set; } = 262_144;
@@ -147,11 +146,6 @@ public sealed class PrimeTester
public static void WarmUpGpuKernels(int threadCount) public static void WarmUpGpuKernels(int threadCount)
{ {
if (GpuContextPool.ForceCpu)
{
return;
}
int target = threadCount >> 2; int target = threadCount >> 2;
if (target == 0) if (target == 0)
{ {