Stabilization improvements. Stream will be released when releasing GPU lease to prevent application crashes.
This commit is contained in:
1 parent
2726c369f6
commit
fa89958736
8 files changed
+1414
-1294
No files matched your search
@@ -3,21 +3,21 @@ using ILGPU.Runtime;
|
||||
|
||||
namespace PerfectNumbers.Core.Gpu
|
||||
{
|
||||
public struct AcceleratorPool(int capacity)
|
||||
public struct AcceleratorPool
|
||||
{
|
||||
internal readonly Accelerator[] Accelerators = [.. Enumerable.Range(1, capacity).Select(_ => {
|
||||
return SharedGpuContext.CreateAccelerator();
|
||||
})];
|
||||
internal readonly Context Context;
|
||||
internal readonly Device Device;
|
||||
internal readonly Accelerator[] Accelerators;
|
||||
|
||||
private int _index;
|
||||
|
||||
public Accelerator Rent()
|
||||
{
|
||||
Atomic.CompareExchange(ref _index, capacity, 0);
|
||||
Atomic.CompareExchange(ref _index, Capacity, 0);
|
||||
var index = Atomic.Add(ref _index, 1);
|
||||
if (index >= capacity)
|
||||
if (index >= Capacity)
|
||||
{
|
||||
index -= capacity;
|
||||
index -= Capacity;
|
||||
}
|
||||
|
||||
return Accelerators[index];
|
||||
@@ -29,5 +29,16 @@ namespace PerfectNumbers.Core.Gpu
|
||||
}
|
||||
|
||||
public static readonly AcceleratorPool Shared = new(PerfectNumberConstants.RollingAccelerators);
|
||||
private readonly int Capacity;
|
||||
|
||||
public AcceleratorPool(int capacity)
|
||||
{
|
||||
Capacity = capacity;
|
||||
var context = Context.CreateDefault();
|
||||
var device = context.GetPreferredDevice(false);
|
||||
Context = context;
|
||||
Device = device;
|
||||
Accelerators = [.. Enumerable.Range(0, capacity).Select(_ => device.CreateAccelerator(context))];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ namespace PerfectNumbers.Core.Gpu.Accelerators;
|
||||
public sealed class Pow2MontgomeryAccelerator
|
||||
{
|
||||
#region Pool
|
||||
|
||||
|
||||
[ThreadStatic]
|
||||
private static Queue<Pow2MontgomeryAccelerator>? _pool;
|
||||
|
||||
@@ -21,7 +21,11 @@ public sealed class Pow2MontgomeryAccelerator
|
||||
if (!pool.TryDequeue(out var gpu))
|
||||
{
|
||||
Accelerator accelerator = _accelerators.Rent();
|
||||
gpu = new(accelerator);
|
||||
gpu = new(accelerator, PerfectNumberConstants.DefaultFactorsBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
gpu.Stream = gpu.Accelerator.CreateStream();
|
||||
}
|
||||
|
||||
return gpu;
|
||||
@@ -40,17 +44,33 @@ public sealed class Pow2MontgomeryAccelerator
|
||||
public readonly Accelerator Accelerator;
|
||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> Input;
|
||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> Output;
|
||||
public MemoryBuffer1D<KeyValuePair<ulong, int>, Stride1D.Dense> ToTestOnDevice;
|
||||
public Dictionary<ulong, int> ToTestOnHost = [];
|
||||
public AcceleratorStream? Stream;
|
||||
|
||||
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>> ConvertToStandardKernel;
|
||||
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>> KeepMontgomeryKernel;
|
||||
|
||||
public Pow2MontgomeryAccelerator(Accelerator accelerator)
|
||||
public readonly Kernel CheckFactorsKernel;
|
||||
|
||||
public void EnsureCapacity(int factorsCount)
|
||||
{
|
||||
if (factorsCount > ToTestOnDevice.Length)
|
||||
{
|
||||
Accelerator accelerator = Accelerator;
|
||||
ToTestOnDevice.Dispose();
|
||||
ToTestOnDevice = accelerator.Allocate1D<KeyValuePair<ulong, int>>(factorsCount);
|
||||
}
|
||||
}
|
||||
|
||||
public Pow2MontgomeryAccelerator(Accelerator accelerator, int factorsCount)
|
||||
{
|
||||
Accelerator = accelerator;
|
||||
Stream = accelerator.CreateStream();
|
||||
|
||||
Input = accelerator.Allocate1D<ulong>(1);
|
||||
Output = accelerator.Allocate1D<ulong>(1);
|
||||
Stream = accelerator.CreateStream();
|
||||
ToTestOnDevice = accelerator.Allocate1D<KeyValuePair<ulong, int>>(factorsCount);
|
||||
|
||||
var keepKernel = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelKeepMontgomery);
|
||||
var keepLauncher = KernelUtil.GetKernel(keepKernel);
|
||||
@@ -61,6 +81,9 @@ public sealed class Pow2MontgomeryAccelerator
|
||||
var convertLauncher = KernelUtil.GetKernel(convertKernel);
|
||||
|
||||
ConvertToStandardKernel = convertLauncher.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
|
||||
|
||||
var checkFactorsKernel = accelerator.LoadStreamKernel<int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.CheckFactorsKernel);
|
||||
CheckFactorsKernel = KernelUtil.GetKernel(checkFactorsKernel);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -68,7 +91,8 @@ public sealed class Pow2MontgomeryAccelerator
|
||||
Input.Dispose();
|
||||
Output.Dispose();
|
||||
Stream?.Dispose();
|
||||
ToTestOnDevice.Dispose();
|
||||
// Accelerator is shared with other threads
|
||||
// Accelerator.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -293,7 +293,7 @@ public static class MersenneNumberDivisorByDivisorTester
|
||||
tasks[taskIndex++] = Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
// startGate.Wait();
|
||||
startGate.Wait();
|
||||
Console.WriteLine($"Task started for range {rangeStart}");
|
||||
|
||||
for (int index = rangeStart; index < rangeEnd; index++)
|
||||
|
||||
@@ -5,7 +5,8 @@ namespace PerfectNumbers.Core;
|
||||
public static class PerfectNumberConstants
|
||||
{
|
||||
public const ulong BiggestKnownEvenPerfectP = 136279841UL;
|
||||
public const int ConsoleInterval = 100_000;
|
||||
public const int ConsoleInterval = 100_000;
|
||||
public const int DefaultFactorsBuffer = 32;
|
||||
public const ulong ExtraDivisorCycleSearchLimit = 64UL;
|
||||
public const int MaxQForDivisorCycles = 4_000_000;
|
||||
public static readonly uint PrimesLimit = 1_000_000; //(ulong)Array.MaxLength;// 1_000_000;
|
||||
|
||||
@@ -64,7 +64,7 @@ internal static partial class PrimeOrderCalculator
|
||||
ulong result;
|
||||
if (phiFactors.Factors is null)
|
||||
{
|
||||
result = CalculateByFactorizationCpu(gpu, prime, divisorData);
|
||||
result = CalculateByFactorizationGpu(gpu, prime, divisorData);
|
||||
phiFactors.Dispose();
|
||||
return result;
|
||||
}
|
||||
@@ -103,7 +103,7 @@ internal static partial class PrimeOrderCalculator
|
||||
{
|
||||
orderFactors?.Dispose();
|
||||
GpuPrimeWorkLimiter.Release();
|
||||
return CalculateByFactorizationCpu(gpu, prime, divisorData);
|
||||
return CalculateByFactorizationGpu(gpu, prime, divisorData);
|
||||
}
|
||||
|
||||
if (TryHeuristicFinishCpu(prime, candidateOrder, previousOrder, divisorData, config, phiFactors, orderFactors, out ulong order))
|
||||
@@ -1658,17 +1658,17 @@ internal static partial class PrimeOrderCalculator
|
||||
{
|
||||
ulong phi = prime - 1UL;
|
||||
Dictionary<ulong, int> counts = new(capacity: 8);
|
||||
FactorCompletely(phi, counts);
|
||||
FactorCompletelyCpu(phi, counts);
|
||||
if (counts.Count == 0)
|
||||
{
|
||||
return phi;
|
||||
}
|
||||
|
||||
List<KeyValuePair<ulong, int>> entries = [.. counts];
|
||||
entries.Sort(static (a, b) => a.Key.CompareTo(b.Key));
|
||||
KeyValuePair<ulong, int>[] entries = [.. counts];
|
||||
Array.Sort(entries, static (a, b) => a.Key.CompareTo(b.Key));
|
||||
|
||||
ulong order = phi;
|
||||
int entryCount = entries.Count;
|
||||
int entryCount = entries.Length;
|
||||
|
||||
GpuPrimeWorkLimiter.Acquire();
|
||||
for (int i = 0; i < entryCount; i++)
|
||||
@@ -1677,12 +1677,14 @@ internal static partial class PrimeOrderCalculator
|
||||
int exponent = entries[i].Value;
|
||||
for (int iteration = 0; iteration < exponent; iteration++)
|
||||
{
|
||||
if ((order % primeFactor) != 0UL)
|
||||
ulong remainder = order % primeFactor;
|
||||
if (remainder != 0UL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
ulong candidate = order / primeFactor;
|
||||
ulong candidate = order - primeFactor * remainder;
|
||||
// ulong candidate = order / primeFactor;
|
||||
|
||||
// if (candidate.Pow2MontgomeryModWindowedCpu(divisorData, keepMontgomery: false) == 1UL)
|
||||
if (candidate.Pow2MontgomeryModWindowedConvertGpu(gpu, divisorData) == 1UL)
|
||||
@@ -1700,7 +1702,7 @@ internal static partial class PrimeOrderCalculator
|
||||
return order;
|
||||
}
|
||||
|
||||
private static void FactorCompletely(ulong value, Dictionary<ulong, int> counts)
|
||||
private static void FactorCompletelyCpu(ulong value, Dictionary<ulong, int> counts)
|
||||
{
|
||||
FactorCompletely(value, counts, knownComposite: false);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using ILGPU;
|
||||
using ILGPU.Runtime;
|
||||
using ILGPU.Runtime.Cuda;
|
||||
using ILGPU.Util;
|
||||
using Open.Collections;
|
||||
using PerfectNumbers.Core.Gpu;
|
||||
using PerfectNumbers.Core.Gpu.Accelerators;
|
||||
|
||||
namespace PerfectNumbers.Core;
|
||||
|
||||
@@ -12,6 +14,47 @@ internal static partial class PrimeOrderCalculator
|
||||
|
||||
private const int GpuSmallPrimeFactorSlots = 64;
|
||||
|
||||
private static ulong CalculateByFactorizationGpu(Pow2MontgomeryAccelerator gpu, ulong prime, in MontgomeryDivisorData divisorData)
|
||||
{
|
||||
ulong phi = prime - 1UL;
|
||||
Dictionary<ulong, int> counts = gpu.ToTestOnHost;
|
||||
counts.Clear();
|
||||
|
||||
FactorCompletelyCpu(phi, counts);
|
||||
if (counts.Count == 0)
|
||||
{
|
||||
return phi;
|
||||
}
|
||||
|
||||
int entryCount = counts.Count;
|
||||
Span<KeyValuePair<ulong, int>> entries = stackalloc KeyValuePair<ulong, int>[entryCount];
|
||||
|
||||
int stored = 0;
|
||||
foreach (var entry in counts)
|
||||
{
|
||||
entries[stored++] = entry;
|
||||
}
|
||||
|
||||
entries.Sort(entries, static (a, b) => a.Key.CompareTo(b.Key));
|
||||
|
||||
AcceleratorStream stream = gpu.Stream!;
|
||||
gpu.EnsureCapacity(entryCount);
|
||||
gpu.ToTestOnDevice.View.CopyFromCPU(stream, entries);
|
||||
|
||||
ulong order = phi;
|
||||
var kernel = gpu.CheckFactorsKernel;
|
||||
stream.Synchronize();
|
||||
|
||||
GpuPrimeWorkLimiter.Acquire();
|
||||
|
||||
kernel.Launch(stream, 1, entryCount, phi, gpu.ToTestOnDevice.View, divisorData, gpu.Output.View);
|
||||
gpu.Output.View.CopyToCPU(stream, ref order, 1);
|
||||
stream.Synchronize();
|
||||
|
||||
GpuPrimeWorkLimiter.Release();
|
||||
return order;
|
||||
}
|
||||
|
||||
private static bool TryPopulateSmallPrimeFactorsGpu(ulong value, uint limit, Dictionary<ulong, int> counts, out int factorCount, out ulong remaining)
|
||||
{
|
||||
var primeBufferArray = ThreadStaticPools.UlongPool.Rent(GpuSmallPrimeFactorSlots);
|
||||
|
||||
@@ -99,7 +99,7 @@ public sealed class PrimeTester
|
||||
var gpu = PrimeTesterGpuContextPool.Rent(1);
|
||||
var accelerator = gpu.Accelerator;
|
||||
var stream = gpu.Stream;
|
||||
var kernel = PrimeTesterGpuContextPool.PrimeTesterGpuContextLease.GetKernel(accelerator);
|
||||
var kernel = PrimeTesterGpuContextPool.PrimeTesterGpuContextLease.GetSmallPrimeSieveKernel(accelerator);
|
||||
|
||||
ulong value = n;
|
||||
// Span<byte> flag = stackalloc byte[1];
|
||||
@@ -167,7 +167,7 @@ public sealed class PrimeTester
|
||||
var gpu = PrimeTesterGpuContextPool.Rent(GpuBatchSize);
|
||||
var accelerator = gpu.Accelerator;
|
||||
var stream = gpu.Stream;
|
||||
var kernel = PrimeTesterGpuContextPool.PrimeTesterGpuContextLease.GetKernel(accelerator);
|
||||
var kernel = PrimeTesterGpuContextPool.PrimeTesterGpuContextLease.GetSmallPrimeSieveKernel(accelerator);
|
||||
int totalLength = values.Length;
|
||||
int batchSize = GpuBatchSize;
|
||||
|
||||
@@ -324,11 +324,11 @@ public sealed class PrimeTester
|
||||
}
|
||||
|
||||
[ThreadStatic]
|
||||
public static Dictionary<Accelerator, Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>>? Kernel;
|
||||
public static Dictionary<Accelerator, Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>>? SmallPrimeSieveKernel;
|
||||
|
||||
internal static Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>> GetKernel(Accelerator accelerator)
|
||||
internal static Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>> GetSmallPrimeSieveKernel(Accelerator accelerator)
|
||||
{
|
||||
var pool = Kernel ??= [];
|
||||
var pool = SmallPrimeSieveKernel ??= [];
|
||||
if (pool.TryGetValue(accelerator, out var cached))
|
||||
{
|
||||
return cached;
|
||||
|
||||
Reference in new issue
Block a user