Skip to content

Instantly share code, notes, and snippets.

@lydonchandra
Created October 5, 2020 17:38
Show Gist options
  • Save lydonchandra/f8c743b00ae7f156a01084219ae622f7 to your computer and use it in GitHub Desktop.
Save lydonchandra/f8c743b00ae7f156a01084219ae622f7 to your computer and use it in GitHub Desktop.
Benchmark array multiplications
//#LINQPad optimize+
public class Bench1
{
private double[] data1;
private double[] data2;
[Params(1_024, 2_048, 4_096)]
public int N;
[GlobalSetup]
public void Setup() {
data1 = Enumerable.Range(0, N)
.Select(idx => Math.Sqrt(idx))
.ToArray();
data2 = Enumerable.Range(0, N)
.Select(idx => Math.Sqrt(idx))
.ToArray();
}
public static void Main()
{
BenchmarkRunner.Run<Bench1>();
// int sz = sizeof(double);
// int maxLen = 1000;
//
// double[] inLeft = Enumerable.Range(0, maxLen)
// .Select(idx => Math.Sqrt(idx))
// .ToArray();
//
// double[] inRight = Enumerable.Range(0, maxLen)
// .Select(idx => Math.Sqrt(idx))
// .ToArray();
//
// double[] res1 = VectorDotProdSIMD(inLeft, inRight);
//
// double[] res2 = VectorDotProd(inLeft, inRight);
}
[Benchmark]
public void VectorDotProdSIMDWrapper() {
VectorDotProdSIMD(data1, data2);
}
[Benchmark]
public void VectorDotProdWrapper()
{
VectorDotProd(data1, data2);
}
double[] VectorDotProdSIMD(double[] left, double[] right)
{
int offset = Vector<double>.Count;
double[] result = new double[left.Length];
int idx = 0;
for (idx = 0; idx < left.Length; idx += offset)
{
var leftVec = new Vector<double>(left, idx);
var rightVec = new Vector<double>(right, idx);
(leftVec * rightVec).CopyTo(result, idx);
}
for (; idx < left.Length; idx++)
{
result[idx] = left[idx] * right[idx];
}
return result;
}
double[] VectorDotProd(double[] left, double[] right)
{
double[] result = new double[left.Length];
for (int idx = 0; idx < left.Length; idx++)
{
result[idx] = left[idx] * right[idx];
}
return result;
}
}
@lydonchandra
Copy link
Author

lydonchandra commented Oct 5, 2020

| Method | N | Mean | Error | StdDev |
|
------------------------- |----- |-----------:|---------:|---------:|
| VectorDotProdSIMDWrapper | 1024 | 601.7 ns | 11.58 ns | 15.05 ns |
| VectorDotProdWrapper | 1024 | 848.3 ns | 13.53 ns | 12.66 ns |

| VectorDotProdSIMDWrapper | 2048 | 1,227.3 ns | 14.10 ns | 13.19 ns |
| VectorDotProdWrapper | 2048 | 1,619.1 ns | 13.39 ns | 11.18 ns |

| VectorDotProdSIMDWrapper | 4096 | 2,462.8 ns | 44.72 ns | 43.92 ns |
| VectorDotProdWrapper | 4096 | 3,137.7 ns | 26.63 ns | 23.60 ns |

// * Legends *

N : Value of the 'N' parameter

Mean : Arithmetic mean of all measurements

Error : Half of 99.9% confidence interval

StdDev : Standard deviation of all measurements

1 ns : 1 Nanosecond (0.000000001 sec)

@lydonchandra
Copy link
Author

using float instead of double, 2x speed up as expected because floats can be packed 2x as many as double can

| Method | N | Mean | Error | StdDev |
|
------------------------------ |----- |-----------:|---------:|---------:|
| VectorDotProdSIMDWrapper | 1024 | 607.3 ns | 11.46 ns | 11.26 ns |
| VectorDotProdSIMDFloatWrapper | 1024 | 321.0 ns | 6.27 ns | 12.37 ns |
| VectorDotProdSIMDWrapper | 2048 | 1,224.9 ns | 13.79 ns | 12.90 ns |
| VectorDotProdSIMDFloatWrapper | 2048 | 624.4 ns | 12.50 ns | 26.64 ns |
| VectorDotProdSIMDWrapper | 4096 | 2,533.3 ns | 49.96 ns | 46.73 ns |
| VectorDotProdSIMDFloatWrapper | 4096 | 1,246.9 ns | 23.80 ns | 25.46 ns |

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment