Add GPU prime tester overload for preallocated buffers
This commit is contained in:
1 parent
f2ce40ade9
commit
6458f6740d
2 files changed
+127
-17
No files matched your search
@@ -1,4 +1,6 @@
|
||||
using FluentAssertions;
|
||||
using ILGPU;
|
||||
using ILGPU.Runtime;
|
||||
using PerfectNumbers.Core.Gpu;
|
||||
using Xunit;
|
||||
|
||||
@@ -27,6 +29,34 @@ public class PrimeTesterGpuTests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsPrimeBatchGpu_with_preallocated_resources_marks_expected_values()
|
||||
{
|
||||
GpuContextPool.ForceCpu = false;
|
||||
using var context = Context.CreateDefault();
|
||||
using var accelerator = context.GetPreferredDevice(false).CreateAccelerator(context);
|
||||
|
||||
try
|
||||
{
|
||||
ulong[] values = [31UL, 33UL, 37UL, 39UL];
|
||||
byte[] results = new byte[values.Length];
|
||||
|
||||
using var inputBuffer = accelerator.Allocate1D<ulong>(values.Length);
|
||||
using var outputBuffer = accelerator.Allocate1D<byte>(values.Length);
|
||||
ulong[] staging = new ulong[values.Length];
|
||||
|
||||
PrimeTester.IsPrimeBatchGpu(values, results, accelerator, inputBuffer, outputBuffer, staging);
|
||||
|
||||
results.Should().Equal(new byte[] { 1, 0, 1, 0 });
|
||||
}
|
||||
finally
|
||||
{
|
||||
PrimeTester.ClearGpuCaches(accelerator);
|
||||
GpuContextPool.ForceCpu = false;
|
||||
GpuContextPool.DisposeAll();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsPrimeGpu_rejects_composites()
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Buffers;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using ILGPU;
|
||||
using ILGPU.Algorithms;
|
||||
@@ -112,7 +113,6 @@ public sealed class PrimeTester
|
||||
var gpu = PrimeTesterGpuContextPool.Rent();
|
||||
var accelerator = gpu.Accelerator;
|
||||
var state = GpuKernelState.GetOrCreate(accelerator);
|
||||
int totalLength = values.Length;
|
||||
int batchSize = Math.Max(1, GpuBatchSize);
|
||||
|
||||
lock (gpu.ExecutionLock)
|
||||
@@ -123,30 +123,110 @@ public sealed class PrimeTester
|
||||
ArrayPool<ulong> pool = ThreadStaticPools.UlongPool;
|
||||
ulong[] temp = pool.Rent(batchSize);
|
||||
|
||||
int pos = 0;
|
||||
while (pos < totalLength)
|
||||
try
|
||||
{
|
||||
int remaining = totalLength - pos;
|
||||
int count = remaining > batchSize ? batchSize : remaining;
|
||||
|
||||
values.Slice(pos, count).CopyTo(temp);
|
||||
input.View.CopyFromCPU(ref temp[0], count);
|
||||
|
||||
state.Kernel(count, input.View, state.DevicePrimes.View, output.View);
|
||||
accelerator.Synchronize();
|
||||
output.View.CopyToCPU(ref results[pos], count);
|
||||
|
||||
pos += count;
|
||||
IsPrimeBatchGpu(values, results, accelerator, input, output, temp);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.Return(temp, clearArray: false);
|
||||
state.ReturnScratch(scratch);
|
||||
}
|
||||
|
||||
pool.Return(temp, clearArray: false);
|
||||
state.ReturnScratch(scratch);
|
||||
}
|
||||
|
||||
gpu.Dispose();
|
||||
limiter.Dispose();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void IsPrimeBatchGpu(
|
||||
ReadOnlySpan<ulong> values,
|
||||
Span<byte> results,
|
||||
Accelerator accelerator,
|
||||
MemoryBuffer1D<ulong, Stride1D.Dense> deviceInput,
|
||||
MemoryBuffer1D<byte, Stride1D.Dense> deviceOutput,
|
||||
Span<ulong> stagingBuffer)
|
||||
{
|
||||
if (accelerator is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(accelerator));
|
||||
}
|
||||
|
||||
if (deviceInput is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(deviceInput));
|
||||
}
|
||||
|
||||
if (deviceOutput is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(deviceOutput));
|
||||
}
|
||||
|
||||
if (results.Length < values.Length)
|
||||
{
|
||||
throw new ArgumentException("The results span must be at least as long as the input values.", nameof(results));
|
||||
}
|
||||
|
||||
if (values.IsEmpty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (stagingBuffer.IsEmpty)
|
||||
{
|
||||
throw new ArgumentException("The staging buffer must contain at least one element.", nameof(stagingBuffer));
|
||||
}
|
||||
|
||||
long inputLength = deviceInput.Length;
|
||||
long outputLength = deviceOutput.Length;
|
||||
if (inputLength <= 0)
|
||||
{
|
||||
throw new ArgumentException("The device input buffer must contain at least one element.", nameof(deviceInput));
|
||||
}
|
||||
|
||||
if (outputLength <= 0)
|
||||
{
|
||||
throw new ArgumentException("The device output buffer must contain at least one element.", nameof(deviceOutput));
|
||||
}
|
||||
|
||||
long stagingLength = stagingBuffer.Length;
|
||||
long capacityLong = Math.Min(Math.Min(inputLength, outputLength), stagingLength);
|
||||
if (capacityLong <= 0)
|
||||
{
|
||||
throw new ArgumentException("The provided buffers must be able to hold at least one element.");
|
||||
}
|
||||
|
||||
int capacity = (int)Math.Min(capacityLong, int.MaxValue);
|
||||
|
||||
var state = GpuKernelState.GetOrCreate(accelerator);
|
||||
var inputView = deviceInput.View;
|
||||
var outputView = deviceOutput.View;
|
||||
var primesView = state.DevicePrimes.View;
|
||||
var stagingSpan = stagingBuffer;
|
||||
ref ulong stagingRef = ref MemoryMarshal.GetReference(stagingSpan);
|
||||
|
||||
int totalLength = values.Length;
|
||||
int pos = 0;
|
||||
while (pos < totalLength)
|
||||
{
|
||||
int remaining = totalLength - pos;
|
||||
int count = remaining > capacity ? capacity : remaining;
|
||||
|
||||
var stagingSlice = stagingSpan.Slice(0, count);
|
||||
values.Slice(pos, count).CopyTo(stagingSlice);
|
||||
|
||||
var inputSlice = inputView.SubView(0, count);
|
||||
inputSlice.CopyFromCPU(ref stagingRef, count);
|
||||
|
||||
var outputSlice = outputView.SubView(0, count);
|
||||
state.Kernel(count, inputSlice, primesView, outputSlice);
|
||||
accelerator.Synchronize();
|
||||
outputSlice.CopyToCPU(ref results[pos], count);
|
||||
|
||||
pos += count;
|
||||
}
|
||||
}
|
||||
|
||||
internal static class PrimeTesterGpuContextPool
|
||||
{
|
||||
internal sealed class PooledContext : IDisposable
|
||||
|
||||
Reference in new issue
Block a user