PrimeTesterByLastDigitAccelerator integrated into Pow2MontgomeryGpuCalculator for better performance.
This commit is contained in:
1 parent
0de9871529
commit
cf5f78c2ef
11 files changed
+222
-241
No files matched your search
@@ -28,7 +28,7 @@ namespace PerfectNumbers.Core.Gpu
|
||||
// Intentionally left empty - there's nothing to do here. We're not really renting anything.
|
||||
}
|
||||
|
||||
public static readonly AcceleratorPool Shared = new(PerfectNumberConstants.RollingAccelerators);
|
||||
public static readonly AcceleratorPool Shared = new(1);
|
||||
private readonly int Capacity;
|
||||
|
||||
public AcceleratorPool(int capacity)
|
||||
@@ -38,7 +38,20 @@ namespace PerfectNumbers.Core.Gpu
|
||||
var device = context.GetPreferredDevice(false);
|
||||
Context = context;
|
||||
Device = device;
|
||||
Accelerators = [.. Enumerable.Range(0, capacity).Select(_ => device.CreateAccelerator(context))];
|
||||
int acceleratorsInContext = 0;
|
||||
Accelerators = [.. Enumerable.Range(0, capacity).Select(_ =>
|
||||
{
|
||||
Accelerator accelerator = device.CreateAccelerator(context);
|
||||
acceleratorsInContext++;
|
||||
if (acceleratorsInContext >= 128)
|
||||
{
|
||||
context = Context.CreateDefault();
|
||||
device = context.GetPreferredDevice(false);
|
||||
acceleratorsInContext = 0;
|
||||
}
|
||||
|
||||
return accelerator;
|
||||
})];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace PerfectNumbers.Core.Gpu.Accelerators;
|
||||
|
||||
internal sealed class HeuristicGpuTables
|
||||
{
|
||||
private static readonly ConcurrentDictionary<Accelerator, HeuristicGpuTables> _sharedTables = new(20_480, PerfectNumberConstants.RollingAccelerators);
|
||||
private static readonly ConcurrentDictionary<Accelerator, HeuristicGpuTables> _sharedTables = new(20_480, 1);
|
||||
|
||||
internal static HeuristicGpuTables EnsureStaticTables(Accelerator accelerator, AcceleratorStream stream)
|
||||
=> _sharedTables.GetOrAdd(accelerator, _ => new HeuristicGpuTables(accelerator, stream));
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace PerfectNumbers.Core.Gpu.Accelerators;
|
||||
|
||||
internal sealed class LastDigitGpuTables
|
||||
{
|
||||
private static readonly ConcurrentDictionary<Accelerator, LastDigitGpuTables> _sharedTables = new(20_480, PerfectNumberConstants.RollingAccelerators);
|
||||
private static readonly ConcurrentDictionary<Accelerator, LastDigitGpuTables> _sharedTables = new(20_480, PerfectNumberConstants.RollingAccelerators * 2);
|
||||
|
||||
internal static LastDigitGpuTables EnsureStaticTables(Accelerator accelerator, AcceleratorStream stream)
|
||||
=> _sharedTables.GetOrAdd(accelerator, _ => new LastDigitGpuTables(accelerator, stream));
|
||||
|
||||
@@ -12,20 +12,21 @@ public sealed class Pow2MontgomeryAccelerator
|
||||
[ThreadStatic]
|
||||
private static Queue<Pow2MontgomeryAccelerator>? _pool;
|
||||
|
||||
private static AcceleratorPool _accelerators = new(PerfectNumberConstants.RollingAccelerators);
|
||||
private static AcceleratorPool _accelerators = new(PerfectNumberConstants.RollingAccelerators << 1);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Pow2MontgomeryAccelerator Rent()
|
||||
public static Pow2MontgomeryAccelerator Rent(int primeTesterCapacity)
|
||||
{
|
||||
var pool = _pool ??= [];
|
||||
if (!pool.TryDequeue(out var gpu))
|
||||
{
|
||||
Accelerator accelerator = _accelerators.Rent();
|
||||
gpu = new(accelerator, PerfectNumberConstants.DefaultFactorsBuffer);
|
||||
gpu = new(accelerator, PerfectNumberConstants.DefaultFactorsBuffer, primeTesterCapacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
gpu.Stream = gpu.Accelerator.CreateStream();
|
||||
gpu.EnsureCapacity(PerfectNumberConstants.DefaultFactorsBuffer,primeTesterCapacity);
|
||||
}
|
||||
|
||||
return gpu;
|
||||
@@ -39,13 +40,69 @@ public sealed class Pow2MontgomeryAccelerator
|
||||
_pool!.Enqueue(gpu);
|
||||
}
|
||||
|
||||
internal static void Clear()
|
||||
{
|
||||
Queue<Pow2MontgomeryAccelerator>? pool = _pool;
|
||||
if (pool != null)
|
||||
{
|
||||
while (pool.TryDequeue(out var lease))
|
||||
{
|
||||
lease.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DisposeAll()
|
||||
{
|
||||
Queue<Pow2MontgomeryAccelerator>? pool = _pool;
|
||||
if (pool != null)
|
||||
{
|
||||
while (pool.TryDequeue(out var lease))
|
||||
{
|
||||
lease.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void WarmUp()
|
||||
{
|
||||
Accelerator[]? accelerators = _accelerators.Accelerators;
|
||||
int acceleratorCount = accelerators.Length;
|
||||
for (var i = 0; i < acceleratorCount; i++)
|
||||
{
|
||||
Console.WriteLine($"Preparing accelerator {i}...");
|
||||
var accelerator = accelerators[i];
|
||||
AcceleratorStream stream = accelerator.CreateStream();
|
||||
LastDigitGpuTables.EnsureStaticTables(accelerator, stream);
|
||||
// SharedHeuristicGpuTables.EnsureStaticTables(accelerator, stream);
|
||||
// _ = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.None);
|
||||
// KernelContainer kernels = GpuKernelPool.GetOrAddKernels(accelerator, stream);
|
||||
// GpuStaticTableInitializer.EnsureStaticTables(accelerator, kernels, stream);
|
||||
stream.Synchronize();
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public readonly Accelerator Accelerator;
|
||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> Input;
|
||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> Output;
|
||||
public MemoryBuffer1D<ulong, Stride1D.Dense> PrimeTestInput;
|
||||
public MemoryBuffer1D<byte, Stride1D.Dense> PrimeTestOutput;
|
||||
public MemoryBuffer1D<int, Stride1D.Dense> HeuristicFlag;
|
||||
public MemoryBuffer1D<KeyValuePair<ulong, int>, Stride1D.Dense> Pow2ModEntriesToTestOnDevice;
|
||||
public Dictionary<ulong, int> Pow2ModEntriesToTestOnHost = [];
|
||||
public readonly MemoryBuffer1D<uint, Stride1D.Dense> DevicePrimesLastOne;
|
||||
public readonly MemoryBuffer1D<uint, Stride1D.Dense> DevicePrimesLastSeven;
|
||||
public readonly MemoryBuffer1D<uint, Stride1D.Dense> DevicePrimesLastThree;
|
||||
public readonly MemoryBuffer1D<uint, Stride1D.Dense> DevicePrimesLastNine;
|
||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> DevicePrimesPow2LastOne;
|
||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> DevicePrimesPow2LastSeven;
|
||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> DevicePrimesPow2LastThree;
|
||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> DevicePrimesPow2LastNine;
|
||||
public readonly Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>> SmallPrimeSieveKernel;
|
||||
|
||||
public AcceleratorStream? Stream;
|
||||
|
||||
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>> ConvertToStandardKernel;
|
||||
@@ -53,7 +110,23 @@ public sealed class Pow2MontgomeryAccelerator
|
||||
|
||||
public readonly Kernel CheckFactorsKernel;
|
||||
|
||||
public void EnsureCapacity(int factorsCount)
|
||||
[ThreadStatic]
|
||||
private static Dictionary<Accelerator, Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>>? SmallPrimeSieveKernelPool;
|
||||
|
||||
internal static Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>> GetSmallPrimeSieveKernel(Accelerator accelerator)
|
||||
{
|
||||
var pool = SmallPrimeSieveKernelPool ??= [];
|
||||
if (pool.TryGetValue(accelerator, out var cached))
|
||||
{
|
||||
return cached;
|
||||
}
|
||||
|
||||
cached = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>(PrimeTesterKernels.SmallPrimeSieveKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>>();
|
||||
pool[accelerator] = cached;
|
||||
return cached;
|
||||
}
|
||||
|
||||
public void EnsureCapacity(int factorsCount, int primeTesterCapacity)
|
||||
{
|
||||
if (factorsCount > Pow2ModEntriesToTestOnDevice.Length)
|
||||
{
|
||||
@@ -61,16 +134,45 @@ public sealed class Pow2MontgomeryAccelerator
|
||||
Pow2ModEntriesToTestOnDevice.Dispose();
|
||||
Pow2ModEntriesToTestOnDevice = accelerator.Allocate1D<KeyValuePair<ulong, int>>(factorsCount);
|
||||
}
|
||||
|
||||
if (primeTesterCapacity > PrimeTestInput.Length)
|
||||
{
|
||||
|
||||
PrimeTestInput?.Dispose();
|
||||
PrimeTestOutput?.Dispose();
|
||||
HeuristicFlag?.Dispose();
|
||||
|
||||
// lock (Accelerator)
|
||||
{
|
||||
PrimeTestInput = Accelerator.Allocate1D<ulong>(primeTesterCapacity);
|
||||
PrimeTestOutput = Accelerator.Allocate1D<byte>(primeTesterCapacity);
|
||||
HeuristicFlag = Accelerator.Allocate1D<int>(primeTesterCapacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Pow2MontgomeryAccelerator(Accelerator accelerator, int factorsCount)
|
||||
public Pow2MontgomeryAccelerator(Accelerator accelerator, int factorsCount, int primeTesterCapacity)
|
||||
{
|
||||
Accelerator = accelerator;
|
||||
Stream = accelerator.CreateStream();
|
||||
AcceleratorStream stream = accelerator.CreateStream();
|
||||
Stream = stream;
|
||||
|
||||
Input = accelerator.Allocate1D<ulong>(1);
|
||||
Output = accelerator.Allocate1D<ulong>(1);
|
||||
Pow2ModEntriesToTestOnDevice = accelerator.Allocate1D<KeyValuePair<ulong, int>>(factorsCount);
|
||||
PrimeTestInput = Accelerator.Allocate1D<ulong>(primeTesterCapacity);
|
||||
PrimeTestOutput = Accelerator.Allocate1D<byte>(primeTesterCapacity);
|
||||
HeuristicFlag = Accelerator.Allocate1D<int>(primeTesterCapacity);
|
||||
|
||||
var sharedTables = LastDigitGpuTables.EnsureStaticTables(accelerator, stream);
|
||||
DevicePrimesLastOne = sharedTables.DevicePrimesLastOne;
|
||||
DevicePrimesLastSeven = sharedTables.DevicePrimesLastSeven;
|
||||
DevicePrimesLastThree = sharedTables.DevicePrimesLastThree;
|
||||
DevicePrimesLastNine = sharedTables.DevicePrimesLastNine;
|
||||
DevicePrimesPow2LastOne = sharedTables.DevicePrimesPow2LastOne;
|
||||
DevicePrimesPow2LastSeven = sharedTables.DevicePrimesPow2LastSeven;
|
||||
DevicePrimesPow2LastThree = sharedTables.DevicePrimesPow2LastThree;
|
||||
DevicePrimesPow2LastNine = sharedTables.DevicePrimesPow2LastNine;
|
||||
|
||||
var keepKernel = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelKeepMontgomery);
|
||||
var keepLauncher = KernelUtil.GetKernel(keepKernel);
|
||||
@@ -84,6 +186,8 @@ public sealed class Pow2MontgomeryAccelerator
|
||||
|
||||
var checkFactorsKernel = accelerator.LoadStreamKernel<int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.CheckFactorsKernel);
|
||||
CheckFactorsKernel = KernelUtil.GetKernel(checkFactorsKernel);
|
||||
|
||||
SmallPrimeSieveKernel = (Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>)KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>(PrimeTesterKernels.SmallPrimeSieveKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>>().Clone();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -92,7 +196,17 @@ public sealed class Pow2MontgomeryAccelerator
|
||||
Output.Dispose();
|
||||
Stream?.Dispose();
|
||||
Pow2ModEntriesToTestOnDevice.Dispose();
|
||||
// Accelerator is shared with other threads
|
||||
PrimeTestInput?.Dispose();
|
||||
PrimeTestOutput?.Dispose();
|
||||
HeuristicFlag?.Dispose();
|
||||
|
||||
// Stream is disposed upon return to the queue, so we don't need to dispose it here.
|
||||
// Stream.Dispose();
|
||||
|
||||
// These resources are shared between GPU leases
|
||||
// ReleaseSharedTables(_sharedTables);
|
||||
// Accelerator.Dispose();
|
||||
// Context.Dispose();
|
||||
// Accelerator.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using ILGPU;
|
||||
using ILGPU.Runtime;
|
||||
|
||||
namespace PerfectNumbers.Core.Gpu.Accelerators;
|
||||
|
||||
internal sealed class PrimeTesterByLastDigitAccelerator
|
||||
{
|
||||
#region Pool
|
||||
|
||||
[ThreadStatic]
|
||||
private static Queue<PrimeTesterByLastDigitAccelerator>? Pool;
|
||||
|
||||
// internal static void EnsureStaticTables(Accelerator accelerator)
|
||||
// {
|
||||
// var tables = CreateSharedTables(accelerator);
|
||||
// }
|
||||
|
||||
internal static void WarmUp()
|
||||
{
|
||||
Accelerator[]? accelerators = AcceleratorPool.Shared.Accelerators;
|
||||
int acceleratorCount = accelerators.Length;
|
||||
Span<AcceleratorStream> streams = new(new AcceleratorStream[acceleratorCount]);
|
||||
for (var i = 0; i < acceleratorCount; i++)
|
||||
{
|
||||
Console.WriteLine($"Preparing accelerator {i}...");
|
||||
var accelerator = accelerators[i];
|
||||
AcceleratorStream stream = accelerator.CreateStream();
|
||||
LastDigitGpuTables.EnsureStaticTables(accelerator, stream);
|
||||
// SharedHeuristicGpuTables.EnsureStaticTables(accelerator, stream);
|
||||
// _ = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.None);
|
||||
// KernelContainer kernels = GpuKernelPool.GetOrAddKernels(accelerator, stream);
|
||||
// GpuStaticTableInitializer.EnsureStaticTables(accelerator, kernels, stream);
|
||||
streams[i] = stream;
|
||||
}
|
||||
|
||||
for (var i = 0; i < acceleratorCount; i++)
|
||||
{
|
||||
AcceleratorStream stream = streams[i];
|
||||
stream.Synchronize();
|
||||
stream.Dispose();
|
||||
Console.WriteLine($"Accelerator {i} is ready");
|
||||
}
|
||||
}
|
||||
|
||||
internal static PrimeTesterByLastDigitAccelerator Rent(int minBufferCapacity = 1)
|
||||
{
|
||||
var pool = Pool ??= new();
|
||||
if (!pool.TryDequeue(out var lease))
|
||||
{
|
||||
lease = new PrimeTesterByLastDigitAccelerator(minBufferCapacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
lease.EnsureCapacity(minBufferCapacity);
|
||||
}
|
||||
|
||||
return lease;
|
||||
}
|
||||
|
||||
internal static void Return(PrimeTesterByLastDigitAccelerator lease)
|
||||
{
|
||||
var pool = Pool ??= new();
|
||||
pool.Enqueue(lease);
|
||||
}
|
||||
|
||||
internal static void DisposeAll()
|
||||
{
|
||||
if (Pool != null)
|
||||
{
|
||||
while (Pool.TryDequeue(out var lease))
|
||||
{
|
||||
lease.DisposeResources();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Clear()
|
||||
{
|
||||
if (Pool != null)
|
||||
{
|
||||
var retained = new List<PrimeTesterByLastDigitAccelerator>();
|
||||
while (Pool.TryDequeue(out var lease))
|
||||
{
|
||||
lease.DisposeResources();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private readonly LastDigitGpuTables _sharedTables;
|
||||
internal readonly Context Context;
|
||||
public readonly Accelerator Accelerator;
|
||||
private AcceleratorStream? _stream;
|
||||
public AcceleratorStream Stream
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _stream ?? Accelerator.CreateStream();
|
||||
}
|
||||
|
||||
[ThreadStatic]
|
||||
public static Dictionary<Accelerator, Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>>? SmallPrimeSieveKernel;
|
||||
|
||||
internal static Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>> GetSmallPrimeSieveKernel(Accelerator accelerator)
|
||||
{
|
||||
var pool = SmallPrimeSieveKernel ??= [];
|
||||
if (pool.TryGetValue(accelerator, out var cached))
|
||||
{
|
||||
return cached;
|
||||
}
|
||||
|
||||
cached = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>(PrimeTesterKernels.SmallPrimeSieveKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>>();
|
||||
pool[accelerator] = cached;
|
||||
return cached;
|
||||
}
|
||||
|
||||
[ThreadStatic]
|
||||
public static Dictionary<Accelerator, Action<AcceleratorStream, Index1D, ArrayView<int>, ulong, ulong, HeuristicGpuDivisorTableKind, HeuristicGpuDivisorTables>>? HeuristicTrialDivisionKernel;
|
||||
|
||||
|
||||
public MemoryBuffer1D<ulong, Stride1D.Dense> Input = null!;
|
||||
public MemoryBuffer1D<byte, Stride1D.Dense> Output = null!;
|
||||
public MemoryBuffer1D<int, Stride1D.Dense> HeuristicFlag = null!;
|
||||
public int BufferCapacity;
|
||||
|
||||
public MemoryBuffer1D<uint, Stride1D.Dense> DevicePrimesLastOne => _sharedTables.DevicePrimesLastOne;
|
||||
public MemoryBuffer1D<uint, Stride1D.Dense> DevicePrimesLastSeven => _sharedTables.DevicePrimesLastSeven;
|
||||
public MemoryBuffer1D<uint, Stride1D.Dense> DevicePrimesLastThree => _sharedTables.DevicePrimesLastThree;
|
||||
public MemoryBuffer1D<uint, Stride1D.Dense> DevicePrimesLastNine => _sharedTables.DevicePrimesLastNine;
|
||||
public MemoryBuffer1D<ulong, Stride1D.Dense> DevicePrimesPow2LastOne => _sharedTables.DevicePrimesPow2LastOne;
|
||||
public MemoryBuffer1D<ulong, Stride1D.Dense> DevicePrimesPow2LastSeven => _sharedTables.DevicePrimesPow2LastSeven;
|
||||
public MemoryBuffer1D<ulong, Stride1D.Dense> DevicePrimesPow2LastThree => _sharedTables.DevicePrimesPow2LastThree;
|
||||
public MemoryBuffer1D<ulong, Stride1D.Dense> DevicePrimesPow2LastNine => _sharedTables.DevicePrimesPow2LastNine;
|
||||
|
||||
internal PrimeTesterByLastDigitAccelerator(int minBufferCapacity)
|
||||
{
|
||||
Accelerator accelerator = AcceleratorPool.Shared.Rent();
|
||||
Context = accelerator.Context;
|
||||
|
||||
Accelerator = accelerator;
|
||||
AcceleratorStream stream = accelerator.CreateStream();
|
||||
|
||||
var sharedTables = LastDigitGpuTables.EnsureStaticTables(accelerator, stream);
|
||||
_sharedTables = sharedTables;
|
||||
|
||||
EnsureCapacity(minBufferCapacity);
|
||||
stream.Synchronize();
|
||||
stream.Dispose();
|
||||
}
|
||||
|
||||
public void EnsureCapacity(int minCapacity)
|
||||
{
|
||||
if (minCapacity <= BufferCapacity)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Input?.Dispose();
|
||||
Output?.Dispose();
|
||||
HeuristicFlag?.Dispose();
|
||||
|
||||
// lock (Accelerator)
|
||||
{
|
||||
Input = Accelerator.Allocate1D<ulong>(minCapacity);
|
||||
Output = Accelerator.Allocate1D<byte>(minCapacity);
|
||||
HeuristicFlag = Accelerator.Allocate1D<int>(minCapacity);
|
||||
}
|
||||
|
||||
BufferCapacity = minCapacity;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_stream?.Dispose();
|
||||
_stream = null;
|
||||
Return(this);
|
||||
}
|
||||
|
||||
internal void DisposeResources()
|
||||
{
|
||||
Input?.Dispose();
|
||||
Output?.Dispose();
|
||||
HeuristicFlag?.Dispose();
|
||||
_stream?.Dispose();
|
||||
_stream = null;
|
||||
// ReleaseSharedTables(_sharedTables);
|
||||
// These resources are shared between GPU leases
|
||||
// Accelerator.Dispose();
|
||||
// AcceleratorContext.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using ILGPU.Runtime;
|
||||
|
||||
namespace PerfectNumbers.Core.Gpu;
|
||||
|
||||
internal readonly struct HeuristicGpuDivisorTables
|
||||
public readonly struct HeuristicGpuDivisorTables
|
||||
{
|
||||
public readonly ArrayView1D<ulong, Stride1D.Dense> CombinedDivisorsEnding1;
|
||||
public readonly ArrayView1D<ulong, Stride1D.Dense> CombinedDivisorsEnding3;
|
||||
|
||||
@@ -5,7 +5,7 @@ using ILGPU.Runtime;
|
||||
|
||||
namespace PerfectNumbers.Core.Gpu;
|
||||
|
||||
internal enum HeuristicGpuDivisorTableKind : byte
|
||||
public enum HeuristicGpuDivisorTableKind : byte
|
||||
{
|
||||
GroupA = 0,
|
||||
GroupBEnding1 = 1,
|
||||
|
||||
@@ -10,9 +10,8 @@ public static class Pow2MontgomeryGpuCalculator
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong CalculateKeep(ulong exponent, in MontgomeryDivisorData divisor)
|
||||
{
|
||||
GpuPrimeWorkLimiter.Acquire();
|
||||
|
||||
var gpu = Pow2MontgomeryAccelerator.Rent();
|
||||
var gpu = Pow2MontgomeryAccelerator.Rent(1);
|
||||
Accelerator? accelerator = gpu.Accelerator;
|
||||
AcceleratorStream stream = gpu.Stream!;
|
||||
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
|
||||
@@ -23,23 +22,24 @@ public static class Pow2MontgomeryGpuCalculator
|
||||
// resultBuffer.MemSetToZero(stream);
|
||||
|
||||
var kernel = gpu.KeepMontgomeryKernel;
|
||||
|
||||
GpuPrimeWorkLimiter.Acquire();
|
||||
kernel(stream, 1, exponentBuffer.View, divisor, resultBuffer.View);
|
||||
|
||||
ulong result = 0UL;
|
||||
resultBuffer.View.CopyToCPU(stream, ref result, 1);
|
||||
stream.Synchronize();
|
||||
GpuPrimeWorkLimiter.Release();
|
||||
|
||||
Pow2MontgomeryAccelerator.Return(gpu);
|
||||
GpuPrimeWorkLimiter.Release();
|
||||
return result;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong CalculateConvert(ulong exponent, in MontgomeryDivisorData divisor)
|
||||
{
|
||||
GpuPrimeWorkLimiter.Acquire();
|
||||
|
||||
var gpu = Pow2MontgomeryAccelerator.Rent();
|
||||
var gpu = Pow2MontgomeryAccelerator.Rent(1);
|
||||
AcceleratorStream stream = gpu.Stream!;
|
||||
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
|
||||
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.Output;
|
||||
@@ -49,14 +49,16 @@ public static class Pow2MontgomeryGpuCalculator
|
||||
// resultBuffer.MemSetToZero(stream);
|
||||
|
||||
var kernel = gpu.ConvertToStandardKernel;
|
||||
|
||||
GpuPrimeWorkLimiter.Acquire();
|
||||
kernel(stream, 1, exponentBuffer.View, divisor, resultBuffer.View);
|
||||
|
||||
ulong result = 0UL;
|
||||
resultBuffer.View.CopyToCPU(stream, ref result, 1);
|
||||
stream.Synchronize();
|
||||
GpuPrimeWorkLimiter.Release();
|
||||
|
||||
Pow2MontgomeryAccelerator.Return(gpu);
|
||||
GpuPrimeWorkLimiter.Release();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,14 +52,14 @@ internal static partial class PrimeOrderCalculator
|
||||
|
||||
ulong phi = prime - 1UL;
|
||||
|
||||
Pow2MontgomeryAccelerator gpu = Pow2MontgomeryAccelerator.Rent();
|
||||
Pow2MontgomeryAccelerator gpu = Pow2MontgomeryAccelerator.Rent(1);
|
||||
if (IsGpuHeuristicDevice && PrimeOrderGpuHeuristics.TryCalculateOrder(prime, previousOrder, config, divisorData, out ulong gpuOrder))
|
||||
{
|
||||
Pow2MontgomeryAccelerator.Return(gpu);
|
||||
return gpuOrder;
|
||||
}
|
||||
|
||||
PartialFactorResult phiFactors = PartialFactor(phi, config);
|
||||
PartialFactorResult phiFactors = PartialFactor(gpu, phi, config);
|
||||
|
||||
ulong result;
|
||||
if (phiFactors.Factors is null)
|
||||
@@ -106,7 +106,7 @@ internal static partial class PrimeOrderCalculator
|
||||
return CalculateByFactorizationGpu(gpu, prime, divisorData);
|
||||
}
|
||||
|
||||
if (TryHeuristicFinishCpu(prime, candidateOrder, previousOrder, divisorData, config, phiFactors, orderFactors, out ulong order))
|
||||
if (TryHeuristicFinishCpu(gpu, prime, candidateOrder, previousOrder, divisorData, config, phiFactors, orderFactors, out ulong order))
|
||||
{
|
||||
GpuPrimeWorkLimiter.Release();
|
||||
return order;
|
||||
@@ -347,7 +347,7 @@ internal static partial class PrimeOrderCalculator
|
||||
return false;
|
||||
}
|
||||
|
||||
PartialFactorResult factorization = PartialFactor(order, config);
|
||||
PartialFactorResult factorization = PartialFactor(gpu, order, config);
|
||||
if (factorization.Factors is null)
|
||||
{
|
||||
factorization.Dispose();
|
||||
@@ -488,6 +488,7 @@ internal static partial class PrimeOrderCalculator
|
||||
}
|
||||
|
||||
private static bool TryHeuristicFinishCpu(
|
||||
Pow2MontgomeryAccelerator gpu,
|
||||
ulong prime,
|
||||
ulong order,
|
||||
ulong? previousOrder,
|
||||
@@ -505,7 +506,7 @@ internal static partial class PrimeOrderCalculator
|
||||
}
|
||||
|
||||
// Reuse the partial factorization from TryConfirmOrderCpu when available.
|
||||
PartialFactorResult orderFactors = cachedOrderFactors ?? PartialFactor(order, config);
|
||||
PartialFactorResult orderFactors = cachedOrderFactors ?? PartialFactor(gpu, order, config);
|
||||
try
|
||||
{
|
||||
if (orderFactors.Factors is null)
|
||||
@@ -621,7 +622,7 @@ internal static partial class PrimeOrderCalculator
|
||||
|
||||
bool equalsOne = powStepper.InitializeCpuIsUnity(candidate);
|
||||
powStepperInitialized = true;
|
||||
if (equalsOne && TryConfirmCandidateCpu(prime, candidate, divisorData, config, ref powUsed, powBudget))
|
||||
if (equalsOne && TryConfirmCandidateCpu(gpu, prime, candidate, divisorData, config, ref powUsed, powBudget))
|
||||
{
|
||||
if (gpuPool is not null)
|
||||
{
|
||||
@@ -658,7 +659,7 @@ internal static partial class PrimeOrderCalculator
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!TryConfirmCandidateCpu(prime, candidate, divisorData, config, ref powUsed, powBudget))
|
||||
if (!TryConfirmCandidateCpu(gpu, prime, candidate, divisorData, config, ref powUsed, powBudget))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -863,9 +864,9 @@ internal static partial class PrimeOrderCalculator
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryConfirmCandidateCpu(ulong prime, ulong candidate, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config, ref int powUsed, int powBudget)
|
||||
private static bool TryConfirmCandidateCpu(Pow2MontgomeryAccelerator gpu, ulong prime, ulong candidate, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config, ref int powUsed, int powBudget)
|
||||
{
|
||||
PartialFactorResult factorization = PartialFactor(candidate, config);
|
||||
PartialFactorResult factorization = PartialFactor(gpu, candidate, config);
|
||||
try
|
||||
{
|
||||
if (factorization.Factors is null)
|
||||
@@ -1056,7 +1057,7 @@ internal static partial class PrimeOrderCalculator
|
||||
// private static ulong _partialFactorPendingHits;
|
||||
// private static ulong _partialFactorCofactorHits;
|
||||
|
||||
private static PartialFactorResult PartialFactor(ulong value, in PrimeOrderSearchConfig config)
|
||||
private static PartialFactorResult PartialFactor(Pow2MontgomeryAccelerator gpu, ulong value, in PrimeOrderSearchConfig config)
|
||||
{
|
||||
if (value <= 1UL)
|
||||
{
|
||||
@@ -1125,6 +1126,8 @@ internal static partial class PrimeOrderCalculator
|
||||
bool pollardRhoDeadlineReached = Stopwatch.GetTimestamp() > deadlineTimestamp;
|
||||
if (!pollardRhoDeadlineReached)
|
||||
{
|
||||
GpuPrimeWorkLimiter.Acquire();
|
||||
|
||||
while (compositeStack.Count > 0)
|
||||
{
|
||||
ulong composite = compositeStack.Pop();
|
||||
@@ -1141,7 +1144,7 @@ internal static partial class PrimeOrderCalculator
|
||||
// Console.WriteLine($"Partial factor hits {Volatile.Read(ref _partialFactorHits)}");
|
||||
|
||||
// bool isPrime = PrimeTester.IsPrimeCpu(composite, CancellationToken.None);
|
||||
bool isPrime = PrimeTester.IsPrime(composite);
|
||||
bool isPrime = PrimeTester.IsPrimeGpu(gpu, composite);
|
||||
// bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite);
|
||||
|
||||
if (isPrime)
|
||||
@@ -1173,6 +1176,8 @@ internal static partial class PrimeOrderCalculator
|
||||
{
|
||||
pollardRhoDeadlineReached = Stopwatch.GetTimestamp() > deadlineTimestamp;
|
||||
}
|
||||
|
||||
GpuPrimeWorkLimiter.Release();
|
||||
}
|
||||
|
||||
if (pollardRhoDeadlineReached)
|
||||
@@ -1188,6 +1193,7 @@ internal static partial class PrimeOrderCalculator
|
||||
bool cofactorContainsComposite = false;
|
||||
int pendingCount = pending.Count;
|
||||
int index = 0;
|
||||
GpuPrimeWorkLimiter.Acquire();
|
||||
for (; index < pendingCount; index++)
|
||||
{
|
||||
PendingEntry entry = pending[index];
|
||||
@@ -1209,7 +1215,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 = PrimeTester.IsPrimeGpu(composite);
|
||||
bool isPrime = PrimeTester.IsPrimeGpu(gpu, composite);
|
||||
// bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite);
|
||||
|
||||
entry = entry.WithPrimality(isPrime);
|
||||
@@ -1228,7 +1234,7 @@ internal static partial class PrimeOrderCalculator
|
||||
cofactorContainsComposite = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool cofactorIsPrime;
|
||||
if (cofactor <= 1UL)
|
||||
{
|
||||
@@ -1246,11 +1252,13 @@ internal static partial class PrimeOrderCalculator
|
||||
// Atomic.Add(ref _partialFactorCofactorHits, 1UL);
|
||||
// Console.WriteLine($"Partial factor cofactor hits {Volatile.Read(ref _partialFactorCofactorHits)}");
|
||||
|
||||
cofactorIsPrime = PrimeTester.IsPrimeGpu(cofactor);
|
||||
cofactorIsPrime = PrimeTester.IsPrimeGpu(gpu, cofactor);
|
||||
// cofactorIsPrime = PrimeTester.IsPrimeGpu(cofactor);
|
||||
// cofactorIsPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(cofactor);
|
||||
}
|
||||
|
||||
GpuPrimeWorkLimiter.Release();
|
||||
|
||||
ArrayPool<FactorEntry> pool = ThreadStaticPools.FactorEntryPool;
|
||||
bool temp;
|
||||
if (factorCount == 0)
|
||||
|
||||
@@ -38,7 +38,7 @@ internal static partial class PrimeOrderCalculator
|
||||
entries.Sort(entries, static (a, b) => a.Key.CompareTo(b.Key));
|
||||
|
||||
AcceleratorStream stream = gpu.Stream!;
|
||||
gpu.EnsureCapacity(entryCount);
|
||||
gpu.EnsureCapacity(entryCount, 1);
|
||||
gpu.Pow2ModEntriesToTestOnDevice.View.CopyFromCPU(stream, entries);
|
||||
|
||||
ulong order = phi;
|
||||
|
||||
@@ -94,17 +94,17 @@ public sealed class PrimeTester
|
||||
public static bool IsPrimeGpu(ulong n)
|
||||
{
|
||||
GpuPrimeWorkLimiter.Acquire();
|
||||
var gpu = PrimeTesterByLastDigitAccelerator.Rent(1);
|
||||
var gpu = Pow2MontgomeryAccelerator.Rent(1);
|
||||
var accelerator = gpu.Accelerator;
|
||||
var stream = gpu.Stream;
|
||||
var kernel = PrimeTesterByLastDigitAccelerator.GetSmallPrimeSieveKernel(accelerator);
|
||||
var stream = gpu.Stream!;
|
||||
var kernel = gpu.SmallPrimeSieveKernel;
|
||||
|
||||
ulong value = n;
|
||||
// Span<byte> flag = stackalloc byte[1];
|
||||
byte flag = 0;
|
||||
|
||||
var input = gpu.Input;
|
||||
var output = gpu.Output;
|
||||
var input = gpu.PrimeTestInput;
|
||||
var output = gpu.PrimeTestOutput;
|
||||
var inputView = input.View;
|
||||
var outputView = output.View;
|
||||
|
||||
@@ -131,6 +131,42 @@ public sealed class PrimeTester
|
||||
return flag != 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsPrimeGpu(Pow2MontgomeryAccelerator gpu, ulong n)
|
||||
{
|
||||
var accelerator = gpu.Accelerator;
|
||||
var stream = gpu.Stream!;
|
||||
Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>? kernel = gpu.SmallPrimeSieveKernel;
|
||||
|
||||
ulong value = n;
|
||||
// Span<byte> flag = stackalloc byte[1];
|
||||
byte flag = 0;
|
||||
|
||||
var input = gpu.PrimeTestInput;
|
||||
var output = gpu.PrimeTestOutput;
|
||||
var inputView = input.View;
|
||||
var outputView = output.View;
|
||||
|
||||
inputView.CopyFromCPU(stream, ref value, 1);
|
||||
kernel(
|
||||
stream,
|
||||
1,
|
||||
inputView,
|
||||
gpu.DevicePrimesLastOne.View,
|
||||
gpu.DevicePrimesLastSeven.View,
|
||||
gpu.DevicePrimesLastThree.View,
|
||||
gpu.DevicePrimesLastNine.View,
|
||||
gpu.DevicePrimesPow2LastOne.View,
|
||||
gpu.DevicePrimesPow2LastSeven.View,
|
||||
gpu.DevicePrimesPow2LastThree.View,
|
||||
gpu.DevicePrimesPow2LastNine.View,
|
||||
outputView);
|
||||
outputView.CopyToCPU(stream, ref flag, 1);
|
||||
stream.Synchronize();
|
||||
|
||||
return flag != 0;
|
||||
}
|
||||
|
||||
public static int GpuBatchSize { get; set; } = 262_144;
|
||||
|
||||
private static readonly object GpuWarmUpLock = new();
|
||||
@@ -151,7 +187,7 @@ public sealed class PrimeTester
|
||||
return;
|
||||
}
|
||||
|
||||
PrimeTesterByLastDigitAccelerator.WarmUp();
|
||||
Pow2MontgomeryAccelerator.WarmUp();
|
||||
WarmedGpuLeaseCount = target;
|
||||
}
|
||||
}
|
||||
@@ -160,15 +196,15 @@ public sealed class PrimeTester
|
||||
public static void IsPrimeBatchGpu(ReadOnlySpan<ulong> values, Span<byte> results)
|
||||
{
|
||||
GpuPrimeWorkLimiter.Acquire();
|
||||
var gpu = PrimeTesterByLastDigitAccelerator.Rent(GpuBatchSize);
|
||||
var gpu = Pow2MontgomeryAccelerator.Rent(GpuBatchSize);
|
||||
var accelerator = gpu.Accelerator;
|
||||
var stream = gpu.Stream;
|
||||
var kernel = PrimeTesterByLastDigitAccelerator.GetSmallPrimeSieveKernel(accelerator);
|
||||
var stream = gpu.Stream!;
|
||||
var kernel = gpu.SmallPrimeSieveKernel;
|
||||
int totalLength = values.Length;
|
||||
int batchSize = GpuBatchSize;
|
||||
|
||||
var input = gpu.Input;
|
||||
var output = gpu.Output;
|
||||
var input = gpu.PrimeTestInput;
|
||||
var output = gpu.PrimeTestOutput;
|
||||
var inputView = input.View;
|
||||
var outputView = output.View;
|
||||
|
||||
@@ -211,12 +247,12 @@ public sealed class PrimeTester
|
||||
// Expose cache clearing for accelerator disposal coordination
|
||||
public static void ClearGpuCaches()
|
||||
{
|
||||
PrimeTesterByLastDigitAccelerator.Clear();
|
||||
Pow2MontgomeryAccelerator.Clear();
|
||||
}
|
||||
|
||||
internal static void DisposeGpuContexts()
|
||||
{
|
||||
PrimeTesterByLastDigitAccelerator.DisposeAll();
|
||||
Pow2MontgomeryAccelerator.DisposeAll();
|
||||
lock (GpuWarmUpLock)
|
||||
{
|
||||
WarmedGpuLeaseCount = 0;
|
||||
@@ -241,9 +277,9 @@ public sealed class PrimeTester
|
||||
// TODO: Route this batch helper through the shared GPU kernel pool from
|
||||
// GpuUInt128BinaryGcdBenchmarks so we reuse cached kernels, pinned host buffers,
|
||||
// and divisor-cycle staging instead of allocating new device buffers per call.
|
||||
var gpu = PrimeTesterByLastDigitAccelerator.Rent();
|
||||
var gpu = Pow2MontgomeryAccelerator.Rent(1);
|
||||
var accelerator = gpu.Accelerator;
|
||||
var stream = gpu.Stream;
|
||||
var stream = gpu.Stream!;
|
||||
|
||||
int length = values.Length;
|
||||
ArrayPool<ulong> pool = ThreadStaticPools.UlongPool;
|
||||
|
||||
Reference in new issue
Block a user