Skip to content

Instantly share code, notes, and snippets.

@Vake93
Created August 7, 2024 19:20
Show Gist options
  • Save Vake93/94fa940efd23e33bf7bcf542dccf4de1 to your computer and use it in GitHub Desktop.
Save Vake93/94fa940efd23e33bf7bcf542dccf4de1 to your computer and use it in GitHub Desktop.
using System.Runtime.Intrinsics;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
public class ConvertToSamplesBenchmark
{
private const int Count = 16000;
private readonly byte[] buffer;
private readonly float[] samplesBase;
private readonly float[] samplesUnrolled;
private readonly float[] samplesVector;
public void CheckCorrectness()
{
var correct = true;
for (int i = 0; i < samplesBase.Length; i++)
{
if (samplesBase[i] != samplesUnrolled[i])
{
correct = false;
Console.WriteLine(
$"Difference! [{i}] Base: {samplesBase[i]}, Unrolled: {samplesUnrolled[i]}"
);
}
if (samplesBase[i] != samplesVector[i])
{
correct = false;
Console.WriteLine(
$"Difference! [{i}] Base: {samplesBase[i]}, Vector: {samplesVector[i]}"
);
}
}
if (correct)
{
Console.WriteLine("All computations correct!");
}
}
public unsafe ConvertToSamplesBenchmark()
{
buffer = new byte[Count];
var random = new Random();
random.NextBytes(buffer);
samplesBase = new float[Count / 2];
samplesUnrolled = new float[Count / 2];
samplesVector = new float[Count / 2];
}
[Benchmark(Baseline = true)]
public void ConvertToSamplesBase()
{
ConvertToSamplesBase(Count, buffer, samplesBase);
}
[Benchmark]
public void ConvertToSamplesUnrolled()
{
ConvertToSamplesUnrolled(Count, buffer, samplesUnrolled);
}
[Benchmark]
public void ConvertToSamplesVector()
{
ConvertToSamplesVector(Count, buffer, samplesVector);
}
static void ConvertToSamplesBase(int count, byte[] buffer, float[] samples)
{
var sampleIndex = 0;
for (var i = 0; i < count; i += 2)
{
samples[sampleIndex++] = BitConverter.ToInt16(buffer, i) / 32768.0f;
}
}
static unsafe void ConvertToSamplesUnrolled(int count, byte[] buffer, float[] samples)
{
var sampleIndex = 0;
var bufferIndex = 0;
fixed (byte* pBuffer = buffer)
{
for (; bufferIndex <= count - 16; bufferIndex += 16)
{
samples[sampleIndex++] = *(short*)(pBuffer + bufferIndex) / 32768.0f;
samples[sampleIndex++] = *(short*)(pBuffer + bufferIndex + 2) / 32768.0f;
samples[sampleIndex++] = *(short*)(pBuffer + bufferIndex + 4) / 32768.0f;
samples[sampleIndex++] = *(short*)(pBuffer + bufferIndex + 6) / 32768.0f;
samples[sampleIndex++] = *(short*)(pBuffer + bufferIndex + 8) / 32768.0f;
samples[sampleIndex++] = *(short*)(pBuffer + bufferIndex + 10) / 32768.0f;
samples[sampleIndex++] = *(short*)(pBuffer + bufferIndex + 12) / 32768.0f;
samples[sampleIndex++] = *(short*)(pBuffer + bufferIndex + 14) / 32768.0f;
}
for (; bufferIndex < count; bufferIndex += 2)
{
samples[sampleIndex++] = *(short*)(pBuffer + bufferIndex) / 32768.0f;
}
}
}
static unsafe void ConvertToSamplesVector(int count, byte[] buffer, float[] samples)
{
var multiplier = Vector512.Create(1 / 32768.0f);
var vectorBytes = Vector512<byte>.Count;
var sampleIncrement = vectorBytes / 2;
var halfSampleIncrement = sampleIncrement / 2;
var bufferIndex = 0;
var sampleIndex = 0;
fixed (byte* fBuffer = buffer)
fixed (float* fSamples = samples)
{
while (bufferIndex < buffer.Length)
{
var sampleLocation = fSamples + sampleIndex;
var sampleOffsetLocation = sampleLocation + halfSampleIncrement;
var input = Vector512.Load(fBuffer + bufferIndex).AsInt16();
var (lower, upper) = Vector512.Widen(input);
(Vector512.ConvertToSingle(lower) * multiplier).Store(sampleLocation);
(Vector512.ConvertToSingle(upper) * multiplier).Store(sampleOffsetLocation);
bufferIndex += vectorBytes;
sampleIndex += sampleIncrement;
}
}
for (; bufferIndex < count; bufferIndex += 2)
{
samples[sampleIndex++] = BitConverter.ToInt16(buffer, bufferIndex) / 32768.0f;
}
}
}
class Program
{
static void Main(string[] args)
{
if (args is ["correctness", ..])
{
var bench = new ConvertToSamplesBenchmark();
bench.ConvertToSamplesBase();
bench.ConvertToSamplesUnrolled();
bench.ConvertToSamplesVector();
bench.CheckCorrectness();
}
else
{
BenchmarkRunner.Run<ConvertToSamplesBenchmark>();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment