using System.Runtime.CompilerServices; using ILGPU; using ILGPU.Runtime; namespace PerfectNumbers.Core.Gpu.Accelerators; public sealed class HeuristicCombinedPrimeTesterAccelerator { #region Pool [ThreadStatic] private static Queue? Pool; public static void WarmUp(int acceleratorIndex, AcceleratorStream stream) { Console.WriteLine($"Preparing heuristic accelerator {acceleratorIndex}..."); HeuristicGpuCombinedTables.WarmUp(acceleratorIndex, stream); // _ = GpuKernelPool.GetOrAddKernels(accelerator, stream, KernelType.None); // KernelContainer kernels = GpuKernelPool.GetOrAddKernels(accelerator, stream); // GpuStaticTableInitializer.EnsureStaticTables(accelerator, kernels, stream); Console.WriteLine($"Heuristic accelerator {acceleratorIndex} is ready"); } public static HeuristicCombinedPrimeTesterAccelerator Rent(int minBufferCapacity = 1) { var pool = Pool ??= new(); if (!pool.TryDequeue(out var lease)) { lease = new HeuristicCombinedPrimeTesterAccelerator(minBufferCapacity); } else { lease.EnsureCapacity(minBufferCapacity); } return lease; } public static void Return(HeuristicCombinedPrimeTesterAccelerator lease) { var pool = Pool ??= new(); pool.Enqueue(lease); } public static void DisposeAll() { if (Pool != null) { while (Pool.TryDequeue(out var lease)) { lease.DisposeResources(); } } } public static void Clear() { if (Pool != null) { var retained = new List(); while (Pool.TryDequeue(out var lease)) { lease.DisposeResources(); } } } #endregion public readonly HeuristicGpuCombinedDivisorTables DivisorTables; internal readonly Context Context; public readonly Accelerator Accelerator; public readonly Kernel HeuristicCombinedTrialDivisionKernel; public MemoryBuffer1D? Input = null; public MemoryBuffer1D? Output = null; public MemoryBuffer1D? HeuristicFlag = null!; public int BufferCapacity; private HeuristicGpuCombinedTables _sharedTables; public MemoryBuffer1D HeuristicCombinedDivisorsEnding1 => _sharedTables.HeuristicCombinedDivisorsEnding1; public MemoryBuffer1D HeuristicCombinedDivisorSquaresEnding1 => _sharedTables.HeuristicCombinedDivisorSquaresEnding1; public MemoryBuffer1D HeuristicCombinedDivisorsEnding3 => _sharedTables.HeuristicCombinedDivisorsEnding3; public MemoryBuffer1D HeuristicCombinedDivisorSquaresEnding3 => _sharedTables.HeuristicCombinedDivisorSquaresEnding3; public MemoryBuffer1D HeuristicCombinedDivisorsEnding7 => _sharedTables.HeuristicCombinedDivisorsEnding7; public MemoryBuffer1D HeuristicCombinedDivisorSquaresEnding7 => _sharedTables.HeuristicCombinedDivisorSquaresEnding7; public MemoryBuffer1D HeuristicCombinedDivisorsEnding9 => _sharedTables.HeuristicCombinedDivisorsEnding9; public MemoryBuffer1D HeuristicCombinedDivisorSquaresEnding9 => _sharedTables.HeuristicCombinedDivisorSquaresEnding9; private static readonly Accelerator[] _accelerators = AcceleratorPool.Shared.Accelerators; internal readonly int AcceleratorIndex; public HeuristicCombinedPrimeTesterAccelerator(int minBufferCapacity) { var acceleratorIndex = AcceleratorPool.Shared.Rent(); AcceleratorIndex = acceleratorIndex; Accelerator accelerator = _accelerators[acceleratorIndex]; Context = accelerator.Context; Accelerator = accelerator; EnsureCapacity(minBufferCapacity); HeuristicCombinedTrialDivisionKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel, ulong, ulong, HeuristicGpuCombinedDivisorTables>(PrimeTesterKernels.HeuristicTrialCombinedDivisionKernel)); AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex); // GpuStaticTableInitializer.EnsureStaticTables(accelerator, kernels, stream); _sharedTables = HeuristicGpuCombinedTables.GetStaticTables(acceleratorIndex); DivisorTables = _sharedTables.CreateHeuristicDivisorTables(); stream.Synchronize(); AcceleratorStreamPool.Return(acceleratorIndex, stream); } public void EnsureCapacity(int minCapacity) { if (minCapacity <= BufferCapacity) { return; } Input?.Dispose(); Output?.Dispose(); HeuristicFlag?.Dispose(); Input = Accelerator.Allocate1D(minCapacity); Output = Accelerator.Allocate1D(minCapacity); HeuristicFlag = Accelerator.Allocate1D(minCapacity); BufferCapacity = minCapacity; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Return() => Return(this); public void DisposeResources() { Input?.Dispose(); Output?.Dispose(); HeuristicFlag?.Dispose(); // ReleaseSharedTables(_sharedTables); // These resources are shared between GPU leases // Accelerator.Dispose(); // AcceleratorContext.Dispose(); } }