Skip to content

Instantly share code, notes, and snippets.

@kipters
Created September 4, 2022 17:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kipters/176da3077e686aa6b5eb1ed0248ed0ff to your computer and use it in GitHub Desktop.
Save kipters/176da3077e686aa6b5eb1ed0248ed0ff to your computer and use it in GitHub Desktop.
.NET 7 intrinsics benchmark
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
#if DEBUG
var testClass = new DotProductBenchmarks { Length = 8 };
testClass.GlobalSetup();
var implementations = typeof(DotProductBenchmarks)
.GetMethods()
.Where(m => m.GetCustomAttribute<BenchmarkAttribute>() is not null);
foreach (var method in implementations)
{
var name = method.Name;
var result = method.Invoke(testClass, null);
Console.WriteLine($"{name}: {result}");
}
Console.WriteLine($"{Vector64.IsHardwareAccelerated} {Vector128.IsHardwareAccelerated} {Vector256.IsHardwareAccelerated}");
#else
BenchmarkRunner.Run<DotProductBenchmarks>();
#endif
[MemoryDiagnoser]
public class DotProductBenchmarks
{
[Params(8, 16, 32, 1024, 32768, 65536)]
public int Length;
private int[] First = Array.Empty<int>();
private int[] Second = Array.Empty<int>();
[GlobalSetup]
public void GlobalSetup()
{
First = Enumerable.Range(0, Length).Select(_ => (int)(Random.Shared.Next() & 0x00FF)).ToArray();
Second = Enumerable.Range(0, Length).Select(_ => (int)(Random.Shared.Next() & 0x00FF)).ToArray();
}
[Benchmark]
public long Scalar()
{
var acc = 0L;
for (var i = 0; i < Length; i++)
{
acc += First[i] * Second[i];
}
return acc;
}
[Benchmark]
public unsafe long Vectorized64()
{
ref var f = ref MemoryMarshal.GetReference<int>(First);
ref var s = ref MemoryMarshal.GetReference<int>(Second);
var acc = Vector64<int>.Zero;
for (var i = 0; i < Length; i += 2)
{
var offset = (nuint)i;
var a = Vector64.LoadUnsafe(ref f, offset);
var b = Vector64.LoadUnsafe(ref s, offset);
acc += a * b;
}
return Vector64.Sum(acc);
}
[Benchmark]
public unsafe long Vectorized128()
{
ref var f = ref MemoryMarshal.GetReference<int>(First);
ref var s = ref MemoryMarshal.GetReference<int>(Second);
var acc = Vector128<int>.Zero;
for (var i = 0; i < Length; i += 4)
{
var offset = (nuint)i;
var a = Vector128.LoadUnsafe(ref f, offset);
var b = Vector128.LoadUnsafe(ref s, offset);
acc += a * b;
}
return Vector128.Sum(acc);
}
[Benchmark]
public unsafe long Vectorized256()
{
ref var f = ref MemoryMarshal.GetReference<int>(First);
ref var s = ref MemoryMarshal.GetReference<int>(Second);
var acc = Vector256<int>.Zero;
for (var i = 0; i < Length; i += 8)
{
var offset = (nuint)i;
var a = Vector256.LoadUnsafe(ref f, offset);
var b = Vector256.LoadUnsafe(ref s, offset);
acc += a * b;
}
return Vector256.Sum(acc);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment