142 lines
4.6 KiB
C#
142 lines
4.6 KiB
C#
using System.Runtime.InteropServices;
|
|
using ILGPU;
|
|
using ILGPU.Runtime;
|
|
using PerfectNumbers.Core.Gpu;
|
|
|
|
namespace PerfectNumbers.Core;
|
|
|
|
internal static partial class PrimeOrderCalculator
|
|
{
|
|
private static bool IsGpuPow2Allowed => s_pow2ModeInitialized && s_allowGpuPow2;
|
|
|
|
private const int GpuSmallPrimeFactorSlots = 64;
|
|
|
|
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 exponentBufferArray = ThreadStaticPools.IntPool.Rent(GpuSmallPrimeFactorSlots);
|
|
Span<ulong> primeBuffer = primeBufferArray.AsSpan(0, GpuSmallPrimeFactorSlots);
|
|
Span<int> exponentBuffer = exponentBufferArray.AsSpan(0, GpuSmallPrimeFactorSlots);
|
|
remaining = value;
|
|
|
|
var lease = GpuKernelPool.Rent();
|
|
Accelerator accelerator = SharedGpuContext.Accelerator;
|
|
var stream = accelerator.CreateStream();
|
|
KernelContainer kernels = GpuKernelPool.Kernels;
|
|
|
|
ScratchBuffer scratch = GpuScratchBufferPool.Rent(accelerator, GpuSmallPrimeFactorSlots, 0);
|
|
|
|
SmallPrimeFactorViews tables = GpuKernelPool.GetSmallPrimeFactorTables();
|
|
|
|
if (kernels.SmallPrimeFactorsPrimes is null) throw new NullReferenceException($"{nameof(kernels.SmallPrimeFactorsPrimes)} is null");
|
|
if (kernels.SmallPrimeFactorsSquares is null) throw new NullReferenceException($"{nameof(kernels.SmallPrimeFactorsSquares)} is null");
|
|
|
|
var kernel = GpuKernelLease.SmallPrimeFactorKernel;
|
|
|
|
ArrayView1D<int, Stride1D.Dense> smallPrimeFactorCountSlotView = scratch.SmallPrimeFactorCountSlot.View;
|
|
ArrayView1D<ulong, Stride1D.Dense> smallPrimeFactorRemainingSlotView = scratch.SmallPrimeFactorRemainingSlot.View;
|
|
ArrayView1D<ulong, Stride1D.Dense> smallPrimeFactorPrimeSlotsView = scratch.SmallPrimeFactorPrimeSlots.View;
|
|
ArrayView1D<int, Stride1D.Dense> smallPrimeFactorExponentSlotsView = scratch.SmallPrimeFactorExponentSlots.View;
|
|
ArrayView1D<uint, Stride1D.Dense> smallPrimeFactorsPrimesView = kernels.SmallPrimeFactorsPrimes!.View;
|
|
|
|
kernel(
|
|
stream,
|
|
1,
|
|
value,
|
|
limit,
|
|
smallPrimeFactorsPrimesView,
|
|
kernels.SmallPrimeFactorsSquares!.View,
|
|
(int)smallPrimeFactorsPrimesView.Length,
|
|
smallPrimeFactorPrimeSlotsView,
|
|
smallPrimeFactorExponentSlotsView,
|
|
smallPrimeFactorCountSlotView,
|
|
smallPrimeFactorRemainingSlotView);
|
|
|
|
|
|
factorCount = 0;
|
|
smallPrimeFactorCountSlotView.CopyToCPU(stream, ref factorCount, 1);
|
|
stream.Synchronize();
|
|
|
|
factorCount = Math.Min(factorCount, GpuSmallPrimeFactorSlots);
|
|
|
|
if (factorCount > 0)
|
|
{
|
|
smallPrimeFactorPrimeSlotsView.CopyToCPU(stream, ref MemoryMarshal.GetReference(primeBuffer), factorCount);
|
|
|
|
smallPrimeFactorExponentSlotsView.CopyToCPU(stream, ref MemoryMarshal.GetReference(exponentBuffer), factorCount);
|
|
}
|
|
|
|
smallPrimeFactorRemainingSlotView.CopyToCPU(stream, ref remaining, 1);
|
|
stream.Synchronize();
|
|
stream.Dispose();
|
|
|
|
for (int i = 0; i < factorCount; i++)
|
|
{
|
|
ulong primeValue = primeBuffer[i];
|
|
int exponent = exponentBuffer[i];
|
|
counts.Add(primeValue, exponent);
|
|
}
|
|
|
|
GpuScratchBufferPool.Return(scratch);
|
|
lease.Dispose();
|
|
return true;
|
|
}
|
|
|
|
private static bool EvaluateSpecialMaxCandidatesGpu(
|
|
Span<ulong> buffer,
|
|
ReadOnlySpan<FactorEntry> factors,
|
|
ulong phi,
|
|
ulong prime,
|
|
in MontgomeryDivisorData divisorData)
|
|
{
|
|
if (factors.Length == 0)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
int factorCount = factors.Length;
|
|
Span<ulong> factorSpan = buffer[..factorCount];
|
|
for (int i = 0; i < factorCount; i++)
|
|
{
|
|
factorSpan[i] = factors[i].Value;
|
|
}
|
|
|
|
GpuKernelLease lease = GpuKernelPool.Rent();
|
|
Accelerator accelerator = SharedGpuContext.Accelerator;
|
|
|
|
var stream = accelerator.CreateStream();
|
|
|
|
ScratchBuffer scratch = GpuScratchBufferPool.Rent(accelerator, 0, factorCount);
|
|
|
|
ArrayView1D<ulong, Stride1D.Dense> specialMaxFactorsView = scratch.SpecialMaxFactors.View;
|
|
specialMaxFactorsView.SubView(0, factorCount).CopyFromCPU(stream, ref MemoryMarshal.GetReference(factorSpan), factorCount);
|
|
|
|
var kernel = GpuKernelLease.SpecialMaxKernel;
|
|
|
|
ArrayView1D<ulong, Stride1D.Dense> specialMaxResultView = scratch.SpecialMaxResult.View;
|
|
|
|
kernel(
|
|
stream,
|
|
1,
|
|
phi,
|
|
specialMaxFactorsView,
|
|
factorCount,
|
|
divisorData,
|
|
scratch.SpecialMaxCandidates.View,
|
|
specialMaxResultView);
|
|
|
|
Span<ulong> result = stackalloc ulong[1];
|
|
// specialMaxResultView.CopyToCPU(stream, ref result, 1);
|
|
specialMaxResultView.CopyToCPU(stream, in result);
|
|
stream.Synchronize();
|
|
stream.Dispose();
|
|
|
|
// stream.Synchronize();
|
|
// return result != 0;
|
|
GpuScratchBufferPool.Return(scratch);
|
|
lease.Dispose();
|
|
return result[0] != 0;
|
|
}
|
|
}
|
|
|