diff --git a/src/benchmarks/micro/MicroBenchmarks.csproj b/src/benchmarks/micro/MicroBenchmarks.csproj index 3d9e9fd4286..867737a3b72 100644 --- a/src/benchmarks/micro/MicroBenchmarks.csproj +++ b/src/benchmarks/micro/MicroBenchmarks.csproj @@ -88,6 +88,10 @@ + + + + @@ -212,9 +216,10 @@ - - - + + + + diff --git a/src/benchmarks/micro/libraries/System.Numerics.Tensors/Perf_BinaryIntegerTensorPrimitives.cs b/src/benchmarks/micro/libraries/System.Numerics.Tensors/Perf_BinaryIntegerTensorPrimitives.cs new file mode 100644 index 00000000000..88aa8df5c99 --- /dev/null +++ b/src/benchmarks/micro/libraries/System.Numerics.Tensors/Perf_BinaryIntegerTensorPrimitives.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Extensions; +using MicroBenchmarks; + +namespace System.Numerics.Tensors.Tests +{ + [BenchmarkCategory(Categories.Libraries, Categories.SIMD, Categories.JIT)] + [GenericTypeArguments(typeof(int))] + public class Perf_BinaryIntegerTensorPrimitives + where T : unmanaged, IBinaryInteger + { + [Params(128, 6 * 512 + 7)] + public int BufferLength; + + private T[] _source1; + private T[] _destination; + + [GlobalSetup] + public void Init() + { + _source1 = ValuesGenerator.Array(BufferLength, seed: 42); + _destination = new T[BufferLength]; + } + + #region Unary Operations + [Benchmark] + public void LeadingZeroCount() => TensorPrimitives.LeadingZeroCount(_source1, _destination); + + [Benchmark] + public void OnesComplement() => TensorPrimitives.OnesComplement(_source1, _destination); + + [Benchmark] + public void PopCount() => TensorPrimitives.PopCount(_source1, _destination); + + [Benchmark] + public void ShiftLeft() => TensorPrimitives.ShiftLeft(_source1, shiftAmount: 3, _destination); + + [Benchmark] + public void TrailingZeroCount() => TensorPrimitives.TrailingZeroCount(_source1, _destination); + #endregion + } +} \ No newline at end of file diff --git a/src/benchmarks/micro/libraries/System.Numerics.Tensors/Perf_FloatingPointTensorPrimitives.cs b/src/benchmarks/micro/libraries/System.Numerics.Tensors/Perf_FloatingPointTensorPrimitives.cs new file mode 100644 index 00000000000..63212e36d44 --- /dev/null +++ b/src/benchmarks/micro/libraries/System.Numerics.Tensors/Perf_FloatingPointTensorPrimitives.cs @@ -0,0 +1,105 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Extensions; +using MicroBenchmarks; +using System.Linq; + +namespace System.Numerics.Tensors.Tests +{ + [BenchmarkCategory(Categories.Libraries, Categories.SIMD, Categories.JIT)] + [GenericTypeArguments(typeof(float))] + [GenericTypeArguments(typeof(double))] + public class Perf_FloatingPointTensorPrimitives + where T : unmanaged, IFloatingPointIeee754 + { + [Params(128, 6 * 512 + 7)] + public int BufferLength; + + private T[] _source1; + private T[] _source2; + private T[] _source3; + private T _scalar1; + private T[] _ones; + private T[] _destination; + + [GlobalSetup] + public void Init() + { + _source1 = ValuesGenerator.Array(BufferLength, seed: 42); + _source2 = ValuesGenerator.Array(BufferLength, seed: 43); + _source3 = ValuesGenerator.Array(BufferLength, seed: 44); + _scalar1 = ValuesGenerator.Value(seed: 45); + _ones = Enumerable.Repeat(T.One, BufferLength).ToArray(); + _destination = new T[BufferLength]; + } + + #region Unary Operations + [Benchmark] + public void AtanPi() => TensorPrimitives.AtanPi(_source1, _destination); + + [Benchmark] + public void Exp() => TensorPrimitives.Exp(_source1, _destination); + + [Benchmark] + public void Log() => TensorPrimitives.Log(_source1, _destination); + + [Benchmark] + public void Round() => TensorPrimitives.Round(_source1, _destination); + + [Benchmark] + public void Sin() => TensorPrimitives.Sin(_source1, _destination); + + [Benchmark] + public void Sinh() => TensorPrimitives.Sinh(_source1, _destination); + + [Benchmark] + public void Sigmoid() => TensorPrimitives.Sigmoid(_source1, _destination); + + [Benchmark] + public void Sqrt() => TensorPrimitives.Sqrt(_source1, _destination); + + [Benchmark] + public void Truncate() => TensorPrimitives.Truncate(_source1, _destination); + #endregion + + #region Binary/Ternary Operations + [Benchmark] + public void FusedMultiplyAdd_Vectors() => TensorPrimitives.FusedMultiplyAdd(_source1, _source2, _source3, _destination); + + [Benchmark] + public void FusedMultiplyAdd_ScalarAddend() => TensorPrimitives.FusedMultiplyAdd(_source1, _scalar1, _source2, _destination); + + [Benchmark] + public void FusedMultiplyAdd_ScalarMultiplier() => TensorPrimitives.FusedMultiplyAdd(_source1, _source2, _scalar1, _destination); + + [Benchmark] + public void Ieee754Remainder_Vector() => TensorPrimitives.Ieee754Remainder(_source1, _source2, _destination); + + [Benchmark] + public void Ieee754Remainder_ScalarDividend() => TensorPrimitives.Ieee754Remainder(_scalar1, _source1, _destination); + + [Benchmark] + public void Ieee754Remainder_ScalarDivisor() => TensorPrimitives.Ieee754Remainder(_source1, _scalar1, _destination); + + [Benchmark] + public void Pow_Vectors() => TensorPrimitives.Pow(_source1, _ones, _destination); + + [Benchmark] + public void Pow_ScalarBase() => TensorPrimitives.Pow(_scalar1, _ones, _destination); + + [Benchmark] + public void Pow_ScalarExponent() => TensorPrimitives.Pow(_source1, T.One, _destination); + #endregion + + #region Reducers + [Benchmark] + public T CosineSimilarity() => TensorPrimitives.CosineSimilarity(_source1, _source2); + + [Benchmark] + public T Distance() => TensorPrimitives.Distance(_source1, _source2); + #endregion + } +} diff --git a/src/benchmarks/micro/libraries/System.Numerics.Tensors/Perf_NumberTensorPrimitives.cs b/src/benchmarks/micro/libraries/System.Numerics.Tensors/Perf_NumberTensorPrimitives.cs new file mode 100644 index 00000000000..a3adab1b054 --- /dev/null +++ b/src/benchmarks/micro/libraries/System.Numerics.Tensors/Perf_NumberTensorPrimitives.cs @@ -0,0 +1,103 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Extensions; +using MicroBenchmarks; +using System.Linq; + +namespace System.Numerics.Tensors.Tests +{ + [BenchmarkCategory(Categories.Libraries, Categories.SIMD, Categories.JIT)] + [GenericTypeArguments(typeof(int))] + [GenericTypeArguments(typeof(float))] + [GenericTypeArguments(typeof(double))] + public class Perf_NumberTensorPrimitives + where T : INumber, IBitwiseOperators + { + [Params(128, 6 * 512 + 7)] + public int BufferLength; + + private T[] _source1; + private T[] _source2; + private T[] _source3; + private T _scalar1; + private T[] _ones; + private T[] _destination; + + [GlobalSetup] + public void Init() + { + _source1 = ValuesGenerator.Array(BufferLength, seed: 42); + _source2 = ValuesGenerator.Array(BufferLength, seed: 43); + _source3 = ValuesGenerator.Array(BufferLength, seed: 44); + _scalar1 = ValuesGenerator.Value(seed: 45); + _ones = Enumerable.Repeat(T.One, BufferLength).ToArray(); + _destination = new T[BufferLength]; + } + + #region Unary Operations + [Benchmark] + public void Abs() => TensorPrimitives.Abs(_source1, _destination); + + [Benchmark] + public void Negate() => TensorPrimitives.Abs(_source1, _destination); + #endregion + + #region Binary/Ternary Operations + [Benchmark] + public void Add_Vector() => TensorPrimitives.Add(_source1, _source2, _destination); + + [Benchmark] + public void Add_Scalar() => TensorPrimitives.Add(_source1, _scalar1, _destination); + + [Benchmark] + public void AddMultiply_Vectors() => TensorPrimitives.AddMultiply(_source1, _source2, _source3, _destination); + + [Benchmark] + public void AddMultiply_ScalarAddend() => TensorPrimitives.AddMultiply(_source1, _scalar1, _source2, _destination); + + [Benchmark] + public void AddMultiply_ScalarMultiplier() => TensorPrimitives.AddMultiply(_source1, _source2, _scalar1, _destination); + + [Benchmark] + public void BitwiseAnd_Vector() => TensorPrimitives.BitwiseAnd(_source1, _source2, _destination); + + [Benchmark] + public void BitwiseAnd_Scalar() => TensorPrimitives.BitwiseAnd(_source1, _scalar1, _destination); + + [Benchmark] + public void Divide_Vector() => TensorPrimitives.Divide(_source1, _ones, _destination); + + [Benchmark] + public void Divide_Scalar() => TensorPrimitives.Divide(_source1, T.One, _destination); + + [Benchmark] + public void Max_Vector() => TensorPrimitives.Max(_source1, _source2, _destination); + + [Benchmark] + public void Max_Scalar() => TensorPrimitives.Max(_source1, _scalar1, _destination); + + [Benchmark] + public void MaxMagnitude_Vector() => TensorPrimitives.MaxMagnitude(_source1, _source2, _destination); + + [Benchmark] + public void MaxMagnitude_Scalar() => TensorPrimitives.MaxMagnitude(_source1, _scalar1, _destination); + #endregion + + #region Reducers + [Benchmark] + public T Max() => TensorPrimitives.Max(_source1); + + [Benchmark] + public T SumOfMagnitudes() => TensorPrimitives.SumOfMagnitudes(_ones); + + [Benchmark] + public T SumOfSquares() => TensorPrimitives.SumOfSquares(_ones); + + [Benchmark] + public int IndexOfMax() => TensorPrimitives.IndexOfMax(_source1); + #endregion + } +} diff --git a/src/harness/BenchmarkDotNet.Extensions/ValuesGenerator.cs b/src/harness/BenchmarkDotNet.Extensions/ValuesGenerator.cs index fa36e3c17a1..1b0bc42c87e 100644 --- a/src/harness/BenchmarkDotNet.Extensions/ValuesGenerator.cs +++ b/src/harness/BenchmarkDotNet.Extensions/ValuesGenerator.cs @@ -67,11 +67,11 @@ public static T[] ArrayOfUniqueValues(int count) /// For byte and sbyte values are built from Random.NextBytes, for other types GenerateValue is used /// to generate a random value in the appropriate range /// - public static T[] Array(int count) + public static T[] Array(int count, int? seed = null) { var result = new T[count]; - var random = new Random(Seed); + var random = new Random(seed ?? Seed); if (typeof(T) == typeof(byte) || typeof(T) == typeof(sbyte)) { @@ -88,6 +88,12 @@ public static T[] Array(int count) return result; } + public static T Value(int? seed = null) + { + var random = new Random(seed ?? Seed); + return GenerateValue(random); + } + public static readonly byte[] s_encodingMap = { 65, 66, 67, 68, 69, 70, 71, 72, //A..H 73, 74, 75, 76, 77, 78, 79, 80, //I..P