GpuScratchBuffer / -Pool naively integrated with PriemOrderCalculatorAccelerator (formerly Pow2MontgomeryAccelerator). FactorEntry replaced with 2 arrays - unused field removed. Small cleanup.

This commit is contained in:
mlemanczyk committed 2025-11-13 14:41:27 +01:00
1 parent 43863d03fb
commit c53aa517f7
14 files changed
+294 -419

No files matched your search

-1
View File
@@ -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,18 +24,14 @@ 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;
DevicePrimesLastOne = accelerator.Allocate1D(stream, primesLastOne);
// lock (accelerator) DevicePrimesLastSeven = accelerator.Allocate1D(stream, primesLastSeven);
{ DevicePrimesLastThree = accelerator.Allocate1D(stream, primesLastThree);
DevicePrimesLastOne = accelerator.Allocate1D(stream, primesLastOne); DevicePrimesLastNine = accelerator.Allocate1D(stream, primesLastNine);
DevicePrimesLastSeven = accelerator.Allocate1D(stream, primesLastSeven); DevicePrimesPow2LastOne = accelerator.Allocate1D(stream, primesPow2LastOne);
DevicePrimesLastThree = accelerator.Allocate1D(stream, primesLastThree); DevicePrimesPow2LastSeven = accelerator.Allocate1D(stream, primesPow2LastSeven);
DevicePrimesLastNine = accelerator.Allocate1D(stream, primesLastNine); DevicePrimesPow2LastThree = accelerator.Allocate1D(stream, primesPow2LastThree);
DevicePrimesPow2LastOne = accelerator.Allocate1D(stream, primesPow2LastOne); DevicePrimesPow2LastNine = accelerator.Allocate1D(stream, primesPow2LastNine);
DevicePrimesPow2LastSeven = accelerator.Allocate1D(stream, primesPow2LastSeven);
DevicePrimesPow2LastThree = accelerator.Allocate1D(stream, primesPow2LastThree);
DevicePrimesPow2LastNine = accelerator.Allocate1D(stream, primesPow2LastNine);
}
} }
internal readonly MemoryBuffer1D<uint, Stride1D.Dense> DevicePrimesLastOne; internal readonly MemoryBuffer1D<uint, Stride1D.Dense> DevicePrimesLastOne;
@@ -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);
{ OutputByte = Accelerator.Allocate1D<byte>(primeTesterCapacity);
PrimeTestInput = Accelerator.Allocate1D<ulong>(primeTesterCapacity); HeuristicFlag = Accelerator.Allocate1D<int>(primeTesterCapacity);
OutputByte = Accelerator.Allocate1D<byte>(primeTesterCapacity);
HeuristicFlag = Accelerator.Allocate1D<int>(primeTesterCapacity);
}
} }
} }
public Pow2MontgomeryAccelerator(Accelerator accelerator, int factorsCount, 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 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();
} }
} }
@@ -5,11 +5,11 @@ namespace PerfectNumbers.Core.Gpu;
public static class GpuPrimeWorkLimiter 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,
+62 -22
View File
@@ -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)
@@ -31,8 +30,31 @@ namespace PerfectNumbers.Core
} }
instance._next = null; instance._next = null;
instance.Factors = factors; instance.Factors = factors;
instance.Cofactor = cofactor; 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.FullyFactored = fullyFactored; instance.FullyFactored = fullyFactored;
instance.Count = count; instance.Count = count;
instance.CofactorIsPrime = cofactorIsPrime; instance.CofactorIsPrime = cofactorIsPrime;
@@ -46,32 +68,50 @@ 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;
FactorEntry[] local = ThreadStaticPools.FactorEntryPool.Rent(1); if (source is null || sourceCount == 0)
local[0] = new FactorEntry(prime, 1, true); {
return Rent(local, 1UL, true, 1, false); source = ThreadStaticPools.UlongPool.Rent(1);
exponents = ThreadStaticPools.IntPool.Rent(1);
// 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)
{ {
Factors = null; int[] exponents = Exponents!;
ThreadStaticPools.FactorEntryPool.Return(factors, clearArray: false); Factors = null;
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;
+93 -58
View File
@@ -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);
+18 -43
View File
@@ -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;
+12 -23
View File
@@ -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);
{ resultBuffer = accelerator.Allocate1D<byte>(length);
inputBuffer = accelerator.Allocate1D<ulong>(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)
+1 -1
View File
@@ -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)]