Various small optimizations
This commit is contained in:
1 parent
76dfe108a9
commit
07be671726
14 files changed
+206
-276
No files matched your search
@@ -28,6 +28,8 @@ internal static class Program
|
||||
[ThreadStatic]
|
||||
private static bool _lastCompositeP;
|
||||
|
||||
private static bool _runPrimesOnCpu;
|
||||
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
try
|
||||
@@ -49,7 +51,7 @@ internal static class Program
|
||||
|
||||
NttGpuMath.GpuTransformBackend = _cliArguments.NttBackend;
|
||||
NttGpuMath.ReductionMode = _cliArguments.ModReductionMode;
|
||||
GpuContextPool.ForceCpu = _cliArguments.ForcePrimeKernelsOnCpu;
|
||||
_runPrimesOnCpu = _cliArguments.ForcePrimeKernelsOnCpu;
|
||||
|
||||
ulong currentP = _cliArguments.StartPrime;
|
||||
ulong remainder = currentP % 6UL;
|
||||
@@ -259,7 +261,7 @@ internal static class Program
|
||||
orderWarmupLimitOverride ?? 5_000_000UL,
|
||||
NttGpuMath.ReductionMode,
|
||||
mersenneOnGpu ? "gpu" : "cpu",
|
||||
GpuContextPool.ForceCpu ? "cpu" : "gpu",
|
||||
_runPrimesOnCpu ? "cpu" : "gpu",
|
||||
orderOnGpu ? "gpu" : "cpu");
|
||||
|
||||
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 (!_cliArguments.UseByDivisor)
|
||||
{
|
||||
if (!(GpuContextPool.ForceCpu
|
||||
if (!(_runPrimesOnCpu
|
||||
? PrimeTester.IsPrime(p)
|
||||
: PrimeTesters.Value!.IsPrimeGpu(p)))
|
||||
{
|
||||
|
||||
@@ -9,88 +9,88 @@ namespace PerfectNumbers.Core.Tests.Gpu;
|
||||
[Collection("GpuNtt")]
|
||||
public class GpuContextPoolTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", "Fast")]
|
||||
public void RentPreferred_cpu_returns_cpu_accelerator()
|
||||
{
|
||||
GpuContextPool.DisposeAll();
|
||||
// [Fact]
|
||||
// [Trait("Category", "Fast")]
|
||||
// public void RentPreferred_cpu_returns_cpu_accelerator()
|
||||
// {
|
||||
// GpuContextPool.DisposeAll();
|
||||
|
||||
GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true);
|
||||
try
|
||||
{
|
||||
lease.Accelerator.AcceleratorType.Should().Be(AcceleratorType.CPU);
|
||||
}
|
||||
finally
|
||||
{
|
||||
lease.Dispose();
|
||||
}
|
||||
// GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true);
|
||||
// try
|
||||
// {
|
||||
// lease.Accelerator.AcceleratorType.Should().Be(AcceleratorType.CPU);
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// lease.Dispose();
|
||||
// }
|
||||
|
||||
GpuContextPool.DisposeAll();
|
||||
}
|
||||
// GpuContextPool.DisposeAll();
|
||||
// }
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", "Fast")]
|
||||
public void RentPreferred_reuses_cpu_context()
|
||||
{
|
||||
GpuContextPool.DisposeAll();
|
||||
// [Fact]
|
||||
// [Trait("Category", "Fast")]
|
||||
// public void RentPreferred_reuses_cpu_context()
|
||||
// {
|
||||
// GpuContextPool.DisposeAll();
|
||||
|
||||
Context firstContext;
|
||||
Accelerator firstAccelerator;
|
||||
GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true);
|
||||
try
|
||||
{
|
||||
firstContext = lease.Context;
|
||||
firstAccelerator = lease.Accelerator;
|
||||
}
|
||||
finally
|
||||
{
|
||||
lease.Dispose();
|
||||
}
|
||||
// Context firstContext;
|
||||
// Accelerator firstAccelerator;
|
||||
// GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true);
|
||||
// try
|
||||
// {
|
||||
// firstContext = lease.Context;
|
||||
// firstAccelerator = lease.Accelerator;
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// lease.Dispose();
|
||||
// }
|
||||
|
||||
lease = GpuContextPool.RentPreferred(preferCpu: true);
|
||||
try
|
||||
{
|
||||
lease.Context.Should().BeSameAs(firstContext);
|
||||
lease.Accelerator.Should().BeSameAs(firstAccelerator);
|
||||
}
|
||||
finally
|
||||
{
|
||||
lease.Dispose();
|
||||
}
|
||||
// lease = GpuContextPool.RentPreferred(preferCpu: true);
|
||||
// try
|
||||
// {
|
||||
// lease.Context.Should().BeSameAs(firstContext);
|
||||
// lease.Accelerator.Should().BeSameAs(firstAccelerator);
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// lease.Dispose();
|
||||
// }
|
||||
|
||||
GpuContextPool.DisposeAll();
|
||||
}
|
||||
// GpuContextPool.DisposeAll();
|
||||
// }
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", "Fast")]
|
||||
public void DisposeAll_clears_pooled_contexts()
|
||||
{
|
||||
GpuContextPool.DisposeAll();
|
||||
// [Fact]
|
||||
// [Trait("Category", "Fast")]
|
||||
// public void DisposeAll_clears_pooled_contexts()
|
||||
// {
|
||||
// GpuContextPool.DisposeAll();
|
||||
|
||||
Context firstContext;
|
||||
GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true);
|
||||
try
|
||||
{
|
||||
firstContext = lease.Context;
|
||||
}
|
||||
finally
|
||||
{
|
||||
lease.Dispose();
|
||||
}
|
||||
// Context firstContext;
|
||||
// GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true);
|
||||
// try
|
||||
// {
|
||||
// firstContext = lease.Context;
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// lease.Dispose();
|
||||
// }
|
||||
|
||||
GpuContextPool.DisposeAll();
|
||||
// GpuContextPool.DisposeAll();
|
||||
|
||||
lease = GpuContextPool.RentPreferred(preferCpu: true);
|
||||
try
|
||||
{
|
||||
lease.Context.Should().NotBeSameAs(firstContext);
|
||||
}
|
||||
finally
|
||||
{
|
||||
lease.Dispose();
|
||||
}
|
||||
// lease = GpuContextPool.RentPreferred(preferCpu: true);
|
||||
// try
|
||||
// {
|
||||
// lease.Context.Should().NotBeSameAs(firstContext);
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// lease.Dispose();
|
||||
// }
|
||||
|
||||
GpuContextPool.DisposeAll();
|
||||
}
|
||||
// GpuContextPool.DisposeAll();
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -167,23 +167,23 @@ public class GpuKernelCompilationTests
|
||||
return new object[] { name, loader };
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[Trait("Category", "Fast")]
|
||||
[MemberData(nameof(KernelLoaders))]
|
||||
public void Kernel_compiles_without_internal_compiler_errors(string name, Action<Accelerator> compile)
|
||||
{
|
||||
GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true);
|
||||
try
|
||||
{
|
||||
var accelerator = lease.Accelerator;
|
||||
Action action = () => compile(accelerator);
|
||||
action.Should().NotThrow($"kernel {name} should compile");
|
||||
}
|
||||
finally
|
||||
{
|
||||
lease.Dispose();
|
||||
}
|
||||
}
|
||||
// [Theory]
|
||||
// [Trait("Category", "Fast")]
|
||||
// [MemberData(nameof(KernelLoaders))]
|
||||
// public void Kernel_compiles_without_internal_compiler_errors(string name, Action<Accelerator> compile)
|
||||
// {
|
||||
// GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true);
|
||||
// try
|
||||
// {
|
||||
// var accelerator = lease.Accelerator;
|
||||
// Action action = () => compile(accelerator);
|
||||
// action.Should().NotThrow($"kernel {name} should compile");
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// lease.Dispose();
|
||||
// }
|
||||
// }
|
||||
|
||||
private static void CompileDivisorCycleCacheKernel(Accelerator accelerator)
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ public class LucasLehmerPrimeTesterTests
|
||||
[Trait("Category", "Fast")]
|
||||
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]
|
||||
@@ -26,7 +26,7 @@ public class LucasLehmerPrimeTesterTests
|
||||
const ulong exponent = 128UL;
|
||||
var tester = new MersenneNumberLucasLehmerGpuTester();
|
||||
tester.WarmUpNttParameters(exponent);
|
||||
tester.IsMersennePrime(exponent).Should().BeFalse();
|
||||
tester.IsPrime(exponent, true).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -49,7 +49,7 @@ public class LucasLehmerPrimeTesterTests
|
||||
{
|
||||
var tester = new MersenneNumberLucasLehmerGpuTester();
|
||||
tester.WarmUpNttParameters(exponent);
|
||||
tester.IsMersennePrime(exponent).Should().BeFalse();
|
||||
tester.IsPrime(exponent, true).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
||||
@@ -10,7 +10,6 @@ public class PrimeTesterGpuTests
|
||||
[Fact]
|
||||
public void IsPrimeGpu_accepts_known_primes()
|
||||
{
|
||||
GpuContextPool.ForceCpu = false;
|
||||
try
|
||||
{
|
||||
var tester = new PrimeTester();
|
||||
@@ -22,7 +21,6 @@ public class PrimeTesterGpuTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
GpuContextPool.ForceCpu = false;
|
||||
GpuContextPool.DisposeAll();
|
||||
}
|
||||
}
|
||||
@@ -30,7 +28,6 @@ public class PrimeTesterGpuTests
|
||||
[Fact]
|
||||
public void IsPrimeGpu_rejects_composites()
|
||||
{
|
||||
GpuContextPool.ForceCpu = false;
|
||||
try
|
||||
{
|
||||
var tester = new PrimeTester();
|
||||
@@ -42,7 +39,6 @@ public class PrimeTesterGpuTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
GpuContextPool.ForceCpu = false;
|
||||
GpuContextPool.DisposeAll();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,26 +7,26 @@ namespace PerfectNumbers.Core.Tests;
|
||||
[Collection("GpuNtt")]
|
||||
public class GpuKernelPoolTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", "Fast")]
|
||||
public void EnsureSmallCyclesOnDevice_returns_same_view_on_subsequent_calls()
|
||||
{
|
||||
GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true);
|
||||
try
|
||||
{
|
||||
var accelerator = lease.Accelerator;
|
||||
// [Fact]
|
||||
// [Trait("Category", "Fast")]
|
||||
// public void EnsureSmallCyclesOnDevice_returns_same_view_on_subsequent_calls()
|
||||
// {
|
||||
// GpuContextPool.GpuContextLease lease = GpuContextPool.RentPreferred(preferCpu: true);
|
||||
// try
|
||||
// {
|
||||
// var accelerator = lease.Accelerator;
|
||||
|
||||
var first = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
||||
var second = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
||||
// var first = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
||||
// var second = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
||||
|
||||
second.Equals(first).Should().BeTrue();
|
||||
second.Length.Should().Be(MersenneDivisorCycles.SmallDivisorsMax + 1);
|
||||
}
|
||||
finally
|
||||
{
|
||||
lease.Dispose();
|
||||
}
|
||||
}
|
||||
// second.Equals(first).Should().BeTrue();
|
||||
// second.Length.Should().Be(MersenneDivisorCycles.SmallDivisorsMax + 1);
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// lease.Dispose();
|
||||
// }
|
||||
// }
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", "Fast")]
|
||||
|
||||
@@ -37,7 +37,6 @@ public class PrimeTesterIsPrimeTests
|
||||
[InlineData(279UL, false)]
|
||||
public void IsPrimeGpu_uses_residue_specific_tables(ulong n, bool expected)
|
||||
{
|
||||
GpuContextPool.ForceCpu = false;
|
||||
var tester = new PrimeTester();
|
||||
|
||||
tester.IsPrimeGpu(n).Should().Be(expected);
|
||||
@@ -48,20 +47,14 @@ public class PrimeTesterIsPrimeTests
|
||||
public void IsPrimeGpu_falls_back_to_cpu_when_forced()
|
||||
{
|
||||
var tester = new PrimeTester();
|
||||
GpuContextPool.ForceCpu = true;
|
||||
|
||||
tester.IsPrimeGpu(137UL).Should().BeTrue();
|
||||
|
||||
tester.IsPrimeGpu(341UL).Should().BeFalse();
|
||||
|
||||
GpuContextPool.ForceCpu = false;
|
||||
PrimeTester.IsPrime(137UL).Should().BeTrue();
|
||||
PrimeTester.IsPrime(341UL).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", "Fast")]
|
||||
public void IsPrimeGpu_handles_parallel_calls_for_known_primes()
|
||||
{
|
||||
GpuContextPool.ForceCpu = false;
|
||||
GpuPrimeWorkLimiter.SetLimit(64);
|
||||
PrimeTester.GpuBatchSize = 256_000;
|
||||
|
||||
|
||||
@@ -7,23 +7,19 @@ namespace PerfectNumbers.Core.Gpu;
|
||||
|
||||
public static class GpuContextPool
|
||||
{
|
||||
// The pool intentionally skips pre-loading ProcessEightBitWindows kernels so accelerator initialization
|
||||
// stays stable; GpuKernelPool JIT-compiles them on first use alongside the small-cycle uploads.
|
||||
// Default device preference for generic GPU kernels (prime scans, NTT, etc.)
|
||||
public static bool ForceCpu { get; set; } = false;
|
||||
// The pool intentionally skips pre-loading ProcessEightBitWindows kernels so accelerator initialization
|
||||
// stays stable; GpuKernelPool JIT-compiles them on first use alongside the small-cycle uploads.
|
||||
// Default device preference for generic GPU kernels (prime scans, NTT, etc.)
|
||||
internal sealed class PooledContext
|
||||
{
|
||||
public Context Context { get; }
|
||||
public Accelerator Accelerator { get; }
|
||||
|
||||
internal sealed class PooledContext
|
||||
{
|
||||
public Context Context { get; }
|
||||
public Accelerator Accelerator { get; }
|
||||
public bool IsCpu { get; }
|
||||
public object ExecutionLock { get; } = new();
|
||||
|
||||
public PooledContext(bool preferCpu)
|
||||
public PooledContext()
|
||||
{
|
||||
Context = Context.CreateDefault();
|
||||
Accelerator = Context.GetPreferredDevice(preferCpu).CreateAccelerator(Context);
|
||||
IsCpu = Accelerator.AcceleratorType == AcceleratorType.CPU;
|
||||
Accelerator = Context.GetPreferredDevice(false).CreateAccelerator(Context);
|
||||
DivisorGeneratorGpuCache.WarmUpByDivisorTables(Accelerator);
|
||||
// NOTE: Avoid loading/compiling any kernel here to prevent implicit
|
||||
// CL stream/queue creation during accelerator construction.
|
||||
// Some OpenCL drivers are fragile when a queue is created immediately
|
||||
@@ -32,7 +28,6 @@ public static class GpuContextPool
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
// Ensure all cached GPU buffers for this accelerator are released.
|
||||
NttGpuMath.ClearCaches(Accelerator);
|
||||
// Release PrimeTester GPU state for this accelerator (kernel/device primes)
|
||||
@@ -45,116 +40,76 @@ public static class GpuContextPool
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly ConcurrentQueue<PooledContext> CpuPool = new();
|
||||
private static readonly ConcurrentQueue<PooledContext> GpuPool = new();
|
||||
private static int WarmedGpuContextCount;
|
||||
|
||||
public static GpuContextLease Rent()
|
||||
{
|
||||
return RentPreferred(ForceCpu);
|
||||
}
|
||||
private static int WarmedGpuContextCount;
|
||||
|
||||
// Allows callers to choose CPU/GPU per use-case, decoupled from ForceCpu.
|
||||
public static GpuContextLease RentPreferred(bool preferCpu)
|
||||
public static GpuContextLease Rent()
|
||||
{
|
||||
if (preferCpu && CpuPool.TryDequeue(out var cpu))
|
||||
{
|
||||
return new GpuContextLease(cpu);
|
||||
}
|
||||
|
||||
if (!preferCpu && GpuPool.TryDequeue(out var gpu))
|
||||
if (GpuPool.TryDequeue(out var gpu))
|
||||
{
|
||||
return new GpuContextLease(gpu);
|
||||
}
|
||||
|
||||
// Create a new accelerator when the pool does not have one available.
|
||||
return new GpuContextLease(new PooledContext(preferCpu));
|
||||
return new GpuContextLease(new PooledContext());
|
||||
}
|
||||
|
||||
public static void WarmUpPool(int threadCount)
|
||||
{
|
||||
if (ForceCpu)
|
||||
{
|
||||
return;
|
||||
}
|
||||
public static void WarmUpPool(int threadCount)
|
||||
{
|
||||
if (threadCount <= WarmedGpuContextCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int target = threadCount >> 2;
|
||||
if (target == 0)
|
||||
{
|
||||
target = threadCount;
|
||||
}
|
||||
int toCreate = threadCount - WarmedGpuContextCount;
|
||||
var contexts = new PooledContext[toCreate];
|
||||
for (int i = 0; i < toCreate; i++)
|
||||
{
|
||||
contexts[i] = new PooledContext();
|
||||
}
|
||||
|
||||
if (target <= WarmedGpuContextCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int toCreate = target - WarmedGpuContextCount;
|
||||
var contexts = new PooledContext[toCreate];
|
||||
for (int i = 0; i < toCreate; i++)
|
||||
{
|
||||
contexts[i] = new PooledContext(preferCpu: false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < toCreate; i++)
|
||||
{
|
||||
GpuPool.Enqueue(contexts[i]);
|
||||
}
|
||||
|
||||
WarmedGpuContextCount = target;
|
||||
}
|
||||
for (int i = 0; i < toCreate; i++)
|
||||
{
|
||||
GpuPool.Enqueue(contexts[i]);
|
||||
}
|
||||
|
||||
WarmedGpuContextCount = threadCount;
|
||||
}
|
||||
|
||||
public static void DisposeAll()
|
||||
{
|
||||
while (CpuPool.TryDequeue(out var cpu))
|
||||
{
|
||||
cpu.Dispose();
|
||||
}
|
||||
|
||||
while (GpuPool.TryDequeue(out var gpu))
|
||||
{
|
||||
gpu.Dispose();
|
||||
}
|
||||
|
||||
PrimeTester.DisposeGpuContexts();
|
||||
WarmedGpuContextCount = 0;
|
||||
WarmedGpuContextCount = 0;
|
||||
}
|
||||
|
||||
private static void Return(PooledContext ctx)
|
||||
{
|
||||
ctx.Accelerator.Synchronize();
|
||||
if (ctx.IsCpu)
|
||||
{
|
||||
CpuPool.Enqueue(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
GpuPool.Enqueue(ctx);
|
||||
}
|
||||
GpuPool.Enqueue(ctx);
|
||||
}
|
||||
|
||||
public struct GpuContextLease
|
||||
{
|
||||
private readonly PooledContext _ctx;
|
||||
public readonly struct GpuContextLease
|
||||
{
|
||||
private readonly PooledContext _ctx;
|
||||
|
||||
internal GpuContextLease(PooledContext ctx)
|
||||
{
|
||||
_ctx = ctx;
|
||||
}
|
||||
internal GpuContextLease(PooledContext ctx)
|
||||
{
|
||||
_ctx = ctx;
|
||||
}
|
||||
|
||||
public Context Context => _ctx.Context;
|
||||
|
||||
public Accelerator Accelerator => _ctx.Accelerator;
|
||||
|
||||
public object ExecutionLock => _ctx.ExecutionLock;
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
public readonly Context Context => _ctx.Context;
|
||||
public readonly Accelerator Accelerator => _ctx.Accelerator;
|
||||
|
||||
public readonly void Dispose()
|
||||
{
|
||||
Return(_ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,7 +280,7 @@ public class GpuKernelPool
|
||||
public static GpuKernelLease GetKernel(bool useGpuOrder)
|
||||
{
|
||||
var limiter = GpuPrimeWorkLimiter.Acquire();
|
||||
var gpu = RentPreferred(preferCpu: !useGpuOrder);
|
||||
var gpu = Rent();
|
||||
var accelerator = gpu.Accelerator;
|
||||
var kernels = GetKernels(accelerator);
|
||||
return GpuKernelLease.Rent(limiter, gpu, kernels);
|
||||
|
||||
@@ -492,7 +492,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
||||
internal DivisorScanSession(MersenneNumberDivisorByDivisorGpuTester owner)
|
||||
{
|
||||
_owner = owner;
|
||||
_lease = GpuContextPool.RentPreferred(preferCpu: false);
|
||||
_lease = GpuContextPool.Rent();
|
||||
_accelerator = _lease.Accelerator;
|
||||
_capacity = Math.Max(1, owner._gpuBatchSize);
|
||||
}
|
||||
@@ -657,7 +657,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
||||
return lease;
|
||||
}
|
||||
|
||||
return GpuContextPool.RentPreferred(preferCpu: false);
|
||||
return GpuContextPool.Rent();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
var gpu = GpuContextPool.RentPreferred(preferCpu: false);
|
||||
var gpu = GpuContextPool.Rent();
|
||||
var accelerator = gpu.Accelerator;
|
||||
var kernel = GetKernel(accelerator);
|
||||
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.
|
||||
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)
|
||||
{
|
||||
// Early rejections aligned with incremental/order sieves, but safe for small p:
|
||||
@@ -78,7 +68,7 @@ public class MersenneNumberLucasLehmerGpuTester
|
||||
}
|
||||
else
|
||||
{
|
||||
var gpu = GpuContextPool.RentPreferred(preferCpu: !runOnGpu);
|
||||
var gpu = GpuContextPool.Rent();
|
||||
var accelerator = gpu.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.
|
||||
@@ -110,7 +100,7 @@ public class MersenneNumberLucasLehmerGpuTester
|
||||
}
|
||||
}
|
||||
|
||||
var gpu = GpuContextPool.RentPreferred(preferCpu: false);
|
||||
var gpu = GpuContextPool.Rent();
|
||||
var accelerator = gpu.Accelerator;
|
||||
var kernel = GetBatchKernel(accelerator);
|
||||
|
||||
@@ -162,7 +152,7 @@ public class MersenneNumberLucasLehmerGpuTester
|
||||
|
||||
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 addKernel = GetAddSmallKernel(accelerator);
|
||||
var subKernel = GetSubSmallKernel(accelerator);
|
||||
|
||||
@@ -132,7 +132,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
||||
return lease;
|
||||
}
|
||||
|
||||
return GpuContextPool.RentPreferred(preferCpu: !_useGpuOrder);
|
||||
return GpuContextPool.Rent();
|
||||
}
|
||||
|
||||
private void ReturnAccelerator(GpuContextPool.GpuContextLease lease) => _acceleratorPool.Add(lease);
|
||||
|
||||
@@ -95,49 +95,48 @@ public sealed class PrimeTester
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
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);
|
||||
}
|
||||
// }
|
||||
|
||||
var limiter = GpuPrimeWorkLimiter.Acquire();
|
||||
var gpu = PrimeTesterGpuContextPool.Rent(1);
|
||||
var accelerator = gpu.Accelerator;
|
||||
var kernel = gpu.Kernel;
|
||||
// var limiter = GpuPrimeWorkLimiter.Acquire();
|
||||
// var gpu = PrimeTesterGpuContextPool.Rent(1);
|
||||
// var accelerator = gpu.Accelerator;
|
||||
// var kernel = gpu.Kernel;
|
||||
|
||||
ulong value = n;
|
||||
byte flag = 0;
|
||||
// ulong value = n;
|
||||
// byte flag = 0;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
// 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();
|
||||
// gpu.Dispose();
|
||||
// limiter.Dispose();
|
||||
|
||||
return flag != 0;
|
||||
// return flag != 0;
|
||||
}
|
||||
|
||||
public static int GpuBatchSize { get; set; } = 262_144;
|
||||
@@ -147,11 +146,6 @@ public sealed class PrimeTester
|
||||
|
||||
public static void WarmUpGpuKernels(int threadCount)
|
||||
{
|
||||
if (GpuContextPool.ForceCpu)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int target = threadCount >> 2;
|
||||
if (target == 0)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user