zyl910

优化技巧、硬件体系、图像处理、图形学、游戏编程、国际化与文本信息处理。

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

发布 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), 会被编译为指令的立即数.
Vectors.ShiftLeft_Core_use_inline.png

例2: 使用 Vectors.ShiftLeft_ArgsVectors.ShiftLeft_Core, 能将部分运算挪到循环外去提前处理. 例如在支持 Avx指令集的机器上运行时, 会在循环外设置好 xmm1, 随后在内循环的vpsllw指令里使用了它. 且这里展示了: 内联编译优化消除了冗余的 xmm/ymm 转换.
Vectors.ShiftLeft_use_inline.png

简介

本库为向量类型提供了许多重要的算术方法(如 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.InstanceVectorTraits256Avx2.

.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.InstanceVectorTraits128AdvSimdB64.

.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.InstanceVectorTraits256Base. 它不是 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的程序运行时的汇编指令, 它已经是按最佳硬件指令运行的. 例如下图.

Vectors.ShiftLeft_use_inline.png

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

文档

文章

向量类型的入门教程:

变更日志

[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

posted on 2023-09-08 00:23  zyl910  阅读(204)  评论(4编辑  收藏  举报