發佈 VectorTraits v1.0,它是 C# 下增強SIMD向量運算的類庫

来源:https://www.cnblogs.com/zyl910/archive/2023/09/08/dotnet_dll_VectorTraits_v1_0.html
-Advertisement-
Play Games

# 前言 ### 在上一篇文章[【基於ASP.NET ZERO,開發SaaS版供應鏈管理系統】](https://www.cnblogs.com/freedyang/p/17679280.html)中有提到對Webhook功能的擴展改造,本文詳細介紹一下具體過程。 ### Webhook功能操作說明 ...


發佈 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
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 作者:七寸知架構 \ 鏈接:https://www.jianshu.com/p/ec40a82cae28 # 1 引言# 本文主要講解JDBC怎麼演變到Mybatis的漸變過程,**重點講解了為什麼要將JDBC封裝成Mybaits這樣一個持久層框架**。再而論述Mybatis作為一個數據持久層框架本 ...
  • 網上查到的設計模式有23種,通過歸納去認識他們也是一種不錯的視角。 我這邊不按照主流的觀點去劃分為創建型、結構型、行為型三大類,我只歸納為創建型(Creational Class)、簡單功能場景(Simple Method Class)、複雜功能場景(Complex Method Class)三大類 ...
  • Matplotlib 中的圖例是幫助觀察者理解圖像數據的重要工具。圖例通常包含在圖像中,用於解釋不同的顏色、形狀、標簽和其他元素。 # 1. 主要參數 當不設置圖例的參數時,預設的圖例是這樣的。 ```python import numpy as np import matplotlib.pyplo ...
  • > 關註微信公眾號【TechLeadCloud】,分享互聯網架構、雲服務技術的全維度知識。作者擁有10+年互聯網服務架構、AI產品研發經驗、團隊管理經驗,同濟本復旦碩,復旦機器人智能實驗室成員,阿裡雲認證的資深架構師,項目管理專業人士,上億營收AI產品研發負責人。 > 本文深入探討了 Go 語言的內 ...
  • 我們來看看如何通過幾個步驟快速的實現一個功能相對齊全的CLI程式。和做飯一樣,能夠快速獲得成就感的方式是找半成品直接下鍋炒一盤 ...
  • 重定位表(Relocation Table)是Windows PE可執行文件中的一部分,主要記錄了與地址相關的信息,它在程式載入和運行時被用來修改程式代碼中的地址的值,因為程式在不同的記憶體地址中載入時,程式中使用到的地址也會受到影響,因此需要重定位表這個數據結構來完成這些地址值的修正。當程式需要被加... ...
  • 本教程適用於idea所有版本,並支持目前最新的2023.2.1版本。直接激活到2099年,支持windows、mac、linux。本文先講windows,mac和linux的跟win的激活方式大差不差。如果已經有了idea,想激活到2099的直接看步驟5 1.先去idea官網下載,官網下載地址:ht ...
  • 支持.Net Core(2.0及以上)與.Net Framework(4.5及以上) 可以部署在Docker, Windows, Linux, Mac。 分散式唯一Id,顧名思義,是指在全世界任何一臺電腦上都不會重覆的唯一Id。 在單機/單伺服器/單資料庫的小型應用中,不需要用到這類東西。但在高並 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...