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.
|
// 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;
|
private readonly int Capacity;
|
||||||
|
|
||||||
public AcceleratorPool(int capacity)
|
public AcceleratorPool(int capacity)
|
||||||
@@ -38,7 +38,20 @@ namespace PerfectNumbers.Core.Gpu
|
|||||||
var device = context.GetPreferredDevice(false);
|
var device = context.GetPreferredDevice(false);
|
||||||
Context = context;
|
Context = context;
|
||||||
Device = device;
|
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
|
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)
|
internal static HeuristicGpuTables EnsureStaticTables(Accelerator accelerator, AcceleratorStream stream)
|
||||||
=> _sharedTables.GetOrAdd(accelerator, _ => new HeuristicGpuTables(accelerator, stream));
|
=> _sharedTables.GetOrAdd(accelerator, _ => new HeuristicGpuTables(accelerator, stream));
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace PerfectNumbers.Core.Gpu.Accelerators;
|
|||||||
|
|
||||||
internal sealed class LastDigitGpuTables
|
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)
|
internal static LastDigitGpuTables EnsureStaticTables(Accelerator accelerator, AcceleratorStream stream)
|
||||||
=> _sharedTables.GetOrAdd(accelerator, _ => new LastDigitGpuTables(accelerator, stream));
|
=> _sharedTables.GetOrAdd(accelerator, _ => new LastDigitGpuTables(accelerator, stream));
|
||||||
|
|||||||
@@ -12,20 +12,21 @@ public sealed class Pow2MontgomeryAccelerator
|
|||||||
[ThreadStatic]
|
[ThreadStatic]
|
||||||
private static Queue<Pow2MontgomeryAccelerator>? _pool;
|
private static Queue<Pow2MontgomeryAccelerator>? _pool;
|
||||||
|
|
||||||
private static AcceleratorPool _accelerators = new(PerfectNumberConstants.RollingAccelerators);
|
private static AcceleratorPool _accelerators = new(PerfectNumberConstants.RollingAccelerators << 1);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static Pow2MontgomeryAccelerator Rent()
|
public static Pow2MontgomeryAccelerator Rent(int primeTesterCapacity)
|
||||||
{
|
{
|
||||||
var pool = _pool ??= [];
|
var pool = _pool ??= [];
|
||||||
if (!pool.TryDequeue(out var gpu))
|
if (!pool.TryDequeue(out var gpu))
|
||||||
{
|
{
|
||||||
Accelerator accelerator = _accelerators.Rent();
|
Accelerator accelerator = _accelerators.Rent();
|
||||||
gpu = new(accelerator, PerfectNumberConstants.DefaultFactorsBuffer);
|
gpu = new(accelerator, PerfectNumberConstants.DefaultFactorsBuffer, primeTesterCapacity);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gpu.Stream = gpu.Accelerator.CreateStream();
|
gpu.Stream = gpu.Accelerator.CreateStream();
|
||||||
|
gpu.EnsureCapacity(PerfectNumberConstants.DefaultFactorsBuffer,primeTesterCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
return gpu;
|
return gpu;
|
||||||
@@ -39,13 +40,69 @@ public sealed class Pow2MontgomeryAccelerator
|
|||||||
_pool!.Enqueue(gpu);
|
_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
|
#endregion
|
||||||
|
|
||||||
public readonly Accelerator Accelerator;
|
public readonly Accelerator Accelerator;
|
||||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> Input;
|
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> Input;
|
||||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> Output;
|
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 MemoryBuffer1D<KeyValuePair<ulong, int>, Stride1D.Dense> Pow2ModEntriesToTestOnDevice;
|
||||||
public Dictionary<ulong, int> Pow2ModEntriesToTestOnHost = [];
|
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 AcceleratorStream? Stream;
|
||||||
|
|
||||||
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>> ConvertToStandardKernel;
|
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 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)
|
if (factorsCount > Pow2ModEntriesToTestOnDevice.Length)
|
||||||
{
|
{
|
||||||
@@ -61,16 +134,45 @@ public sealed class Pow2MontgomeryAccelerator
|
|||||||
Pow2ModEntriesToTestOnDevice.Dispose();
|
Pow2ModEntriesToTestOnDevice.Dispose();
|
||||||
Pow2ModEntriesToTestOnDevice = accelerator.Allocate1D<KeyValuePair<ulong, int>>(factorsCount);
|
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;
|
Accelerator = accelerator;
|
||||||
Stream = accelerator.CreateStream();
|
AcceleratorStream stream = accelerator.CreateStream();
|
||||||
|
Stream = stream;
|
||||||
|
|
||||||
Input = accelerator.Allocate1D<ulong>(1);
|
Input = accelerator.Allocate1D<ulong>(1);
|
||||||
Output = accelerator.Allocate1D<ulong>(1);
|
Output = accelerator.Allocate1D<ulong>(1);
|
||||||
Pow2ModEntriesToTestOnDevice = accelerator.Allocate1D<KeyValuePair<ulong, int>>(factorsCount);
|
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 keepKernel = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelKeepMontgomery);
|
||||||
var keepLauncher = KernelUtil.GetKernel(keepKernel);
|
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);
|
var checkFactorsKernel = accelerator.LoadStreamKernel<int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.CheckFactorsKernel);
|
||||||
CheckFactorsKernel = KernelUtil.GetKernel(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()
|
public void Dispose()
|
||||||
@@ -92,7 +196,17 @@ public sealed class Pow2MontgomeryAccelerator
|
|||||||
Output.Dispose();
|
Output.Dispose();
|
||||||
Stream?.Dispose();
|
Stream?.Dispose();
|
||||||
Pow2ModEntriesToTestOnDevice.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();
|
// 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;
|
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> CombinedDivisorsEnding1;
|
||||||
public readonly ArrayView1D<ulong, Stride1D.Dense> CombinedDivisorsEnding3;
|
public readonly ArrayView1D<ulong, Stride1D.Dense> CombinedDivisorsEnding3;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using ILGPU.Runtime;
|
|||||||
|
|
||||||
namespace PerfectNumbers.Core.Gpu;
|
namespace PerfectNumbers.Core.Gpu;
|
||||||
|
|
||||||
internal enum HeuristicGpuDivisorTableKind : byte
|
public enum HeuristicGpuDivisorTableKind : byte
|
||||||
{
|
{
|
||||||
GroupA = 0,
|
GroupA = 0,
|
||||||
GroupBEnding1 = 1,
|
GroupBEnding1 = 1,
|
||||||
|
|||||||
@@ -10,9 +10,8 @@ public static class Pow2MontgomeryGpuCalculator
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ulong CalculateKeep(ulong exponent, in MontgomeryDivisorData divisor)
|
public static ulong CalculateKeep(ulong exponent, in MontgomeryDivisorData divisor)
|
||||||
{
|
{
|
||||||
GpuPrimeWorkLimiter.Acquire();
|
|
||||||
|
|
||||||
var gpu = Pow2MontgomeryAccelerator.Rent();
|
var gpu = Pow2MontgomeryAccelerator.Rent(1);
|
||||||
Accelerator? accelerator = gpu.Accelerator;
|
Accelerator? accelerator = gpu.Accelerator;
|
||||||
AcceleratorStream stream = gpu.Stream!;
|
AcceleratorStream stream = gpu.Stream!;
|
||||||
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
|
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
|
||||||
@@ -23,23 +22,24 @@ public static class Pow2MontgomeryGpuCalculator
|
|||||||
// resultBuffer.MemSetToZero(stream);
|
// resultBuffer.MemSetToZero(stream);
|
||||||
|
|
||||||
var kernel = gpu.KeepMontgomeryKernel;
|
var kernel = gpu.KeepMontgomeryKernel;
|
||||||
|
|
||||||
|
GpuPrimeWorkLimiter.Acquire();
|
||||||
kernel(stream, 1, exponentBuffer.View, divisor, resultBuffer.View);
|
kernel(stream, 1, exponentBuffer.View, divisor, resultBuffer.View);
|
||||||
|
|
||||||
ulong result = 0UL;
|
ulong result = 0UL;
|
||||||
resultBuffer.View.CopyToCPU(stream, ref result, 1);
|
resultBuffer.View.CopyToCPU(stream, ref result, 1);
|
||||||
stream.Synchronize();
|
stream.Synchronize();
|
||||||
|
GpuPrimeWorkLimiter.Release();
|
||||||
|
|
||||||
Pow2MontgomeryAccelerator.Return(gpu);
|
Pow2MontgomeryAccelerator.Return(gpu);
|
||||||
GpuPrimeWorkLimiter.Release();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ulong CalculateConvert(ulong exponent, in MontgomeryDivisorData divisor)
|
public static ulong CalculateConvert(ulong exponent, in MontgomeryDivisorData divisor)
|
||||||
{
|
{
|
||||||
GpuPrimeWorkLimiter.Acquire();
|
|
||||||
|
|
||||||
var gpu = Pow2MontgomeryAccelerator.Rent();
|
var gpu = Pow2MontgomeryAccelerator.Rent(1);
|
||||||
AcceleratorStream stream = gpu.Stream!;
|
AcceleratorStream stream = gpu.Stream!;
|
||||||
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
|
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
|
||||||
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.Output;
|
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.Output;
|
||||||
@@ -49,14 +49,16 @@ public static class Pow2MontgomeryGpuCalculator
|
|||||||
// resultBuffer.MemSetToZero(stream);
|
// resultBuffer.MemSetToZero(stream);
|
||||||
|
|
||||||
var kernel = gpu.ConvertToStandardKernel;
|
var kernel = gpu.ConvertToStandardKernel;
|
||||||
|
|
||||||
|
GpuPrimeWorkLimiter.Acquire();
|
||||||
kernel(stream, 1, exponentBuffer.View, divisor, resultBuffer.View);
|
kernel(stream, 1, exponentBuffer.View, divisor, resultBuffer.View);
|
||||||
|
|
||||||
ulong result = 0UL;
|
ulong result = 0UL;
|
||||||
resultBuffer.View.CopyToCPU(stream, ref result, 1);
|
resultBuffer.View.CopyToCPU(stream, ref result, 1);
|
||||||
stream.Synchronize();
|
stream.Synchronize();
|
||||||
|
GpuPrimeWorkLimiter.Release();
|
||||||
|
|
||||||
Pow2MontgomeryAccelerator.Return(gpu);
|
Pow2MontgomeryAccelerator.Return(gpu);
|
||||||
GpuPrimeWorkLimiter.Release();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,14 +52,14 @@ internal static partial class PrimeOrderCalculator
|
|||||||
|
|
||||||
ulong phi = prime - 1UL;
|
ulong phi = prime - 1UL;
|
||||||
|
|
||||||
Pow2MontgomeryAccelerator gpu = Pow2MontgomeryAccelerator.Rent();
|
Pow2MontgomeryAccelerator gpu = Pow2MontgomeryAccelerator.Rent(1);
|
||||||
if (IsGpuHeuristicDevice && PrimeOrderGpuHeuristics.TryCalculateOrder(prime, previousOrder, config, divisorData, out ulong gpuOrder))
|
if (IsGpuHeuristicDevice && PrimeOrderGpuHeuristics.TryCalculateOrder(prime, previousOrder, config, divisorData, out ulong gpuOrder))
|
||||||
{
|
{
|
||||||
Pow2MontgomeryAccelerator.Return(gpu);
|
Pow2MontgomeryAccelerator.Return(gpu);
|
||||||
return gpuOrder;
|
return gpuOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
PartialFactorResult phiFactors = PartialFactor(phi, config);
|
PartialFactorResult phiFactors = PartialFactor(gpu, phi, config);
|
||||||
|
|
||||||
ulong result;
|
ulong result;
|
||||||
if (phiFactors.Factors is null)
|
if (phiFactors.Factors is null)
|
||||||
@@ -106,7 +106,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
return CalculateByFactorizationGpu(gpu, prime, divisorData);
|
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();
|
GpuPrimeWorkLimiter.Release();
|
||||||
return order;
|
return order;
|
||||||
@@ -347,7 +347,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PartialFactorResult factorization = PartialFactor(order, config);
|
PartialFactorResult factorization = PartialFactor(gpu, order, config);
|
||||||
if (factorization.Factors is null)
|
if (factorization.Factors is null)
|
||||||
{
|
{
|
||||||
factorization.Dispose();
|
factorization.Dispose();
|
||||||
@@ -488,6 +488,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryHeuristicFinishCpu(
|
private static bool TryHeuristicFinishCpu(
|
||||||
|
Pow2MontgomeryAccelerator gpu,
|
||||||
ulong prime,
|
ulong prime,
|
||||||
ulong order,
|
ulong order,
|
||||||
ulong? previousOrder,
|
ulong? previousOrder,
|
||||||
@@ -505,7 +506,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reuse the partial factorization from TryConfirmOrderCpu when available.
|
// Reuse the partial factorization from TryConfirmOrderCpu when available.
|
||||||
PartialFactorResult orderFactors = cachedOrderFactors ?? PartialFactor(order, config);
|
PartialFactorResult orderFactors = cachedOrderFactors ?? PartialFactor(gpu, order, config);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (orderFactors.Factors is null)
|
if (orderFactors.Factors is null)
|
||||||
@@ -621,7 +622,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
|
|
||||||
bool equalsOne = powStepper.InitializeCpuIsUnity(candidate);
|
bool equalsOne = powStepper.InitializeCpuIsUnity(candidate);
|
||||||
powStepperInitialized = true;
|
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)
|
if (gpuPool is not null)
|
||||||
{
|
{
|
||||||
@@ -658,7 +659,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryConfirmCandidateCpu(prime, candidate, divisorData, config, ref powUsed, powBudget))
|
if (!TryConfirmCandidateCpu(gpu, prime, candidate, divisorData, config, ref powUsed, powBudget))
|
||||||
{
|
{
|
||||||
continue;
|
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
|
try
|
||||||
{
|
{
|
||||||
if (factorization.Factors is null)
|
if (factorization.Factors is null)
|
||||||
@@ -1056,7 +1057,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
// private static ulong _partialFactorPendingHits;
|
// private static ulong _partialFactorPendingHits;
|
||||||
// private static ulong _partialFactorCofactorHits;
|
// 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)
|
if (value <= 1UL)
|
||||||
{
|
{
|
||||||
@@ -1125,6 +1126,8 @@ internal static partial class PrimeOrderCalculator
|
|||||||
bool pollardRhoDeadlineReached = Stopwatch.GetTimestamp() > deadlineTimestamp;
|
bool pollardRhoDeadlineReached = Stopwatch.GetTimestamp() > deadlineTimestamp;
|
||||||
if (!pollardRhoDeadlineReached)
|
if (!pollardRhoDeadlineReached)
|
||||||
{
|
{
|
||||||
|
GpuPrimeWorkLimiter.Acquire();
|
||||||
|
|
||||||
while (compositeStack.Count > 0)
|
while (compositeStack.Count > 0)
|
||||||
{
|
{
|
||||||
ulong composite = compositeStack.Pop();
|
ulong composite = compositeStack.Pop();
|
||||||
@@ -1141,7 +1144,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
// Console.WriteLine($"Partial factor hits {Volatile.Read(ref _partialFactorHits)}");
|
// Console.WriteLine($"Partial factor hits {Volatile.Read(ref _partialFactorHits)}");
|
||||||
|
|
||||||
// bool isPrime = PrimeTester.IsPrimeCpu(composite, CancellationToken.None);
|
// 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);
|
// bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite);
|
||||||
|
|
||||||
if (isPrime)
|
if (isPrime)
|
||||||
@@ -1173,6 +1176,8 @@ internal static partial class PrimeOrderCalculator
|
|||||||
{
|
{
|
||||||
pollardRhoDeadlineReached = Stopwatch.GetTimestamp() > deadlineTimestamp;
|
pollardRhoDeadlineReached = Stopwatch.GetTimestamp() > deadlineTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GpuPrimeWorkLimiter.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pollardRhoDeadlineReached)
|
if (pollardRhoDeadlineReached)
|
||||||
@@ -1188,6 +1193,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
bool cofactorContainsComposite = false;
|
bool cofactorContainsComposite = false;
|
||||||
int pendingCount = pending.Count;
|
int pendingCount = pending.Count;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
GpuPrimeWorkLimiter.Acquire();
|
||||||
for (; index < pendingCount; index++)
|
for (; index < pendingCount; index++)
|
||||||
{
|
{
|
||||||
PendingEntry entry = pending[index];
|
PendingEntry entry = pending[index];
|
||||||
@@ -1209,7 +1215,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
// Console.WriteLine($"Partial factor pending hits {Volatile.Read(ref _partialFactorPendingHits)}");
|
// Console.WriteLine($"Partial factor pending hits {Volatile.Read(ref _partialFactorPendingHits)}");
|
||||||
|
|
||||||
// bool isPrime = PrimeTester.IsPrimeCpu(composite, CancellationToken.None);
|
// 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);
|
// bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite);
|
||||||
|
|
||||||
entry = entry.WithPrimality(isPrime);
|
entry = entry.WithPrimality(isPrime);
|
||||||
@@ -1228,7 +1234,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
cofactorContainsComposite = true;
|
cofactorContainsComposite = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cofactorIsPrime;
|
bool cofactorIsPrime;
|
||||||
if (cofactor <= 1UL)
|
if (cofactor <= 1UL)
|
||||||
{
|
{
|
||||||
@@ -1246,11 +1252,13 @@ internal static partial class PrimeOrderCalculator
|
|||||||
// Atomic.Add(ref _partialFactorCofactorHits, 1UL);
|
// Atomic.Add(ref _partialFactorCofactorHits, 1UL);
|
||||||
// Console.WriteLine($"Partial factor cofactor hits {Volatile.Read(ref _partialFactorCofactorHits)}");
|
// Console.WriteLine($"Partial factor cofactor hits {Volatile.Read(ref _partialFactorCofactorHits)}");
|
||||||
|
|
||||||
cofactorIsPrime = PrimeTester.IsPrimeGpu(cofactor);
|
cofactorIsPrime = PrimeTester.IsPrimeGpu(gpu, cofactor);
|
||||||
// cofactorIsPrime = PrimeTester.IsPrimeGpu(cofactor);
|
// cofactorIsPrime = PrimeTester.IsPrimeGpu(cofactor);
|
||||||
// cofactorIsPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(cofactor);
|
// cofactorIsPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(cofactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GpuPrimeWorkLimiter.Release();
|
||||||
|
|
||||||
ArrayPool<FactorEntry> pool = ThreadStaticPools.FactorEntryPool;
|
ArrayPool<FactorEntry> pool = ThreadStaticPools.FactorEntryPool;
|
||||||
bool temp;
|
bool temp;
|
||||||
if (factorCount == 0)
|
if (factorCount == 0)
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
entries.Sort(entries, static (a, b) => a.Key.CompareTo(b.Key));
|
entries.Sort(entries, static (a, b) => a.Key.CompareTo(b.Key));
|
||||||
|
|
||||||
AcceleratorStream stream = gpu.Stream!;
|
AcceleratorStream stream = gpu.Stream!;
|
||||||
gpu.EnsureCapacity(entryCount);
|
gpu.EnsureCapacity(entryCount, 1);
|
||||||
gpu.Pow2ModEntriesToTestOnDevice.View.CopyFromCPU(stream, entries);
|
gpu.Pow2ModEntriesToTestOnDevice.View.CopyFromCPU(stream, entries);
|
||||||
|
|
||||||
ulong order = phi;
|
ulong order = phi;
|
||||||
|
|||||||
@@ -94,17 +94,17 @@ public sealed class PrimeTester
|
|||||||
public static bool IsPrimeGpu(ulong n)
|
public static bool IsPrimeGpu(ulong n)
|
||||||
{
|
{
|
||||||
GpuPrimeWorkLimiter.Acquire();
|
GpuPrimeWorkLimiter.Acquire();
|
||||||
var gpu = PrimeTesterByLastDigitAccelerator.Rent(1);
|
var gpu = Pow2MontgomeryAccelerator.Rent(1);
|
||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
var stream = gpu.Stream;
|
var stream = gpu.Stream!;
|
||||||
var kernel = PrimeTesterByLastDigitAccelerator.GetSmallPrimeSieveKernel(accelerator);
|
var kernel = gpu.SmallPrimeSieveKernel;
|
||||||
|
|
||||||
ulong value = n;
|
ulong value = n;
|
||||||
// Span<byte> flag = stackalloc byte[1];
|
// Span<byte> flag = stackalloc byte[1];
|
||||||
byte flag = 0;
|
byte flag = 0;
|
||||||
|
|
||||||
var input = gpu.Input;
|
var input = gpu.PrimeTestInput;
|
||||||
var output = gpu.Output;
|
var output = gpu.PrimeTestOutput;
|
||||||
var inputView = input.View;
|
var inputView = input.View;
|
||||||
var outputView = output.View;
|
var outputView = output.View;
|
||||||
|
|
||||||
@@ -131,6 +131,42 @@ public sealed class PrimeTester
|
|||||||
return flag != 0;
|
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;
|
public static int GpuBatchSize { get; set; } = 262_144;
|
||||||
|
|
||||||
private static readonly object GpuWarmUpLock = new();
|
private static readonly object GpuWarmUpLock = new();
|
||||||
@@ -151,7 +187,7 @@ public sealed class PrimeTester
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrimeTesterByLastDigitAccelerator.WarmUp();
|
Pow2MontgomeryAccelerator.WarmUp();
|
||||||
WarmedGpuLeaseCount = target;
|
WarmedGpuLeaseCount = target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,15 +196,15 @@ public sealed class PrimeTester
|
|||||||
public static void IsPrimeBatchGpu(ReadOnlySpan<ulong> values, Span<byte> results)
|
public static void IsPrimeBatchGpu(ReadOnlySpan<ulong> values, Span<byte> results)
|
||||||
{
|
{
|
||||||
GpuPrimeWorkLimiter.Acquire();
|
GpuPrimeWorkLimiter.Acquire();
|
||||||
var gpu = PrimeTesterByLastDigitAccelerator.Rent(GpuBatchSize);
|
var gpu = Pow2MontgomeryAccelerator.Rent(GpuBatchSize);
|
||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
var stream = gpu.Stream;
|
var stream = gpu.Stream!;
|
||||||
var kernel = PrimeTesterByLastDigitAccelerator.GetSmallPrimeSieveKernel(accelerator);
|
var kernel = gpu.SmallPrimeSieveKernel;
|
||||||
int totalLength = values.Length;
|
int totalLength = values.Length;
|
||||||
int batchSize = GpuBatchSize;
|
int batchSize = GpuBatchSize;
|
||||||
|
|
||||||
var input = gpu.Input;
|
var input = gpu.PrimeTestInput;
|
||||||
var output = gpu.Output;
|
var output = gpu.PrimeTestOutput;
|
||||||
var inputView = input.View;
|
var inputView = input.View;
|
||||||
var outputView = output.View;
|
var outputView = output.View;
|
||||||
|
|
||||||
@@ -211,12 +247,12 @@ public sealed class PrimeTester
|
|||||||
// Expose cache clearing for accelerator disposal coordination
|
// Expose cache clearing for accelerator disposal coordination
|
||||||
public static void ClearGpuCaches()
|
public static void ClearGpuCaches()
|
||||||
{
|
{
|
||||||
PrimeTesterByLastDigitAccelerator.Clear();
|
Pow2MontgomeryAccelerator.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void DisposeGpuContexts()
|
internal static void DisposeGpuContexts()
|
||||||
{
|
{
|
||||||
PrimeTesterByLastDigitAccelerator.DisposeAll();
|
Pow2MontgomeryAccelerator.DisposeAll();
|
||||||
lock (GpuWarmUpLock)
|
lock (GpuWarmUpLock)
|
||||||
{
|
{
|
||||||
WarmedGpuLeaseCount = 0;
|
WarmedGpuLeaseCount = 0;
|
||||||
@@ -241,9 +277,9 @@ public sealed class PrimeTester
|
|||||||
// TODO: Route this batch helper through the shared GPU kernel pool from
|
// TODO: Route this batch helper through the shared GPU kernel pool from
|
||||||
// GpuUInt128BinaryGcdBenchmarks so we reuse cached kernels, pinned host buffers,
|
// GpuUInt128BinaryGcdBenchmarks so we reuse cached kernels, pinned host buffers,
|
||||||
// and divisor-cycle staging instead of allocating new device buffers per call.
|
// 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 accelerator = gpu.Accelerator;
|
||||||
var stream = gpu.Stream;
|
var stream = gpu.Stream!;
|
||||||
|
|
||||||
int length = values.Length;
|
int length = values.Length;
|
||||||
ArrayPool<ulong> pool = ThreadStaticPools.UlongPool;
|
ArrayPool<ulong> pool = ThreadStaticPools.UlongPool;
|
||||||
|
|||||||
Reference in new issue
Block a user