发布 VectorTraits v1.0, 它是C#下增强SIMD向量运算的类库
VectorTraits: SIMD Vector type traits methods (SIMD向量类型的特征方法).
NuGet: https://www.nuget.org/packages/VectorTraits/1.0.0
源代码: https://github.com/zyl910/VectorTraits
用途
总所周知,使用SIMD指令集,能够加速 多媒体处理(图形、图像、音频、视频…)、人工智能、科学计算 等。
然而,传统的SIMD编程存在以下痛点:
- 难以跨平台。因为不同的CPU体系,提供了不同的SIMD指令集,例如 X86与Arm平台的SIMD指令集存在很多差异。如果程序欲移植到另一平台下,则需要查找该平台的SIMD指令集手册,重新开发一遍。
- 位宽难以升级。即使是同一个平台,随着发展,会逐渐增加位数更宽的指令集。例如X86平台,除了已淘汰的64位MMX系列指令外,提供了了 128位SSE指令集、256位的AVX指令集,且部分高端处理器开始支持 512位的AVX-512指令集。以前用128位SSE系列指令编写的算法,若想移植到256位的AVX指令集,需要重新开发一遍,才能充分利用更宽的SIMD指令集。
- 代码可读性差,开发门槛高。很多现代C语言编译器为SIMD指令,映射了
内在函数
(Intrinsic Functions),比编写汇编代码要容易了不少,且可读性提升了不少。但是由于函数名使用了一些晦涩的缩写,且C语言不支持函数名重载,以及C语言本身的复杂性,导致代码可读性与开发难度,仍有较高的门槛。
2016年的 .NET Core 1.0
新增了 Vector<T>
等向量类型,在很大程度上解决了以上痛点。
- 容易跨平台。
.NET
平台的程序,是通过JIT(Just-In-Time Compiler,即时编译器)运行的。只编写一套基于向量方法的算法,且仅需编译为一套程序。随后该程序在不同平台上运行时,向量方法会被JIT编译为平台特有的SIMD指令集,从而充分的享用硬件加速。 - 位宽能自动升级。对于
Vector<T>
类型,它的长度不是固定的,而是与该处理器的最长向量寄存器相同。具体来说,若CPU支持AVX指令集(严格来说是AVX2及以上),Vector<T>
类型便是256位;若CPU仅支持SSE指令集(严格来说是SSE2及以上),Vector<T>
类型便是128位。简单来说,在编写程序时仅使用Vector<T>
类型就行,程序运行时,JIT会自动使用最宽的SIMD指令集。 - 代码可读性较高,降低了开发门槛。
.NET
平台下,向量类型的方法名都是用完整英文单词所组成,并充分利用了函数名重载等 C# 语法特点,使这些方法名既简洁、又清晰。使得代码可读性有了很大的提高。
向量类型Vector<T>
虽然设计的好,但它缺少许多重要的向量函数,如 Ceiling、Sum、Shift、Shuffle 等。导致很多算法,难以用向量类型来实现。
当 .NET
平台版本升级时, 有时会增加若干个向量方法。例如2022年发布的 .NET 7.0
,增加了ShiftRightArithmetic、Shuffle 等函数。但目前的向量方法还是较少, 例如缺少饱和处理等.
为了解决缺少向量方法的问题,.NET Core 3.0
开始支持了内在函数。这能让开发者直接使用SIMD指令集,但这又面临了难以跨平台与位宽难以升级等问题。随着 .NET
平台的不断升级,会增加了更多的内在函数。例如 .NET 5.0
增加了 Arm平台的内在函数。
对于开发类库, 不能仅支持 .NET 7.0
,而是需要支持多个 .NET
版本。于是你会面临繁琐的版本检查与条件处理. 而且 .NET Standard
类库的最高版本(2.1),仍是是不支持Ceiling等向量方法的,导致版本检查更加繁琐.
本库致力于解决以上麻烦, 使您能更方便的编写跨平台的SIMD算法。
特点:
- 支持低版本的
.NET
程序(.NET Standard 1.1
,.NET Core 1.0
,.NET Framework 4.5
, …)。能使低版本的.NET
程序,也能使用最新的向量函数. 例如.NET 7.0
所新增的 ShiftRightArithmetic、Shuffle 等。 - 功能强. 除了参考高版本
.NET
的向量方法外,本库还参考内在函数,提供了很多有用的向量方法。例如 YClamp, YNarrowSaturate … - 性能高。本库能充分利用 X86、Arm架构的内在函数对向量类型的运算进行硬件加速,且能够享受内联编译优化。且本库解决了BCL的部分向量方法(如Multiply, Shuffle等)在一些平台上没有硬件加速的问题, 因它补充了硬件加速算法.
- 软件算法也很快。若发现向量类型的某个方法不支持硬件加速时,.NET Bcl会切换为软件算法,但它软件算法很多是含有分支语句的,性能较差。而本库的软件算法,是高度优化的无分支算法。
- 使用方便。本库不仅支持
Vector<T>
,还支持Vector128<T>
/Vector256<T>
等向量类型。工具类的类名很好记(Vectors/Vector64s/Vector128s/Vector256s),且通过同名的泛型类提供了许多常用的向量常数。 - 为每一个特征方法, 增加了一些获取信息的的属性. e.g.
_AcceleratedTypes
,_FullAcceleratedTypes
.
提示: 在 Visual Studio 的 Disassembly窗口可以查看运行时的汇编代码. 例如在支持 Avx指令集的机器上运行时, Vectors.ShiftLeft_Const
会被内联编译优化为使用 vpsllw
指令. 且对于常量值(1), 会被编译为指令的立即数.
例2: 使用 Vectors.ShiftLeft_Args
与 Vectors.ShiftLeft_Core
, 能将部分运算挪到循环外去提前处理. 例如在支持 Avx指令集的机器上运行时, 会在循环外设置好 xmm1
, 随后在内循环的vpsllw
指令里使用了它. 且这里展示了: 内联编译优化消除了冗余的 xmm/ymm 转换.
简介
本库为向量类型提供了许多重要的算术方法(如 Shift, Shuffle, NarrowSaturate)及常数, 使您能更方便的编写跨平台的SIMD运算代码。它充分利用了 X86、Arm架构的内在函数实现硬件加速,且能够享受内联编译优化。
常用类型:
Vectors
: 为向量类型, 提供了常用工具函数, e.g. Create(T/T[]/Span/ReadOnlySpan), CreatePadding, CreateRotate, CreateByFunc, CreateByDouble … 它还为向量提供了特征方法, e.g. ShiftLeft、ShiftRightArithmetic、ShiftRightLogical、Shuffle …Vectors<T>
: 为向量类型, 提供了各种元素类型的常数. e.g. Serial, SerialDesc, XyzwWMask, MantissaMask, MaxValue, MinValue, NormOne, FixedOne, E, Pi, Tau, VMaxByte, VReciprocalMaxSByte …Vector64s/Vector128s/Vector256s
: 为固定位宽的向量(Vector64/Vector128/Vector256),提供了常用工具函数与特征方法.Vector64s<T>/Vector128s<T>/Vector256s<T>
: 为固定位宽的向量,提供了各种元素类型的常数.Scalars
: 为标量类型, 提供了各种工具函数. e.g. GetByDouble, GetFixedByDouble, GetByBits, GetBitsMask …Scalars<T>
: 为标量类型, 提供了许多常数. e.g. ExponentBits, MantissaBits, MantissaMask, MaxValue, MinValue, NormOne, FixedOne, E, Pi, Tau, VMaxByte, VReciprocalMaxSByte …VectorTextUtil
: 提供了一些向量的文本性工具函数. e.g. GetHex, Format, WriteLine …
特征方法:
- 支持
.NET Standard 2.1
新增的向量方法: ConvertToDouble, ConvertToInt32, ConvertToInt64, ConvertToSingle, ConvertToUInt32, ConvertToUInt64, Narrow, Widen . - 支持
.NET 5.0
新增的向量方法: Ceiling, Floor . - 支持
.NET 6.0
新增的向量方法: Sum . - 支持
.NET 7.0
新增的向量方法: ExtractMostSignificantBits, Shuffle, ShiftLeft, ShiftRightArithmetic, ShiftRightLogical . - 提供缩窄饱和的向量方法: YNarrowSaturate, YNarrowSaturateUnsigned .
- 提供舍入的向量方法: YRoundToEven, YRoundToZero .
- 提供换位的向量方法: YShuffleInsert, YShuffleKernel, YShuffleG2, YShuffleG4, YShuffleG4X2 . 且提供了 ShuffleControlG2/ShuffleControlG4 enum.
- …
- 完整列表: TraitsMethodList
支持的指令集:
- x86
- 256位向量: Avx, Avx2 .
- Arm
- 128位向量: AdvSimd .
入门指南
1) 通过NuGet安装
可在’包管理器控制台’里输入以下命令, 或是使用’包管理器’GUI来安装本库.
NuGet: PM> Install-Package VectorTraits
2) 用法示例
静态类 Vectors
提供了许多方法, 例如 CreateRotate, ShiftLeft, Shuffle.
泛型结构体 Vectors<T>
为常用常数提供了字段.
范例代码在 samples/VectorTraits.Sample
文件夹. 源代码如下.
using System;
using System.IO;
using System.Numerics;
#if NETCOREAPP3_0_OR_GREATER
using System.Runtime.Intrinsics;
#endif
using Zyl.VectorTraits;
namespace Zyl.VectorTraits.Sample {
class Program {
private static readonly TextWriter writer = Console.Out;
static void Main(string[] args) {
writer.WriteLine("VectorTraits.Sample");
writer.WriteLine();
VectorTraitsGlobal.Init(); // Initialization (初始化).
TraitsOutput.OutputEnvironment(writer); // Output environment info. It depends on `VectorTraits.InfoInc`. This row can be deleted when only VectorTraits are used (输出环境信息. 它依赖 `VectorTraits.InfoInc`. 当仅使用 VectorTraits 时, 可以删除本行).
writer.WriteLine();
// -- Start --
Vector<short> src = Vectors.CreateRotate<short>(0, 1, 2, 3, 4, 5, 6, 7); // The `Vectors` class provides some methods. For example, 'CreateRotate' is rotate fill (`Vectors` 类提供了许多方法. 例如 `CreateRotate` 是旋转填充).
VectorTextUtil.WriteLine(writer, "src:\t{0}", src); // It can not only format the string, but also display the hexadecimal of each element in the vector on the right Easy to view vector data (它不仅能格式化字符串, 且会在右侧显示向量中各元素的十六进制. 便于查看向量数据).
// ShiftLeft. It is a new vector method in `.NET 7.0` (左移位. 它是 `.NET 7.0` 新增的向量方法)
const int shiftAmount = 1;
Vector<short> shifted = Vectors.ShiftLeft(src, shiftAmount); // shifted[i] = src[i] << shiftAmount.
VectorTextUtil.WriteLine(writer, "ShiftLeft:\t{0}", shifted);
#if NET7_0_OR_GREATER
// Compare BCL function (与BCL的函数做对比).
Vector<short> shiftedBCL = Vector.ShiftLeft(src, shiftAmount);
VectorTextUtil.WriteLine(writer, "Equals to BCL ShiftLeft:\t{0}", shifted.Equals(shiftedBCL));
#endif
// ShiftLeft_Const
VectorTextUtil.WriteLine(writer, "Equals to ShiftLeft_Const:\t{0}", shifted.Equals(Vectors.ShiftLeft_Const(src, shiftAmount))); // If the parameter shiftAmount is a constant, you can also use the Vectors' ShiftLeft_Const method. It is faster in many scenarios (若参数 shiftAmount 是常数, 还可以使用 Vectors 的 ShiftLeft_Const 方法. 它在不少场景下更快).
writer.WriteLine();
// Shuffle. It is a new vector method in `.NET 7.0` (换位. 它是 `.NET 7.0` 新增的向量方法)
Vector<short> desc = Vectors<short>.SerialDesc; // The generic structure 'Vectors<T>' provides fields for commonly used constants. For example, 'SerialDesc' is a descending order value (泛型结构体 `Vectors<T>` 为常用常数提供了字段. 例如 `SerialDesc` 是降序的顺序值).
VectorTextUtil.WriteLine(writer, "desc:\t{0}", desc);
Vector<short> dst = Vectors.Shuffle(shifted, desc); // dst[i] = shifted[desc[i]].
VectorTextUtil.WriteLine(writer, "Shuffle:\t{0}", dst);
#if NET7_0_OR_GREATER
// Compare BCL function (与BCL的函数做对比).
Vector<short> dstBCL = default; // Since `.NET 7.0`, the Shuffle method has been provided in Vector128/Vector256, but the Shuffle method has not yet been provided in Vector (自 `.NET 7.0` 开始, Vector128/Vector256 里提供了 Shuffle 方法, 但 Vector 里尚未提供 Shuffle 方法).
if (Vector<short>.Count == Vector128<short>.Count) {
dstBCL = Vector128.Shuffle(shifted.AsVector128(), desc.AsVector128()).AsVector();
} else if (Vector<short>.Count == Vector256<short>.Count) {
dstBCL = Vector256.Shuffle(shifted.AsVector256(), desc.AsVector256()).AsVector();
}
VectorTextUtil.WriteLine(writer, "Equals to BCL Shuffle:\t{0}", dst.Equals(dstBCL));
#endif
// Shuffle_Args and Shuffle_Core
Vectors.Shuffle_Args(desc, out var args0, out var args1); // The suffix is the `Args' method used for parameter calculation, which involves processing such as parameter transformation in advance It is suitable for external loop (后缀是 `Args` 的方法, 用于参数计算, 即提前进行参数变换等处理. 它适合放在外循环).
Vector<short> dst2 = Vectors.Shuffle_Core(shifted, args0, args1); // The suffix is the `Core` method used for core calculations, which calculates based on cached parameters It is suitable for internal loop to improve performance (后缀是 `Core` 方法, 用于核心计算, 既根据已缓存的参数进行计算. 它适合放在内循环, 便于改善性能).
VectorTextUtil.WriteLine(writer, "Equals to Shuffle_Core:\t{0}", dst.Equals(dst2));
writer.WriteLine();
// Show AcceleratedTypes.
VectorTextUtil.WriteLine(writer, "ShiftLeft_AcceleratedTypes:\t{0}", Vectors.ShiftLeft_AcceleratedTypes);
VectorTextUtil.WriteLine(writer, "Shuffle_AcceleratedTypes:\t{0}", Vectors.Shuffle_AcceleratedTypes);
}
}
}
3) 示例的运行结果
.NET7.0
on X86
程序: VectorTraits.Sample
VectorTraits.Sample
IsRelease: True
EnvironmentVariable(PROCESSOR_IDENTIFIER): Intel64 Family 6 Model 142 Stepping 10, GenuineIntel
Environment.ProcessorCount: 8
Environment.Is64BitProcess: True
Environment.OSVersion: Microsoft Windows NT 10.0.19045.0
Environment.Version: 7.0.3
Stopwatch.Frequency: 10000000
RuntimeEnvironment.GetRuntimeDirectory: C:\Program Files\dotnet\shared\Microsoft.NETCore.App\7.0.3\
RuntimeInformation.FrameworkDescription: .NET 7.0.3
RuntimeInformation.OSArchitecture: X64
RuntimeInformation.OSDescription: Microsoft Windows 10.0.19045
RuntimeInformation.RuntimeIdentifier: win10-x64
IntPtr.Size: 8
BitConverter.IsLittleEndian: True
Vector.IsHardwareAccelerated: True
Vector<byte>.Count: 32 # 256bit
Vector<float>.Count: 8 # 256bit
VectorTraitsGlobal.InitCheckSum: 7960959 # 0x0079797F
Vector<T>.Assembly.CodeBase: file:///C:/Program Files/dotnet/shared/Microsoft.NETCore.App/7.0.3/System.Private.CoreLib.dll
GetTargetFrameworkDisplayName(VectorTextUtil): .NET 7.0
GetTargetFrameworkDisplayName(TraitsOutput): .NET 7.0
Vectors.Instance: VectorTraits256Avx2
src: <0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7> # (0000 0001 0002 0003 0004 0005 0006 0007 0000 0001 0002 0003 0004 0005 0006 0007)
ShiftLeft: <0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14> # (0000 0002 0004 0006 0008 000A 000C 000E 0000 0002 0004 0006 0008 000A 000C 000E)
Equals to BCL ShiftLeft: True
Equals to ShiftLeft_Const: True
desc: <15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0> # (000F 000E 000D 000C 000B 000A 0009 0008 0007 0006 0005 0004 0003 0002 0001 0000)
Shuffle: <14, 12, 10, 8, 6, 4, 2, 0, 14, 12, 10, 8, 6, 4, 2, 0> # (000E 000C 000A 0008 0006 0004 0002 0000 000E 000C 000A 0008 0006 0004 0002 0000)
Equals to BCL Shuffle: True
Equals to Shuffle_Core: True
ShiftLeft_AcceleratedTypes: SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64 # (00001FE0)
Shuffle_AcceleratedTypes: SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double # (00007FE0)
注: Vectors.Instance
及之前的文本, 是TraitsOutput.OutputEnvironment
输出的环境信息. 而从 src
开始的, 才是示例的主体代码.
由于CPU支持X86的Avx2指令集, 于是 Vector<byte>.Count
为 32(256bit), Vectors.Instance
为 VectorTraits256Avx2
.
.NET7.0
on Arm
程序: VectorTraits.Sample
VectorTraits.Sample
IsRelease: True
EnvironmentVariable(PROCESSOR_IDENTIFIER):
Environment.ProcessorCount: 2
Environment.Is64BitProcess: True
Environment.OSVersion: Unix 5.19.0.1025
Environment.Version: 7.0.8
Stopwatch.Frequency: 1000000000
RuntimeEnvironment.GetRuntimeDirectory: /home/ubuntu/.dotnet/shared/Microsoft.NETCore.App/7.0.8/
RuntimeInformation.FrameworkDescription: .NET 7.0.8
RuntimeInformation.OSArchitecture: Arm64
RuntimeInformation.OSDescription: Linux 5.19.0-1025-aws #26~22.04.1-Ubuntu SMP Mon Apr 24 01:58:03 UTC 2023
RuntimeInformation.RuntimeIdentifier: ubuntu.22.04-arm64
IntPtr.Size: 8
BitConverter.IsLittleEndian: True
Vector.IsHardwareAccelerated: True
Vector<byte>.Count: 16 # 128bit
Vector<float>.Count: 4 # 128bit
VectorTraitsGlobal.InitCheckSum: 7960961 # 0x00797981
Vector<T>.Assembly.CodeBase: file:///home/ubuntu/.dotnet/shared/Microsoft.NETCore.App/7.0.8/System.Private.CoreLib.dll
GetTargetFrameworkDisplayName(VectorTextUtil): .NET 7.0
GetTargetFrameworkDisplayName(TraitsOutput): .NET 7.0
Vectors.Instance: VectorTraits128AdvSimdB64
src: <0, 1, 2, 3, 4, 5, 6, 7> # (0000 0001 0002 0003 0004 0005 0006 0007)
ShiftLeft: <0, 2, 4, 6, 8, 10, 12, 14> # (0000 0002 0004 0006 0008 000A 000C 000E)
Equals to BCL ShiftLeft: True
Equals to ShiftLeft_Const: True
desc: <7, 6, 5, 4, 3, 2, 1, 0> # (0007 0006 0005 0004 0003 0002 0001 0000)
Shuffle: <14, 12, 10, 8, 6, 4, 2, 0> # (000E 000C 000A 0008 0006 0004 0002 0000)
Equals to BCL Shuffle: True
Equals to Shuffle_Core: True
ShiftLeft_AcceleratedTypes: SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64 # (00001FE0)
Shuffle_AcceleratedTypes: SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double # (00007FE0)
运算结果与X86的相同,只是环境信息不同。
由于CPU支持Arm的AdvSimd指令集, 于是 Vector<byte>.Count
为 16(128bit), Vectors.Instance
为 VectorTraits128AdvSimdB64
.
.NET Framework 4.5
on X86
程序: VectorTraits.Sample.NetFw
.
VectorTraits.Sample
IsRelease: True
EnvironmentVariable(PROCESSOR_IDENTIFIER): Intel64 Family 6 Model 142 Stepping 10, GenuineIntel
Environment.ProcessorCount: 8
Environment.Is64BitProcess: True
Environment.OSVersion: Microsoft Windows NT 6.2.9200.0
Environment.Version: 4.0.30319.42000
Stopwatch.Frequency: 10000000
RuntimeEnvironment.GetRuntimeDirectory: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\
RuntimeInformation.FrameworkDescription: .NET Framework 4.8.9167.0
RuntimeInformation.OSArchitecture: X64
RuntimeInformation.OSDescription: Microsoft Windows 10.0.19045
IntPtr.Size: 8
BitConverter.IsLittleEndian: True
Vector.IsHardwareAccelerated: True
Vector<byte>.Count: 32 # 256bit
Vector<float>.Count: 8 # 256bit
VectorTraitsGlobal.InitCheckSum: -25396097 # 0xFE7C7C7F
Vector<T>.Assembly.CodeBase: file:///E:/zylSelf/Code/cs/base/VectorTraits/samples/VectorTraits.Sample.NetFw/bin/Release/System.Numerics.Vectors.DLL
GetTargetFrameworkDisplayName(VectorTextUtil): .NET Standard 1.1
GetTargetFrameworkDisplayName(TraitsOutput): .NET Framework 4.5
Vectors.Instance: VectorTraits256Base
src: <0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7> # (0000 0001 0002 0003 0004 0005 0006 0007 0000 0001 0002 0003 0004 0005 0006 0007)
ShiftLeft: <0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14> # (0000 0002 0004 0006 0008 000A 000C 000E 0000 0002 0004 0006 0008 000A 000C 000E)
Equals to ShiftLeft_Const: True
desc: <15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0> # (000F 000E 000D 000C 000B 000A 0009 0008 0007 0006 0005 0004 0003 0002 0001 0000)
Shuffle: <14, 12, 10, 8, 6, 4, 2, 0, 14, 12, 10, 8, 6, 4, 2, 0> # (000E 000C 000A 0008 0006 0004 0002 0000 000E 000C 000A 0008 0006 0004 0002 0000)
Equals to Shuffle_Core: True
ShiftLeft_AcceleratedTypes: SByte, Byte, Int16, UInt16, Int32, UInt32 # (000007E0)
Shuffle_AcceleratedTypes: None # (00000000)
Vectors 的 ShiftLeft/Shuffle 都能正常工作.
由于CPU支持X86的Avx2指令集, 于是 Vector<byte>.Count
为 32(256bit). Vectors.Instance
为 VectorTraits256Base
. 它不是 VectorTraits256Avx2
, 是因为直到 .NET Core 3.0
才支持内在函数.
ShiftLeft_AcceleratedTypes的值含有“Int16”等类型,这表示ShiftLeft在使用这些类型时, 是存在硬件加速的. 本库巧妙的利用了向量算法, 即使在没有内在函数时,也尽量实现了硬件加速.
基准测试结果
数据的单位: 百万次操作/秒. 数字越大, 性能越好.
ShiftLeft
ShiftLeft: 将向量的每个元素左移指定量.
它是.NET 7.0
所新增的向量方法.
ShiftLeft - x86 - lntel Core i5-8250U
Type | Method | .NET Framework | .NET Core 2.1 | .NET Core 3.1 | .NET 5.0 | .NET 6.0 | .NET 7.0 |
---|---|---|---|---|---|---|---|
Byte | SumSLLScalar | 853.802 | 817.528 | 1104.993 | 1118.381 | 1374.255 | 1480.225 |
Byte | SumSLLNetBcl | 1128.290 | |||||
Byte | SumSLLNetBcl_Const | 1137.564 | |||||
Byte | SumSLLTraits | 8296.682 | 8114.085 | 21811.573 | 19960.732 | 21044.192 | 23074.627 |
Byte | SumSLLTraits_Core | 33328.333 | 35503.285 | 41644.146 | 35703.816 | 36615.138 | 32872.874 |
Byte | SumSLLConstTraits | 10849.899 | 10168.754 | 25029.290 | 29761.737 | 33785.502 | 32862.094 |
Byte | SumSLLConstTraits_Core | 36537.668 | 31837.586 | 39307.523 | 35698.909 | 35679.744 | 33994.997 |
Int16 | SumSLLScalar | 823.668 | 806.395 | 1176.133 | 1183.966 | 1379.498 | 1486.900 |
Int16 | SumSLLNetBcl | 18445.571 | |||||
Int16 | SumSLLNetBcl_Const | 19054.243 | |||||
Int16 | SumSLLTraits | 5076.036 | 5047.453 | 16986.361 | 16653.329 | 16496.182 | 16114.543 |
Int16 | SumSLLTraits_Core | 20318.984 | 18959.033 | 20182.655 | 17683.717 | 18500.302 | 18439.182 |
Int16 | SumSLLConstTraits | 5899.256 | 5693.084 | 16944.673 | 19378.434 | 21059.682 | 19572.551 |
Int16 | SumSLLConstTraits_Core | 20172.952 | 19339.311 | 18407.673 | 19850.711 | 21232.279 | 18136.492 |
Int32 | SumSLLScalar | 803.506 | 820.639 | 1307.614 | 1328.703 | 2199.685 | 1587.071 |
Int32 | SumSLLNetBcl | 9469.894 | |||||
Int32 | SumSLLNetBcl_Const | 10657.900 | |||||
Int32 | SumSLLTraits | 2571.456 | 2678.866 | 8246.402 | 7799.748 | 8221.382 | 9594.126 |
Int32 | SumSLLTraits_Core | 8574.361 | 8465.712 | 10320.833 | 10408.381 | 10626.910 | 10035.217 |
Int32 | SumSLLConstTraits | 1493.590 | 2922.103 | 8155.046 | 9293.148 | 10579.400 | 10185.431 |
Int32 | SumSLLConstTraits_Core | 8467.974 | 8554.920 | 9784.699 | 10384.732 | 9790.898 | 10329.112 |
Int64 | SumSLLScalar | 797.703 | 816.504 | 1295.009 | 1305.611 | 2043.527 | 1535.809 |
Int64 | SumSLLNetBcl | 4143.077 | |||||
Int64 | SumSLLNetBcl_Const | 4903.130 | |||||
Int64 | SumSLLTraits | 426.950 | 458.517 | 3867.136 | 3941.999 | 3964.762 | 3713.754 |
Int64 | SumSLLTraits_Core | 441.378 | 463.537 | 4802.911 | 4813.018 | 4776.182 | 4653.104 |
Int64 | SumSLLConstTraits | 490.135 | 536.949 | 3929.109 | 4018.072 | 4725.293 | 4712.366 |
Int64 | SumSLLConstTraits_Core | 491.263 | 531.946 | 4930.099 | 4737.462 | 4782.430 | 4371.649 |
说明:
- SumSLLScalar: 使用标量算法.
- SumSLLNetBcl: 使用BCL的方法(
Vector.ShiftLeft
), 参数是变量. 注意.NET 7.0
才提供该方法. - SumSLLNetBcl_Const: 使用BCL的方法(
Vector.ShiftLeft
), 参数是常量. 注意.NET 7.0
才提供该方法. - SumSLLTraits: 使用本库的普通方法(
Vectors.ShiftLeft
), 参数是变量. - SumSLLTraits_Core: 使用本库的
Core
后缀的方法(Vectors.ShiftLeft_Args
,Vectors.ShiftLeft_Core
), 参数是变量. - SumSLLConstTraits: 使用本库的
Const
后缀的方法(Vectors.ShiftLeft_Const
), 参数是常量. - SumSLLConstTraits_Core: 使用本库的
ConstCore
后缀的方法(Vectors.ShiftLeft_Args
,Vectors.ShiftLeft_ConstCore
), 参数是常量.
BCL的方法(Vector.ShiftLeft
) 在X86平台运行时, 仅 Int16/Int32/Int64 有硬件加速, 而 Byte 没有硬件加速. 这是可能是因为 Avx2 指令集仅有 16~64位 的左移位指令, 未提供其他类型的指令, BCL便转为软件算法了.
而本库对于这些数字类型, 会换成由其他指令组合实现的高效算法. 例如对于 Byte类型, SumSLLConstTraits_Core 在.NET 7.0
的值为“32872.874”, 性能是 标量算法的 32872.874/1480.225≈22.2080
倍, 且是BCL方法的 32872.874/1137.564≈28.8976
倍.
因为X86的内在函数是从.NET Core 3.0
开始才提供的. 故对于 Int64类型, 在 .NET Core 3.0
之后才有硬件加速.
对于ShiftLeft来说, 当参数shiftAmount
是常量时, 性能一般会比用变量时更高. 无论是 BCL还是本库的方法, 都是如此.
使用本库的 Core
后缀的方法, 能将部分运算挪到循环外去提前处理, 从而优化了性能. 而当 CPU提供了常数参数的指令时(专业术语是“立即数参数”), 该指令的性能一般会更高. 于是本库还提供了 ConstCore
后缀的方法, 会选择该平台最快的指令.
因“CPU睿频”、“其他进程抢占CPU资源”等因素, 有时性能波动比较大. 但请放心, 已经检查过了Release的程序运行时的汇编指令, 它已经是按最佳硬件指令运行的. 例如下图.
ShiftLeft - Arm - AWS Arm t4g.small
Type | Method | .NET Core 3.1 | .NET 5.0 | .NET 6.0 | .NET 7.0 |
---|---|---|---|---|---|
Byte | SumSLLScalar | 610.192 | 610.563 | 653.197 | 891.088 |
Byte | SumSLLNetBcl | 19580.464 | |||
Byte | SumSLLNetBcl_Const | 19599.073 | |||
Byte | SumSLLTraits | 5668.036 | 13252.891 | 13253.575 | 13241.598 |
Byte | SumSLLTraits_Core | 14341.895 | 15888.315 | 15887.520 | 19595.005 |
Byte | SumSLLConstTraits | 9946.663 | 13243.304 | 15895.672 | 19466.408 |
Byte | SumSLLConstTraits_Core | 13201.657 | 15896.748 | 15894.093 | 19447.318 |
Int16 | SumSLLScalar | 606.942 | 607.226 | 607.742 | 765.154 |
Int16 | SumSLLNetBcl | 9332.186 | |||
Int16 | SumSLLNetBcl_Const | 9240.256 | |||
Int16 | SumSLLTraits | 4231.310 | 6553.072 | 6603.431 | 9351.061 |
Int16 | SumSLLTraits_Core | 7881.834 | 7897.878 | 8449.502 | 9356.142 |
Int16 | SumSLLConstTraits | 6577.829 | 6620.078 | 8444.304 | 9359.246 |
Int16 | SumSLLConstTraits_Core | 8383.107 | 7923.119 | 8443.802 | 9317.663 |
Int32 | SumSLLScalar | 749.491 | 746.414 | 747.273 | 1403.533 |
Int32 | SumSLLNetBcl | 4537.804 | |||
Int32 | SumSLLNetBcl_Const | 4533.257 | |||
Int32 | SumSLLTraits | 3233.214 | 3531.441 | 3530.389 | 4545.497 |
Int32 | SumSLLTraits_Core | 3901.975 | 4140.171 | 4142.377 | 4505.555 |
Int32 | SumSLLConstTraits | 3510.471 | 3865.285 | 4134.108 | 4568.054 |
Int32 | SumSLLConstTraits_Core | 3905.829 | 3895.898 | 3896.719 | 4547.294 |
Int64 | SumSLLScalar | 743.187 | 742.685 | 743.760 | 1372.299 |
Int64 | SumSLLNetBcl | 2473.172 | |||
Int64 | SumSLLNetBcl_Const | 2468.456 | |||
Int64 | SumSLLTraits | 482.056 | 1637.232 | 1640.547 | 1981.831 |
Int64 | SumSLLTraits_Core | 488.072 | 1970.152 | 2088.793 | 2468.202 |
Int64 | SumSLLConstTraits | 467.942 | 1958.432 | 2099.095 | 2460.619 |
Int64 | SumSLLConstTraits_Core | 470.112 | 1971.898 | 2097.693 | 2465.419 |
说明:
- SumSLLScalar: 使用标量算法.
- SumSLLNetBcl: 使用BCL的方法(
Vector.ShiftLeft
), 参数是变量. 注意.NET 7.0
才提供该方法. - SumSLLNetBcl_Const: 使用BCL的方法(
Vector.ShiftLeft
), 参数是常量. 注意.NET 7.0
才提供该方法. - SumSLLTraits: 使用本库的普通方法(
Vectors.ShiftLeft
), 参数是变量. - SumSLLTraits_Core: 使用本库的
Core
后缀的方法(Vectors.ShiftLeft_Args
,Vectors.ShiftLeft_Core
), 参数是变量. - SumSLLConstTraits: 使用本库的
Const
后缀的方法(Vectors.ShiftLeft_Const
), 参数是常量. - SumSLLConstTraits_Core: 使用本库的
ConstCore
后缀的方法(Vectors.ShiftLeft_Args
,Vectors.ShiftLeft_ConstCore
), 参数是常量.
BCL的方法(Vector.ShiftLeft
) 在Arm平台运行时, 整数类型都有硬件加速. 对于8~64位整数的左移位, AdvSimd指令集都提供了专用指令.
本库在Arm平台运行时, 也使用了同样的指令. 于是性能接近.
因为从 .NET 5.0
开始, 才提供了 Arm的内在函数. 故对于 Int64类型, 在 .NET 5.0
之后才有硬件加速.
ShiftRightArithmetic
ShiftRightArithmetic: 将向量的每个有符号元素算术右移指定量.
它是.NET 7.0
所新增的向量方法.
ShiftRightArithmetic - x86 - lntel Core i5-8250U
Type | Method | .NET Framework | .NET Core 2.1 | .NET Core 3.1 | .NET 5.0 | .NET 6.0 | .NET 7.0 |
---|---|---|---|---|---|---|---|
Int16 | SumSRAScalar | 823.804 | 827.734 | 1180.933 | 1182.307 | 1341.171 | 1592.939 |
Int16 | SumSRANetBcl | 18480.038 | |||||
Int16 | SumSRANetBcl_Const | 21052.686 | |||||
Int16 | SumSRATraits | 1557.132 | 1559.674 | 17325.184 | 17699.944 | 16372.799 | 17193.661 |
Int16 | SumSRATraits_Core | 1653.816 | 1653.714 | 18414.632 | 19664.147 | 17938.068 | 18476.248 |
Int16 | SumSRAConstTraits | 1672.258 | 1675.044 | 17658.703 | 20409.889 | 20233.738 | 20835.294 |
Int16 | SumSRAConstTraits_Core | 1714.582 | 1667.090 | 20076.043 | 20212.774 | 20994.717 | 21053.837 |
Int32 | SumSRAScalar | 825.056 | 829.789 | 1275.799 | 1342.349 | 1621.295 | 1620.315 |
Int32 | SumSRANetBcl | 10132.774 | |||||
Int32 | SumSRANetBcl_Const | 11033.258 | |||||
Int32 | SumSRATraits | 764.013 | 759.588 | 8195.470 | 8298.404 | 8314.921 | 9937.082 |
Int32 | SumSRATraits_Core | 826.612 | 825.854 | 10576.367 | 10449.535 | 9783.716 | 11108.074 |
Int32 | SumSRAConstTraits | 837.650 | 834.126 | 8484.959 | 9238.089 | 9979.236 | 10053.944 |
Int32 | SumSRAConstTraits_Core | 856.397 | 859.426 | 10201.125 | 10314.334 | 11009.384 | 10772.948 |
Int64 | SumSRAScalar | 815.238 | 811.645 | 1300.052 | 1280.982 | 1322.441 | 1602.916 |
Int64 | SumSRANetBcl | 578.499 | |||||
Int64 | SumSRANetBcl_Const | 553.963 | |||||
Int64 | SumSRATraits | 447.196 | 441.690 | 3032.903 | 2830.935 | 2988.130 | 2922.851 |
Int64 | SumSRATraits_Core | 459.781 | 458.269 | 3639.092 | 3352.255 | 3336.974 | 3488.018 |
Int64 | SumSRAConstTraits | 491.449 | 491.420 | 3074.926 | 2820.864 | 3365.642 | 3397.660 |
Int64 | SumSRAConstTraits_Core | 496.174 | 491.022 | 3660.380 | 3365.210 | 3398.657 | 3237.150 |
SByte | SumSRAScalar | 827.231 | 823.643 | 1101.518 | 1105.244 | 1348.340 | 1619.984 |
SByte | SumSRANetBcl | 1161.428 | |||||
SByte | SumSRANetBcl_Const | 1156.552 | |||||
SByte | SumSRATraits | 3108.569 | 3100.703 | 17944.555 | 17103.399 | 17926.975 | 20115.939 |
SByte | SumSRATraits_Core | 3298.491 | 3288.742 | 30742.095 | 30212.469 | 29604.498 | 33040.654 |
SByte | SumSRAConstTraits | 3320.813 | 3327.910 | 18297.669 | 25989.446 | 28437.425 | 31118.235 |
SByte | SumSRAConstTraits_Core | 3423.868 | 3427.681 | 29454.032 | 27559.316 | 30075.338 | 30565.076 |
说明:
- SumSRAScalar: 使用标量算法.
- SumSRANetBcl: 使用BCL的方法(
Vector.ShiftRightArithmetic
), 参数是变量. 注意.NET 7.0
才提供该方法. - SumSRANetBcl_Const: 使用BCL的方法(
Vector.ShiftRightArithmetic
), 参数是常量. 注意.NET 7.0
才提供该方法. - SumSRATraits: 使用本库的普通方法(
Vectors.ShiftRightArithmetic
), 参数是变量. - SumSRATraits_Core: 使用本库的
Core
后缀的方法(Vectors.ShiftRightArithmetic_Args
,Vectors.ShiftRightArithmetic_Core
), 参数是变量. - SumSRAConstTraits: 使用本库的
Const
后缀的方法(Vectors.ShiftRightArithmetic_Const
), 参数是常量. - SumSRAConstTraits_Core: 使用本库的
ConstCore
后缀的方法(Vectors.ShiftRightArithmetic_Args
,Vectors.ShiftRightArithmetic_ConstCore
), 参数是常量.
BCL的方法(Vector.ShiftRightArithmetic
) 在X86平台运行时, 仅 Int16/Int32 有硬件加速, 而 SByte/Int64 没有硬件加速. 这是可能是因为 Avx2 指令集仅有 16~32位 的算术右移位指令.
而本库对于这些数字类型, 会换成由其他指令组合实现的高效算法. 从 .NET Core 3.0
开始, 具有硬件加速.
ShiftRightArithmetic - Arm - AWS Arm t4g.small
Type | Method | .NET Core 3.1 | .NET 5.0 | .NET 6.0 | .NET 7.0 |
---|---|---|---|---|---|
Int16 | SumSRAScalar | 587.279 | 541.166 | 607.230 | 822.580 |
Int16 | SumSRANetBcl | 9941.333 | |||
Int16 | SumSRANetBcl_Const | 9938.477 | |||
Int16 | SumSRATraits | 1559.138 | 4950.480 | 5645.497 | 9938.217 |
Int16 | SumSRATraits_Core | 1823.509 | 8388.956 | 7904.366 | 9938.584 |
Int16 | SumSRAConstTraits | 1808.965 | 6589.881 | 7892.407 | 9871.343 |
Int16 | SumSRAConstTraits_Core | 1810.527 | 8392.943 | 7896.220 | 9925.543 |
Int32 | SumSRAScalar | 712.668 | 746.666 | 747.055 | 1188.551 |
Int32 | SumSRANetBcl | 4861.897 | |||
Int32 | SumSRANetBcl_Const | 4859.816 | |||
Int32 | SumSRATraits | 779.787 | 2944.169 | 2945.026 | 4868.865 |
Int32 | SumSRATraits_Core | 914.346 | 4125.748 | 4135.353 | 4862.075 |
Int32 | SumSRAConstTraits | 884.914 | 3266.272 | 3892.016 | 4841.364 |
Int32 | SumSRAConstTraits_Core | 920.389 | 4134.164 | 3893.088 | 4844.364 |
Int64 | SumSRAScalar | 717.640 | 742.361 | 742.337 | 1189.925 |
Int64 | SumSRANetBcl | 2468.196 | |||
Int64 | SumSRANetBcl_Const | 2471.434 | |||
Int64 | SumSRATraits | 451.956 | 1235.429 | 1233.818 | 1420.116 |
Int64 | SumSRATraits_Core | 435.180 | 1972.734 | 1966.992 | 2465.932 |
Int64 | SumSRAConstTraits | 437.799 | 1962.084 | 1966.946 | 2470.825 |
Int64 | SumSRAConstTraits_Core | 436.419 | 2099.303 | 2097.296 | 2469.149 |
SByte | SumSRAScalar | 577.766 | 610.669 | 672.786 | 925.515 |
SByte | SumSRANetBcl | 19792.701 | |||
SByte | SumSRANetBcl_Const | 19792.641 | |||
SByte | SumSRATraits | 2991.228 | 11281.229 | 11275.758 | 11356.994 |
SByte | SumSRATraits_Core | 3529.326 | 16818.297 | 16827.844 | 19798.924 |
SByte | SumSRAConstTraits | 3476.138 | 15680.873 | 16829.920 | 19774.470 |
SByte | SumSRAConstTraits_Core | 3577.927 | 16813.202 | 15762.243 | 19759.552 |
说明:
- SumSRAScalar: 使用标量算法.
- SumSRANetBcl: 使用BCL的方法(
Vector.ShiftRightArithmetic
), 参数是变量. 注意.NET 7.0
才提供该方法. - SumSRANetBcl_Const: 使用BCL的方法(
Vector.ShiftRightArithmetic
), 参数是常量. 注意.NET 7.0
才提供该方法. - SumSRATraits: 使用本库的普通方法(
Vectors.ShiftRightArithmetic
), 参数是变量. - SumSRATraits_Core: 使用本库的
Core
后缀的方法(Vectors.ShiftRightArithmetic_Args
,Vectors.ShiftRightArithmetic_Core
), 参数是变量. - SumSRAConstTraits: 使用本库的
Const
后缀的方法(Vectors.ShiftRightArithmetic_Const
), 参数是常量. - SumSRAConstTraits_Core: 使用本库的
ConstCore
后缀的方法(Vectors.ShiftRightArithmetic_Args
,Vectors.ShiftRightArithmetic_ConstCore
), 参数是常量.
BCL的方法(Vector.ShiftRightArithmetic
) 在Arm平台运行时, 整数类型都有硬件加速. 对于8~64位整数的算术右移位, AdvSimd指令集都提供了专用指令.
本库在Arm平台运行时, 也使用了同样的指令. 于是性能接近. 从 .NET 5.0
开始, 具有硬件加速.
Shuffle
Shuffle: 换位并清零. 通过使用一组索引从输入向量中选择值,来创建一个新向量.
它是.NET 7.0
所新增的向量方法. 自 .NET 7.0
开始, Vector128/Vector256 里提供了 Shuffle 方法, 但 Vector 里尚未提供 Shuffle 方法.
Shuffle 允许索引超过有效范围, 此次会将对应元素置0. 这个特性会稍微拖慢性能, 于是本库还提供了 YShuffleKernel 方法(仅换位). 若能确保索引总是在有效范围内, 用 YShuffleKernel 更快.
Shuffle - x86 - lntel Core i5-8250U
Type | Method | .NET Framework | .NET Core 2.1 | .NET Core 3.1 | .NET 5.0 | .NET 6.0 | .NET 7.0 |
---|---|---|---|---|---|---|---|
Int16 | SumScalar | 1009.132 | 1007.748 | 992.299 | 1004.370 | 1034.912 | 989.043 |
Int16 | Sum256_Bcl | 775.841 | |||||
Int16 | SumTraits | 1012.626 | 1008.900 | 6025.629 | 8058.075 | 8017.278 | 9060.106 |
Int16 | SumTraits_Args0 | 1008.925 | 988.646 | 14845.370 | 14590.246 | 14413.193 | 14209.436 |
Int16 | SumTraits_Args | 1008.981 | 991.790 | 14644.219 | 14527.035 | 14198.718 | 14024.591 |
Int16 | SumKernelTraits | 1011.528 | 1009.289 | 7566.266 | 9381.227 | 9585.573 | 10330.592 |
Int16 | SumKernelTraits_Args0 | 1006.331 | 989.488 | 15045.753 | 14575.460 | 14464.147 | 14484.413 |
Int16 | SumKernelTraits_Args | 1017.264 | 990.161 | 14900.553 | 13672.167 | 14556.627 | 14280.139 |
Int32 | SumScalar | 723.019 | 725.013 | 704.809 | 708.372 | 735.378 | 747.651 |
Int32 | Sum256_Bcl | 611.393 | |||||
Int32 | SumTraits | 716.509 | 724.369 | 5216.757 | 5813.206 | 7139.337 | 9250.625 |
Int32 | SumTraits_Args0 | 716.520 | 703.636 | 9278.507 | 9221.310 | 9159.683 | 9728.639 |
Int32 | SumTraits_Args | 722.854 | 709.654 | 9010.834 | 9164.854 | 8992.356 | 9828.623 |
Int32 | SumKernelTraits | 722.441 | 725.218 | 9554.766 | 7064.711 | 6932.192 | 9996.960 |
Int32 | SumKernelTraits_Args0 | 724.689 | 706.345 | 11017.874 | 11092.301 | 11134.924 | 11279.116 |
Int32 | SumKernelTraits_Args | 727.981 | 701.155 | 11030.886 | 10970.116 | 10510.208 | 11324.558 |
Int64 | SumScalar | 459.881 | 457.952 | 188.562 | 477.806 | 459.242 | 462.021 |
Int64 | Sum256_Bcl | 515.863 | |||||
Int64 | SumTraits | 459.302 | 459.876 | 2143.129 | 2518.325 | 2433.449 | 3524.309 |
Int64 | SumTraits_Args0 | 465.064 | 441.576 | 4508.754 | 4449.098 | 4406.994 | 4484.512 |
Int64 | SumTraits_Args | 459.786 | 408.545 | 4466.028 | 4214.808 | 4293.438 | 4270.565 |
Int64 | SumKernelTraits | 460.058 | 458.858 | 2702.105 | 3195.810 | 1714.735 | 4046.124 |
Int64 | SumKernelTraits_Args0 | 464.705 | 438.224 | 4820.767 | 4705.843 | 4042.262 | 4882.344 |
Int64 | SumKernelTraits_Args | 463.218 | 411.905 | 4884.277 | 5433.558 | 4140.529 | 4788.233 |
SByte | SumScalar | 1263.210 | 1262.732 | 844.749 | 1013.924 | 1077.513 | 1261.932 |
SByte | Sum256_Bcl | 930.329 | |||||
SByte | SumTraits | 1264.393 | 1264.667 | 13239.408 | 17766.242 | 16140.964 | 24537.440 |
SByte | SumTraits_Args0 | 1262.368 | 1242.503 | 31793.487 | 31423.344 | 31314.488 | 34322.789 |
SByte | SumTraits_Args | 1221.542 | 1248.121 | 31118.400 | 31615.120 | 31980.794 | 33156.240 |
SByte | SumKernelTraits | 1260.097 | 1266.056 | 19996.806 | 23032.250 | 23853.314 | 29612.169 |
SByte | SumKernelTraits_Args0 | 1260.461 | 1245.530 | 31084.955 | 30974.022 | 31913.287 | 33643.052 |
SByte | SumKernelTraits_Args | 1260.272 | 1249.316 | 30827.152 | 30734.831 | 32311.418 | 32977.071 |
说明:
- SumScalar: 使用标量算法.
- Sum256_Bcl: 使用BCL的方法(
Vector256.Shuffle
). - SumTraits: 使用本库的普通方法(
Vectors.Shuffle
). - SumTraits_Args0: 使用本库的
Core
后缀的方法(Vectors.Shuffle_Args
,Vectors.Shuffle_Core
), 不使用ValueTuple, 而是用“out”关键字返回多个值. - SumTraits_Args: 使用本库的
Core
后缀的方法(Vectors.Shuffle_Args
,Vectors.Shuffle_Core
), 使用ValueTuple. - SumKernelTraits: 使用本库的YShuffleKernel的普通方法(
Vectors.YShuffleKernel
). - SumKernelTraits_Args0: 使用本库的YShuffleKernel的
Core
后缀的方法(Vectors.YShuffleKernel_Args
,Vectors.YShuffleKernel_Core
), 不使用ValueTuple, 而是用“out”关键字返回多个值. - SumKernelTraits_Args: 使用本库的YShuffleKernel的
Core
后缀的方法(Vectors.YShuffleKernel_Args
,Vectors.YShuffleKernel_Core
), 使用ValueTuple.
BCL的方法(Vector.Shuffle
) 在X86平台运行时, 所有数字类型, 均没有硬件加速.
而本库对于这些数字类型, 会换成由其他指令组合实现的高效算法. 从 .NET Core 3.0
开始, 具有硬件加速.
使用本库的 Core
后缀的方法, 能将部分运算挪到循环外去提前处理, 从而优化了性能. 特别对于Shuffle方法来说, 性能提升幅度较大.
若能确保索引总是在有效范围内, 能用 YShuffleKernel 替代Shuffle. 它更快.
对于Args
后缀的方法, 除了可以用“out”关键字返回多个值外, 还可以用 ValueTuple 来接收多个值, 简化了代码. 但得注意 ValueTuple 有时会降低性能.
Shuffle - Arm - AWS Arm t4g.small
Type | Method | .NET Core 3.1 | .NET 5.0 | .NET 6.0 | .NET 7.0 |
---|---|---|---|---|---|
Int16 | SumScalar | 424.835 | 422.286 | 423.070 | 526.071 |
Int16 | Sum128_Bcl | 482.320 | |||
Int16 | SumTraits | 423.942 | 4925.034 | 4938.077 | 5853.245 |
Int16 | SumTraits_Args0 | 423.872 | 8381.395 | 7862.055 | 9821.786 |
Int16 | SumTraits_Args | 400.767 | 2982.755 | 2976.138 | 9769.321 |
Int16 | Sum128_AdvSimd | 3169.036 | 3115.859 | 3239.207 | |
Int16 | SumKernelTraits | 424.317 | 5644.808 | 6565.519 | 7904.834 |
Int16 | SumKernelTraits_Args0 | 423.899 | 7881.823 | 7847.868 | 9835.768 |
Int16 | SumKernelTraits_Args | 399.772 | 2982.013 | 2868.286 | 9778.383 |
Int32 | SumScalar | 288.211 | 281.081 | 276.668 | 317.268 |
Int32 | Sum128_Bcl | 303.702 | |||
Int32 | SumTraits | 287.942 | 2447.812 | 2561.501 | 2912.918 |
Int32 | SumTraits_Args0 | 286.646 | 4103.084 | 4110.550 | 4796.704 |
Int32 | SumTraits_Args | 268.613 | 1487.180 | 1483.994 | 4775.891 |
Int32 | SumKernelTraits | 287.900 | 2805.355 | 3237.345 | 3909.519 |
Int32 | SumKernelTraits_Args0 | 286.556 | 4112.689 | 4128.402 | 4825.180 |
Int32 | SumKernelTraits_Args | 268.858 | 1487.021 | 1430.400 | 4755.708 |
Int64 | SumScalar | 378.628 | 188.199 | 447.044 | 552.523 |
Int64 | Sum128_Bcl | 712.025 | |||
Int64 | SumTraits | 379.643 | 1015.811 | 1089.628 | 1242.552 |
Int64 | SumTraits_Args0 | 380.133 | 2091.948 | 1967.766 | 2465.800 |
Int64 | SumTraits_Args | 326.603 | 743.033 | 744.908 | 2452.967 |
Int64 | SumKernelTraits | 379.696 | 1221.923 | 1480.182 | 1756.478 |
Int64 | SumKernelTraits_Args0 | 379.788 | 2096.124 | 2095.536 | 2464.674 |
Int64 | SumKernelTraits_Args | 170.957 | 715.532 | 717.549 | 2457.398 |
SByte | SumScalar | 668.450 | 650.673 | 659.984 | 833.921 |
SByte | Sum128_Bcl | 648.985 | |||
SByte | SumTraits | 667.527 | 13135.356 | 16713.009 | 19730.059 |
SByte | SumTraits_Args0 | 664.988 | 15734.264 | 15708.758 | 19741.441 |
SByte | SumTraits_Args | 625.410 | 5723.523 | 5948.766 | 19692.665 |
SByte | SumKernelTraits | 667.280 | 15584.505 | 15643.225 | 19741.523 |
SByte | SumKernelTraits_Args0 | 664.914 | 16731.942 | 16685.534 | 19726.599 |
SByte | SumKernelTraits_Args | 625.761 | 5723.910 | 5950.549 | 19685.073 |
说明:
- SumScalar: 使用标量算法.
- Sum128_Bcl: 使用BCL的方法(
Vector128.Shuffle
). - SumTraits: 使用本库的普通方法(
Vectors.Shuffle
). - SumTraits_Args0: 使用本库的
Core
后缀的方法(Vectors.Shuffle_Args
,Vectors.Shuffle_Core
), 不使用ValueTuple, 而是用“out”关键字返回多个值. - SumTraits_Args: 使用本库的
Core
后缀的方法(Vectors.Shuffle_Args
,Vectors.Shuffle_Core
), 使用ValueTuple. - SumKernelTraits: 使用本库的YShuffleKernel的普通方法(
Vectors.YShuffleKernel
). - SumKernelTraits_Args0: 使用本库的YShuffleKernel的
Core
后缀的方法(Vectors.YShuffleKernel_Args
,Vectors.YShuffleKernel_Core
), 不使用ValueTuple, 而是用“out”关键字返回多个值. - SumKernelTraits_Args: 使用本库的YShuffleKernel的
Core
后缀的方法(Vectors.YShuffleKernel_Args
,Vectors.YShuffleKernel_Core
), 使用ValueTuple.
BCL的方法(Vector.Shuffle
) 在Arm平台运行时, 所有数字类型, 均没有硬件加速.
而本库对于这些数字类型, 会换成由其他指令组合实现的高效算法. 从 .NET 5.0
开始, 具有硬件加速.
注意在.NET 7.0
之前, SumTraits_Args 有时与 SumTraits_Args0 的性能相差较大, 这是因为ValueTuple 在Arm下的性能损失较大.
YNarrowSaturate
YNarrowSaturate: 将两个 Vector 实例饱和缩窄为一个 Vector .
YNarrowSaturate - x86 - lntel Core i5-8250U
Type | Method | .NET Framework | .NET Core 2.1 | .NET Core 3.1 | .NET 5.0 | .NET 6.0 | .NET 7.0 |
---|---|---|---|---|---|---|---|
Int16 | SumNarrow_If | 209.442 | 209.620 | 210.928 | 199.480 | 211.138 | 215.694 |
Int16 | SumNarrow_MinMax | 202.714 | 215.451 | 212.224 | 214.893 | 175.099 | 219.752 |
Int16 | SumNarrowVectorBase | 13095.098 | 13774.472 | 13161.165 | 13013.472 | 13168.239 | 15964.293 |
Int16 | SumNarrowVectorTraits | 13024.364 | 13662.396 | 28118.834 | 25049.004 | 28198.282 | 27819.176 |
Int32 | SumNarrow_If | 210.834 | 212.404 | 213.735 | 214.810 | 208.985 | 222.597 |
Int32 | SumNarrow_MinMax | 212.099 | 211.786 | 210.670 | 205.029 | 210.333 | 208.573 |
Int32 | SumNarrowVectorBase | 6933.036 | 6441.062 | 6584.000 | 7382.254 | 6728.319 | 7703.530 |
Int32 | SumNarrowVectorTraits | 6856.456 | 6398.525 | 12533.505 | 14263.835 | 12888.771 | 13992.887 |
Int64 | SumNarrow_If | 195.128 | 186.841 | 195.864 | 199.460 | 193.475 | 204.264 |
Int64 | SumNarrow_MinMax | 189.209 | 178.971 | 196.065 | 191.231 | 191.600 | 203.201 |
Int64 | SumNarrowVectorBase | 1959.806 | 1878.724 | 2000.976 | 2118.858 | 1976.264 | 2658.885 |
Int64 | SumNarrowVectorTraits | 1956.908 | 1872.465 | 2587.636 | 2763.282 | 2689.931 | 2418.496 |
UInt16 | SumNarrow_If | 1066.840 | 902.516 | 1078.540 | 974.749 | 1067.768 | 1083.124 |
UInt16 | SumNarrow_MinMax | 1066.895 | 903.120 | 901.484 | 959.577 | 900.228 | 823.878 |
UInt16 | SumNarrowVectorBase | 16884.658 | 17052.914 | 15147.602 | 17094.243 | 17200.043 | 19717.119 |
UInt16 | SumNarrowVectorTraits | 16862.587 | 16975.925 | 21142.034 | 26121.170 | 26440.908 | 24575.123 |
UInt32 | SumNarrow_If | 1116.417 | 961.764 | 856.272 | 901.272 | 872.811 | 1111.046 |
UInt32 | SumNarrow_MinMax | 1115.502 | 902.014 | 900.357 | 877.358 | 839.361 | 854.364 |
UInt32 | SumNarrowVectorBase | 7824.674 | 7015.984 | 8617.594 | 8176.926 | 8059.923 | 8801.283 |
UInt32 | SumNarrowVectorTraits | 7879.556 | 7024.438 | 12181.180 | 10713.260 | 11063.765 | 11314.953 |
UInt64 | SumNarrow_If | 997.327 | 847.431 | 871.820 | 875.547 | 858.060 | 1109.023 |
UInt64 | SumNarrow_MinMax | 865.420 | 1083.437 | 1107.671 | 1095.561 | 886.387 | 735.609 |
UInt64 | SumNarrowVectorBase | 2015.328 | 1971.981 | 1833.610 | 2446.346 | 2636.137 | 3336.732 |
UInt64 | SumNarrowVectorTraits | 2020.405 | 1979.078 | 2918.828 | 3258.796 | 3341.184 | 3108.173 |
说明:
- SumNarrow_If: 基于if语句的标量算法.
- SumNarrow_MinMax: 基于Math类的 Min/Max 方法的标量算法.
- SumNarrowVectorBase: 使用本库的基础方法(
VectorTraitsBase.Statics.YNarrowSaturate
). 它是通过组合使用BCL的向量方法来实现的, 能够利用硬件加速. - SumNarrowVectorTraits: 使用本库的特征方法(
Vectors.YNarrowSaturate
). 它是通过内在函数来实现的, 能获得更佳硬件加速.
对于 16~32位整数, 在 .NET Core 3.1
之后, SumNarrowVectorTraits的性能比SumNarrowVectorBase强很多. 这是因为 X86提供了专门的指令。
对于 64位整数(Int64/UInt64), 虽然X86没有提供对应指令. 但由于 SumNarrowVectorTraits 版代码使用了更佳的内在函数算法, 所以在很多时候它的性能仍是比SumNarrowVectorBase 更强。
YNarrowSaturate - Arm - AWS Arm t4g.small
Type | Method | .NET Core 3.1 | .NET 5.0 | .NET 6.0 | .NET 7.0 |
---|---|---|---|---|---|
Int16 | SumNarrow_If | 154.717 | 163.350 | 157.517 | 181.894 |
Int16 | SumNarrow_MinMax | 160.654 | 161.130 | 108.656 | 184.712 |
Int16 | SumNarrowVectorBase | 6124.516 | 5210.880 | 6055.721 | 7165.511 |
Int16 | SumNarrowVectorTraits | 6125.113 | 13574.329 | 13433.471 | 15507.867 |
Int32 | SumNarrow_If | 163.905 | 165.250 | 160.416 | 190.897 |
Int32 | SumNarrow_MinMax | 155.399 | 155.059 | 159.092 | 195.986 |
Int32 | SumNarrowVectorBase | 2701.810 | 3219.290 | 2766.267 | 3025.432 |
Int32 | SumNarrowVectorTraits | 2703.709 | 6306.022 | 6210.719 | 8003.142 |
Int64 | SumNarrow_If | 161.985 | 162.089 | 160.805 | 205.371 |
Int64 | SumNarrow_MinMax | 154.244 | 153.980 | 165.349 | 197.005 |
Int64 | SumNarrowVectorBase | 716.880 | 1189.192 | 1156.627 | 1229.301 |
Int64 | SumNarrowVectorTraits | 716.661 | 3282.455 | 3283.969 | 3921.550 |
UInt16 | SumNarrow_If | 525.100 | 530.550 | 525.952 | 608.947 |
UInt16 | SumNarrow_MinMax | 528.430 | 527.506 | 539.088 | 609.259 |
UInt16 | SumNarrowVectorBase | 7945.777 | 8739.615 | 7945.913 | 8916.311 |
UInt16 | SumNarrowVectorTraits | 7943.115 | 14158.586 | 14166.207 | 13814.007 |
UInt32 | SumNarrow_If | 544.871 | 540.266 | 538.649 | 621.107 |
UInt32 | SumNarrow_MinMax | 541.719 | 536.718 | 535.769 | 621.414 |
UInt32 | SumNarrowVectorBase | 4001.590 | 4022.504 | 3954.723 | 4379.473 |
UInt32 | SumNarrowVectorTraits | 4018.815 | 6824.637 | 6400.947 | 6722.416 |
UInt64 | SumNarrow_If | 620.408 | 620.900 | 622.076 | 828.917 |
UInt64 | SumNarrow_MinMax | 620.012 | 619.806 | 622.201 | 828.565 |
UInt64 | SumNarrowVectorBase | 1291.051 | 1863.543 | 1869.904 | 1816.732 |
UInt64 | SumNarrowVectorTraits | 1293.997 | 3233.726 | 3491.369 | 3501.256 |
说明:
- SumNarrow_If: 基于if语句的标量算法.
- SumNarrow_MinMax: 基于Math类的 Min/Max 方法的标量算法.
- SumNarrowVectorBase: 使用本库的基础方法(
VectorTraitsBase.Statics.YNarrowSaturate
). 它是通过组合使用BCL的向量方法来实现的, 能够利用硬件加速. - SumNarrowVectorTraits: 使用本库的特征方法(
Vectors.YNarrowSaturate
). 它是通过内在函数来实现的, 能获得更佳硬件加速.
因为从 .NET 5.0
开始,提供了 Arm的内在函数. 故从 .NET 5.0
开始, SumNarrowVectorTraits的性能比SumNarrowVectorBase强很多.
更多结果
详见: BenchmarkResults
文档
- 特征方法列表: TraitsMethodList
- DocFX: 运行
docfx_serve.bat
. 随后浏览 http://localhost:8080/ . - Doxygen: 运行 Doxywizard, 点击菜单栏的 File->Open. 选择
Doxyfile
文件,并点击“OK”. 点击“Run”Tab, 点击“Run doxygen”按钮. 它会在“doc_gen”文件夹生成文档.
变更日志
[2023-09-07] v1.0
- Major: 支持 x86的Avx指令集, 以及Arm的 AdvSimd 指令集; 支持 NET 5.0-7.0 新增的向量方法; 还提供了 4元素换位(YShuffleG4)、饱和变窄(YNarrowSaturate, YNarrowSaturateUnsigned) 等原创的向量方法.
- 为向量类型提供了一些工具方法及常数. e.g. Vectors, Vector64s, Vector128s, Vector256s, VectorTextUtil …
- 支持
.NET Standard 2.1
新增的向量方法: ConvertToDouble, ConvertToInt32, ConvertToInt64, ConvertToSingle, ConvertToUInt32, ConvertToUInt64, Narrow, Widen . - 支持
.NET 5.0
新增的向量方法: Ceiling, Floor . - 支持
.NET 6.0
新增的向量方法: Sum . - 支持
.NET 7.0
新增的向量方法: ExtractMostSignificantBits, ShiftLeft, ShiftRightArithmetic, ShiftRightLogical, Shuffle . - 为 Vector128/Vector256 补充向量方法: Abs, Add, AndNot, BitwiseAnd, BitwiseOr, ConditionalSelect, Divide, GreaterThan, LessThan, Max, Min, Multiply, Negate, OnesComplement, Subtract, Xor .
- 提供限制的向量方法: YClamp .
- 提供缩窄饱和的向量方法: YNarrowSaturate, YNarrowSaturateUnsigned .
- 提供舍入的向量方法: YRoundToEven, YRoundToZero .
- 提供换位的向量方法: YShuffleInsert, YShuffleKernel, YShuffleG2, YShuffleG4, YShuffleG4X2 . Also provides ShuffleControlG2/ShuffleControlG4 enum.
完整列表: ChangeLog