GpuScratchBuffer / -Pool naively integrated with PriemOrderCalculatorAccelerator (formerly Pow2MontgomeryAccelerator). FactorEntry replaced with 2 arrays - unused field removed. Small cleanup.
This commit is contained in:
1 parent
43863d03fb
commit
c53aa517f7
14 files changed
+273
-398
No files matched your search
@@ -67,7 +67,6 @@ internal static class Program
|
|||||||
PrimeTester.WarmUpGpuKernels(1024);
|
PrimeTester.WarmUpGpuKernels(1024);
|
||||||
// PrimeTester.WarmUpGpuKernels(gpuPrimeThreads >> 4);
|
// PrimeTester.WarmUpGpuKernels(gpuPrimeThreads >> 4);
|
||||||
Console.WriteLine("Warming up scratch buffers");
|
Console.WriteLine("Warming up scratch buffers");
|
||||||
GpuScratchBufferPool.WarmUp(gpuPrimeThreads >> 4, 64, 128);
|
|
||||||
Console.WriteLine("Starting up threads...");
|
Console.WriteLine("Starting up threads...");
|
||||||
_ = UnboundedTaskScheduler.Instance;
|
_ = UnboundedTaskScheduler.Instance;
|
||||||
int blockSize = Math.Max(1, _cliArguments.BlockSize);
|
int blockSize = Math.Max(1, _cliArguments.BlockSize);
|
||||||
|
|||||||
@@ -6,21 +6,20 @@ namespace PerfectNumbers.Core.Gpu.Accelerators;
|
|||||||
|
|
||||||
public static class AcceleratorStreamPool
|
public static class AcceleratorStreamPool
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<Accelerator, ConcurrentQueue<AcceleratorStream>> _streams = new(PerfectNumberConstants .RollingAccelerators);
|
private static readonly Dictionary<Accelerator, ConcurrentQueue<AcceleratorStream>> _streams = new(PerfectNumberConstants .RollingAccelerators << 1);
|
||||||
// private static readonly ConcurrentDictionary<Accelerator, AcceleratorStream> _streams = new(AcceleratorPool.Shared.Accelerators.ToDictionary(static x => x, CreateStream));
|
|
||||||
|
|
||||||
private static SemaphoreSlim CreateLock() => new(PerfectNumberConstants.ThreadsByStream);
|
private static SemaphoreSlim CreateLock() => new(PerfectNumberConstants.ThreadsByStream);
|
||||||
private static AcceleratorStream CreateStream(Accelerator accelerator) => accelerator.CreateStream();
|
|
||||||
|
|
||||||
private static readonly Dictionary<Accelerator, SemaphoreSlim> _locks = new(AcceleratorPool.Shared.Accelerators.ToDictionary(x => x, static x => CreateLock()));
|
private static readonly Dictionary<Accelerator, SemaphoreSlim> _locks = new(PerfectNumberConstants.RollingAccelerators << 1);
|
||||||
|
|
||||||
|
// private static int _rented;
|
||||||
|
|
||||||
public static AcceleratorStream Rent(Accelerator accelerator)
|
public static AcceleratorStream Rent(Accelerator accelerator)
|
||||||
{
|
{
|
||||||
var streamLock = _locks[accelerator];
|
var streamLock = _locks[accelerator];
|
||||||
// var streamLock = _locks.GetOrAdd(accelerator, static _ => CreateLock());
|
var queue = _streams[accelerator];
|
||||||
|
|
||||||
streamLock.Wait();
|
streamLock.Wait();
|
||||||
var queue = _streams[accelerator];
|
|
||||||
|
|
||||||
return queue.TryDequeue(out var stream)
|
return queue.TryDequeue(out var stream)
|
||||||
? stream
|
? stream
|
||||||
@@ -40,13 +39,5 @@ public static class AcceleratorStreamPool
|
|||||||
{
|
{
|
||||||
_streams.Add(accelerator, new());
|
_streams.Add(accelerator, new());
|
||||||
_ = _locks.TryAdd(accelerator, CreateLock());
|
_ = _locks.TryAdd(accelerator, CreateLock());
|
||||||
|
|
||||||
// ConcurrentQueue<AcceleratorStream> streamQueue = new();
|
|
||||||
// var stream = accelerator.CreateStream();
|
|
||||||
// // var stream = accelerator.CreateStream();
|
|
||||||
// streamQueue.Enqueue(stream);
|
|
||||||
// _streams[accelerator] = streamQueue;
|
|
||||||
// _locks[accelerator] = CreateLock();
|
|
||||||
// stream.Synchronize();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Runtime.CompilerServices;
|
||||||
using ILGPU;
|
using ILGPU;
|
||||||
using ILGPU.Runtime;
|
using ILGPU.Runtime;
|
||||||
|
|
||||||
@@ -6,10 +6,13 @@ 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 * 2);
|
private static readonly Dictionary<Accelerator, LastDigitGpuTables> _sharedTables = new(PerfectNumberConstants.RollingAccelerators);
|
||||||
|
|
||||||
internal static LastDigitGpuTables EnsureStaticTables(Accelerator accelerator, AcceleratorStream stream)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
=> _sharedTables.GetOrAdd(accelerator, _ => new LastDigitGpuTables(accelerator, stream));
|
internal static LastDigitGpuTables EnsureStaticTables(Accelerator accelerator) => _sharedTables[accelerator];
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal static void WarmUp(Accelerator accelerator, AcceleratorStream stream) => _sharedTables[accelerator] = new LastDigitGpuTables(accelerator, stream);
|
||||||
|
|
||||||
internal LastDigitGpuTables(Accelerator accelerator, AcceleratorStream stream)
|
internal LastDigitGpuTables(Accelerator accelerator, AcceleratorStream stream)
|
||||||
{
|
{
|
||||||
@@ -21,9 +24,6 @@ internal sealed class LastDigitGpuTables
|
|||||||
var primesPow2LastSeven = DivisorGenerator.SmallPrimesPow2LastSeven;
|
var primesPow2LastSeven = DivisorGenerator.SmallPrimesPow2LastSeven;
|
||||||
var primesPow2LastThree = DivisorGenerator.SmallPrimesPow2LastThree;
|
var primesPow2LastThree = DivisorGenerator.SmallPrimesPow2LastThree;
|
||||||
var primesPow2LastNine = DivisorGenerator.SmallPrimesPow2LastNine;
|
var primesPow2LastNine = DivisorGenerator.SmallPrimesPow2LastNine;
|
||||||
|
|
||||||
// lock (accelerator)
|
|
||||||
{
|
|
||||||
DevicePrimesLastOne = accelerator.Allocate1D(stream, primesLastOne);
|
DevicePrimesLastOne = accelerator.Allocate1D(stream, primesLastOne);
|
||||||
DevicePrimesLastSeven = accelerator.Allocate1D(stream, primesLastSeven);
|
DevicePrimesLastSeven = accelerator.Allocate1D(stream, primesLastSeven);
|
||||||
DevicePrimesLastThree = accelerator.Allocate1D(stream, primesLastThree);
|
DevicePrimesLastThree = accelerator.Allocate1D(stream, primesLastThree);
|
||||||
@@ -33,7 +33,6 @@ internal sealed class LastDigitGpuTables
|
|||||||
DevicePrimesPow2LastThree = accelerator.Allocate1D(stream, primesPow2LastThree);
|
DevicePrimesPow2LastThree = accelerator.Allocate1D(stream, primesPow2LastThree);
|
||||||
DevicePrimesPow2LastNine = accelerator.Allocate1D(stream, primesPow2LastNine);
|
DevicePrimesPow2LastNine = accelerator.Allocate1D(stream, primesPow2LastNine);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
internal readonly MemoryBuffer1D<uint, Stride1D.Dense> DevicePrimesLastOne;
|
internal readonly MemoryBuffer1D<uint, Stride1D.Dense> DevicePrimesLastOne;
|
||||||
internal readonly MemoryBuffer1D<uint, Stride1D.Dense> DevicePrimesLastSeven;
|
internal readonly MemoryBuffer1D<uint, Stride1D.Dense> DevicePrimesLastSeven;
|
||||||
|
|||||||
+72
-64
@@ -5,27 +5,26 @@ using PerfectNumbers.Core.Gpu.Kernels;
|
|||||||
|
|
||||||
namespace PerfectNumbers.Core.Gpu.Accelerators;
|
namespace PerfectNumbers.Core.Gpu.Accelerators;
|
||||||
|
|
||||||
public sealed class Pow2MontgomeryAccelerator
|
public sealed class PrimeOrderCalculatorAccelerator
|
||||||
{
|
{
|
||||||
#region Pool
|
#region Pool
|
||||||
|
|
||||||
[ThreadStatic]
|
[ThreadStatic]
|
||||||
private static Queue<Pow2MontgomeryAccelerator>? _pool;
|
private static Queue<PrimeOrderCalculatorAccelerator>? _pool;
|
||||||
|
|
||||||
private static AcceleratorPool _accelerators = new(PerfectNumberConstants.RollingAccelerators);
|
private static readonly AcceleratorPool _accelerators = new(PerfectNumberConstants.RollingAccelerators);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static Pow2MontgomeryAccelerator Rent(int primeTesterCapacity)
|
public static PrimeOrderCalculatorAccelerator 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, primeTesterCapacity);
|
gpu = new(accelerator, PerfectNumberConstants.DefaultFactorsBuffer, primeTesterCapacity, PerfectNumberConstants.DefaultSmallPrimeFactorSlotCount, PerfectNumberConstants.DefaultSpecialMaxFactorCapacity);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// gpu.Stream = gpu.Accelerator.CreateStream();
|
|
||||||
gpu.EnsureCapacity(PerfectNumberConstants.DefaultFactorsBuffer, primeTesterCapacity);
|
gpu.EnsureCapacity(PerfectNumberConstants.DefaultFactorsBuffer, primeTesterCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,33 +32,28 @@ public sealed class Pow2MontgomeryAccelerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void Return(Pow2MontgomeryAccelerator gpu)
|
public static void Return(PrimeOrderCalculatorAccelerator gpu) => _pool!.Enqueue(gpu);
|
||||||
{
|
|
||||||
// gpu.Stream!.Dispose();
|
|
||||||
// gpu.Stream = null;
|
|
||||||
_pool!.Enqueue(gpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void Clear()
|
internal static void Clear()
|
||||||
{
|
{
|
||||||
Queue<Pow2MontgomeryAccelerator>? pool = _pool;
|
Queue<PrimeOrderCalculatorAccelerator>? pool = _pool;
|
||||||
if (pool != null)
|
if (pool != null)
|
||||||
{
|
{
|
||||||
while (pool.TryDequeue(out var lease))
|
while (pool.TryDequeue(out var gpu))
|
||||||
{
|
{
|
||||||
lease.Dispose();
|
gpu.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void DisposeAll()
|
internal static void DisposeAll()
|
||||||
{
|
{
|
||||||
Queue<Pow2MontgomeryAccelerator>? pool = _pool;
|
Queue<PrimeOrderCalculatorAccelerator>? pool = _pool;
|
||||||
if (pool != null)
|
if (pool != null)
|
||||||
{
|
{
|
||||||
while (pool.TryDequeue(out var lease))
|
while (pool.TryDequeue(out var gpu))
|
||||||
{
|
{
|
||||||
lease.Dispose();
|
gpu.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,17 +67,15 @@ public sealed class Pow2MontgomeryAccelerator
|
|||||||
Console.WriteLine($"Preparing accelerator {i}...");
|
Console.WriteLine($"Preparing accelerator {i}...");
|
||||||
var accelerator = accelerators[i];
|
var accelerator = accelerators[i];
|
||||||
AcceleratorStreamPool.WarmUp(accelerator);
|
AcceleratorStreamPool.WarmUp(accelerator);
|
||||||
// AcceleratorStream stream = AcceleratorStreamPool.Rent(accelerator);
|
// Don't take this from the pool as quick uploads of data to the accelerator consumes much of GPU's memory and throws.
|
||||||
AcceleratorStream stream = accelerator.CreateStream();
|
AcceleratorStream stream = accelerator.CreateStream();
|
||||||
LastDigitGpuTables.EnsureStaticTables(accelerator, stream);
|
LastDigitGpuTables.WarmUp(accelerator, stream);
|
||||||
// SharedHeuristicGpuTables.EnsureStaticTables(accelerator, stream);
|
// SharedHeuristicGpuTables.EnsureStaticTables(accelerator, stream);
|
||||||
// _ = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.None);
|
// _ = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.None);
|
||||||
// KernelContainer kernels = GpuKernelPool.GetOrAddKernels(accelerator, stream);
|
// KernelContainer kernels = GpuKernelPool.GetOrAddKernels(accelerator, stream);
|
||||||
// GpuStaticTableInitializer.EnsureStaticTables(accelerator, kernels, stream);
|
// GpuStaticTableInitializer.EnsureStaticTables(accelerator, kernels, stream);
|
||||||
stream.Synchronize();
|
stream.Synchronize();
|
||||||
stream.Dispose();
|
stream.Dispose();
|
||||||
|
|
||||||
// AcceleratorStreamPool.Return(stream);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,31 +97,20 @@ public sealed class Pow2MontgomeryAccelerator
|
|||||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> DevicePrimesPow2LastSeven;
|
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> DevicePrimesPow2LastSeven;
|
||||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> DevicePrimesPow2LastThree;
|
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> DevicePrimesPow2LastThree;
|
||||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> DevicePrimesPow2LastNine;
|
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> DevicePrimesPow2LastNine;
|
||||||
|
public readonly MemoryBuffer1D<int, Stride1D.Dense> SmallPrimeFactorCountSlot;
|
||||||
|
public MemoryBuffer1D<int, Stride1D.Dense> SmallPrimeFactorExponentSlots;
|
||||||
|
public MemoryBuffer1D<ulong, Stride1D.Dense> SmallPrimeFactorPrimeSlots;
|
||||||
|
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> SmallPrimeFactorRemainingSlot;
|
||||||
|
public MemoryBuffer1D<ulong, Stride1D.Dense> SpecialMaxCandidates;
|
||||||
|
public MemoryBuffer1D<ulong, Stride1D.Dense> SpecialMaxFactors;
|
||||||
|
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> SpecialMaxResult;
|
||||||
|
|
||||||
public readonly Kernel SmallPrimeSieveKernel;
|
public readonly Kernel SmallPrimeSieveKernel;
|
||||||
|
|
||||||
// public AcceleratorStream? Stream;
|
|
||||||
|
|
||||||
public readonly Kernel CheckFactorsKernel;
|
public readonly Kernel CheckFactorsKernel;
|
||||||
public readonly Kernel ConvertToStandardKernel;
|
public readonly Kernel ConvertToStandardKernel;
|
||||||
public readonly Kernel KeepMontgomeryKernel;
|
public readonly Kernel KeepMontgomeryKernel;
|
||||||
public readonly Kernel PollardRhoKernel;
|
public readonly Kernel PollardRhoKernel;
|
||||||
|
|
||||||
[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)
|
public void EnsureCapacity(int factorsCount, int primeTesterCapacity)
|
||||||
{
|
{
|
||||||
if (factorsCount > Pow2ModEntriesToTestOnDevice.Length)
|
if (factorsCount > Pow2ModEntriesToTestOnDevice.Length)
|
||||||
@@ -141,35 +122,62 @@ public sealed class Pow2MontgomeryAccelerator
|
|||||||
|
|
||||||
if (primeTesterCapacity > PrimeTestInput.Length)
|
if (primeTesterCapacity > PrimeTestInput.Length)
|
||||||
{
|
{
|
||||||
PrimeTestInput?.Dispose();
|
PrimeTestInput.Dispose();
|
||||||
OutputByte?.Dispose();
|
OutputByte.Dispose();
|
||||||
HeuristicFlag?.Dispose();
|
HeuristicFlag.Dispose();
|
||||||
|
|
||||||
// lock (Accelerator)
|
|
||||||
{
|
|
||||||
PrimeTestInput = Accelerator.Allocate1D<ulong>(primeTesterCapacity);
|
PrimeTestInput = Accelerator.Allocate1D<ulong>(primeTesterCapacity);
|
||||||
OutputByte = Accelerator.Allocate1D<byte>(primeTesterCapacity);
|
OutputByte = Accelerator.Allocate1D<byte>(primeTesterCapacity);
|
||||||
HeuristicFlag = Accelerator.Allocate1D<int>(primeTesterCapacity);
|
HeuristicFlag = Accelerator.Allocate1D<int>(primeTesterCapacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void EnsureSmallPrimeFactorSlotsCapacity(int newSize)
|
||||||
|
{
|
||||||
|
// Console.WriteLine($"Resizing GPU scratch buffer from pool ({buffer.SmallPrimeFactorPrimeSlots.Length} / {smallPrimeFactorSlotCount}), ({buffer.SpecialMaxFactors.Length}/{specialMaxFactorCapacity})");
|
||||||
|
if (SmallPrimeFactorPrimeSlots.Length < newSize)
|
||||||
|
{
|
||||||
|
SmallPrimeFactorPrimeSlots.Dispose();
|
||||||
|
SmallPrimeFactorExponentSlots.Dispose();
|
||||||
|
|
||||||
|
var accelerator = Accelerator;
|
||||||
|
SmallPrimeFactorPrimeSlots = accelerator.Allocate1D<ulong>(newSize);
|
||||||
|
SmallPrimeFactorExponentSlots = accelerator.Allocate1D<int>(newSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pow2MontgomeryAccelerator(Accelerator accelerator, int factorsCount, int primeTesterCapacity)
|
public void EnsureSpecialMaxFactorsCapacity(int newSize)
|
||||||
|
{
|
||||||
|
if (SpecialMaxFactors.Length < newSize)
|
||||||
|
{
|
||||||
|
SpecialMaxFactors.Dispose();
|
||||||
|
SpecialMaxCandidates.Dispose();
|
||||||
|
|
||||||
|
var accelerator = Accelerator;
|
||||||
|
SpecialMaxFactors = accelerator.Allocate1D<ulong>(newSize);
|
||||||
|
SpecialMaxCandidates = accelerator.Allocate1D<ulong>(newSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrimeOrderCalculatorAccelerator(Accelerator accelerator, int factorsCount, int primeTesterCapacity, int smallPrimeFactorSlotCount, int specialMaxFactorCapacity)
|
||||||
{
|
{
|
||||||
Accelerator = accelerator;
|
Accelerator = accelerator;
|
||||||
AcceleratorStream stream = AcceleratorStreamPool.Rent(accelerator);
|
|
||||||
// AcceleratorStream stream = accelerator.DefaultStream;
|
|
||||||
// AcceleratorStream stream = accelerator.CreateStream();
|
|
||||||
// Stream = stream;
|
|
||||||
|
|
||||||
Input = accelerator.Allocate1D<ulong>(1);
|
Input = accelerator.Allocate1D<ulong>(1);
|
||||||
OutputUlong = accelerator.Allocate1D<ulong>(1);
|
OutputUlong = accelerator.Allocate1D<ulong>(1);
|
||||||
Pow2ModEntriesToTestOnDevice = accelerator.Allocate1D<KeyValuePair<ulong, int>>(factorsCount);
|
Pow2ModEntriesToTestOnDevice = accelerator.Allocate1D<KeyValuePair<ulong, int>>(factorsCount);
|
||||||
PrimeTestInput = Accelerator.Allocate1D<ulong>(primeTesterCapacity);
|
PrimeTestInput = Accelerator.Allocate1D<ulong>(primeTesterCapacity);
|
||||||
OutputByte = Accelerator.Allocate1D<byte>(primeTesterCapacity);
|
OutputByte = Accelerator.Allocate1D<byte>(primeTesterCapacity);
|
||||||
HeuristicFlag = Accelerator.Allocate1D<int>(primeTesterCapacity);
|
HeuristicFlag = Accelerator.Allocate1D<int>(primeTesterCapacity);
|
||||||
|
SmallPrimeFactorPrimeSlots = accelerator.Allocate1D<ulong>(smallPrimeFactorSlotCount);
|
||||||
|
SmallPrimeFactorExponentSlots = accelerator.Allocate1D<int>(smallPrimeFactorSlotCount);
|
||||||
|
SmallPrimeFactorCountSlot = accelerator.Allocate1D<int>(1);
|
||||||
|
SmallPrimeFactorRemainingSlot = accelerator.Allocate1D<ulong>(1);
|
||||||
|
|
||||||
var sharedTables = LastDigitGpuTables.EnsureStaticTables(accelerator, stream);
|
SpecialMaxFactors = accelerator.Allocate1D<ulong>(specialMaxFactorCapacity);
|
||||||
|
SpecialMaxCandidates = accelerator.Allocate1D<ulong>(specialMaxFactorCapacity);
|
||||||
|
SpecialMaxResult = accelerator.Allocate1D<ulong>(1);
|
||||||
|
|
||||||
|
var sharedTables = LastDigitGpuTables.EnsureStaticTables(accelerator);
|
||||||
DevicePrimesLastOne = sharedTables.DevicePrimesLastOne;
|
DevicePrimesLastOne = sharedTables.DevicePrimesLastOne;
|
||||||
DevicePrimesLastSeven = sharedTables.DevicePrimesLastSeven;
|
DevicePrimesLastSeven = sharedTables.DevicePrimesLastSeven;
|
||||||
DevicePrimesLastThree = sharedTables.DevicePrimesLastThree;
|
DevicePrimesLastThree = sharedTables.DevicePrimesLastThree;
|
||||||
@@ -191,27 +199,27 @@ public sealed class Pow2MontgomeryAccelerator
|
|||||||
SmallPrimeSieveKernel = 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));
|
SmallPrimeSieveKernel = 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));
|
||||||
|
|
||||||
PollardRhoKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel<ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.TryPollardRhoKernel));
|
PollardRhoKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel<ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.TryPollardRhoKernel));
|
||||||
|
|
||||||
AcceleratorStreamPool.Return(stream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Input.Dispose();
|
Input.Dispose();
|
||||||
OutputUlong.Dispose();
|
OutputUlong.Dispose();
|
||||||
// Stream?.Dispose();
|
|
||||||
Pow2ModEntriesToTestOnDevice.Dispose();
|
Pow2ModEntriesToTestOnDevice.Dispose();
|
||||||
PrimeTestInput?.Dispose();
|
PrimeTestInput.Dispose();
|
||||||
OutputByte?.Dispose();
|
OutputByte.Dispose();
|
||||||
HeuristicFlag?.Dispose();
|
HeuristicFlag.Dispose();
|
||||||
|
SmallPrimeFactorPrimeSlots.Dispose();
|
||||||
// Stream is disposed upon return to the queue, so we don't need to dispose it here.
|
SmallPrimeFactorExponentSlots.Dispose();
|
||||||
// Stream.Dispose();
|
SmallPrimeFactorCountSlot.Dispose();
|
||||||
|
SmallPrimeFactorRemainingSlot.Dispose();
|
||||||
|
SpecialMaxFactors.Dispose();
|
||||||
|
SpecialMaxCandidates.Dispose();
|
||||||
|
SpecialMaxResult.Dispose();
|
||||||
|
|
||||||
// These resources are shared between GPU leases
|
// These resources are shared between GPU leases
|
||||||
// ReleaseSharedTables(_sharedTables);
|
// Stream.Dispose();
|
||||||
// Accelerator.Dispose();
|
// Accelerator.Dispose();
|
||||||
// Context.Dispose();
|
// Context.Dispose();
|
||||||
// Accelerator.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,8 +8,8 @@ public static class GpuPrimeWorkLimiter
|
|||||||
private static SemaphoreSlim _semaphore = new(1, int.MaxValue);
|
private static SemaphoreSlim _semaphore = new(1, int.MaxValue);
|
||||||
private static int _currentLimit = 1;
|
private static int _currentLimit = 1;
|
||||||
|
|
||||||
public static void Acquire() => _semaphore.Wait();
|
public static void Acquire() { } // => _semaphore.Wait();
|
||||||
public static void Release() => _semaphore.Release();
|
public static void Release() { }// => _semaphore.Release();
|
||||||
|
|
||||||
public static void SetLimit(int value)
|
public static void SetLimit(int value)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,157 +0,0 @@
|
|||||||
using ILGPU;
|
|
||||||
using ILGPU.Runtime;
|
|
||||||
|
|
||||||
namespace PerfectNumbers.Core.Gpu;
|
|
||||||
|
|
||||||
public sealed class GpuScratchBuffer
|
|
||||||
{
|
|
||||||
internal readonly Accelerator _accelerator;
|
|
||||||
public readonly MemoryBuffer1D<int, Stride1D.Dense> SmallPrimeFactorCountSlot;
|
|
||||||
public MemoryBuffer1D<int, Stride1D.Dense> SmallPrimeFactorExponentSlots;
|
|
||||||
public MemoryBuffer1D<ulong, Stride1D.Dense> SmallPrimeFactorPrimeSlots;
|
|
||||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> SmallPrimeFactorRemainingSlot;
|
|
||||||
public MemoryBuffer1D<ulong, Stride1D.Dense> SpecialMaxCandidates;
|
|
||||||
public MemoryBuffer1D<ulong, Stride1D.Dense> SpecialMaxFactors;
|
|
||||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> SpecialMaxResult;
|
|
||||||
|
|
||||||
public GpuScratchBuffer(Accelerator accelerator, int smallPrimeFactorSlotCount, int specialMaxFactorCapacity)
|
|
||||||
{
|
|
||||||
_accelerator = accelerator;
|
|
||||||
|
|
||||||
// lock (accelerator)
|
|
||||||
{
|
|
||||||
SmallPrimeFactorPrimeSlots = accelerator.Allocate1D<ulong>(smallPrimeFactorSlotCount);
|
|
||||||
SmallPrimeFactorExponentSlots = accelerator.Allocate1D<int>(smallPrimeFactorSlotCount);
|
|
||||||
SmallPrimeFactorCountSlot = accelerator.Allocate1D<int>(1);
|
|
||||||
SmallPrimeFactorRemainingSlot = accelerator.Allocate1D<ulong>(1);
|
|
||||||
|
|
||||||
SpecialMaxFactors = accelerator.Allocate1D<ulong>(specialMaxFactorCapacity);
|
|
||||||
SpecialMaxCandidates = accelerator.Allocate1D<ulong>(specialMaxFactorCapacity);
|
|
||||||
SpecialMaxResult = accelerator.Allocate1D<ulong>(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResizeSmallPrimeFactorSlots(int newSize)
|
|
||||||
{
|
|
||||||
if (SmallPrimeFactorPrimeSlots.Length < newSize)
|
|
||||||
{
|
|
||||||
SmallPrimeFactorPrimeSlots.Dispose();
|
|
||||||
SmallPrimeFactorExponentSlots.Dispose();
|
|
||||||
|
|
||||||
// lock(_accelerator)
|
|
||||||
{
|
|
||||||
SmallPrimeFactorPrimeSlots = _accelerator.Allocate1D<ulong>(newSize);
|
|
||||||
SmallPrimeFactorExponentSlots = _accelerator.Allocate1D<int>(newSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResizeSpecialMaxFactors(int newSize)
|
|
||||||
{
|
|
||||||
if (SpecialMaxFactors.Length < newSize)
|
|
||||||
{
|
|
||||||
SpecialMaxFactors.Dispose();
|
|
||||||
SpecialMaxCandidates.Dispose();
|
|
||||||
|
|
||||||
// lock(_accelerator)
|
|
||||||
{
|
|
||||||
SpecialMaxFactors = _accelerator.Allocate1D<ulong>(newSize);
|
|
||||||
SpecialMaxCandidates = _accelerator.Allocate1D<ulong>(newSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void Dispose()
|
|
||||||
{
|
|
||||||
SmallPrimeFactorPrimeSlots.Dispose();
|
|
||||||
SmallPrimeFactorExponentSlots.Dispose();
|
|
||||||
SmallPrimeFactorCountSlot.Dispose();
|
|
||||||
SmallPrimeFactorRemainingSlot.Dispose();
|
|
||||||
SpecialMaxFactors.Dispose();
|
|
||||||
SpecialMaxCandidates.Dispose();
|
|
||||||
SpecialMaxResult.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class GpuScratchBufferPool
|
|
||||||
{
|
|
||||||
[ThreadStatic]
|
|
||||||
private static Dictionary<Accelerator, Queue<GpuScratchBuffer>>? _pools;
|
|
||||||
|
|
||||||
// private static readonly ConcurrentDictionary<Accelerator, ConcurrentQueue<ScratchBuffer>> _pools = new();
|
|
||||||
private const int DefaultSmallPrimeFactorSlotCount = 64; // From PrimeOrderCalculator.Gpu.cs
|
|
||||||
private const int DefaultSpecialMaxFactorCapacity = 1024; // A reasonable default, will be resized if needed
|
|
||||||
|
|
||||||
public static GpuScratchBuffer Rent(Accelerator accelerator, int smallPrimeFactorSlotCount, int specialMaxFactorCapacity)
|
|
||||||
{
|
|
||||||
const int WarmUpCapacity = 100;
|
|
||||||
// var pool = _pools.GetOrAdd(accelerator, _ => new ConcurrentQueue<ScratchBuffer>());
|
|
||||||
if (_pools is not { })
|
|
||||||
{
|
|
||||||
_pools = new(WarmUpCapacity);
|
|
||||||
WarmUp(WarmUpCapacity, DefaultSmallPrimeFactorSlotCount, DefaultSpecialMaxFactorCapacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
var pools = _pools;
|
|
||||||
if (!pools.TryGetValue(accelerator, out var pool))
|
|
||||||
{
|
|
||||||
pool = new();
|
|
||||||
pools[accelerator] = pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
// var pool = _pools.GetOrAdd(accelerator, _ => new ConcurrentQueue<ScratchBuffer>());
|
|
||||||
if (pool.TryDequeue(out var buffer))
|
|
||||||
{
|
|
||||||
if (buffer.SmallPrimeFactorPrimeSlots.Length < smallPrimeFactorSlotCount || buffer.SpecialMaxFactors.Length < specialMaxFactorCapacity)
|
|
||||||
{
|
|
||||||
// throw new InvalidOperationException();
|
|
||||||
// lock (accelerator)
|
|
||||||
{
|
|
||||||
// Console.WriteLine($"Resizing GPU scratch buffer from pool ({buffer.SmallPrimeFactorPrimeSlots.Length} / {smallPrimeFactorSlotCount}), ({buffer.SpecialMaxFactors.Length}/{specialMaxFactorCapacity})");
|
|
||||||
buffer.ResizeSmallPrimeFactorSlots(smallPrimeFactorSlotCount);
|
|
||||||
buffer.ResizeSpecialMaxFactors(specialMaxFactorCapacity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new GpuScratchBuffer(accelerator, smallPrimeFactorSlotCount, specialMaxFactorCapacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Return(GpuScratchBuffer buffer)
|
|
||||||
{
|
|
||||||
if (_pools!.TryGetValue(buffer._accelerator, out var pool))
|
|
||||||
{
|
|
||||||
pool.Enqueue(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void WarmUp(int count, int smallPrimeFactorSlots, int specialMaxFactorCapacity)
|
|
||||||
{
|
|
||||||
// Accelerator accelerator = SharedGpuContext.Accelerator;
|
|
||||||
|
|
||||||
// for (int i = 0; i < count; i++)
|
|
||||||
// {
|
|
||||||
// var buffer = Rent(accelerator, smallPrimeFactorSlots, specialMaxFactorCapacity);
|
|
||||||
// Return(buffer);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DisposeAll()
|
|
||||||
{
|
|
||||||
var pool = _pools;
|
|
||||||
if (pool is not null)
|
|
||||||
{
|
|
||||||
foreach (var queue in pool.Values)
|
|
||||||
{
|
|
||||||
while (queue.TryDequeue(out var buffer))
|
|
||||||
{
|
|
||||||
buffer.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pool.Clear();
|
|
||||||
_pools = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,10 +12,9 @@ public static class Pow2MontgomeryGpuCalculator
|
|||||||
{
|
{
|
||||||
GpuPrimeWorkLimiter.Acquire();
|
GpuPrimeWorkLimiter.Acquire();
|
||||||
|
|
||||||
var gpu = Pow2MontgomeryAccelerator.Rent(1);
|
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||||
Accelerator? accelerator = gpu.Accelerator;
|
Accelerator? accelerator = gpu.Accelerator;
|
||||||
AcceleratorStream stream = AcceleratorStreamPool.Rent(accelerator);
|
AcceleratorStream stream = AcceleratorStreamPool.Rent(accelerator);
|
||||||
// AcceleratorStream stream = gpu.Stream!;
|
|
||||||
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
|
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
|
||||||
|
|
||||||
exponentBuffer.View.CopyFromCPU(stream, ref exponent, 1);
|
exponentBuffer.View.CopyFromCPU(stream, ref exponent, 1);
|
||||||
@@ -27,7 +26,6 @@ public static class Pow2MontgomeryGpuCalculator
|
|||||||
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
|
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
|
||||||
|
|
||||||
kernelLauncher(stream, 1, exponentBuffer.View, divisor, resultBuffer.View);
|
kernelLauncher(stream, 1, exponentBuffer.View, divisor, resultBuffer.View);
|
||||||
// kernel.Launch(stream, 1, 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);
|
||||||
@@ -35,7 +33,7 @@ public static class Pow2MontgomeryGpuCalculator
|
|||||||
AcceleratorStreamPool.Return(stream);
|
AcceleratorStreamPool.Return(stream);
|
||||||
GpuPrimeWorkLimiter.Release();
|
GpuPrimeWorkLimiter.Release();
|
||||||
|
|
||||||
Pow2MontgomeryAccelerator.Return(gpu);
|
PrimeOrderCalculatorAccelerator.Return(gpu);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,9 +42,8 @@ public static class Pow2MontgomeryGpuCalculator
|
|||||||
{
|
{
|
||||||
GpuPrimeWorkLimiter.Acquire();
|
GpuPrimeWorkLimiter.Acquire();
|
||||||
|
|
||||||
var gpu = Pow2MontgomeryAccelerator.Rent(1);
|
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||||
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
|
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
|
||||||
// AcceleratorStream stream = gpu.Stream!;
|
|
||||||
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
|
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
|
||||||
|
|
||||||
exponentBuffer.View.CopyFromCPU(stream, ref exponent, 1);
|
exponentBuffer.View.CopyFromCPU(stream, ref exponent, 1);
|
||||||
@@ -64,15 +61,14 @@ public static class Pow2MontgomeryGpuCalculator
|
|||||||
AcceleratorStreamPool.Return(stream);
|
AcceleratorStreamPool.Return(stream);
|
||||||
GpuPrimeWorkLimiter.Release();
|
GpuPrimeWorkLimiter.Release();
|
||||||
|
|
||||||
Pow2MontgomeryAccelerator.Return(gpu);
|
PrimeOrderCalculatorAccelerator.Return(gpu);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ulong CalculateConvert(Pow2MontgomeryAccelerator gpu, ulong exponent, in MontgomeryDivisorData divisor)
|
public static ulong CalculateConvert(PrimeOrderCalculatorAccelerator gpu, ulong exponent, in MontgomeryDivisorData divisor)
|
||||||
{
|
{
|
||||||
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
|
AcceleratorStream stream = AcceleratorStreamPool.Rent(gpu.Accelerator);
|
||||||
// AcceleratorStream stream = gpu.Stream!;
|
|
||||||
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
|
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
|
||||||
|
|
||||||
exponentBuffer.View.CopyFromCPU(stream, ref exponent, 1);
|
exponentBuffer.View.CopyFromCPU(stream, ref exponent, 1);
|
||||||
@@ -84,7 +80,6 @@ public static class Pow2MontgomeryGpuCalculator
|
|||||||
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
|
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
|
||||||
|
|
||||||
kernelLauncher(stream, 1,exponentBuffer.View, divisor, resultBuffer.View);
|
kernelLauncher(stream, 1,exponentBuffer.View, divisor, resultBuffer.View);
|
||||||
// kernel.Launch(stream, 1, 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);
|
||||||
|
|||||||
@@ -304,8 +304,7 @@ public static class MersenneNumberDivisorByDivisorTester
|
|||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine($"Task finished for range {rangeStart}");
|
Console.WriteLine($"Task finished for range {rangeStart}");
|
||||||
Pow2MontgomeryAccelerator.DisposeAll();
|
PrimeOrderCalculatorAccelerator.DisposeAll();
|
||||||
GpuScratchBufferPool.DisposeAll();
|
|
||||||
},
|
},
|
||||||
CancellationToken.None,
|
CancellationToken.None,
|
||||||
TaskCreationOptions.DenyChildAttach,
|
TaskCreationOptions.DenyChildAttach,
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using System.Buffers;
|
|
||||||
|
|
||||||
namespace PerfectNumbers.Core
|
namespace PerfectNumbers.Core
|
||||||
{
|
{
|
||||||
public sealed class PartialFactorResult
|
public sealed class PartialFactorResult
|
||||||
@@ -7,7 +5,8 @@ namespace PerfectNumbers.Core
|
|||||||
[ThreadStatic]
|
[ThreadStatic]
|
||||||
private static PartialFactorResult? s_poolHead;
|
private static PartialFactorResult? s_poolHead;
|
||||||
|
|
||||||
public FactorEntry[]? Factors;
|
public ulong[]? Factors;
|
||||||
|
public int[]? Exponents;
|
||||||
private PartialFactorResult? _next;
|
private PartialFactorResult? _next;
|
||||||
public ulong Cofactor;
|
public ulong Cofactor;
|
||||||
public bool FullyFactored;
|
public bool FullyFactored;
|
||||||
@@ -18,7 +17,7 @@ namespace PerfectNumbers.Core
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PartialFactorResult Rent(in FactorEntry[]? factors, ulong cofactor, bool fullyFactored, int count, bool cofactorIsPrime)
|
public static PartialFactorResult Rent(in ulong[]? factors, in int[]? exponents, ulong cofactor, bool fullyFactored, int count, bool cofactorIsPrime)
|
||||||
{
|
{
|
||||||
PartialFactorResult? instance = s_poolHead;
|
PartialFactorResult? instance = s_poolHead;
|
||||||
if (instance is null)
|
if (instance is null)
|
||||||
@@ -32,6 +31,29 @@ namespace PerfectNumbers.Core
|
|||||||
|
|
||||||
instance._next = null;
|
instance._next = null;
|
||||||
instance.Factors = factors;
|
instance.Factors = factors;
|
||||||
|
instance.Exponents = exponents;
|
||||||
|
instance.Cofactor = cofactor;
|
||||||
|
instance.FullyFactored = fullyFactored;
|
||||||
|
instance.Count = count;
|
||||||
|
instance.CofactorIsPrime = cofactorIsPrime;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PartialFactorResult Rent(ulong cofactor, bool fullyFactored, int count, bool cofactorIsPrime)
|
||||||
|
{
|
||||||
|
PartialFactorResult? instance = s_poolHead;
|
||||||
|
if (instance is null)
|
||||||
|
{
|
||||||
|
instance = new PartialFactorResult();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s_poolHead = instance._next;
|
||||||
|
}
|
||||||
|
|
||||||
|
instance._next = null;
|
||||||
|
instance.Factors = null;
|
||||||
|
instance.Exponents = null;
|
||||||
instance.Cofactor = cofactor;
|
instance.Cofactor = cofactor;
|
||||||
instance.FullyFactored = fullyFactored;
|
instance.FullyFactored = fullyFactored;
|
||||||
instance.Count = count;
|
instance.Count = count;
|
||||||
@@ -47,31 +69,49 @@ namespace PerfectNumbers.Core
|
|||||||
|
|
||||||
public PartialFactorResult WithAdditionalPrime(ulong prime)
|
public PartialFactorResult WithAdditionalPrime(ulong prime)
|
||||||
{
|
{
|
||||||
FactorEntry[]? source = Factors;
|
ulong[]? source = Factors;
|
||||||
if (source is null || Count == 0)
|
int sourceCount = Count;
|
||||||
|
int[] exponents;
|
||||||
|
if (source is null || sourceCount == 0)
|
||||||
{
|
{
|
||||||
FactorEntry[] local = ThreadStaticPools.FactorEntryPool.Rent(1);
|
source = ThreadStaticPools.UlongPool.Rent(1);
|
||||||
local[0] = new FactorEntry(prime, 1, true);
|
exponents = ThreadStaticPools.IntPool.Rent(1);
|
||||||
return Rent(local, 1UL, true, 1, false);
|
// source = new ulong[1];
|
||||||
|
// exponents = new int[1];
|
||||||
|
source[0] = prime;
|
||||||
|
exponents[0] = 1;
|
||||||
|
|
||||||
|
return Rent(source, exponents, 1UL, true, 1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
FactorEntry[] extended = ThreadStaticPools.FactorEntryPool.Rent(Count + 1);
|
ulong[] extended = ThreadStaticPools.UlongPool.Rent(sourceCount + 1);
|
||||||
Array.Copy(source, 0, extended, 0, Count);
|
Array.Copy(source, 0, extended, 0, sourceCount);
|
||||||
extended[Count] = new FactorEntry(prime, 1, true);
|
extended[sourceCount] = prime;
|
||||||
Span<FactorEntry> span = extended.AsSpan(0, Count + 1);
|
|
||||||
span.Sort(static (a, b) => a.Value.CompareTo(b.Value));
|
exponents = ThreadStaticPools.IntPool.Rent(sourceCount + 1);
|
||||||
return Rent(extended, 1UL, true, Count + 1, false);
|
Array.Copy(Exponents!, 0, exponents, 0, sourceCount);
|
||||||
|
exponents[sourceCount] = 1;
|
||||||
|
Array.Sort(extended, exponents, 0, sourceCount + 1);
|
||||||
|
|
||||||
|
return Rent(extended, exponents, 1UL, true, sourceCount + 1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (this != Empty)
|
if (this != Empty)
|
||||||
{
|
{
|
||||||
FactorEntry[]? factors = Factors;
|
ulong[]? factors = Factors;
|
||||||
if (factors is not null)
|
if (factors is not null)
|
||||||
{
|
{
|
||||||
|
int[] exponents = Exponents!;
|
||||||
Factors = null;
|
Factors = null;
|
||||||
ThreadStaticPools.FactorEntryPool.Return(factors, clearArray: false);
|
Exponents = null;
|
||||||
|
|
||||||
|
// if (factors.Length > 1)
|
||||||
|
// {
|
||||||
|
ThreadStaticPools.UlongPool.Return(factors, clearArray: false);
|
||||||
|
ThreadStaticPools.IntPool.Return(exponents, clearArray: false);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
_next = s_poolHead;
|
_next = s_poolHead;
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ public static class PerfectNumberConstants
|
|||||||
public const ulong BiggestKnownEvenPerfectP = 136279841UL;
|
public const ulong BiggestKnownEvenPerfectP = 136279841UL;
|
||||||
public const int ConsoleInterval = 100_000;
|
public const int ConsoleInterval = 100_000;
|
||||||
public const int DefaultFactorsBuffer = 32;
|
public const int DefaultFactorsBuffer = 32;
|
||||||
|
public const int DefaultSmallPrimeFactorSlotCount = 64;
|
||||||
|
public const int DefaultSpecialMaxFactorCapacity = 1024;
|
||||||
public const ulong ExtraDivisorCycleSearchLimit = 64UL;
|
public const ulong ExtraDivisorCycleSearchLimit = 64UL;
|
||||||
public const int MaxQForDivisorCycles = 4_000_000;
|
public const int MaxQForDivisorCycles = 4_000_000;
|
||||||
public static readonly uint PrimesLimit = 1_000_000; //(ulong)Array.MaxLength;// 1_000_000;
|
public static readonly uint PrimesLimit = 1_000_000; //(ulong)Array.MaxLength;// 1_000_000;
|
||||||
|
|||||||
@@ -53,10 +53,10 @@ internal static partial class PrimeOrderCalculator
|
|||||||
|
|
||||||
ulong phi = prime - 1UL;
|
ulong phi = prime - 1UL;
|
||||||
|
|
||||||
Pow2MontgomeryAccelerator gpu = Pow2MontgomeryAccelerator.Rent(1);
|
PrimeOrderCalculatorAccelerator gpu = PrimeOrderCalculatorAccelerator.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);
|
PrimeOrderCalculatorAccelerator.Return(gpu);
|
||||||
return gpuOrder;
|
return gpuOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,18 +67,18 @@ internal static partial class PrimeOrderCalculator
|
|||||||
{
|
{
|
||||||
result = CalculateByFactorizationGpu(gpu, prime, divisorData);
|
result = CalculateByFactorizationGpu(gpu, prime, divisorData);
|
||||||
phiFactors.Dispose();
|
phiFactors.Dispose();
|
||||||
Pow2MontgomeryAccelerator.Return(gpu);
|
PrimeOrderCalculatorAccelerator.Return(gpu);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = RunHeuristicPipelineCpu(gpu, prime, previousOrder, config, divisorData, phi, phiFactors);
|
result = RunHeuristicPipelineCpu(gpu, prime, previousOrder, config, divisorData, phi, phiFactors);
|
||||||
phiFactors.Dispose();
|
phiFactors.Dispose();
|
||||||
Pow2MontgomeryAccelerator.Return(gpu);
|
PrimeOrderCalculatorAccelerator.Return(gpu);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ulong RunHeuristicPipelineCpu(
|
private static ulong RunHeuristicPipelineCpu(
|
||||||
Pow2MontgomeryAccelerator gpu,
|
PrimeOrderCalculatorAccelerator gpu,
|
||||||
ulong prime,
|
ulong prime,
|
||||||
ulong? previousOrder,
|
ulong? previousOrder,
|
||||||
in PrimeOrderSearchConfig config,
|
in PrimeOrderSearchConfig config,
|
||||||
@@ -119,7 +119,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// private static ulong specialMaxHits;
|
// private static ulong specialMaxHits;
|
||||||
private static bool TrySpecialMaxCpu(Pow2MontgomeryAccelerator gpu, ulong phi, ulong prime, PartialFactorResult factors, in MontgomeryDivisorData divisorData)
|
private static bool TrySpecialMaxCpu(PrimeOrderCalculatorAccelerator gpu, ulong phi, ulong prime, PartialFactorResult factors, in MontgomeryDivisorData divisorData)
|
||||||
{
|
{
|
||||||
int length = factors.Count;
|
int length = factors.Count;
|
||||||
// The phi factorization on the scanner path always yields at least one entry for phi >= 2,
|
// The phi factorization on the scanner path always yields at least one entry for phi >= 2,
|
||||||
@@ -129,7 +129,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
// return true;
|
// return true;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
ReadOnlySpan<FactorEntry> factorSpan = new(factors.Factors, 0, length);
|
ReadOnlySpan<ulong> factorSpan = new(factors.Factors, 0, length);
|
||||||
|
|
||||||
Span<ulong> stackBuffer = stackalloc ulong[length];
|
Span<ulong> stackBuffer = stackalloc ulong[length];
|
||||||
|
|
||||||
@@ -138,18 +138,17 @@ internal static partial class PrimeOrderCalculator
|
|||||||
return EvaluateSpecialMaxCandidates(stackBuffer, factorSpan, phi, prime, divisorData);
|
return EvaluateSpecialMaxCandidates(stackBuffer, factorSpan, phi, prime, divisorData);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Atomic.Add(ref specialMaxHits, 1);
|
return EvaluateSpecialMaxCandidatesGpu(gpu, factorSpan, phi, prime, divisorData);
|
||||||
// Console.WriteLine($"Special max GPU hit {specialMaxHits} ({length})");
|
|
||||||
return EvaluateSpecialMaxCandidatesGpu(gpu, stackBuffer, factorSpan, phi, prime, divisorData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool EvaluateSpecialMaxCandidates(Span<ulong> buffer, ReadOnlySpan<FactorEntry> factors, ulong phi, ulong prime, in MontgomeryDivisorData divisorData)
|
private static bool EvaluateSpecialMaxCandidates(Span<ulong> buffer, ReadOnlySpan<ulong> factors, ulong phi, ulong prime, in MontgomeryDivisorData divisorData)
|
||||||
{
|
{
|
||||||
int actual = 0;
|
int actual = 0;
|
||||||
int factorCount = factors.Length;
|
int factorCount = factors.Length;
|
||||||
for (int i = 0; i < factorCount; i++)
|
for (int i = 0; i < factorCount; i++)
|
||||||
{
|
{
|
||||||
ulong factor = factors[i].Value;
|
ulong factor = factors[i];
|
||||||
|
|
||||||
// The partial factor pipeline never feeds zero or oversized factors while scanning candidate orders.
|
// The partial factor pipeline never feeds zero or oversized factors while scanning candidate orders.
|
||||||
// if (factor == 0UL || factor > phi)
|
// if (factor == 0UL || factor > phi)
|
||||||
// {
|
// {
|
||||||
@@ -196,7 +195,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ulong InitializeStartingOrderCpu(Pow2MontgomeryAccelerator gpu, ulong prime, ulong phi, in MontgomeryDivisorData divisorData)
|
private static ulong InitializeStartingOrderCpu(PrimeOrderCalculatorAccelerator gpu, ulong prime, ulong phi, in MontgomeryDivisorData divisorData)
|
||||||
{
|
{
|
||||||
ulong order = phi;
|
ulong order = phi;
|
||||||
if ((prime & 7UL) == 1UL || (prime & 7UL) == 7UL)
|
if ((prime & 7UL) == 1UL || (prime & 7UL) == 7UL)
|
||||||
@@ -213,22 +212,29 @@ internal static partial class PrimeOrderCalculator
|
|||||||
|
|
||||||
private static ulong ExponentLoweringCpu(ulong order, ulong prime, PartialFactorResult factors, in MontgomeryDivisorData divisorData)
|
private static ulong ExponentLoweringCpu(ulong order, ulong prime, PartialFactorResult factors, in MontgomeryDivisorData divisorData)
|
||||||
{
|
{
|
||||||
ArrayPool<FactorEntry> pool = ThreadStaticPools.FactorEntryPool;
|
ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool;
|
||||||
|
ArrayPool<int> intPool = ThreadStaticPools.IntPool;
|
||||||
|
|
||||||
|
ReadOnlySpan<ulong> factorSpan = factors.Factors;
|
||||||
|
ReadOnlySpan<int> exponentsSpan = factors.Exponents;
|
||||||
|
|
||||||
ReadOnlySpan<FactorEntry> factorSpan = factors.Factors;
|
|
||||||
int length = factors.Count;
|
int length = factors.Count;
|
||||||
FactorEntry[] tempArray = pool.Rent(length + 1);
|
ulong[] tempFactorsArray = ulongPool.Rent(length + 1);
|
||||||
|
int[] tempExponentsArray = intPool.Rent(length + 1);
|
||||||
|
|
||||||
Span<FactorEntry> buffer = tempArray;
|
Span<ulong> ulongBuffer = tempFactorsArray;
|
||||||
factorSpan.CopyTo(buffer);
|
factorSpan.CopyTo(ulongBuffer);
|
||||||
|
Span<int> intBuffer = tempExponentsArray;
|
||||||
|
exponentsSpan.CopyTo(intBuffer);
|
||||||
|
|
||||||
if (!factors.FullyFactored && factors.Cofactor > 1UL && factors.CofactorIsPrime)
|
if (!factors.FullyFactored && factors.Cofactor > 1UL && factors.CofactorIsPrime)
|
||||||
{
|
{
|
||||||
buffer[length] = new FactorEntry(factors.Cofactor, 1, true);
|
ulongBuffer[length] = factors.Cofactor;
|
||||||
|
intBuffer[length] = 1;
|
||||||
length++;
|
length++;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer[..length].Sort(static (a, b) => a.Value.CompareTo(b.Value));
|
Array.Sort(tempFactorsArray, tempExponentsArray, 0, length);
|
||||||
|
|
||||||
ExponentRemainderStepperCpu stepper = ThreadStaticPools.RentExponentStepperCpu(divisorData);
|
ExponentRemainderStepperCpu stepper = ThreadStaticPools.RentExponentStepperCpu(divisorData);
|
||||||
|
|
||||||
@@ -243,8 +249,8 @@ internal static partial class PrimeOrderCalculator
|
|||||||
|
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < length; i++)
|
||||||
{
|
{
|
||||||
ulong primeFactor = buffer[i].Value;
|
ulong primeFactor = ulongBuffer[i];
|
||||||
int exponent = buffer[i].Exponent;
|
int exponent = intBuffer[i];
|
||||||
// Factor exponents produced by Pollard-Rho and trial division are always positive in the scanner flow.
|
// Factor exponents produced by Pollard-Rho and trial division are always positive in the scanner flow.
|
||||||
// if (exponent <= 0)
|
// if (exponent <= 0)
|
||||||
// {
|
// {
|
||||||
@@ -275,7 +281,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
ThreadStaticPools.BoolPool.Return(heapEvaluationArray!);
|
ThreadStaticPools.BoolPool.Return(heapEvaluationArray!);
|
||||||
}
|
}
|
||||||
|
|
||||||
pool.Return(tempArray, clearArray: false);
|
ulongPool.Return(tempFactorsArray, clearArray: false);
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,7 +336,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryConfirmOrderCpu(
|
private static bool TryConfirmOrderCpu(
|
||||||
Pow2MontgomeryAccelerator gpu,
|
PrimeOrderCalculatorAccelerator gpu,
|
||||||
ulong prime,
|
ulong prime,
|
||||||
ulong order,
|
ulong order,
|
||||||
in MontgomeryDivisorData divisorData,
|
in MontgomeryDivisorData divisorData,
|
||||||
@@ -385,7 +391,9 @@ internal static partial class PrimeOrderCalculator
|
|||||||
in MontgomeryDivisorData divisorData,
|
in MontgomeryDivisorData divisorData,
|
||||||
PartialFactorResult factorization)
|
PartialFactorResult factorization)
|
||||||
{
|
{
|
||||||
ReadOnlySpan<FactorEntry> span = factorization.Factors!;
|
ReadOnlySpan<ulong> factorsSpan = factorization.Factors!;
|
||||||
|
ReadOnlySpan<int> exponentsSpan = factorization.Exponents!;
|
||||||
|
|
||||||
int length = factorization.Count;
|
int length = factorization.Count;
|
||||||
|
|
||||||
const int StackExponentCapacity = 32;
|
const int StackExponentCapacity = 32;
|
||||||
@@ -399,8 +407,9 @@ internal static partial class PrimeOrderCalculator
|
|||||||
|
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < length; i++)
|
||||||
{
|
{
|
||||||
ulong primeFactor = span[i].Value;
|
ulong primeFactor = factorsSpan[i];
|
||||||
int exponent = span[i].Exponent;
|
int exponent = exponentsSpan[i];
|
||||||
|
|
||||||
// Factor exponents emitted by TryConfirmCandidateCpu stay positive for production workloads.
|
// Factor exponents emitted by TryConfirmCandidateCpu stay positive for production workloads.
|
||||||
// if (exponent <= 0)
|
// if (exponent <= 0)
|
||||||
// {
|
// {
|
||||||
@@ -490,7 +499,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryHeuristicFinishCpu(
|
private static bool TryHeuristicFinishCpu(
|
||||||
Pow2MontgomeryAccelerator gpu,
|
PrimeOrderCalculatorAccelerator gpu,
|
||||||
ulong prime,
|
ulong prime,
|
||||||
ulong order,
|
ulong order,
|
||||||
ulong? previousOrder,
|
ulong? previousOrder,
|
||||||
@@ -523,7 +532,6 @@ internal static partial class PrimeOrderCalculator
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (!PrimeTester.IsPrimeCpu(orderFactors.Cofactor, CancellationToken.None))
|
|
||||||
if (!orderFactors.CofactorIsPrime)
|
if (!orderFactors.CofactorIsPrime)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -536,12 +544,13 @@ internal static partial class PrimeOrderCalculator
|
|||||||
|
|
||||||
int capacity = config.MaxPowChecks <= 0 ? 64 : config.MaxPowChecks << 2;
|
int capacity = config.MaxPowChecks <= 0 ? 64 : config.MaxPowChecks << 2;
|
||||||
List<ulong> candidates = ThreadStaticPools.RentUlongList(capacity);
|
List<ulong> candidates = ThreadStaticPools.RentUlongList(capacity);
|
||||||
FactorEntry[] factorArray = orderFactors.Factors!;
|
candidates.Clear();
|
||||||
|
ulong[] factorArray = orderFactors.Factors!;
|
||||||
|
int[] exponentsArray = orderFactors.Exponents!;
|
||||||
// DebugLog("Building candidates list");
|
// DebugLog("Building candidates list");
|
||||||
BuildCandidates(order, factorArray, orderFactors.Count, candidates, capacity);
|
BuildCandidates(order, factorArray, exponentsArray, orderFactors.Count, candidates, capacity);
|
||||||
if (candidates.Count == 0)
|
if (candidates.Count == 0)
|
||||||
{
|
{
|
||||||
candidates.Clear();
|
|
||||||
ThreadStaticPools.ReturnUlongList(candidates);
|
ThreadStaticPools.ReturnUlongList(candidates);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -798,19 +807,21 @@ internal static partial class PrimeOrderCalculator
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void BuildCandidates(ulong order, FactorEntry[] factors, int count, List<ulong> candidates, int limit)
|
private static readonly Comparer<ulong> _comparer = Comparer<ulong>.Default;
|
||||||
|
|
||||||
|
private static void BuildCandidates(ulong order, ulong[] factors, int[] exponents, int count, List<ulong> candidates, int limit)
|
||||||
{
|
{
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Span<FactorEntry> buffer = factors.AsSpan(0, count);
|
Array.Sort(factors, exponents, 0, count);
|
||||||
buffer.Sort(static (a, b) => a.Value.CompareTo(b.Value));
|
BuildCandidatesRecursive(order, factors, exponents, 0, 1UL, candidates, limit);
|
||||||
BuildCandidatesRecursive(order, buffer, 0, 1UL, candidates, limit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void BuildCandidatesRecursive(ulong order, in ReadOnlySpan<FactorEntry> factors, int index, ulong divisorProduct, List<ulong> candidates, int limit)
|
// private static void BuildCandidatesRecursive(ulong order, in ReadOnlySpan<FactorEntry> factors, int index, ulong divisorProduct, List<ulong> candidates, int limit)
|
||||||
|
private static void BuildCandidatesRecursive(ulong order, in ulong[] factors, in int[] exponents, int index, ulong divisorProduct, List<ulong> candidates, int limit)
|
||||||
{
|
{
|
||||||
if (candidates.Count >= limit)
|
if (candidates.Count >= limit)
|
||||||
{
|
{
|
||||||
@@ -833,11 +844,15 @@ internal static partial class PrimeOrderCalculator
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FactorEntry factor = factors[index];
|
// FactorEntry factor = factors[index];
|
||||||
int factorExponent = factor.Exponent;
|
// int factorExponent = factor.Exponent;
|
||||||
ulong primeFactor = factor.Value;
|
// ulong primeFactor = factor.Value;
|
||||||
|
|
||||||
|
ulong factor = factors[index];
|
||||||
|
int factorExponent = exponents[index];
|
||||||
|
|
||||||
ulong contribution = 1UL;
|
ulong contribution = 1UL;
|
||||||
ulong contributionLimit = factorExponent == 0 ? 0UL : order / primeFactor;
|
ulong contributionLimit = factorExponent == 0 ? 0UL : order / factor;
|
||||||
for (int exponent = 0; exponent <= factorExponent; exponent++)
|
for (int exponent = 0; exponent <= factorExponent; exponent++)
|
||||||
{
|
{
|
||||||
ulong nextDivisor = divisorProduct * contribution;
|
ulong nextDivisor = divisorProduct * contribution;
|
||||||
@@ -846,7 +861,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildCandidatesRecursive(order, factors, index + 1, nextDivisor, candidates, limit);
|
BuildCandidatesRecursive(order, factors, exponents, index + 1, nextDivisor, candidates, limit);
|
||||||
if (candidates.Count >= limit)
|
if (candidates.Count >= limit)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -862,11 +877,11 @@ internal static partial class PrimeOrderCalculator
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
contribution *= primeFactor;
|
contribution *= factor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryConfirmCandidateCpu(Pow2MontgomeryAccelerator gpu, ulong prime, ulong candidate, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config, ref int powUsed, int powBudget)
|
private static bool TryConfirmCandidateCpu(PrimeOrderCalculatorAccelerator gpu, ulong prime, ulong candidate, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config, ref int powUsed, int powBudget)
|
||||||
{
|
{
|
||||||
PartialFactorResult factorization = PartialFactor(gpu, candidate, config);
|
PartialFactorResult factorization = PartialFactor(gpu, candidate, config);
|
||||||
try
|
try
|
||||||
@@ -893,7 +908,9 @@ internal static partial class PrimeOrderCalculator
|
|||||||
factorization = extended;
|
factorization = extended;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadOnlySpan<FactorEntry> span = factorization.Factors;
|
// ReadOnlySpan<FactorEntry> span = factorization.Factors;
|
||||||
|
ReadOnlySpan<ulong> factorsSpan = factorization.Factors;
|
||||||
|
ReadOnlySpan<int> exponentsSpan = factorization.Exponents;
|
||||||
int length = factorization.Count;
|
int length = factorization.Count;
|
||||||
|
|
||||||
const int StackExponentCapacity = 32;
|
const int StackExponentCapacity = 32;
|
||||||
@@ -906,8 +923,11 @@ internal static partial class PrimeOrderCalculator
|
|||||||
|
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < length; i++)
|
||||||
{
|
{
|
||||||
ulong primeFactor = span[i].Value;
|
// ulong primeFactor = factorsSpan[i].Value;
|
||||||
int exponent = span[i].Exponent;
|
// int exponent = factorsSpan[i].Exponent;
|
||||||
|
ulong primeFactor = factorsSpan[i];
|
||||||
|
int exponent = exponentsSpan[i];
|
||||||
|
|
||||||
// Factorization entries for candidate confirmation are always positive here.
|
// Factorization entries for candidate confirmation are always positive here.
|
||||||
// if (exponent <= 0)
|
// if (exponent <= 0)
|
||||||
// {
|
// {
|
||||||
@@ -1036,7 +1056,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
|
|
||||||
private static ulong _pow2GpuHits;
|
private static ulong _pow2GpuHits;
|
||||||
private static ulong _pow2CpuHits;
|
private static ulong _pow2CpuHits;
|
||||||
private static bool Pow2EqualsOneCpu(Pow2MontgomeryAccelerator gpu, ulong exponent, ulong prime, in MontgomeryDivisorData divisorData)
|
private static bool Pow2EqualsOneCpu(PrimeOrderCalculatorAccelerator gpu, ulong exponent, ulong prime, in MontgomeryDivisorData divisorData)
|
||||||
{
|
{
|
||||||
if (exponent <= (PerfectNumberConstants.MaxQForDivisorCycles) || prime <= (PerfectNumberConstants.MaxQForDivisorCycles))
|
if (exponent <= (PerfectNumberConstants.MaxQForDivisorCycles) || prime <= (PerfectNumberConstants.MaxQForDivisorCycles))
|
||||||
{
|
{
|
||||||
@@ -1059,7 +1079,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(Pow2MontgomeryAccelerator gpu, ulong value, in PrimeOrderSearchConfig config)
|
private static PartialFactorResult PartialFactor(PrimeOrderCalculatorAccelerator gpu, ulong value, in PrimeOrderSearchConfig config)
|
||||||
{
|
{
|
||||||
if (value <= 1UL)
|
if (value <= 1UL)
|
||||||
{
|
{
|
||||||
@@ -1262,17 +1282,17 @@ internal static partial class PrimeOrderCalculator
|
|||||||
|
|
||||||
GpuPrimeWorkLimiter.Release();
|
GpuPrimeWorkLimiter.Release();
|
||||||
|
|
||||||
ArrayPool<FactorEntry> pool = ThreadStaticPools.FactorEntryPool;
|
// ArrayPool<FactorEntry> pool = ThreadStaticPools.FactorEntryPool;
|
||||||
bool temp;
|
bool temp;
|
||||||
if (factorCount == 0)
|
if (factorCount == 0)
|
||||||
{
|
{
|
||||||
if (cofactor == value)
|
if (cofactor == value)
|
||||||
{
|
{
|
||||||
result = PartialFactorResult.Rent(null, cofactor, false, 0, cofactorIsPrime);
|
result = PartialFactorResult.Rent(cofactor, false, 0, cofactorIsPrime);
|
||||||
goto ReturnResult;
|
goto ReturnResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = PartialFactorResult.Rent(null, cofactor, cofactor == 1UL, 0, cofactorIsPrime);
|
result = PartialFactorResult.Rent(cofactor, cofactor == 1UL, 0, cofactorIsPrime);
|
||||||
goto ReturnResult;
|
goto ReturnResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1289,12 +1309,21 @@ internal static partial class PrimeOrderCalculator
|
|||||||
// goto ReturnResult;
|
// goto ReturnResult;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
FactorEntry[] array = pool.Rent(factorCount);
|
ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool;
|
||||||
|
ArrayPool<int> intPool = ThreadStaticPools.IntPool;
|
||||||
|
// ArrayPool<bool> boolPool = ThreadStaticPools.BoolPool;
|
||||||
|
|
||||||
|
// FactorEntry[] array = pool.Rent(factorCount);
|
||||||
|
ulong[] factorsArray = ulongPool.Rent(factorCount);
|
||||||
|
int[] exponentsArray = intPool.Rent(factorCount);
|
||||||
|
// bool[] cofactorIsPrimesArray = boolPool.Rent(factorCount);
|
||||||
|
|
||||||
int arrayIndex = 0;
|
int arrayIndex = 0;
|
||||||
for (int i = 0; i < factorCount; i++)
|
for (int i = 0; i < factorCount; i++)
|
||||||
{
|
{
|
||||||
ulong primeValue = primeSlots[i];
|
ulong primeValue = primeSlots[i];
|
||||||
int exponentValue = exponentSlots[i];
|
int exponentValue = exponentSlots[i];
|
||||||
|
|
||||||
// This will never happen on the execution path from production code
|
// This will never happen on the execution path from production code
|
||||||
// if (primeValue == 0UL || exponentValue == 0)
|
// if (primeValue == 0UL || exponentValue == 0)
|
||||||
// {
|
// {
|
||||||
@@ -1302,14 +1331,20 @@ internal static partial class PrimeOrderCalculator
|
|||||||
// continue;
|
// continue;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
array[arrayIndex] = new FactorEntry(primeValue, exponentValue, true);
|
// factorsArray[arrayIndex] = new FactorEntry(primeValue, exponentValue, true);
|
||||||
|
factorsArray[arrayIndex] = primeValue;
|
||||||
|
exponentsArray[arrayIndex] = exponentValue;
|
||||||
|
// cofactorIsPrimesArray[arrayIndex] = true;
|
||||||
arrayIndex++;
|
arrayIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
Span<FactorEntry> arraySpan = array.AsSpan(0, arrayIndex);
|
// Span<FactorEntry> arraySpan = factorsArray.AsSpan(0, arrayIndex);
|
||||||
arraySpan.Sort(static (a, b) => a.Value.CompareTo(b.Value));
|
// Span<ulong> arraySpan = factorsArray.AsSpan(0, arrayIndex);
|
||||||
|
// arraySpan.Sort(static (a, b) => a.CompareTo(b));
|
||||||
|
Array.Sort(factorsArray, exponentsArray, 0, arrayIndex);
|
||||||
temp = cofactor == 1UL;
|
temp = cofactor == 1UL;
|
||||||
result = PartialFactorResult.Rent(array, cofactor, temp, arrayIndex, cofactorIsPrime);
|
// result = PartialFactorResult.Rent(factorsArray, exponentsArray, cofactorIsPrimesArray, cofactor, temp, arrayIndex, cofactorIsPrime);
|
||||||
|
result = PartialFactorResult.Rent(factorsArray, exponentsArray, cofactor, temp, arrayIndex, cofactorIsPrime);
|
||||||
|
|
||||||
ReturnResult:
|
ReturnResult:
|
||||||
if (primeSlotArray is not null)
|
if (primeSlotArray is not null)
|
||||||
@@ -1665,7 +1700,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
exponents = newExponentSpan;
|
exponents = newExponentSpan;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ulong CalculateByFactorizationCpu(Pow2MontgomeryAccelerator gpu, ulong prime, in MontgomeryDivisorData divisorData)
|
private static ulong CalculateByFactorizationCpu(PrimeOrderCalculatorAccelerator gpu, ulong prime, in MontgomeryDivisorData divisorData)
|
||||||
{
|
{
|
||||||
ulong phi = prime - 1UL;
|
ulong phi = prime - 1UL;
|
||||||
Dictionary<ulong, int> counts = new(capacity: 8);
|
Dictionary<ulong, int> counts = new(capacity: 8);
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using ILGPU;
|
using ILGPU;
|
||||||
using ILGPU.Runtime;
|
using ILGPU.Runtime;
|
||||||
using ILGPU.Util;
|
|
||||||
using Open.Collections;
|
|
||||||
using PerfectNumbers.Core.Gpu;
|
using PerfectNumbers.Core.Gpu;
|
||||||
using PerfectNumbers.Core.Gpu.Accelerators;
|
using PerfectNumbers.Core.Gpu.Accelerators;
|
||||||
|
|
||||||
@@ -16,7 +12,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
|
|
||||||
private const int GpuSmallPrimeFactorSlots = 64;
|
private const int GpuSmallPrimeFactorSlots = 64;
|
||||||
|
|
||||||
private static ulong CalculateByFactorizationGpu(Pow2MontgomeryAccelerator gpu, ulong prime, in MontgomeryDivisorData divisorData)
|
private static ulong CalculateByFactorizationGpu(PrimeOrderCalculatorAccelerator gpu, ulong prime, in MontgomeryDivisorData divisorData)
|
||||||
{
|
{
|
||||||
ulong phi = prime - 1UL;
|
ulong phi = prime - 1UL;
|
||||||
Dictionary<ulong, int> counts = gpu.Pow2ModEntriesToTestOnHost;
|
Dictionary<ulong, int> counts = gpu.Pow2ModEntriesToTestOnHost;
|
||||||
@@ -59,7 +55,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryPopulateSmallPrimeFactorsGpu(ulong value, uint limit, Dictionary<ulong, int> counts, out int factorCount, out ulong remaining)
|
private static bool TryPopulateSmallPrimeFactorsGpu(PrimeOrderCalculatorAccelerator gpu, ulong value, uint limit, Dictionary<ulong, int> counts, out int factorCount, out ulong remaining)
|
||||||
{
|
{
|
||||||
var primeBufferArray = ThreadStaticPools.UlongPool.Rent(GpuSmallPrimeFactorSlots);
|
var primeBufferArray = ThreadStaticPools.UlongPool.Rent(GpuSmallPrimeFactorSlots);
|
||||||
var exponentBufferArray = ThreadStaticPools.IntPool.Rent(GpuSmallPrimeFactorSlots);
|
var exponentBufferArray = ThreadStaticPools.IntPool.Rent(GpuSmallPrimeFactorSlots);
|
||||||
@@ -67,8 +63,8 @@ internal static partial class PrimeOrderCalculator
|
|||||||
Span<int> exponentBuffer = exponentBufferArray.AsSpan(0, GpuSmallPrimeFactorSlots);
|
Span<int> exponentBuffer = exponentBufferArray.AsSpan(0, GpuSmallPrimeFactorSlots);
|
||||||
remaining = value;
|
remaining = value;
|
||||||
|
|
||||||
Accelerator accelerator = AcceleratorPool.Shared.Rent();
|
gpu.EnsureSmallPrimeFactorSlotsCapacity(GpuSmallPrimeFactorSlots);
|
||||||
GpuScratchBuffer scratch = GpuScratchBufferPool.Rent(accelerator, GpuSmallPrimeFactorSlots, 0);
|
var accelerator = gpu.Accelerator;
|
||||||
|
|
||||||
GpuPrimeWorkLimiter.Acquire();
|
GpuPrimeWorkLimiter.Acquire();
|
||||||
var stream = AcceleratorStreamPool.Rent(accelerator);
|
var stream = AcceleratorStreamPool.Rent(accelerator);
|
||||||
@@ -78,10 +74,10 @@ internal static partial class PrimeOrderCalculator
|
|||||||
var kernel = kernels.SmallPrimeFactor!;
|
var kernel = kernels.SmallPrimeFactor!;
|
||||||
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, uint, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>();
|
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, uint, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>();
|
||||||
|
|
||||||
ArrayView1D<int, Stride1D.Dense> smallPrimeFactorCountSlotView = scratch.SmallPrimeFactorCountSlot.View;
|
ArrayView1D<int, Stride1D.Dense> smallPrimeFactorCountSlotView = gpu.SmallPrimeFactorCountSlot.View;
|
||||||
ArrayView1D<ulong, Stride1D.Dense> smallPrimeFactorRemainingSlotView = scratch.SmallPrimeFactorRemainingSlot.View;
|
ArrayView1D<ulong, Stride1D.Dense> smallPrimeFactorRemainingSlotView = gpu.SmallPrimeFactorRemainingSlot.View;
|
||||||
ArrayView1D<ulong, Stride1D.Dense> smallPrimeFactorPrimeSlotsView = scratch.SmallPrimeFactorPrimeSlots.View;
|
ArrayView1D<ulong, Stride1D.Dense> smallPrimeFactorPrimeSlotsView = gpu.SmallPrimeFactorPrimeSlots.View;
|
||||||
ArrayView1D<int, Stride1D.Dense> smallPrimeFactorExponentSlotsView = scratch.SmallPrimeFactorExponentSlots.View;
|
ArrayView1D<int, Stride1D.Dense> smallPrimeFactorExponentSlotsView = gpu.SmallPrimeFactorExponentSlots.View;
|
||||||
ArrayView1D<uint, Stride1D.Dense> smallPrimeFactorsPrimesView = kernels.SmallPrimeFactorsPrimes!.View;
|
ArrayView1D<uint, Stride1D.Dense> smallPrimeFactorsPrimesView = kernels.SmallPrimeFactorsPrimes!.View;
|
||||||
|
|
||||||
kernelLauncher(
|
kernelLauncher(
|
||||||
@@ -117,7 +113,6 @@ internal static partial class PrimeOrderCalculator
|
|||||||
stream.Synchronize();
|
stream.Synchronize();
|
||||||
|
|
||||||
AcceleratorStreamPool.Return(stream);
|
AcceleratorStreamPool.Return(stream);
|
||||||
GpuScratchBufferPool.Return(scratch);
|
|
||||||
GpuPrimeWorkLimiter.Release();
|
GpuPrimeWorkLimiter.Release();
|
||||||
|
|
||||||
for (int i = 0; i < factorCount; i++)
|
for (int i = 0; i < factorCount; i++)
|
||||||
@@ -131,38 +126,26 @@ internal static partial class PrimeOrderCalculator
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static bool EvaluateSpecialMaxCandidatesGpu(
|
private static bool EvaluateSpecialMaxCandidatesGpu(
|
||||||
Pow2MontgomeryAccelerator gpu,
|
PrimeOrderCalculatorAccelerator gpu,
|
||||||
Span<ulong> buffer,
|
ReadOnlySpan<ulong> factors,
|
||||||
ReadOnlySpan<FactorEntry> factors,
|
|
||||||
ulong phi,
|
ulong phi,
|
||||||
ulong prime,
|
ulong prime,
|
||||||
in MontgomeryDivisorData divisorData)
|
in MontgomeryDivisorData divisorData)
|
||||||
{
|
{
|
||||||
if (factors.Length == 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int factorCount = factors.Length;
|
int factorCount = factors.Length;
|
||||||
Span<ulong> factorSpan = buffer[..factorCount];
|
gpu.EnsureSpecialMaxFactorsCapacity(factorCount);
|
||||||
for (int i = 0; i < factorCount; i++)
|
|
||||||
{
|
|
||||||
factorSpan[i] = factors[i].Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Accelerator accelerator = gpu.Accelerator;
|
||||||
GpuPrimeWorkLimiter.Acquire();
|
GpuPrimeWorkLimiter.Acquire();
|
||||||
Accelerator accelerator = gpu.Accelerator; //AcceleratorPool.Shared.Rent();
|
var stream = AcceleratorStreamPool.Rent(accelerator);
|
||||||
var stream = AcceleratorStreamPool.Rent(accelerator);// accelerator.CreateStream();
|
|
||||||
var kernels = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.EvaluateSpecialMaxCandidatesKernel);
|
var kernels = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.EvaluateSpecialMaxCandidatesKernel);
|
||||||
|
|
||||||
GpuScratchBuffer scratch = GpuScratchBufferPool.Rent(accelerator, 0, factorCount);
|
ArrayView1D<ulong, Stride1D.Dense> specialMaxFactorsView = gpu.SpecialMaxFactors.View;
|
||||||
|
specialMaxFactorsView.SubView(0, factorCount).CopyFromCPU(stream, ref MemoryMarshal.GetReference(factors), factorCount);
|
||||||
ArrayView1D<ulong, Stride1D.Dense> specialMaxFactorsView = scratch.SpecialMaxFactors.View;
|
|
||||||
specialMaxFactorsView.SubView(0, factorCount).CopyFromCPU(stream, ref MemoryMarshal.GetReference(factorSpan), factorCount);
|
|
||||||
|
|
||||||
var kernel = kernels.SpecialMax!;
|
var kernel = kernels.SpecialMax!;
|
||||||
|
|
||||||
ArrayView1D<ulong, Stride1D.Dense> specialMaxResultView = scratch.SpecialMaxResult.View;
|
ArrayView1D<ulong, Stride1D.Dense> specialMaxResultView = gpu.SpecialMaxResult.View;
|
||||||
|
|
||||||
kernel(
|
kernel(
|
||||||
stream,
|
stream,
|
||||||
@@ -171,28 +154,20 @@ internal static partial class PrimeOrderCalculator
|
|||||||
specialMaxFactorsView,
|
specialMaxFactorsView,
|
||||||
factorCount,
|
factorCount,
|
||||||
divisorData,
|
divisorData,
|
||||||
scratch.SpecialMaxCandidates.View,
|
gpu.SpecialMaxCandidates.View,
|
||||||
specialMaxResultView);
|
specialMaxResultView);
|
||||||
|
|
||||||
// Span<ulong> result = stackalloc ulong[1];
|
|
||||||
ulong result = 0UL;
|
ulong result = 0UL;
|
||||||
// specialMaxResultView.CopyToCPU(stream, ref result, 1);
|
|
||||||
specialMaxResultView.CopyToCPU(stream, ref result, 1);
|
specialMaxResultView.CopyToCPU(stream, ref result, 1);
|
||||||
stream.Synchronize();
|
stream.Synchronize();
|
||||||
|
|
||||||
AcceleratorStreamPool.Return(stream);
|
AcceleratorStreamPool.Return(stream);
|
||||||
// stream.Dispose();
|
|
||||||
|
|
||||||
// stream.Synchronize();
|
|
||||||
// return result != 0;
|
|
||||||
GpuScratchBufferPool.Return(scratch);
|
|
||||||
GpuPrimeWorkLimiter.Release();
|
GpuPrimeWorkLimiter.Release();
|
||||||
return result != 0;
|
return result != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryPollardRhoGpu(Pow2MontgomeryAccelerator gpu, ulong n, out ulong factor)
|
private static bool TryPollardRhoGpu(PrimeOrderCalculatorAccelerator gpu, ulong n, out ulong factor)
|
||||||
{
|
{
|
||||||
// var stream = gpu.Stream!;
|
|
||||||
Span<ulong> randomStateSpan = stackalloc ulong[1];
|
Span<ulong> randomStateSpan = stackalloc ulong[1];
|
||||||
randomStateSpan[0] = ThreadStaticDeterministicRandomGpu.Exclusive.State;
|
randomStateSpan[0] = ThreadStaticDeterministicRandomGpu.Exclusive.State;
|
||||||
|
|
||||||
|
|||||||
@@ -93,10 +93,7 @@ public sealed class PrimeTester
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool IsPrimeGpu(ulong n)
|
public static bool IsPrimeGpu(ulong n)
|
||||||
{
|
{
|
||||||
var gpu = Pow2MontgomeryAccelerator.Rent(1);
|
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||||
|
|
||||||
// Span<byte> flag = stackalloc byte[1];
|
|
||||||
|
|
||||||
|
|
||||||
var inputView = gpu.PrimeTestInput.View;
|
var inputView = gpu.PrimeTestInput.View;
|
||||||
var outputView = gpu.OutputByte.View;
|
var outputView = gpu.OutputByte.View;
|
||||||
@@ -128,15 +125,14 @@ public sealed class PrimeTester
|
|||||||
stream.Synchronize();
|
stream.Synchronize();
|
||||||
|
|
||||||
AcceleratorStreamPool.Return(stream);
|
AcceleratorStreamPool.Return(stream);
|
||||||
// gpu.Dispose();
|
PrimeOrderCalculatorAccelerator.Return(gpu);
|
||||||
Pow2MontgomeryAccelerator.Return(gpu);
|
|
||||||
GpuPrimeWorkLimiter.Release();
|
GpuPrimeWorkLimiter.Release();
|
||||||
|
|
||||||
return flag != 0;
|
return flag != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool IsPrimeGpu(Pow2MontgomeryAccelerator gpu, ulong n)
|
public static bool IsPrimeGpu(PrimeOrderCalculatorAccelerator gpu, ulong n)
|
||||||
{
|
{
|
||||||
var input = gpu.PrimeTestInput;
|
var input = gpu.PrimeTestInput;
|
||||||
var inputView = input.View;
|
var inputView = input.View;
|
||||||
@@ -191,7 +187,7 @@ public sealed class PrimeTester
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pow2MontgomeryAccelerator.WarmUp();
|
PrimeOrderCalculatorAccelerator.WarmUp();
|
||||||
WarmedGpuLeaseCount = target;
|
WarmedGpuLeaseCount = target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,9 +196,8 @@ 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 = Pow2MontgomeryAccelerator.Rent(GpuBatchSize);
|
var gpu = PrimeOrderCalculatorAccelerator.Rent(GpuBatchSize);
|
||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
// var stream = gpu.Stream!;
|
|
||||||
var kernel = gpu.SmallPrimeSieveKernel!;
|
var kernel = gpu.SmallPrimeSieveKernel!;
|
||||||
int totalLength = values.Length;
|
int totalLength = values.Length;
|
||||||
int batchSize = GpuBatchSize;
|
int batchSize = GpuBatchSize;
|
||||||
@@ -244,20 +239,19 @@ public sealed class PrimeTester
|
|||||||
|
|
||||||
stream.Synchronize();
|
stream.Synchronize();
|
||||||
AcceleratorStreamPool.Return(stream);
|
AcceleratorStreamPool.Return(stream);
|
||||||
Pow2MontgomeryAccelerator.Return(gpu);
|
PrimeOrderCalculatorAccelerator.Return(gpu);
|
||||||
// gpu.Dispose();
|
|
||||||
GpuPrimeWorkLimiter.Release();
|
GpuPrimeWorkLimiter.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expose cache clearing for accelerator disposal coordination
|
// Expose cache clearing for accelerator disposal coordination
|
||||||
public static void ClearGpuCaches()
|
public static void ClearGpuCaches()
|
||||||
{
|
{
|
||||||
Pow2MontgomeryAccelerator.Clear();
|
PrimeOrderCalculatorAccelerator.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void DisposeGpuContexts()
|
internal static void DisposeGpuContexts()
|
||||||
{
|
{
|
||||||
Pow2MontgomeryAccelerator.DisposeAll();
|
PrimeOrderCalculatorAccelerator.DisposeAll();
|
||||||
lock (GpuWarmUpLock)
|
lock (GpuWarmUpLock)
|
||||||
{
|
{
|
||||||
WarmedGpuLeaseCount = 0;
|
WarmedGpuLeaseCount = 0;
|
||||||
@@ -282,9 +276,8 @@ 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 = Pow2MontgomeryAccelerator.Rent(1);
|
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
// var stream = gpu.Stream!;
|
|
||||||
|
|
||||||
int length = values.Length;
|
int length = values.Length;
|
||||||
ArrayPool<ulong> pool = ThreadStaticPools.UlongPool;
|
ArrayPool<ulong> pool = ThreadStaticPools.UlongPool;
|
||||||
@@ -294,11 +287,8 @@ public sealed class PrimeTester
|
|||||||
MemoryBuffer1D<ulong, Stride1D.Dense>? inputBuffer;
|
MemoryBuffer1D<ulong, Stride1D.Dense>? inputBuffer;
|
||||||
MemoryBuffer1D<byte, Stride1D.Dense>? resultBuffer;
|
MemoryBuffer1D<byte, Stride1D.Dense>? resultBuffer;
|
||||||
|
|
||||||
// lock (accelerator)
|
|
||||||
{
|
|
||||||
inputBuffer = accelerator.Allocate1D<ulong>(length);
|
inputBuffer = accelerator.Allocate1D<ulong>(length);
|
||||||
resultBuffer = accelerator.Allocate1D<byte>(length);
|
resultBuffer = accelerator.Allocate1D<byte>(length);
|
||||||
}
|
|
||||||
|
|
||||||
AcceleratorStream stream = AcceleratorStreamPool.Rent(accelerator);
|
AcceleratorStream stream = AcceleratorStreamPool.Rent(accelerator);
|
||||||
inputBuffer.View.CopyFromCPU(stream, ref temp[0], length);
|
inputBuffer.View.CopyFromCPU(stream, ref temp[0], length);
|
||||||
@@ -311,8 +301,7 @@ public sealed class PrimeTester
|
|||||||
pool.Return(temp, clearArray: false);
|
pool.Return(temp, clearArray: false);
|
||||||
resultBuffer.Dispose();
|
resultBuffer.Dispose();
|
||||||
inputBuffer.Dispose();
|
inputBuffer.Dispose();
|
||||||
Pow2MontgomeryAccelerator.Return(gpu);
|
PrimeOrderCalculatorAccelerator.Return(gpu);
|
||||||
// gpu.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<byte>> GetSharesFactorKernel(Accelerator accelerator)
|
private static Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<byte>> GetSharesFactorKernel(Accelerator accelerator)
|
||||||
|
|||||||
@@ -323,7 +323,7 @@ public static partial class ULongExtensions
|
|||||||
=> Pow2MontgomeryGpuCalculator.CalculateConvert(exponent, divisor);
|
=> Pow2MontgomeryGpuCalculator.CalculateConvert(exponent, divisor);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ulong Pow2MontgomeryModWindowedConvertGpu(this ulong exponent, Pow2MontgomeryAccelerator gpu, in MontgomeryDivisorData divisor)
|
public static ulong Pow2MontgomeryModWindowedConvertGpu(this ulong exponent, PrimeOrderCalculatorAccelerator gpu, in MontgomeryDivisorData divisor)
|
||||||
=> Pow2MontgomeryGpuCalculator.CalculateConvert(gpu, exponent, divisor);
|
=> Pow2MontgomeryGpuCalculator.CalculateConvert(gpu, exponent, divisor);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
|||||||
Reference in new issue
Block a user