Created
August 7, 2024 19:20
-
-
Save Vake93/94fa940efd23e33bf7bcf542dccf4de1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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