Skip to content

Instantly share code, notes, and snippets.

@Sergio0694
Last active September 8, 2019 20:06
Show Gist options
  • Save Sergio0694/a7e2c443dc73121c4a9ad0521b477129 to your computer and use it in GitHub Desktop.
Save Sergio0694/a7e2c443dc73121c4a9ad0521b477129 to your computer and use it in GitHub Desktop.
Benchmark with both Parallel.For and ComputeSharp for frames averaging
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using ComputeSharp;
namespace KinectBenchmark
{
public class Program
{
public static void Main(string[] args)
{
BenchmarkRunner.Run<AverageTest>();
}
}
public class AverageTest
{
[Params(150, 300)]
public int Frames;
public const int Width = 512;
public const int Height = 424;
// Source frames tensor (N*H*W)
public ushort[] FramesCpu;
// Frames buffer on the GPU
public ReadOnlyBuffer<int> FramesGpu;
// Result frame
public ushort[] ResultCpu;
// Result frame on the GPU
public ReadWriteBuffer<int> ResultGpu;
// Temporary result frame as int[]
public int[] Temp;
[GlobalSetup]
public void Setup()
{
Random random = new Random(Frames);
ushort[] data = new ushort[Frames * Width * Height];
for (int i = 0; i < data.Length; i++)
data[i] = (ushort)random.Next(0, ushort.MaxValue);
FramesCpu = data;
ResultCpu = new ushort[Width * Height];
int[] temp = new int[data.Length];
for (int i = 0; i < data.Length; i++)
temp[i] = data[i];
Temp = temp;
FramesGpu = Gpu.Default.AllocateReadOnlyBuffer(temp);
ResultGpu = Gpu.Default.AllocateReadWriteBuffer<int>(Width * Height);
GpuAvg(); // Preload shader
}
[GlobalCleanup]
public void Cleanup()
{
FramesGpu.Dispose();
ResultGpu.Dispose();
}
[Benchmark]
public void CpuAvg()
{
int frames = Frames;
Parallel.For(0, Height, y =>
{
// Clear the target row
ResultCpu.AsSpan(y * Width, Width).Clear();
ref ushort rSource = ref FramesCpu[y * Width];
ref ushort rDest = ref ResultCpu[y * Width];
// Compute the sum for the current row
for (int c = 0; c < frames; c++, rSource = Unsafe.Add(ref rSource, Width * Height))
for (int x = 0; x < Width; x++)
Unsafe.Add(ref rDest, x) += Unsafe.Add(ref rSource, x);
// Average the row
for (int x = 0; x < Width; x++)
Unsafe.Add(ref rDest, x) /= (ushort)frames;
});
}
[Benchmark]
public void GpuAvg()
{
int frames = Frames;
ReadOnlyBuffer<int> source = FramesGpu;
ReadWriteBuffer<int> result = ResultGpu; // Local variables for closure
Gpu.Default.For(Height, Width, id =>
{
int offset = id.Y * Height + id.X;
result[offset] = 0;
// Depth sum (across frames)
for (int c = 0; c < frames; c++)
result[offset] += source[offset + Width * Height];
// Average for the current pixel
result[offset] /= frames;
});
// Copy result int[] array from the GPU
ResultGpu.GetData(Temp);
ref int rSource = ref Temp[0];
ref ushort rDest = ref ResultCpu[0];
int length = Width * Height;
// Convert to final ushort[] frame
for (int i = 0; i < length; i++)
Unsafe.Add(ref rDest, i) = (ushort)Unsafe.Add(ref rSource, i);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment