using System.Runtime.CompilerServices; using ILGPU; using ILGPU.Runtime; using PerfectNumbers.Core.Gpu.Kernels; namespace PerfectNumbers.Core.Gpu.Accelerators; public sealed class Pow2MontgomeryAccelerator { #region Pool [ThreadStatic] private static Queue? _pool; private static AcceleratorPool _accelerators = new(PerfectNumberConstants.RollingAccelerators); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Pow2MontgomeryAccelerator Rent() { var pool = _pool ??= []; if (!pool.TryDequeue(out var gpu)) { Accelerator accelerator = _accelerators.Rent(); gpu = new(accelerator); } return gpu; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Return(Pow2MontgomeryAccelerator gpu) { gpu.Stream!.Dispose(); gpu.Stream = null; _pool!.Enqueue(gpu); } #endregion public readonly Accelerator Accelerator; public readonly MemoryBuffer1D Input; public readonly MemoryBuffer1D Output; public AcceleratorStream? Stream; public readonly Action, MontgomeryDivisorData, ArrayView1D> ConvertToStandardKernel; public readonly Action, MontgomeryDivisorData, ArrayView1D> KeepMontgomeryKernel; public Pow2MontgomeryAccelerator(Accelerator accelerator) { Accelerator = accelerator; Input = accelerator.Allocate1D(1); Output = accelerator.Allocate1D(1); Stream = accelerator.CreateStream(); var keepKernel = accelerator.LoadAutoGroupedStreamKernel, MontgomeryDivisorData, ArrayView1D>(Pow2MontgomeryKernels.Pow2MontgomeryKernelKeepMontgomery); var keepLauncher = KernelUtil.GetKernel(keepKernel); KeepMontgomeryKernel = keepLauncher.CreateLauncherDelegate, MontgomeryDivisorData, ArrayView1D>>(); var convertKernel = accelerator.LoadAutoGroupedStreamKernel, MontgomeryDivisorData, ArrayView1D>(Pow2MontgomeryKernels.Pow2MontgomeryKernelConvertToStandard); var convertLauncher = KernelUtil.GetKernel(convertKernel); ConvertToStandardKernel = convertLauncher.CreateLauncherDelegate, MontgomeryDivisorData, ArrayView1D>>(); } public void Dispose() { Input.Dispose(); Output.Dispose(); Stream?.Dispose(); // Accelerator is shared with other threads // Accelerator.Dispose(); } }