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
+1412
-1292
No files matched your search
@@ -3,21 +3,21 @@ using ILGPU.Runtime;
|
|||||||
|
|
||||||
namespace PerfectNumbers.Core.Gpu
|
namespace PerfectNumbers.Core.Gpu
|
||||||
{
|
{
|
||||||
public struct AcceleratorPool(int capacity)
|
public struct AcceleratorPool
|
||||||
{
|
{
|
||||||
internal readonly Accelerator[] Accelerators = [.. Enumerable.Range(1, capacity).Select(_ => {
|
internal readonly Context Context;
|
||||||
return SharedGpuContext.CreateAccelerator();
|
internal readonly Device Device;
|
||||||
})];
|
internal readonly Accelerator[] Accelerators;
|
||||||
|
|
||||||
private int _index;
|
private int _index;
|
||||||
|
|
||||||
public Accelerator Rent()
|
public Accelerator Rent()
|
||||||
{
|
{
|
||||||
Atomic.CompareExchange(ref _index, capacity, 0);
|
Atomic.CompareExchange(ref _index, Capacity, 0);
|
||||||
var index = Atomic.Add(ref _index, 1);
|
var index = Atomic.Add(ref _index, 1);
|
||||||
if (index >= capacity)
|
if (index >= Capacity)
|
||||||
{
|
{
|
||||||
index -= capacity;
|
index -= Capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Accelerators[index];
|
return Accelerators[index];
|
||||||
@@ -29,5 +29,16 @@ namespace PerfectNumbers.Core.Gpu
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static readonly AcceleratorPool Shared = new(PerfectNumberConstants.RollingAccelerators);
|
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))];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,7 +21,11 @@ public sealed class Pow2MontgomeryAccelerator
|
|||||||
if (!pool.TryDequeue(out var gpu))
|
if (!pool.TryDequeue(out var gpu))
|
||||||
{
|
{
|
||||||
Accelerator accelerator = _accelerators.Rent();
|
Accelerator accelerator = _accelerators.Rent();
|
||||||
gpu = new(accelerator);
|
gpu = new(accelerator, PerfectNumberConstants.DefaultFactorsBuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gpu.Stream = gpu.Accelerator.CreateStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
return gpu;
|
return gpu;
|
||||||
@@ -40,17 +44,33 @@ public sealed class Pow2MontgomeryAccelerator
|
|||||||
public readonly Accelerator Accelerator;
|
public readonly Accelerator Accelerator;
|
||||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> Input;
|
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> Input;
|
||||||
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> Output;
|
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> Output;
|
||||||
|
public MemoryBuffer1D<KeyValuePair<ulong, int>, Stride1D.Dense> ToTestOnDevice;
|
||||||
|
public Dictionary<ulong, int> ToTestOnHost = [];
|
||||||
public AcceleratorStream? Stream;
|
public AcceleratorStream? Stream;
|
||||||
|
|
||||||
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>> ConvertToStandardKernel;
|
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>> ConvertToStandardKernel;
|
||||||
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>> KeepMontgomeryKernel;
|
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;
|
Accelerator = accelerator;
|
||||||
|
Stream = accelerator.CreateStream();
|
||||||
|
|
||||||
Input = accelerator.Allocate1D<ulong>(1);
|
Input = accelerator.Allocate1D<ulong>(1);
|
||||||
Output = 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 keepKernel = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelKeepMontgomery);
|
||||||
var keepLauncher = KernelUtil.GetKernel(keepKernel);
|
var keepLauncher = KernelUtil.GetKernel(keepKernel);
|
||||||
@@ -61,6 +81,9 @@ public sealed class Pow2MontgomeryAccelerator
|
|||||||
var convertLauncher = KernelUtil.GetKernel(convertKernel);
|
var convertLauncher = KernelUtil.GetKernel(convertKernel);
|
||||||
|
|
||||||
ConvertToStandardKernel = convertLauncher.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
|
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()
|
public void Dispose()
|
||||||
@@ -68,6 +91,7 @@ public sealed class Pow2MontgomeryAccelerator
|
|||||||
Input.Dispose();
|
Input.Dispose();
|
||||||
Output.Dispose();
|
Output.Dispose();
|
||||||
Stream?.Dispose();
|
Stream?.Dispose();
|
||||||
|
ToTestOnDevice.Dispose();
|
||||||
// Accelerator is shared with other threads
|
// Accelerator is shared with other threads
|
||||||
// Accelerator.Dispose();
|
// 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(
|
tasks[taskIndex++] = Task.Factory.StartNew(
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
// startGate.Wait();
|
startGate.Wait();
|
||||||
Console.WriteLine($"Task started for range {rangeStart}");
|
Console.WriteLine($"Task started for range {rangeStart}");
|
||||||
|
|
||||||
for (int index = rangeStart; index < rangeEnd; index++)
|
for (int index = rangeStart; index < rangeEnd; index++)
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ namespace PerfectNumbers.Core;
|
|||||||
public static class PerfectNumberConstants
|
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 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;
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
ulong result;
|
ulong result;
|
||||||
if (phiFactors.Factors is null)
|
if (phiFactors.Factors is null)
|
||||||
{
|
{
|
||||||
result = CalculateByFactorizationCpu(gpu, prime, divisorData);
|
result = CalculateByFactorizationGpu(gpu, prime, divisorData);
|
||||||
phiFactors.Dispose();
|
phiFactors.Dispose();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -103,7 +103,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
{
|
{
|
||||||
orderFactors?.Dispose();
|
orderFactors?.Dispose();
|
||||||
GpuPrimeWorkLimiter.Release();
|
GpuPrimeWorkLimiter.Release();
|
||||||
return CalculateByFactorizationCpu(gpu, prime, divisorData);
|
return CalculateByFactorizationGpu(gpu, prime, divisorData);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryHeuristicFinishCpu(prime, candidateOrder, previousOrder, divisorData, config, phiFactors, orderFactors, out ulong order))
|
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;
|
ulong phi = prime - 1UL;
|
||||||
Dictionary<ulong, int> counts = new(capacity: 8);
|
Dictionary<ulong, int> counts = new(capacity: 8);
|
||||||
FactorCompletely(phi, counts);
|
FactorCompletelyCpu(phi, counts);
|
||||||
if (counts.Count == 0)
|
if (counts.Count == 0)
|
||||||
{
|
{
|
||||||
return phi;
|
return phi;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<KeyValuePair<ulong, int>> entries = [.. counts];
|
KeyValuePair<ulong, int>[] entries = [.. counts];
|
||||||
entries.Sort(static (a, b) => a.Key.CompareTo(b.Key));
|
Array.Sort(entries, static (a, b) => a.Key.CompareTo(b.Key));
|
||||||
|
|
||||||
ulong order = phi;
|
ulong order = phi;
|
||||||
int entryCount = entries.Count;
|
int entryCount = entries.Length;
|
||||||
|
|
||||||
GpuPrimeWorkLimiter.Acquire();
|
GpuPrimeWorkLimiter.Acquire();
|
||||||
for (int i = 0; i < entryCount; i++)
|
for (int i = 0; i < entryCount; i++)
|
||||||
@@ -1677,12 +1677,14 @@ internal static partial class PrimeOrderCalculator
|
|||||||
int exponent = entries[i].Value;
|
int exponent = entries[i].Value;
|
||||||
for (int iteration = 0; iteration < exponent; iteration++)
|
for (int iteration = 0; iteration < exponent; iteration++)
|
||||||
{
|
{
|
||||||
if ((order % primeFactor) != 0UL)
|
ulong remainder = order % primeFactor;
|
||||||
|
if (remainder != 0UL)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong candidate = order / primeFactor;
|
ulong candidate = order - primeFactor * remainder;
|
||||||
|
// ulong candidate = order / primeFactor;
|
||||||
|
|
||||||
// if (candidate.Pow2MontgomeryModWindowedCpu(divisorData, keepMontgomery: false) == 1UL)
|
// if (candidate.Pow2MontgomeryModWindowedCpu(divisorData, keepMontgomery: false) == 1UL)
|
||||||
if (candidate.Pow2MontgomeryModWindowedConvertGpu(gpu, divisorData) == 1UL)
|
if (candidate.Pow2MontgomeryModWindowedConvertGpu(gpu, divisorData) == 1UL)
|
||||||
@@ -1700,7 +1702,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
return order;
|
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);
|
FactorCompletely(value, counts, knownComposite: false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using ILGPU;
|
using ILGPU;
|
||||||
using ILGPU.Runtime;
|
using ILGPU.Runtime;
|
||||||
using ILGPU.Runtime.Cuda;
|
using ILGPU.Util;
|
||||||
|
using Open.Collections;
|
||||||
using PerfectNumbers.Core.Gpu;
|
using PerfectNumbers.Core.Gpu;
|
||||||
|
using PerfectNumbers.Core.Gpu.Accelerators;
|
||||||
|
|
||||||
namespace PerfectNumbers.Core;
|
namespace PerfectNumbers.Core;
|
||||||
|
|
||||||
@@ -12,6 +14,47 @@ 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)
|
||||||
|
{
|
||||||
|
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)
|
private static bool TryPopulateSmallPrimeFactorsGpu(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);
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ public sealed class PrimeTester
|
|||||||
var gpu = PrimeTesterGpuContextPool.Rent(1);
|
var gpu = PrimeTesterGpuContextPool.Rent(1);
|
||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
var stream = gpu.Stream;
|
var stream = gpu.Stream;
|
||||||
var kernel = PrimeTesterGpuContextPool.PrimeTesterGpuContextLease.GetKernel(accelerator);
|
var kernel = PrimeTesterGpuContextPool.PrimeTesterGpuContextLease.GetSmallPrimeSieveKernel(accelerator);
|
||||||
|
|
||||||
ulong value = n;
|
ulong value = n;
|
||||||
// Span<byte> flag = stackalloc byte[1];
|
// Span<byte> flag = stackalloc byte[1];
|
||||||
@@ -167,7 +167,7 @@ public sealed class PrimeTester
|
|||||||
var gpu = PrimeTesterGpuContextPool.Rent(GpuBatchSize);
|
var gpu = PrimeTesterGpuContextPool.Rent(GpuBatchSize);
|
||||||
var accelerator = gpu.Accelerator;
|
var accelerator = gpu.Accelerator;
|
||||||
var stream = gpu.Stream;
|
var stream = gpu.Stream;
|
||||||
var kernel = PrimeTesterGpuContextPool.PrimeTesterGpuContextLease.GetKernel(accelerator);
|
var kernel = PrimeTesterGpuContextPool.PrimeTesterGpuContextLease.GetSmallPrimeSieveKernel(accelerator);
|
||||||
int totalLength = values.Length;
|
int totalLength = values.Length;
|
||||||
int batchSize = GpuBatchSize;
|
int batchSize = GpuBatchSize;
|
||||||
|
|
||||||
@@ -324,11 +324,11 @@ public sealed class PrimeTester
|
|||||||
}
|
}
|
||||||
|
|
||||||
[ThreadStatic]
|
[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))
|
if (pool.TryGetValue(accelerator, out var cached))
|
||||||
{
|
{
|
||||||
return cached;
|
return cached;
|
||||||
|
|||||||
Reference in new issue
Block a user