Created
October 5, 2020 17:38
-
-
Save lydonchandra/f8c743b00ae7f156a01084219ae622f7 to your computer and use it in GitHub Desktop.
Benchmark array multiplications
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
//#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; | |
} | |
} |
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
| 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)