文章目录

VectorTraits已更新至 v3.0版。支持Vector512类型及 X86架构的Avx512系列指令集; 支持 Wasm架构及PackedSimd指令集; 还提供了 多向量换位(YShuffleX2、YShuffleX3)、交织(Group2Zip, Group2Unzip) 等原创的向量方法。

  • NuGet: https://www.nuget.org/packages/VectorTraits/3.0.0
  • 源代码: https://github.com/zyl910/VectorTraits
  • 在线文档: https://zyl910.github.io/VectorTraits_doc/

变更日志如下。

  • Supports Vector512 type and X86 architecture’s Avx512 family instruction sets (支持Vector512类型及 X86架构的Avx512系列指令集).
  • Improved algorithms for 128/256 bit vectors using the Avx512 family instruction sets (使用Avx512系列指令集, 改进了128/256位向量的算法).
  • Supports Wasm(WebAssembly) architecture, supports PackedSimd instruction set (支持 Wasm(WebAssembly)架构及PackedSimd指令集).
  • Added VectorTraits.Benchmarks.Wasm project. Used for unit test and benchmark vector types on the Wasm architecture (增加了 VectorTraits.Benchmarks.Wasm 项目. 用于在 Wasm 架构上对向量类型进行单元测试与基准测试).
  • Support for .NET 8.0 new vector methods (支持 .NET 8.0 新增的向量方法): WidenLower, WidenUpper.
  • Provides vector methods for de-interleave (提供解交织的向量方法): YGroup2Unzip, YGroup2UnzipEven, YGroup2UnzipOdd, YGroup3Unzip, YGroup3UnzipX2, YGroup4Unzip, YGroup6Unzip_Bit128.
  • Provides vector methods for interleave (提供交织的向量方法): YGroup2Zip, YGroup2ZipHigh, YGroup2ZipLow, YGroup3Zip, YGroup3ZipX2, YGroup4Unzip, YGroup6Zip_Bit128.
  • Provides vector methods for reconstruction groups (提供重新构造组的向量方法): YGroup1ToGroup3, YGroup1ToGroup4, YGroup1ToGroup4WithW, YGroup3ToGroup4, YGroup4ToGroup3.
  • Provides vector methods for multi vector shuffle (提供多向量换位的向量方法): YShuffleX2, YShuffleX2Insert, YShuffleX2Kernel, YShuffleX3, YShuffleX3Insert, YShuffleX3Kernel, YShuffleX4, YShuffleX4Insert, YShuffleX4Kernel.
  • Provides vector methods for transpose (提供转置的向量方法): YGroup2Transpose, YGroup2TransposeEven, YGroup2TransposeOdd.
  • Provides vector methods for compare (提供比较的向量方法): GreaterThan_Unsigned.
  • Provides extension method for vectors (提供向量的扩展方法): AsSigned, AsUnsigned.
  • VectorSameWExtensions add As method. Vector<T> add As Extension Methods (Vector<T> 增加 As 扩展方法).
  • The IsHardwareAccelerated property has been added to the Vectors(/Vector128s/Vector256s/Vector512s) classes (Vectors(/Vector128s/Vector256s/Vector512s) 类增加了 IsHardwareAccelerated 属性).
  • Added 128-bit integer type - ExInt128/ExUInt128 (增加了128位整数类型 - ExInt128/ExUInt128).
  • (Experimental) Experimentally added the ExType(Extended type) mechanism to enable vector types to support 128-bit integers(ExInt128/ExUInt128). However, it is found that some functions do not work properly under some .NET versions. Therefore, it is recommended to prioritize using functions with the suffix “_Bit128” instead of ExType (实验性的增加了 ExType(扩展类型) 机制, 使向量类型能支持128位整数(ExInt128/ExUInt128). 但发现某些.NET版本下,个别函数的工作不正常. 故建议优先使用“_Bit128”后缀的函数, 而不是 ExType).
  • The MathBitOperations class has been added. It provides these functions (增加了 MathBitOperations 类. 它提供了这些函数): Crc32C, IsPow2, LeadingZeroCount, Log2, PopCount, RoundUpToPowerOf2, RotateLeft, RotateRight, TrailingZeroCount.
  • Package “System.Runtime.CompilerServices.Unsafe” upgraded to version 5.0.0. UnsafeUtil obsoletes methods such as IsNullRef, NullRef, SkipInit (Unsafe包升级到 5.0.0 版. UnsafeUtil 废弃了 IsNullRef 等函数).
  • The UnsafeUtil class add methods (UnsafeUtil类增加了方法): GetArrayDataReference, Dec, Inc, PreDec, PreInc, PostDec, PostDecExcept, PostDecExceptZero, PostInc, PostIncExcept, PostIncExceptZero .
  • Optimize type conversion for vector generic types by replacing (object) with the As method (优化向量泛型类型的类型转换, 用 As 方法取代 (object)).
  • Optimize the combining of two vectors, using WithUpper instead of Create (优化两个向量的组合, 用 WithUpper 代替 Create). e,g, Narrow and more.
  • Optimized hardware acceleration of YBitToByte, YBitToInt16, YBitToInt32, YBitToInt64 methods on all architecture. It no longer uses OnesComplement (优化YBitToByte, YBitToInt16, YBitToInt32, YBitToInt64方法在所有架构的硬件加速. 它不再使用 OnesComplement).
  • Optimized hardware acceleration of Shuffle/YShuffleInsert methods on X86 architecture. Use EqualsShift arithmetic (优化Shuffle/YShuffleInsert方法在X86架构的硬件加速. 使用 EqualsShift 算法). For 16~64 bit types.
  • Fix all YShuffleG4X2 methods, remove redundant ConstantExpected attribute(修正所有 YShuffleG4X2 方法, 移除多余的 ConstantExpected 特性).
  • Removal of obsolete project file VectorTraits_vs2019.sln (移除过时的项目文件 VectorTraits_vs2019.sln).
  • Deprecation notice: Deprecation notice: The next version will remove such as WVectorTraits128AdvSimdB64/WVectorTraits128Avx2 classes (废弃预告: 下个版本将会移除 WVectorTraits128AdvSimdB64, WVectorTraits128Avx2 等类).

完整列表: ChangeLog

支持 X86架构的Avx512系列指令集

相关日志:

  • Supports Vector512 type and X86 architecture’s Avx512 family instruction sets (支持Vector512类型及 X86架构的Avx512系列指令集).
  • Improved algorithms for 128/256 bit vectors using the Avx512 family instruction sets (使用Avx512系列指令集, 改进了128/256位向量的算法).

本库已经支持了X86架构的Avx512系列指令集。既:Avx512BW, Avx512DQ, Avx512F, Avx512Vbmi, Avx512VL。

提示,目前支持Avx512系列指令集的CPU有——

  • Intel: 第11代酷睿处理器,如“Intel Core i7-11700”。注意从第12代酷睿处理器开始,Intel对消费级处理器禁用了Avx512,仅部分服务器级处理器有Avx512。
  • AMD: Zen4架构及之后机构的处理器,例如“AMD Ryzen 7 7840H”.

为了方便处理Vector512, 本库增加了以下类型:

  • Vector512s: 为512位向量(Vector512)提供了常用工具函数与特征方法. 在支持Avx512系列指令集的电脑上运行时, 会获得充分的硬件加速。
  • Vector512s<T>: 为512位向量(Vector512)提供了各种元素类型的常数.

而且本库根据 Avx512系列指令集中 128/256位向量指令,改进 128/256位向量中(Vector128s、Vector256s、Vectors)各个方法的算法,使它们的性能得到了进一步的提升。

在运行 .NET 程序时,可以通过环境变量来控制是否启用Avx512。例如加上“COMPlus_EnableAVX512F=0”的环境变量后,便会禁用Avx512。

遗憾的是,.NET 8.0 里的Vector类型,仅是128~256位的长度。当“Vector512.IsHardwareAccelerated”为true时(CPU支持Avx512指令集),Vector的长度并未升级到512位,而是仍然保持 256位。据说 .NET 9.0 会支持,只能期待它发布了。

支持Avx512时的输出信息

当支持Avx512指令集,范例程序 samples/VectorTraits.Sample 的输出信息如下。

VectorTraits.Sample

IsRelease:	True
Environment.ProcessorCount:	16
Environment.Is64BitProcess:	True
Environment.OSVersion:	Microsoft Windows NT 10.0.22631.0
Environment.Version:	8.0.8
Stopwatch.Frequency:	10000000
RuntimeEnvironment.GetRuntimeDirectory:	C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.8\
RuntimeInformation.FrameworkDescription:	.NET 8.0.8
RuntimeInformation.OSArchitecture:	X64
RuntimeInformation.OSDescription:	Microsoft Windows 10.0.22631
RuntimeInformation.RuntimeIdentifier:	win-x64
IntPtr.Size:	8
BitConverter.IsLittleEndian:	True
Vector.IsHardwareAccelerated:	True
Vector<byte>.Count:	32	# 256bit
Vector<float>.Count:	8	# 256bit
Vector128.IsHardwareAccelerated:	True
Vector256.IsHardwareAccelerated:	True
Vector512.IsHardwareAccelerated:	True
Vector<T>.Assembly.CodeBase:	file:///C:/Program Files/dotnet/shared/Microsoft.NETCore.App/8.0.8/System.Private.CoreLib.dll
GetTargetFrameworkDisplayName(VectorTextUtil):	.NET 8.0
GetTargetFrameworkDisplayName(TraitsOutput):	.NET 8.0
VectorTraitsGlobal.InitCheckSum:	-2122844161	# 0x8177F7FF
VectorEnvironment.CpuModelName:	AMD Ryzen 7 7840H w/ Radeon 780M Graphics
VectorEnvironment.SupportedInstructionSets:	Aes, Avx, Avx2, Avx512BW, Avx512CD, Avx512DQ, Avx512F, Avx512Vbmi, Avx512VL, Bmi1, Bmi2, Fma, Lzcnt, Pclmulqdq, Popcnt, Sse, Sse2, Sse3, Ssse3, Sse41, Sse42, X86Base
Vector128s.Instance:	WVectorTraits128Avx2	// Sse, Sse2, Sse3, Ssse3, Sse41, Sse42, Avx, Avx2, Avx512VL
Vector256s.Instance:	WVectorTraits256Avx2	// Avx, Avx2, Sse, Sse2, Avx512VL
Vector512s.Instance:	WVectorTraits512Avx512	// Avx512BW, Avx512DQ, Avx512F, Avx512Vbmi, Avx, Avx2, Sse, Sse2
Vectors.Instance:	VectorTraits256Avx2	// Avx, Avx2, Sse, Sse2, Avx512VL
Vectors.BaseInstance:	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 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)

其中最关键的是这几行,分别展示了各种向量类型所用的指令集。

Vector128s.Instance:	WVectorTraits128Avx2	// Sse, Sse2, Sse3, Ssse3, Sse41, Sse42, Avx, Avx2, Avx512VL
Vector256s.Instance:	WVectorTraits256Avx2	// Avx, Avx2, Sse, Sse2, Avx512VL
Vector512s.Instance:	WVectorTraits512Avx512	// Avx512BW, Avx512DQ, Avx512F, Avx512Vbmi, Avx, Avx2, Sse, Sse2
Vectors.Instance:	VectorTraits256Avx2	// Avx, Avx2, Sse, Sse2, Avx512VL

输出信息中的“Vector512.IsHardwareAccelerated: True”,表示512位向量支持硬件加速。

支持 Wasm架构及PackedSimd指令集

相关日志:

  • Supports Wasm(WebAssembly) architecture, supports PackedSimd instruction set (支持 Wasm(WebAssembly)架构及PackedSimd指令集).
  • Added VectorTraits.Benchmarks.Wasm project. Used for unit test and benchmark vector types on the Wasm architecture (增加了 VectorTraits.Benchmarks.Wasm 项目. 用于在 Wasm 架构上对向量类型进行单元测试与基准测试).

本库已经支持了支持 Wasm(WebAssembly)架构,以及PackedSimd指令集。

PackedSimd指令集是一个128位的SIMD硬件加速指令集。故在使用 Vector128s 时,能获得充分的硬件加速。

遗憾的是,目前.NET 8.0 里的Vector类型,在WASM架构上运行时是没有硬件加速的,仅Vector128有硬件加速。这就导致了 Vectors 的部分方法也是没有硬件加速的,需改为使用 Vector128s。

支持PackedSimd时的输出信息

当在WASM环境下运行,且支持PackedSimd指令集,范例程序的输出信息如下。

VectorTraits.Sample on Wasm

IsRelease:	True
Environment.ProcessorCount:	1
Environment.Is64BitProcess:	False
Environment.OSVersion:	Other 1.0.0.0
Environment.Version:	8.0.4
Stopwatch.Frequency:	1000000000
RuntimeEnvironment.GetRuntimeDirectory:	/
RuntimeInformation.FrameworkDescription:	.NET 8.0.4
RuntimeInformation.OSArchitecture:	Wasm
RuntimeInformation.OSDescription:	Browser
RuntimeInformation.RuntimeIdentifier:	browser-wasm
IntPtr.Size:	4
BitConverter.IsLittleEndian:	True
Vector.IsHardwareAccelerated:	False
Vector<byte>.Count:	16	# 128bit
Vector<float>.Count:	4	# 128bit
Vector128.IsHardwareAccelerated:	True
Vector256.IsHardwareAccelerated:	False
Vector512.IsHardwareAccelerated:	False
Vector<T>.Assembly.CodeBase:	
GetTargetFrameworkDisplayName(VectorTextUtil):	.NET 8.0
GetTargetFrameworkDisplayName(TraitsOutput):	.NET 8.0
VectorTraitsGlobal.InitCheckSum:	-2122844158	# 0x8177F802
VectorEnvironment.CpuModelName:	
VectorEnvironment.SupportedInstructionSets:	PackedSimd
Vector128s.Instance:	WVectorTraits128PackedSimd	// PackedSimd
Vectors.Instance:	VectorTraits128PackedSimd	// PackedSimd
Vectors.BaseInstance:	VectorTraits128Base

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:	None	# (00000000)
Shuffle_AcceleratedTypes:	None	# (00000000)

其中最关键的是这几行:

Vector.IsHardwareAccelerated:	False
Vector128.IsHardwareAccelerated:	True
Vector256.IsHardwareAccelerated:	False
Vector512.IsHardwareAccelerated:	False
VectorEnvironment.SupportedInstructionSets:	PackedSimd
Vector128s.Instance:	WVectorTraits128PackedSimd	// PackedSimd
Vectors.Instance:	VectorTraits128PackedSimd	// PackedSimd
Vectors.BaseInstance:	VectorTraits128Base

可以看出,浏览器支持PackedSimd。于是128位向量(Vector128)具有硬件加速。

VectorTraits.Benchmarks.Wasm 使用说明

传统的 .NET 程序,无论是命令行程序,还是UI界面程序,甚至 ASP.Net 后台程序,都是在本机上运行,而不是在浏览器中运行。
为了能直接在浏览器中运行 .NET 程序, 需使用“Blazor Wasm”项目类型。它会将 .NET 程序 编译为Wasm,用于在浏览器中运行。

本库已经建立了 VectorTraits.Benchmarks.Wasm 项目,可以用它来测试 .NET 程序在Wasm架构运行时的表现。且支持基准测试与单元测试。

启动VectorTraits.Benchmarks.Wasm 项目后,VS会自动打开浏览器,并浏览主页(Home)。如下图。
wasm_home.png

在左侧的导航栏中点击“View benchmark”,便会打开基准测试的页面,用于对比测试各种算法的性能。点击“Test”按钮,便会开始测试。该测试是异步进行的,还会在“Test”按钮的右侧显示进度。
wasm_benchmark.png

默认情况下,仅运行少量的基准测试。若勾选了“AllowFakeBenchmark”复选框,会运行所有的基准测试,会花费一个小时或更长的时间。

在左侧的导航栏中点击“View unit test”,便会打开基准测试的页面,用于验证算法的正确性。点击“Test”按钮,便会开始测试。
wasm_unit_test.png

由于 .NET 8.0 时的“Blazor Wasm”尚不支持多线程,且NUnit尚不支持异步执行。故只能以同步方式运行,需等到所有单元测试均执行完毕后,才能获得结果。一般需花费数分钟不等。

新增了向量方法

相关日志:

  • Support for .NET 8.0 new vector methods (支持 .NET 8.0 新增的向量方法): WidenLower, WidenUpper.
  • Provides vector methods for de-interleave (提供解交织的向量方法): YGroup2Unzip, YGroup2UnzipEven, YGroup2UnzipOdd, YGroup3Unzip, YGroup3UnzipX2, YGroup4Unzip, YGroup6Unzip_Bit128.
  • Provides vector methods for interleave (提供交织的向量方法): YGroup2Zip, YGroup2ZipHigh, YGroup2ZipLow, YGroup3Zip, YGroup3ZipX2, YGroup4Unzip, YGroup6Zip_Bit128.
  • Provides vector methods for reconstruction groups (提供重新构造组的向量方法): YGroup1ToGroup3, YGroup1ToGroup4, YGroup1ToGroup4WithW, YGroup3ToGroup4, YGroup4ToGroup3.
  • Provides vector methods for multi vector shuffle (提供多向量换位的向量方法): YShuffleX2, YShuffleX2Insert, YShuffleX2Kernel, YShuffleX3, YShuffleX3Insert, YShuffleX3Kernel, YShuffleX4, YShuffleX4Insert, YShuffleX4Kernel.
  • Provides vector methods for transpose (提供转置的向量方法): YGroup2Transpose, YGroup2TransposeEven, YGroup2TransposeOdd.

支持 .NET 8.0 新增的向量方法

.NET 8.0 新增了这些向量方法——

  • WidenLower: Widens the lower half of a Vector into a Vector (将向量的低半部分扩宽为一个向量).
    Mnemonic: rt[i] := widen(source[i]).
  • WidenUpper: Widens the upper half of a Vector into a Vector (将向量的高半部分扩宽为一个向量).
    Mnemonic: rt[i] := widen(source[i - Count/2]).

Vectors/Vector128s/Vector256s/Vector512s 均支持了这些方法。

提供交织与解交织的向量方法

在使用向量化运算时,有时需要重新排列元素的位置。例如在做图形、图像处理时,经常需要对 已打包的RGB或RGBA数据 进行交织和解交织运算。

虽然 .NET 7.0 开始提供了 Shuffle 方法,但它存在很多问题——变长的Vector类型里还未提供该方法,直到 .NET 8.0很多架构上仍没有硬件加速。
为了解决官方的 Shuffle 方法的问题,本库提供 Shuffle 系列方法,能够在 X86、Arm等架构上享受硬件加速。但还存在2个缺点——

  • 若让使用者基于Shuffle来开发交织和解交织运算的函数,写起来会比较繁琐。
  • 对于交织和解交织算法来说,Shuffle实现的算法的性能并不是最优的。有一些特殊算法,能带来更大的性能提升。

于是本库提供了交织与解交织的向量方法。且将其抽象为 2~4-元素组的处理,使它们能具有更强的通用性。相关方法的说明见下。

  • YGroup2Unzip[/_Bit128]: De-Interleave 2-element groups into 2 vectors. It converts the 2-element groups AoS to SoA (将2-元素组解交织为2个向量. 它能将2元素组的 数组结构体 转为 结构体数组).
    Mnemonic: x[i] =: element_ref(2*i, data0, data1), y[i] =: element_ref(2*i+1, data0, data1).
  • YGroup2UnzipEven: De-Interleave the 2-element groups into 2 vectors, and return the vector of even positions (将2-元素组解交织为2个向量, 并返回偶数位置的数据).
    Mnemonic: rt[i] =: element_ref(2*i, data0, data1).
  • YGroup2UnzipOdd: De-Interleave the 2-element groups into 2 vectors, and return the vector of odd positions (将2-元素组解交织为2个向量, 并返回奇数位置的数据).
    Mnemonic: rt[i] =: element_ref(2*i+1, data0, data1).
  • YGroup2Zip[/_Bit128]: Interleave 2 vectors into 2-element groups. It converts the 2-element groups SoA to AoS (将2个向量交织为2-元素组. 它能将2元素组的 结构体数组 转为 数组结构体).
    Mnemonic: element_ref(i, data0, data1) := (0==(i&1))?( x[i2] ):( y[i2] ), i2 := i/2.
  • YGroup2ZipHigh: Interleave 2 vectors into 2-element groups and returns the data in the high position. (将2个向量交织为2-元素组, 并返回高位置的数据).
    Mnemonic: rt[i] := (0==(i&1))?( x[i2] ):( y[i2] ), i2 := (i+T.Count)/2.
  • YGroup2ZipLow: Interleave 2 vectors into 2-element groups and returns the data in the low position. (将2个向量交织为2-元素组, 并返回低位置的数据).
    Mnemonic: rt[i] := (0==(i&1))?( x[i2] ):( y[i2] ), i2 := i/2.
  • YGroup3Unzip[/_Bit128]: De-Interleave 3-element groups into 3 vectors. It converts the 3-element groups AoS to SoA. It can also deinterleave packed RGB pixel data into R,G,B planar data (将3-元素组解交织为3个向量. 它能将3元素组的 数组结构体 转为 结构体数组. 它还能将 已打包的RGB像素数据, 解交织为 R,G,B 平面数据).
    Mnemonic: x[i] =: element_ref(3*i, data0, data1, data2), y[i] =: element_ref(3*i+1, data0, data1, data2), z[i] =: element_ref(3*i+2, data0, data1, data2).
  • YGroup3UnzipX2[/_Bit128]: De-Interleave 3-element groups into 3 vectors and process 2x data (将3-元素组解交织为3个向量, 且处理2倍数据).
    Mnemonic: (x, y, z) = YGroup3Unzip(data0, data1, data2), (xB, yB, zB) = YGroup3Unzip(data3, data4, data5).
  • YGroup3Zip[/_Bit128]: Interleave 3 vectors into 3-element groups. It converts the 3-element groups SoA to AoS. It can also interleave R,G,B planar data into packed RGB pixel data (将3个向量交织为3-元素组. 它能将3元素组的 结构体数组 转为 数组结构体. 它还能将 R,G,B 平面数据, 交织为 已打包的RGB像素数据).
    Mnemonic: element_ref(i, data0, data1, data2) := (0==(i%3))?( x[i2] ):( (1==(i%3))?( y[i2] ):( z[i2] ) ), i2 := i/3.
  • YGroup3ZipX2[/_Bit128]: Interleave 3 vectors into 3-element groups and process 2x data (将3个向量交织为3-元素组, 且处理2倍数据).
    Mnemonic: (data0, data1, data2) = YGroup3Zip(x, y, z), (data3, data4, data5) = YGroup3Zip(xB, yB, zB).
  • YGroup4Unzip[/_Bit128]: De-Interleave 4-element groups into 4 vectors. It converts the 4-element groups AoS to SoA. It can also deinterleave packed RGBA pixel data into R,G,B,A planar data (将4-元素组解交织为4个向量. 它能将4元素组的 数组结构体 转为 结构体数组. 它还能将 已打包的RGBA像素数据, 解交织为 R,G,B,A 平面数据).
    Mnemonic: x[i] =: element_ref(4*i, data0, data1, data2, data3), y[i] =: element_ref(4*i+1, data0, data1, data2, data3), z[i] =: element_ref(4*i+2, data0, data1, data2, data3), w[i] =: element_ref(4*i+3, data0, data1, data2, data3).
  • YGroup4Zip[/_Bit128]: Interleave 4 vectors into 4-element groups. It converts the 4-element groups SoA to AoS. It can also interleave R,G,B,A planar data into packed RGBA pixel data (将4个向量交织为4-元素组. 它能将4元素组的 结构体数组 转为 数组结构体. 它还能将 R,G,B,A 平面数据, 交织为 已打包的RGBA像素数据).
    Mnemonic: element_ref(i, data0, data1, data2, data3) := (0==(i&3))?( x[i2] ):( (1==(i&3))?( y[i2] ):( (2==(i&3))?( z[i2] ):( w[i2] ) ) ), i2 := i/4.
  • YGroup6Unzip_Bit128: De-Interleave 6-element groups into 6 vectors. It converts the 6-element groups AoS to SoA (将6-元素组解交织为6个向量. 它能将6元素组的 数组结构体 转为 结构体数组). It is specialized for process 128-bit element (它专门用于处理128位元素).
    Mnemonic: x[i] =: element_ref(6*i, data0, data1, data2, data3, data4, data5), y[i] =: element_ref(6*i+1, data0, data1, data2, data3, data4, data5), z[i] =: element_ref(6*i+2, data0, data1, data2, data3, data4, data5), w[i] =: element_ref(6*i+3, data0, data1, data2, data3, data4, data5), u[i] =: element_ref(6*i+4, data0, data1, data2, data3, data4, data5), v[i] =: element_ref(6*i+5, data0, data1, data2, data3, data4, data5).
  • YGroup6Zip_Bit128: Interleave 6 vectors into 6-element groups. It converts the 6-element groups SoA to AoS (将6个向量交织为6-元素组. 它能将6元素组的 结构体数组 转为 数组结构体). It is specialized for process 128-bit element (它专门用于处理128位元素).
    Mnemonic: element_ref(i, data0, data1, data2, data3, data4, data5) := (0==(i%6))?( x[i2] ):( (1==(i%6))?( y[i2] ):( (2==(i%6))?( z[i2] ):( (3==(i%6))?( w[i2] ):( (4==(i%6))?( u[i2] ):( v[i2] ) ) ) ) ), i2 := i/6.

对于 3-元素组的交织,有一种算法是可以同时处理2倍数据的,于是提供了 YGroup3UnzipX2、YGroup3ZipX2 方法。且这些算法的内部需要处理“128位6-元素组”的交织,于是还暴露了 YGroup6Unzip_Bit128、YGroup6Zip_Bit128 方法。

YGroup3Unzip的范例代码

下面是范例代码。

private static void ShowYGroup3Unzip(TextWriter writer) {
    writer.WriteLine("[YGroup3Unzip]");
    // Byte
    int cnt = Vector<byte>.Count;
    var a0 = Vectors.CreateByDoubleLoop<byte>(0, 1);
    var a1 = Vectors.CreateByDoubleLoop<byte>(cnt * 1, 1);
    var a2 = Vectors.CreateByDoubleLoop<byte>(cnt * 2, 1);
    var s0 = Vectors.YGroup3Unzip(a0, a1, a2, out var s1, out var s2);
    var t0 = Vectors.YGroup3Zip(s0, s1, s2, out var t1, out var t2);
    VectorTextUtil.WriteLine(writer, "Before      :\t{0}, {1}, {2}", a0, a1, a2);
    VectorTextUtil.WriteLine(writer, "YGroup3Unzip:\t{0}, {1}, {2}", s0, s1, s2);
    VectorTextUtil.WriteLine(writer, "YGroup3Zip  :\t{0}, {1}, {2}", t0, t1, t2);
    writer.WriteLine();
}

这个方法里,先使用 CreateByDoubleLoop 创建向量,使 a0、a1、a2 为连续的数字。

随后使用 YGroup3Unzip 对这3个向量进行 3-元素组的解交织,结果存储到 s0、s1、s2。若 a0、a1、a2 存储的是 已打包的RGB像素值 的话,可以看出 R、G、B 通道的数值正好被分离到 s0、s1、s2 这3个向量里了。

再使用 YGroup3Zip 对这3个向量进行 3-元素组的交织,结果存储到 t0、t1、t2。它们与先前的 a0、a1、a2 的值相同。

下面是输出结果。

[YGroup3Unzip]
Before      :   <0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31>, <32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63>, <64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95>      # (00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F), (20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F), (40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F)
YGroup3Unzip:   <0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93>, <1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49, 52, 55, 58, 61, 64, 67, 70, 73, 76, 79, 82, 85, 88, 91, 94>, <2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 56, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95>      # (00 03 06 09 0C 0F 12 15 18 1B 1E 21 24 27 2A 2D 30 33 36 39 3C 3F 42 45 48 4B 4E 51 54 57 5A 5D), (01 04 07 0A 0D 10 13 16 19 1C 1F 22 25 28 2B 2E 31 34 37 3A 3D 40 43 46 49 4C 4F 52 55 58 5B 5E), (02 05 08 0B 0E 11 14 17 1A 1D 20 23 26 29 2C 2F 32 35 38 3B 3E 41 44 47 4A 4D 50 53 56 59 5C 5F)
YGroup3Zip  :   <0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31>, <32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63>, <64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95>      # (00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F), (20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F), (40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F)

由于是在支持Avx2指令集的X86电脑上运行,故向量是256位的。

使用 YGroup3Unzip与YGroup3Zip,能很方便处理RGB像素值。一般步骤为:先用 YGroup3Unzip进行解交织,然后分别对3个通道的数据进行处理。最后使用 YGroup3Zip,将3个通道的数据,交织为已打包的RGB像素值。

提供重新构造组的向量方法

将 3-元素组 与 4-元素组 进行转换,虽然可以先解交织(Unzip),然后再做交织处理(Zip)。但是有些算法的性能更高,于是本库提供了重新构造组的向量方法。相关方法的说明见下。

  • YGroup1ToGroup3: Convert a 1-element group, to a 3-element group. It also converts grayscale pixel data to packed RGB pixel data (将1-元素组, 转为3-元素组. 它还能将 灰度像素数据, 转换为 已打包的RGB像素数据).
    Mnemonic: View for group: (result0, result1, result2) = YGroup3Zip(x, x, x). View for element: element_ref(i, result0, result1, result2) := x[i/3].
  • YGroup1ToGroup4: Convert a 1-element group, to a 4-element group. It also converts grayscale pixel data to packed RGBA pixel data (将1-元素组, 转为4-元素组. 它还能将 灰度像素数据, 转换为 已打包的RGBA像素数据).
    Mnemonic: View for group: (result0, result1, result2, result4) = YGroup4Zip(x, x, x, x). View for element: element_ref(i, result0, result1, result2, result4) := x[i/4].
  • YGroup1ToGroup4WithW: Convert a 1-element group and w argument, to a 4-element group. It also converts grayscale pixel data to packed RGBA pixel data (将1-元素组及w参数, 转为4-元素组. 它还能将 灰度像素数据, 转换为 已打包的RGBA像素数据).
    Mnemonic: View for group: (result0, result1, result2, result4) = YGroup4Zip(x, x, x, w). View for element: element_ref(i, result0, result1, result2, result4) := ((i%4)<3)?( x[i2] ):( w[i2] ), i2 := i/4.
  • YGroup3ToGroup4: Convert a 3-element group, to a 4-element group. It also converts packed RGB pixel data to packed RGBA pixel data (将3-元素组, 转为4-元素组. 它还能将 已打包的RGB像素数据, 转换为 已打包的RGBA像素数据).
    Mnemonic: View for group: (result0, result1, result2, result3) = YGroup4Zip(YGroup3Unzip(data0, data1, data2), Vector.Zero)). View for element: element_ref(i, result0, result1, result2, result3) := (3!=(i%4))?element_ref((i/4)*3+(i%4), data0, data1, data2):0.
  • YGroup4ToGroup3: Convert a 4-element group, to a 3-element group. It also converts packed RGBA pixel data to packed RGB pixel data (将4-元素组, 转为3-元素组. 它还能将 已打包的RGBA像素数据, 转换为 已打包的RGB像素数据).
    Mnemonic: View for group: (result0, result1, result2) = YGroup3Zip(YGroup4Unzip(data0, data1, data2, data3))). View for element: element_ref(i, result0, result1, result2) := element_ref((i/3)*4+(i%3), data0, data1, data2, data3).

提供转置的向量方法

相关方法的说明见下。

  • YGroup2Transpose: Transpose a 22 matrix (对22矩阵进行转置).
    Mnemonic: result0[i] := (0==(i&1))?( x[i&~1] ):( y[i&~1] ), result1[i] := (0==(i&1))?( x[(i&~1) + 1] ):( y[(i&~1) + 1] ).
  • YGroup2TransposeEven: Transpose a 22 matrix and return a data in even positions (对22矩阵进行转置, 并返回偶数位置的数据).
    Mnemonic: rt[i] := (0==(i&1))?( x[i&~1] ):( y[i&~1] ).
  • YGroup2TransposeOdd: Transpose a 22 matrix and return a data in odd positions (对22矩阵进行转置, 并返回奇数位置的数据).
    Mnemonic: rt[i] := (0==(i&1))?( x[(i&~1) + 1] ):( y[(i&~1) + 1] ).

对于熟悉 Arm 架构中AdvSimd指令集的朋友来说,很容易看出它们借鉴了 AdvSimd.Arm64.TransposeEvenAdvSimd.Arm64.TransposeOdd

提供多向量换位的向量方法

.NET8增加了Arm架构的多寄存器的查表函数(VectorTableLookup/VectorTableLookupExtension)。
单个向量查表(如 vqvtbl1q_u8)时,只能在 16字节(128位)的范围内进行查表。而使用4个向量查表(如 vqtbl4q_u8 )时,能在 16*4=64字节(512位)的范围内进行查表。

且.NET8.0增加了对Avx512系列指令集的支持。Avx512提供了2个向量查表的指令,例如 VPERMI2B。

本库参考了这2类指令,提供了 2~4个向量换位的方法。即下面的这些方法。

  • YShuffleX2[/_Args/_Core]: Shuffle and clear on 2 vectors (在2个向量上进行换位并清零). Creates a new vector by selecting values from an input vector using a set of indices (通过使用一组索引从输入向量中选择值,来创建一个新向量). If the indices value is out of range, the element will be cleared (若索引值超出范围, 元素会被清零).
    Mnemonic: rt[i] := (0<=indices[i] && indices[i]<(Count*2))?( element_ref(indices[i], vector0, vector1) ):0.
  • YShuffleX2Insert[/_Args/_Core]: Shuffle and insert on 2 vectors (在2个向量上进行换位并插入). Creates a new vector by selecting values from an input vector using a set of indices (通过使用一组索引从输入向量中选择值,来创建一个新向量). If the index value is out of range, the elements of the background vector will be inserted (若索引值超出范围, 会插入背景向量的元素).
    Mnemonic: rt[i] := (0<=indices[i] && indices[i]<(Count*2))?( element_ref(indices[i], vector0, vector1) ):back[i].
  • YShuffleX2Kernel[/_Args/_Core]: Only shuffle on 2 vectors (在2个向量上进行仅换位). Creates a new vector by selecting values from an input vector using a set of indices (通过使用一组索引从输入向量中选择值,来创建一个新向量). If the index value is out of range, the result is undefined (若索引值超出范围, 结果是未定义的). You can use the IndexMask mask to constrain the parameters (可使用 IndexMask 掩码来约束参数).
    Mnemonic: rt[i] := element_ref(indices[i], vector0, vector1). Conditions: 0<=indices[i] && indices[i]<(Count*2).
  • YShuffleX3[/_Args/_Core]: Shuffle and clear on 3 vectors (在3个向量上进行换位并清零). Creates a new vector by selecting values from an input vector using a set of indices (通过使用一组索引从输入向量中选择值,来创建一个新向量). If the indices value is out of range, the element will be cleared (若索引值超出范围, 元素会被清零).
    Mnemonic: rt[i] := (0<=indices[i] && indices[i]<3*Count)?( element_ref(indices[i], vector0, vector1, vector2) ):0.
  • YShuffleX3Insert[/_Args/_Core]: Shuffle and insert on 3 vectors (在3个向量上进行换位并插入). Creates a new vector by selecting values from an input vector using a set of indices (通过使用一组索引从输入向量中选择值,来创建一个新向量). If the index value is out of range, the elements of the background vector will be inserted (若索引值超出范围, 会插入背景向量的元素).
    Mnemonic: rt[i] := (0<=indices[i] && indices[i]<3*Count)?( element_ref(indices[i], vector0, vector1, vector2) ):back[i].
  • YShuffleX3Kernel[/_Args/_Core]: Only shuffle on 3 vectors (在3个向量上进行仅换位). Creates a new vector by selecting values from an input vector using a set of indices (通过使用一组索引从输入向量中选择值,来创建一个新向量). If the index value is out of range, the result is undefined (若索引值超出范围, 结果是未定义的).
    Mnemonic: rt[i] := element_ref(indices[i], vector0, vector1, vector2). Conditions: 0<=indices[i] && indices[i]<(Count*3).
  • YShuffleX4[/_Args/_Core]: Shuffle and clear on 4 vectors (在4个向量上进行换位并清零). Creates a new vector by selecting values from an input vector using a set of indices (通过使用一组索引从输入向量中选择值,来创建一个新向量). If the indices value is out of range, the element will be cleared (若索引值超出范围, 元素会被清零).
    Mnemonic: rt[i] := (0<=indices[i] && indices[i]<(Count*4))?( element_ref(indices[i], vector0, vector1, vector2, vector3) ):0.
  • YShuffleX4Insert[/_Args/_Core]: Shuffle and insert on 4 vectors (在4个向量上进行换位并插入). Creates a new vector by selecting values from an input vector using a set of indices (通过使用一组索引从输入向量中选择值,来创建一个新向量). If the index value is out of range, the elements of the background vector will be inserted (若索引值超出范围, 会插入背景向量的元素).
    Mnemonic: rt[i] := (0<=indices[i] && indices[i]<(Count*4))?( element_ref(indices[i], vector0, vector1, vector2, vector3) ):back[i].
  • YShuffleX4Kernel[/_Args/_Core]: Only shuffle on 4 vectors (在4个向量上进行仅换位). Creates a new vector by selecting values from an input vector using a set of indices (通过使用一组索引从输入向量中选择值,来创建一个新向量). If the index value is out of range, the result is undefined (若索引值超出范围, 结果是未定义的). You can use the IndexMask mask to constrain the parameters (可使用 IndexMask 掩码来约束参数).
    Mnemonic: rt[i] := element_ref(indices[i], vector0, vector1, vector2, vector3). Conditions: 0<=indices[i] && indices[i]<(Count*4).
Shuffle方法所用到的指令
Architecture8bit16bit32bit64bit
Armvqvtbl1q_u8(None)(None)(None)
Wasmi8x16.swizzle(None)(None)(None)
X86_mm_shuffle_epi8(Ssse3)_mm_permutexvar_epi16(Avx512BW)_mm256_permutevar8x32_epi32(Avx2)_mm256_permutexvar_epi64(Avx512F)

“(None)”表示该架构没有提供对应的指令,需要多条指令组合才能实现。

YShuffleX2方法所用到的指令
Architecture8bit16bit32bit64bit
Armvqtbl2q_u8(None)(None)(None)
Wasm(None)(None)(None)(None)
X86_mm_permutex2var_epi8(Avx512Vbmi)_mm_permutex2var_epi16(Avx512BW)_mm_permutex2var_epi32(Avx512F)_mm_permutex2var_epi64(Avx512F)
YShuffleX3方法所用到的指令
Architecture8bit16bit32bit64bit
Armvqtbl3q_u8(None)(None)(None)
Wasm(None)(None)(None)(None)
X86(None)(None)(None)(None)
YShuffleX4方法所用到的指令
Architecture8bit16bit32bit64bit
Armvqtbl4q_u8(None)(None)(None)
Wasm(None)(None)(None)(None)
X86(None)(None)(None)(None)

简化了无符号数的处理

相关日志:

  • Provides vector methods for compare (提供比较的向量方法): GreaterThan_Unsigned.
  • Provides extension method for vectors (提供向量的扩展方法): AsSigned, AsUnsigned.

有时需要对有符号整数元素的向量类型,进行一些无符号处理。这是需要使用 As进行转型,且处理完毕后再用 As 将类型转换回来。As 方法不能自动填充泛型参数,而是需要手动填写,写起来很繁琐、臃肿。

于是本库为向量类型提供了 AsSigned, AsUnsigned 扩展方法。能直接转换为对应的 有符号或无符号 类型,不用再手动填写类型参数。
而且为了最常用的“无符号比较”功能,为向量类型提供了 GreaterThan_Unsigned 方法.

Vector128s 等类增加了 IsHardwareAccelerated 属性

相关日志:

  • The IsHardwareAccelerated property has been added to the Vectors(/Vector128s/Vector256s/Vector512s) classes (Vectors(/Vector128s/Vector256s/Vector512s) 类增加了 IsHardwareAccelerated 属性).

.NET 7.0 开始, Vector128 等向量类型增加了 IsHardwareAccelerated, 用于检测是否支持硬件加速。
为了便于早期版本 .NET 的使用,本库给 Vectors(/Vector128s/Vector256s/Vector512s) 类型也增加了 IsHardwareAccelerated。即使低于 .NET 7.0, 也能通过该属性来检测是否有硬件加速。

增加了128位整数类型,使向量类型能支持128位整数

相关日志:

  • Added 128-bit integer type - ExInt128/ExUInt128 (增加了128位整数类型 - ExInt128/ExUInt128).
  • (Experimental) Experimentally added the ExType(Extended type) mechanism to enable vector types to support 128-bit integers(ExInt128/ExUInt128). However, it is found that some functions do not work properly under some .NET versions. Therefore, it is recommended to prioritize using functions with the suffix “_Bit128” instead of ExType (实验性的增加了 ExType(扩展类型) 机制, 使向量类型能支持128位整数(ExInt128/ExUInt128). 但发现某些.NET版本下,个别函数的工作不正常. 故建议优先使用“_Bit128”后缀的函数, 而不是 ExType).

增加了128位整数类型

.NET 7.0 开始, 官方类库中增加了128位整数类型, 即 Int128与UInt128。

在处理某些向量类型的算法时,需要以 128位元素为单位进行处理。由于Int128与UInt128是.NET 7.0才提供的,为了兼容早期版本的 .NET,本库在“Zyl.VectorTraits.ExTypes”命名空间里增加了128位整数类型。

  • ExInt128: 表示 128 位有符号整数. 它与 Int128 是二进制兼容的.
  • ExUInt128: 表示 128 位无符号整数. 它与 UInt128 是二进制兼容的.

它们的用法,与 Int128与UInt128 是完全相同的。

使向量类型能支持128位整数

Vector128 等向量类型为了避免程序员误操作,故在很多地方增加了类型检查。只有在使用它所允许的数字类型时才能正常工作,而对其他类型,会报异常。

本库实验性的增加了 ExType(扩展类型) 机制, 使向量类型能支持128位整数(ExInt128/ExUInt128). 具体办法是增加了一系列以“Ex”开头的扩展方法,它们利用 Unsafe类的功能,绕过了类型检查。

但发现某些.NET版本下,个别函数的工作不正常. 故建议优先使用“_Bit128”后缀的函数, 而不是 ExType。例如使用“YGroup2Unzip_Bit128”等方法.

ExType的范例

下面介绍一下ExType机制的范例。虽然目前不建议使用,但可以给有兴趣的开发者试试。

ExType的范例1 - ShowExTypes(显示含有扩展类型的向量)

下面是范例代码。

private static void ShowExTypes(TextWriter writer) {
    writer.WriteLine("[ExTypes]");
    // -- Create (创建) --
    //Vector<ExInt128> temp = new Vector<ExInt128>((ExInt128)0x102); // System.NotSupportedException: Specified type is not supported
    Vector<ExInt128> temp = Vectors.Create((ExInt128)0x102);

    // -- ToString (转字符串) --
    //writer.WriteLine("ToString:\t" + temp.ToString()); // System.NotSupportedException: Specified type is not supported
    //writer.WriteLine(string.Format("Format:\t{0}", temp)); // System.NotSupportedException: Specified type is not supported
    //writer.WriteLine($"InterpolatedString:\t{temp}."); // System.NotSupportedException: Specified type is not supported
    writer.WriteLine("ToString:\t" + ExVectorUtil.Format(temp));
    writer.WriteLine(ExVectorUtil.Format("Format:\t{0}", temp));
#if NETCOREAPP1_0_OR_GREATER || NET461_OR_GREATER
    writer.WriteLine(ExVectorUtil.ToString($"InterpolatedString:\t{temp}."));
#endif
    VectorTextUtil.WriteLine(writer, "ValueWithHex:\t{0}", temp);

    // -- Property (属性) --
    //VectorTextUtil.WriteLine(writer, "Count:\t{0}", Vector<ExInt128>.Count); // System.NotSupportedException: Specified type is not supported
    //VectorTextUtil.WriteLine(writer, "Zero:\t{0}", Vector<ExInt128>.Zero); // System.NotSupportedException: Specified type is not supported
    VectorTextUtil.WriteLine(writer, "Count:\t{0}", Vectors<ExInt128>.Count);
    VectorTextUtil.WriteLine(writer, "Zero:\t{0}", Vectors<ExInt128>.Zero);

    // -- Equals (相等) --
    //VectorTextUtil.WriteLine(writer, "Equals zero:\t{0}", Vectors<ExInt128>.Zero.Equals(temp)); // System.NotSupportedException: Specified type is not supported
    VectorTextUtil.WriteLine(writer, "Equals zero:\t{0}", Vectors<ExInt128>.Zero.BitEquals(temp));

    // -- Reinterprets (重新解释) --
    VectorTextUtil.WriteLine(writer, "ExAsInt64:\t{0}", temp.ExAsInt64());

    // -- Done --
    writer.WriteLine();
}

创建变量时,若使用new Vector<ExInt128> ,会遇到NotSupportedException异常。改为用 Vectors.Create((ExInt128)...) 之后便能顺利的创建 元素类型为ExInt128的向量.

创建好向量后,若直接用 WriteLine输出, 或是用 格式化字符串(string.Format)、插值字符串 ,会遇到NotSupportedException异常。 改为使用 ExVectorUtil 的方法后, 能顺利的输出。还可以使用 VectorTextUtil 里的方法,它不仅能输出格式化后的字符串,且自动在末尾拼接了十六进制值,便于观察数据。

在访问 Vector 的属性(如 Count、Zero)或方法(如 Equals)时,会遇到NotSupportedException异常。 改为使用 Vectors 的属性或方法后,便能顺利执行了。

本库还提供了“ExAs”开头的扩展方法,能够对向量类型进行重新解释。例如使用 ExAsInt64,能够将含有扩展类型的向量,安全的转换为 Int64向量。

下面是输出结果。

ToString:       <258, 258>
Format: <258, 258>
InterpolatedString:     <258, 258>.
ValueWithHex:   <258, 258>      # (00000000000000000000000000000102 00000000000000000000000000000102)
Count:  2       # (2)
Zero:   <0, 0>  # (00000000000000000000000000000000 00000000000000000000000000000000)
Equals zero:    False
ExAsInt64:      <258, 0, 258, 0>        # (0000000000000102 0000000000000000 0000000000000102 0000000000000000)

由于是在支持Avx2指令集的X86电脑上运行,故向量是256位的。

ExType的范例2 - YGroup2Zip(2-元素组的交织)

下面是范例代码。

private static void ShowYGroup2Zip(TextWriter writer) {
    writer.WriteLine("[YGroup2Zip]");
#if NETCOREAPP3_0_OR_GREATER
    // Int64
    var a0 = Vector256s.CreateByDoubleLoop<long>(0, 2);
    var a1 = Vector256s.CreateByDoubleLoop<long>(1, 2);
    var s0 = Vector256s.YGroup2Zip(a0, a1, out var s1);
    var t0 = Vector256s.YGroup2Unzip(s0, s1, out var t1);
    VectorTextUtil.WriteLine(writer, "Before      :\t{0}, {1}", a0, a1);
    VectorTextUtil.WriteLine(writer, "YGroup2Zip  :\t{0}, {1}", s0, s1);
    VectorTextUtil.WriteLine(writer, "YGroup2Unzip:\t{0}, {1}", t0, t1);
    // Int128 - ExType
    var b0 = a0.ExAsExInt128();
    var b1 = a1.ExAsExInt128();
    var c0 = Vector256s.YGroup2Zip(b0, b1, out var c1);
    var d0 = c0.ExAsInt64();
    var d1 = c1.ExAsInt64();
    VectorTextUtil.WriteLine(writer, "ExAsExInt128:\t{0}, {1}", b0, b1);
    VectorTextUtil.WriteLine(writer, "YGroup2Zip  :\t{0}, {1}", c0, c1);
    VectorTextUtil.WriteLine(writer, "ExAsInt64   :\t{0}, {1}", d0, d1);
    // Int128 - _Bit128
    var e0 = Vector256s.YGroup2Zip_Bit128(a0, a1, out var e1);
    VectorTextUtil.WriteLine(writer, "_Bit128     :\t{0}, {1}", e0, e1);
#endif // NETCOREAPP3_0_OR_GREATER
    writer.WriteLine();
}

这个方法里,先使用 CreateByDoubleLoop 创建向量——

  • a0: 由偶数组成的向量(0, 2, 4, 6)。故CreateByDoubleLoop的参数里,起始值为0,步长为2。
  • a1: 由奇数组成的向量(1, 3, 5, 7)。故CreateByDoubleLoop的参数里,起始值为1,步长为2。

随后使用 YGroup2Zip 对这2个向量进行2元素组的交织,会得到连续的数字。s0存储了前半部分(0, 1, 2, 3),s1存储了后半部分(4, 5, 6, 7)。

再使用 YGroup2Unzip 对这2个向量进行2元素组的解交织,得到了——由偶数组成的向量t0、由奇数组成的向量t1。它们与先前的 a0、a1 的值相同。

除了 8~64 位的交织外,有时需要对128位元素进行交织。本库提供了2种办法:

  1. 第一种办法是使用 ExType 机制。先使用 ExAsExInt128 扩展方法,将类型转为 Vector256<ExInt128>,随后调用 YGroup2Zip 便是按128位元素来处理了。最后使用 ExAsInt64 扩展方法,将类型转回为 Vector256<Int64>
  2. 另一种办法是使用“_Bit128”后缀的函数。例如对于2元素组的交织,可使用 YGroup2Zip_Bit128。它是泛型函数,返回值的类型与输入参数相同,都是 Vector256<Int64>

下面是输出结果。

Output of 256-bit vectors on X86 architecture:
Before      :   <0, 2, 4, 6>, <1, 3, 5, 7>      # (0000000000000000 0000000000000002 0000000000000004 0000000000000006), (0000000000000001 0000000000000003 0000000000000005 0000000000000007)
YGroup2Zip  :   <0, 1, 2, 3>, <4, 5, 6, 7>      # (0000000000000000 0000000000000001 0000000000000002 0000000000000003), (0000000000000004 0000000000000005 0000000000000006 0000000000000007)
YGroup2Unzip:   <0, 2, 4, 6>, <1, 3, 5, 7>      # (0000000000000000 0000000000000002 0000000000000004 0000000000000006), (0000000000000001 0000000000000003 0000000000000005 0000000000000007)
ExAsExInt128:   <36893488147419103232, 110680464442257309700>, <55340232221128654849, 129127208515966861317>    # (00000000000000020000000000000000 00000000000000060000000000000004), (00000000000000030000000000000001 00000000000000070000000000000005)
YGroup2Zip  :   <36893488147419103232, 55340232221128654849>, <110680464442257309700, 129127208515966861317>    # (00000000000000020000000000000000 00000000000000030000000000000001), (00000000000000060000000000000004 00000000000000070000000000000005)
ExAsInt64   :   <0, 2, 1, 3>, <4, 6, 5, 7>      # (0000000000000000 0000000000000002 0000000000000001 0000000000000003), (0000000000000004 0000000000000006 0000000000000005 0000000000000007)
_Bit128     :   <0, 2, 1, 3>, <4, 6, 5, 7>      # (0000000000000000 0000000000000002 0000000000000001 0000000000000003), (0000000000000004 0000000000000006 0000000000000005 0000000000000007)

发现某些.NET版本下,个别函数的ExType工作不正常. 故建议优先使用“_Bit128”后缀的函数, 而不是 ExType。

增加了MathBitOperations类,增加了对应的数学函数

相关日志:

  • The MathBitOperations class has been added. It provides these functions (增加了 MathBitOperations 类. 它提供了这些函数): Crc32C, IsPow2, LeadingZeroCount, Log2, PopCount, RoundUpToPowerOf2, RotateLeft, RotateRight, TrailingZeroCount.

改进UnsafeUtil类

相关日志:

  • Package “System.Runtime.CompilerServices.Unsafe” upgraded to version 5.0.0. UnsafeUtil obsoletes methods such as IsNullRef, NullRef, SkipInit (Unsafe包升级到 5.0.0 版. UnsafeUtil 废弃了 IsNullRef 等函数).
  • The UnsafeUtil class add methods (UnsafeUtil类增加了方法): GetArrayDataReference, Dec, Inc, PreDec, PreInc, PostDec, PostDecExcept, PostDecExceptZero, PostInc, PostIncExcept, PostIncExceptZero .

Unsafe包升级到 5.0.0 版。从而能够使用原生的 IsNullRef 等函数,一些底层操作改善了性能。
UnsafeUtil还增加了Inc、Dec等方法,使引用能像指针那样能够增减地址(++--)。简化了地址计算。

优化

相关日志:

  • Optimize type conversion for vector generic types by replacing (object) with the As method (优化向量泛型类型的类型转换, 用 As 方法取代 (object)).
  • Optimize the combining of two vectors, using WithUpper instead of Create (优化两个向量的组合, 用 WithUpper 代替 Create). e,g, Narrow and more.
  • Optimized hardware acceleration of YBitToByte, YBitToInt16, YBitToInt32, YBitToInt64 methods on all architecture. It no longer uses OnesComplement (优化YBitToByte, YBitToInt16, YBitToInt32, YBitToInt64方法在所有架构的硬件加速. 它不再使用 OnesComplement).
  • Optimized hardware acceleration of Shuffle/YShuffleInsert methods on X86 architecture. Use EqualsShift arithmetic (优化Shuffle/YShuffleInsert方法在X86架构的硬件加速. 使用 EqualsShift 算法). For 16~64 bit types.
  • Fix all YShuffleG4X2 methods, remove redundant ConstantExpected attribute(修正所有 YShuffleG4X2 方法, 移除多余的 ConstantExpected 特性).

废弃内容说明

相关日志:

  • Removal of obsolete project file VectorTraits_vs2019.sln (移除过时的项目文件 VectorTraits_vs2019.sln).
  • Deprecation notice: Deprecation notice: The next version will remove such as WVectorTraits128AdvSimdB64/WVectorTraits128Avx2 classes (废弃预告: 下个版本将会移除 WVectorTraits128AdvSimdB64, WVectorTraits128Avx2 等类).

基准测试结果

数据的单位: 百万次操作/秒. 数字越大, 性能越好.

ShiftLeft

ShiftLeft: 将向量的每个元素左移指定量.
它是.NET 7.0所新增的向量方法.

ShiftLeft - X86 - AMD Ryzen 7 7840H
TypeMethod.NET Framework.NET Core 2.1.NET Core 3.1.NET 5.0.NET 6.0.NET 7.0.NET 8.0
ByteSumSLLScalar1062.0461025.9361287.8651265.4461445.5751416.7121693.330
ByteSumSLLNetBcl1344.7381109.752
ByteSumSLLNetBcl_Const1281.9011164.382
ByteSumSLLTraits11312.49910715.92028897.86828611.23428219.20534068.74157456.802
ByteSumSLLTraits_Core55791.67552165.73253563.42168653.35959916.62267868.29174889.177
ByteSumSLLConstTraits13408.91612604.41238925.38857842.08157095.29462012.69262729.225
ByteSumSLLConstTraits_Core56843.52355673.52853642.48462674.39765797.70850869.84073873.979
Int16SumSLLScalar1081.716999.7671261.4751198.1111218.7671365.7541547.294
Int16SumSLLNetBcl32011.64634816.284
Int16SumSLLNetBcl_Const39975.92437368.541
Int16SumSLLTraits6752.3496185.96825221.85626382.70827125.95532617.94436448.716
Int16SumSLLTraits_Core34727.28331457.23831800.31032231.55335687.99637750.30530731.745
Int16SumSLLConstTraits6037.3676498.81927783.52637605.55940699.91439598.66336242.630
Int16SumSLLConstTraits_Core37678.43534784.61632625.54333694.33840019.32539380.40436914.775
Int32SumSLLScalar1369.1401315.8521514.6901521.5162284.6702484.4072409.358
Int32SumSLLNetBcl17373.56715954.004
Int32SumSLLNetBcl_Const17967.08015983.409
Int32SumSLLTraits3762.3743511.43313343.30412906.29312661.42317279.76015886.410
Int32SumSLLTraits_Core17324.27515468.38114587.93717407.82317886.65118052.16214126.571
Int32SumSLLConstTraits3910.6003724.41212646.54515290.34017745.99217829.07815991.615
Int32SumSLLConstTraits_Core16235.15414216.59815282.56516088.40017940.33015961.16616378.506
Int64SumSLLScalar1394.7191281.1561517.9381441.1602270.5212508.5772421.558
Int64SumSLLNetBcl7528.1848530.835
Int64SumSLLNetBcl_Const8743.5048471.981
Int64SumSLLTraits483.430494.3356677.5446570.7116635.0706891.7057469.236
Int64SumSLLTraits_Core479.761488.8277758.5158525.7848596.2908267.8557879.060
Int64SumSLLConstTraits509.585525.1957036.2236787.1018246.6018254.8808526.022
Int64SumSLLConstTraits_Core512.652528.3818229.9548747.1258711.5238871.9488647.339

说明:

  • 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 8.0的值为“73873.979”, 性能是 标量算法的 73873.979/1693.330≈43.6264 倍, 且是BCL方法的 73873.979/1164.382≈63.4448 倍.
因为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
TypeMethod.NET Core 3.1.NET 5.0.NET 6.0.NET 7.0.NET 8.0
ByteSumSLLScalar606.721607.751674.256890.8781238.814
ByteSumSLLNetBcl19585.98219831.927
ByteSumSLLNetBcl_Const19564.84019840.232
ByteSumSLLTraits5541.53213075.25913190.70513209.92719844.497
ByteSumSLLTraits_Core14048.51116947.48515828.57119589.43019841.525
ByteSumSLLConstTraits9734.87015699.31515853.77219511.95219811.385
ByteSumSLLConstTraits_Core13007.02816817.24715838.06019422.22219839.627
Int16SumSLLScalar606.135603.800605.734820.8801031.035
Int16SumSLLNetBcl9943.2209803.495
Int16SumSLLNetBcl_Const9937.6399837.136
Int16SumSLLTraits4215.3696547.5146558.2999923.0889839.256
Int16SumSLLTraits_Core7918.6888431.9347892.2359939.4699839.496
Int16SumSLLConstTraits6568.6067829.8607887.8429925.9889839.534
Int16SumSLLConstTraits_Core8494.5508416.7967902.4449914.3849823.608
Int32SumSLLScalar747.656746.013749.1081406.1221410.137
Int32SumSLLNetBcl4926.6514826.909
Int32SumSLLNetBcl_Const4917.7324840.232
Int32SumSLLTraits3293.9433269.1293278.3034925.4884836.941
Int32SumSLLTraits_Core4210.8113930.6193927.4084923.8674844.083
Int32SumSLLConstTraits3275.9863249.8093923.1764926.4634846.238
Int32SumSLLConstTraits_Core4205.2454199.1554156.6344925.4484844.679
Int64SumSLLScalar739.137729.158741.6731372.4801296.655
Int64SumSLLNetBcl2477.0252264.032
Int64SumSLLNetBcl_Const2473.1022251.272
Int64SumSLLTraits486.7341638.8351636.2331985.5962285.512
Int64SumSLLTraits_Core489.5542075.2731967.9022474.1052289.521
Int64SumSLLConstTraits467.3931930.8211968.7982471.1242308.745
Int64SumSLLConstTraits_Core466.2932074.6561968.8342476.6022281.018

说明:

  • 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 - AMD Ryzen 7 7840H
TypeMethod.NET Framework.NET Core 2.1.NET Core 3.1.NET 5.0.NET 6.0.NET 7.0.NET 8.0
Int16SumSRAScalar1085.1761043.7311227.8221215.7291209.2301310.6451397.378
Int16SumSRANetBcl31888.64535102.079
Int16SumSRANetBcl_Const39751.01836630.458
Int16SumSRATraits1829.4051861.93825643.09626584.67526634.09331578.60237184.123
Int16SumSRATraits_Core1837.6631874.26233248.48136967.97236890.50837648.79837673.670
Int16SumSRAConstTraits1836.6531880.35128724.61336985.52839429.04132925.58837356.009
Int16SumSRAConstTraits_Core1830.4441879.35433935.62537498.16538127.79433120.54935752.947
Int32SumSRAScalar1362.8761321.5071508.8311508.3782226.6482555.6222327.611
Int32SumSRANetBcl16806.95815967.982
Int32SumSRANetBcl_Const18365.86116092.208
Int32SumSRATraits883.925895.13712901.50712508.76211931.48017609.10316282.512
Int32SumSRATraits_Core919.507931.41915956.78615252.82917412.02518296.49316230.128
Int32SumSRAConstTraits911.750942.52313450.04317314.81614198.09516799.44516393.351
Int32SumSRAConstTraits_Core917.228938.78915344.13615470.62917084.81618274.41116054.229
Int32SumSRAFastTraits915.754946.52113266.16815337.17114562.12917003.22416124.004
Int64SumSRAScalar1393.5401331.9631532.7191544.3061513.2451801.8592560.284
Int64SumSRANetBcl524.7028652.579
Int64SumSRANetBcl_Const557.1528870.207
Int64SumSRATraits482.604490.8044949.3284970.3284932.2774902.2397541.726
Int64SumSRATraits_Core509.432521.7695941.5476050.3226104.4336043.3378537.297
Int64SumSRAConstTraits510.778529.2985526.8935360.4605834.0756217.5097562.071
Int64SumSRAConstTraits_Core509.597531.3445899.7525978.3986049.7566171.2117720.979
SByteSumSRAScalar997.067974.1471278.0491350.0821227.7881328.3801387.993
SByteSumSRANetBcl1135.1771113.944
SByteSumSRANetBcl_Const1165.7801061.118
SByteSumSRATraits3635.5923696.78024686.30222906.32322437.12924879.96244225.353
SByteSumSRATraits_Core3652.6703743.42741915.60845147.92545375.30046792.94145642.076
SByteSumSRAConstTraits3651.1093753.76129819.07642019.51543095.16944048.30047091.982
SByteSumSRAConstTraits_Core3662.6943753.27039588.70146397.66547507.64843046.47746878.753

说明:

  • 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位 的算术右移位指令. Avx512 指令集增加了64位的算术右移位指令.
而本库对于这些数字类型, 会换成由其他指令组合实现的高效算法. 从 .NET Core 3.0 开始, 具有硬件加速.

ShiftRightArithmetic - Arm - AWS Arm t4g.small
TypeMethod.NET Core 3.1.NET 5.0.NET 6.0.NET 7.0.NET 8.0
Int16SumSRAScalar604.429602.027606.297818.740830.302
Int16SumSRANetBcl9941.4129837.372
Int16SumSRANetBcl_Const9931.3979838.530
Int16SumSRATraits1713.8185611.3164949.5029932.2699837.893
Int16SumSRATraits_Core1928.1977881.8508435.0439930.9189707.757
Int16SumSRAConstTraits1936.0577776.3468432.0649926.3489834.469
Int16SumSRAConstTraits_Core1895.2917825.0368426.0859923.4149834.395
Int32SumSRAScalar745.287749.467747.4861181.6511244.019
Int32SumSRANetBcl4929.4384848.848
Int32SumSRANetBcl_Const4937.8244854.964
Int32SumSRATraits859.1732815.1132819.1164937.5624813.108
Int32SumSRATraits_Core945.6943917.3143916.9434933.9394787.843
Int32SumSRAConstTraits967.5763904.7504188.7134901.6804849.051
Int32SumSRAConstTraits_Core947.9553906.4714192.9514908.3544853.184
Int64SumSRAScalar738.902734.754741.3431185.2171243.954
Int64SumSRANetBcl2474.6202433.159
Int64SumSRANetBcl_Const2478.5192438.677
Int64SumSRATraits467.8381233.5061233.4011418.9702424.896
Int64SumSRATraits_Core468.4701952.9671971.4532478.2292424.819
Int64SumSRAConstTraits467.1821939.9691970.3212474.3402413.790
Int64SumSRAConstTraits_Core468.6342095.3522102.9582474.4732432.455
SByteSumSRAScalar608.671609.771652.251889.935830.400
SByteSumSRANetBcl19779.97219615.987
SByteSumSRANetBcl_Const19803.79919613.758
SByteSumSRATraits3482.53711212.3409894.24511352.19919512.654
SByteSumSRATraits_Core3857.46416756.19515733.71219816.16319419.454
SByteSumSRAConstTraits3905.02715518.19915732.34419791.97219617.529
SByteSumSRAConstTraits_Core3796.01816708.14216787.09019791.89119619.300

说明:

  • 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 - AMD Ryzen 7 7840H
TypeMethod.NET Framework.NET Core 2.1.NET Core 3.1.NET 5.0.NET 6.0.NET 7.0.NET 8.0
Int16SumScalar1236.9441263.9081214.4841278.6571195.1881408.1791235.365
Int16Sum256_Bcl1074.656938.447
Int16Sum512_Bcl918.911
Int16SumTraits1221.0461255.3418067.49310943.13410421.69614194.28032579.746
Int16SumTraits_Args01278.6501211.36122661.64825363.98824123.55526722.24334671.910
Int16SumTraits_Args1255.1091154.80122911.64926138.76624804.17026585.68433172.777
Int16SumKernelTraits1269.7331192.0798698.11712377.32611972.40717610.47735632.301
Int16SumKernelTraits_Args01297.7651199.69723028.56425852.12225176.48224261.58236741.022
Int16SumKernelTraits_Args1270.8521142.88523265.59525960.40521744.41823156.07837227.607
Int32SumScalar850.057829.782816.013859.672817.223853.140837.720
Int32Sum256_Bcl755.314770.558
Int32Sum512_Bcl930.330
Int32SumTraits821.394844.38810852.53410832.76010943.34212695.69215067.794
Int32SumTraits_Args0864.447818.04212704.59115953.12715574.55414391.78515559.766
Int32SumTraits_Args810.166762.18312531.31014746.99114125.33513524.19315368.528
Int32SumKernelTraits825.747841.22914515.30814407.19014545.13116276.64815999.993
Int32SumKernelTraits_Args0856.015814.05514754.81014880.91617262.39014319.19916261.174
Int32SumKernelTraits_Args806.479765.21815073.76814604.62116999.00716367.11916422.220
Int64SumScalar425.474430.216457.179497.203465.105432.348425.921
Int64Sum256_Bcl506.686515.520
Int64Sum512_Bcl688.892
Int64SumTraits474.906431.2963789.3274192.9514280.5684155.8198171.028
Int64SumTraits_Args0423.703461.6646979.8857855.2418501.2717846.3038198.449
Int64SumTraits_Args446.260420.9256704.8748599.4418317.5507312.3628378.340
Int64SumKernelTraits473.823426.0814854.7935862.4405735.0745938.6998560.856
Int64SumKernelTraits_Args0424.508458.2487804.5758108.4089181.0868364.1068701.155
Int64SumKernelTraits_Args446.097428.5388386.2799239.3319198.7988344.9528673.715
SByteSumScalar1496.7831403.3481448.6601239.2771468.8271415.1391213.582
SByteSum256_Bcl901.1141022.223
SByteSum512_Bcl989.131
SByteSumTraits1476.7711494.14417086.31424231.46424097.62230243.43460885.250
SByteSumTraits_Args01392.1581331.08345038.80250540.40949090.08146979.78360672.985
SByteSumTraits_Args1389.0741295.64146794.99751069.26550078.24946518.75065261.554
SByteSumKernelTraits1476.6371242.19827650.93332894.21832711.66439630.93972350.167
SByteSumKernelTraits_Args01523.5431440.01144451.89149973.81351540.23648754.50272615.251
SByteSumKernelTraits_Args1395.1061274.94341001.99650067.09949654.80545904.50471412.964

说明:

  • SumScalar: 使用标量算法.
  • Sum256_Bcl: 使用BCL的256位向量方法(Vector256.Shuffle).
  • Sum512_Bcl: 使用BCL的512位向量方法(Vector512.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
TypeMethod.NET Core 3.1.NET 5.0.NET 6.0.NET 7.0.NET 8.0
Int16SumScalar427.276421.887421.454526.589516.294
Int16Sum128_Bcl482.907468.383
Int16SumTraits428.2814922.8765555.6555864.1939711.569
Int16SumTraits_Args0428.9287902.4208416.6249925.4419709.555
Int16SumTraits_Args405.5372809.4832798.9259880.8049707.490
Int16SumKernelTraits427.6375650.9136540.4467957.1759833.813
Int16SumKernelTraits_Args0427.5787897.2247891.8949929.8639819.774
Int16SumKernelTraits_Args405.2232811.1952797.1709861.3309829.822
Int32SumScalar286.900281.167281.838317.876309.427
Int32Sum128_Bcl304.320301.222
Int32SumTraits286.5962311.2092472.5922917.3434801.979
Int32SumTraits_Args0288.0664185.4303928.6044934.5904821.784
Int32SumTraits_Args270.2491396.3231401.7424886.6694806.886
Int32SumKernelTraits287.3862677.3943247.6923953.5734846.437
Int32SumKernelTraits_Args0286.7243919.6194182.6174930.4694852.808
Int32SumKernelTraits_Args270.7241399.9681395.9534899.3594853.093
Int64SumScalar448.592440.758444.884552.061534.531
Int64Sum128_Bcl708.356692.663
Int64SumTraits190.9131005.6141064.6501255.0252448.365
Int64SumTraits_Args0426.8092090.8872100.5272479.8212451.574
Int64SumTraits_Args179.534698.013699.2002457.8982451.414
Int64SumKernelTraits448.0651237.2581412.8761753.4572434.096
Int64SumKernelTraits_Args0449.8572101.4111967.1522469.0542443.626
Int64SumKernelTraits_Args345.877701.805698.7532456.7612451.680
SByteSumScalar665.739664.224658.168834.224803.566
SByteSum128_Bcl647.757610.244
SByteSumTraits680.59013176.73016739.16119723.56719531.685
SByteSumTraits_Args0660.59515704.39315724.34019723.85219530.241
SByteSumTraits_Args637.5685597.6445602.80319605.28919527.338
SByteSumKernelTraits672.78415604.59716732.62919692.57119533.892
SByteSumKernelTraits_Args0675.23616718.95915715.51219729.14419534.508
SByteSumKernelTraits_Args642.7955573.9995598.16819588.65519538.006

说明:

  • 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 - AMD Ryzen 7 7840H
TypeMethod.NET Framework.NET Core 2.1.NET Core 3.1.NET 5.0.NET 6.0.NET 7.0.NET 8.0
Int16SumNarrow_If208.976197.924195.466200.430197.261205.623221.224
Int16SumNarrow_MinMax200.034201.184197.505208.715199.736222.635208.102
Int16SumNarrowVectorBase21160.11919565.03519063.34619960.92519532.39819258.68924197.090
Int16SumNarrowVectorTraits20477.03818251.73144050.63045196.12843674.65444677.38947325.429
Int32SumNarrow_If211.070218.235225.479211.761207.353223.740232.860
Int32SumNarrow_MinMax221.396206.735214.815214.341211.238210.944223.415
Int32SumNarrowVectorBase9753.2589549.3139743.0429519.1889577.99310513.07112059.829
Int32SumNarrowVectorTraits9117.8699253.89120503.08820225.44719198.94719012.81519398.087
Int64SumNarrow_If207.654206.920215.020207.405207.239220.198227.592
Int64SumNarrow_MinMax205.724201.036203.815200.292213.422213.819231.741
Int64SumNarrowVectorBase2951.2642720.6632835.8822949.4232915.4734372.6125917.536
Int64SumNarrowVectorTraits2941.3362696.5434690.3914875.8514917.1493808.7449411.507
UInt16SumNarrow_If1263.9601205.8761247.4091184.5371124.5201175.7331387.128
UInt16SumNarrow_MinMax1363.2981283.0271336.1031178.8601344.978761.9081487.848
UInt16SumNarrowVectorBase25617.83125358.18225019.79525056.65626527.17025337.76930941.796
UInt16SumNarrowVectorTraits24795.43324950.27933163.80141303.84640678.06729966.48145560.104
UInt32SumNarrow_If1446.2971396.1481364.9531339.8051382.4701240.1581507.078
UInt32SumNarrow_MinMax1461.8841346.5421363.8531376.3901373.016960.1041383.498
UInt32SumNarrowVectorBase12509.78011160.71111971.25911511.97811080.15811897.23715997.508
UInt32SumNarrowVectorTraits12962.03011581.01414895.00916343.37217051.60214727.10719760.603
UInt64SumNarrow_If1003.5701326.642913.881912.071878.8481312.3521874.180
UInt64SumNarrow_MinMax1455.4021404.3911392.157891.629902.245937.792895.795
UInt64SumNarrowVectorBase3340.3773102.9543033.0443449.1133649.4225104.5507693.314
UInt64SumNarrowVectorTraits3306.0183050.4924497.3855401.9145969.6214527.5889530.757

说明:

  • 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
TypeMethod.NET Core 3.1.NET 5.0.NET 6.0.NET 7.0.NET 8.0
Int16SumNarrow_If157.270154.692157.383181.610193.265
Int16SumNarrow_MinMax160.909165.733108.425184.240189.973
Int16SumNarrowVectorBase6100.2756193.9386308.1187201.7358261.974
Int16SumNarrowVectorTraits6102.23813460.35813445.82415514.26113674.647
Int32SumNarrow_If163.854165.352165.160190.240213.807
Int32SumNarrow_MinMax154.976162.019161.884195.349194.881
Int32SumNarrowVectorBase3047.9233268.9333253.3783532.1284034.752
Int32SumNarrowVectorTraits3125.4986121.5536162.5337914.6416782.358
Int64SumNarrow_If161.788160.690161.656203.670190.163
Int64SumNarrow_MinMax160.836157.655164.693194.496201.793
Int64SumNarrowVectorBase728.6291157.1041139.3721231.8771326.584
Int64SumNarrowVectorTraits727.6033114.7203307.2054088.6773409.341
UInt16SumNarrow_If527.761515.076531.818608.056832.441
UInt16SumNarrow_MinMax573.087525.410576.628608.744893.594
UInt16SumNarrowVectorBase8361.1208439.5777945.4868853.73111829.808
UInt16SumNarrowVectorTraits8307.68013106.61314179.29713964.21316532.648
UInt32SumNarrow_If537.550534.718539.467620.874989.646
UInt32SumNarrow_MinMax539.997537.029545.333620.923827.472
UInt32SumNarrowVectorBase4099.7034021.1543963.4634356.8045896.924
UInt32SumNarrowVectorTraits4024.3106340.9946977.1516619.0097993.300
UInt64SumNarrow_If619.788621.120620.256827.649995.113
UInt64SumNarrow_MinMax619.494620.151620.119818.259994.695
UInt64SumNarrowVectorBase1229.7231821.2321848.6321805.4992169.309
UInt64SumNarrowVectorTraits1228.9113489.3033526.5483480.2124100.727

说明:

  • 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强很多.

YGroup3Unzip

YGroup3Unzip: 将3-元素组解交织为3个向量. 它能将3元素组的 数组结构体 转为 结构体数组. 它还能将 已打包的RGB像素数据, 解交织为 R,G,B 平面数据 .

YGroup3UnzipX2: 将3-元素组解交织为3个向量, 且处理2倍数据.

YGroup3Unzip - X86 - AMD Ryzen 7 7840H
TypeMethod.NET Framework.NET Core 2.1.NET Core 3.1.NET 5.0.NET 6.0.NET 7.0.NET 8.0
ByteSumBase_Basic255.172496.713501.725499.601566.925505.052670.702
ByteSumBase1140.6161053.3521089.1031138.2351111.1141478.6751463.708
ByteSumTraits1121.9041086.7997468.21611280.24611541.67112438.17121865.365
ByteSumX2Base2169.0252088.3532171.1432111.3322179.0992812.5752973.122
ByteSumX2Traits2229.9772160.51610419.95110989.67310985.33011472.25122393.695
Int16SumBase_Basic213.465389.617439.760352.833453.870404.842533.252
Int16SumBase738.972723.809686.669739.079728.0611015.7091008.942
Int16SumTraits759.109691.2733767.0555383.5955638.0946270.97110452.168
Int16SumX2Base1327.2171262.4001260.5471312.8661288.7271723.5431761.102
Int16SumX2Traits1320.5451227.5306120.1756190.4446208.9935798.71810909.299
Int32SumBase_Basic186.128276.261295.992219.993323.416280.863391.511
Int32SumBase184.001273.403306.846224.431320.332551.148555.068
Int32SumTraits189.108277.0596262.6876454.6416392.2896488.1276951.683
Int32SumX2Base155.218257.316284.894247.659318.4921072.5981093.091
Int32SumX2Traits160.252253.3195049.7206341.3906285.6816215.0977422.183
Int64SumBase_Basic136.976170.057187.362131.130193.633175.953240.232
Int64SumBase135.652170.323187.933125.485192.634168.300238.422
Int64SumTraits135.704167.9004095.4103868.1994015.4114061.9204385.505
Int64SumX2Base108.319151.252178.444137.145182.990155.501243.663
Int64SumX2Traits109.441151.2432684.6133883.2373978.6483893.3584785.675

说明:

  • SumBase_Basic: 使用标量算法.
  • SumBase: 使用本库的基础方法(VectorTraitsBase.Statics.YGroup3Unzip). 它是通过组合使用BCL的向量方法来实现的, 能够利用硬件加速.
  • SumTraits: 使用本库的特征方法(Vectors.YGroup3Unzip). 它是通过内在函数来实现的, 能获得更佳硬件加速.
  • SumX2Base: 使用 VectorTraitsBase.Statics.YGroup3UnzipX2. 对于 8~16位整数, YGroup3UnzipX2 一般比 YGroup3Unzip 更快, 在早期版本的.NET下更明显.
  • SumX2Traits: 使用 Vectors.YGroup3UnzipX2.
YGroup3Unzip - Arm - AWS Arm t4g.small
TypeMethod.NET Core 3.1.NET 6.0.NET 7.0.NET 8.0
ByteSumBase_Basic263.957265.524327.819381.159
ByteSumBase380.369406.259430.545443.813
ByteSumTraits378.7104381.5754113.3046510.157
ByteSumX2Base702.851728.691740.690767.491
ByteSumX2Traits700.5394412.7854273.7635294.112
Int16SumBase_Basic188.885189.823222.856279.398
Int16SumBase213.360228.410235.157242.377
Int16SumTraits213.3561926.5592134.9253037.124
Int16SumX2Base419.434448.638466.043475.565
Int16SumX2Traits419.4422413.7942650.0312638.161
Int32SumBase_Basic138.088143.089154.241196.818
Int32SumBase141.071143.390186.784198.177
Int32SumTraits144.6961033.8991069.9741494.205
Int32SumX2Base121.726138.986275.479310.983
Int32SumX2Traits119.4681598.1851547.7951618.239
Int64SumBase_Basic109.766100.52384.039189.270
Int64SumBase109.531102.08481.358185.056
Int64SumTraits107.3351153.3331176.3151191.362
Int64SumX2Base97.85796.11179.729203.008
Int64SumX2Traits98.1621216.7161155.3021374.619

YGroup3Zip

YGroup3Zip: 将3个向量交织为3-元素组. 它能将3元素组的 结构体数组 转为 数组结构体. 它还能将 R,G,B 平面数据, 交织为 已打包的RGB像素数据.

YGroup3ZipX2: 将3个向量交织为3-元素组, 且处理2倍数据.

YGroup3Zip - X86 - AMD Ryzen 7 7840H
TypeMethod.NET Framework.NET Core 2.1.NET Core 3.1.NET 5.0.NET 6.0.NET 7.0.NET 8.0
ByteSumBase_Basic320.545532.958571.109523.083555.271600.353679.783
ByteSumBase305.180519.605553.415467.029549.7621589.6421708.570
ByteSumTraits290.232529.1088108.84412125.73511513.73212224.63221531.572
ByteSumX2Base604.991596.515601.072579.109591.3153092.9863409.277
ByteSumX2Traits602.261596.7986290.0952711.2538337.47911463.08822736.985
Int16SumBase_Basic254.953426.213487.379305.837522.485483.501563.462
Int16SumBase268.055442.283490.271297.784493.8981095.1261146.176
Int16SumTraits259.538444.5254016.2555534.7135845.9076165.24010349.838
Int16SumX2Base248.608387.791468.835430.473495.9501897.1742065.269
Int16SumX2Traits253.817394.0473148.7901355.5134127.7915693.95710673.106
Int32SumBase_Basic187.137275.319365.431178.558362.014332.869376.437
Int32SumBase183.103288.307356.854178.660362.193560.215643.577
Int32SumTraits184.919307.0325705.5396074.1495954.7705886.4806313.509
Int32SumX2Base164.949244.899334.504271.947349.6921124.1931286.062
Int32SumX2Traits165.592245.6694987.9325943.0905998.7085822.1416613.310
Int64SumBase_Basic120.917160.615209.36996.724219.178199.561226.295
Int64SumBase119.616158.049217.46497.743214.023198.233225.900
Int64SumTraits118.939157.7224001.0164190.3474236.1784017.0944583.389
Int64SumX2Base106.922138.779203.837156.484207.290184.203207.557
Int64SumX2Traits105.277137.5112688.5234121.3964146.6744052.0234574.568

说明:

  • SumBase_Basic: 使用标量算法.
  • SumBase: 使用本库的基础方法(VectorTraitsBase.Statics.YGroup3Zip). 它是通过组合使用BCL的向量方法来实现的, 能够利用硬件加速.
  • SumTraits: 使用本库的特征方法(Vectors.YGroup3Zip). 它是通过内在函数来实现的, 能获得更佳硬件加速.
  • SumX2Base: 使用 VectorTraitsBase.Statics.YGroup3ZipX2. 对于 8~16位整数, YGroup3ZipX2 一般比 YGroup3Zip 更快, 在早期版本的.NET下更明显.
  • SumX2Traits: 使用 Vectors.YGroup3ZipX2.
YGroup3Zip - Arm - AWS Arm t4g.small
TypeMethod.NET Core 3.1.NET 6.0.NET 7.0.NET 8.0
ByteSumBase_Basic277.096281.447408.006334.832
ByteSumBase277.206281.101779.019786.843
ByteSumTraits276.8773952.7024015.5096498.419
ByteSumX2Base242.179275.4441290.4831375.898
ByteSumX2Traits241.5864410.9794079.7574416.939
Int16SumBase_Basic214.291218.814299.398283.789
Int16SumBase214.247217.945422.929432.557
Int16SumTraits214.4001947.6942124.4893037.442
Int16SumX2Base209.544212.671807.496817.343
Int16SumX2Traits209.5572537.1412565.9812618.864
Int32SumBase_Basic177.759180.043226.880218.206
Int32SumBase177.694178.579343.191358.961
Int32SumTraits177.4341072.0261053.0631494.637
Int32SumX2Base171.969172.323504.015552.706
Int32SumX2Traits171.8721592.3141582.6891611.841
Int64SumBase_Basic167.955186.335184.875188.208
Int64SumBase168.658187.520189.109187.830
Int64SumTraits168.3151146.4981177.3731182.660
Int64SumX2Base162.566169.710163.148174.322
Int64SumX2Traits160.8911220.2581237.2151232.484

YShuffleX2Kernel

YShuffleX2Kernel: 在2个向量上进行仅换位. 通过使用一组索引从输入向量中选择值,来创建一个新向量. 若索引值超出范围, 结果是未定义的.

YShuffleX2Kernel - X86 - AMD Ryzen 7 7840H
TypeMethod.NET Framework.NET Core 2.1.NET Core 3.1.NET 5.0.NET 6.0.NET 7.0.NET 8.0
ByteSumBase_Basic323.974734.453745.261769.117808.343694.312917.774
ByteSumBase317.773740.475710.133772.591786.548686.563945.338
ByteSumTraits315.705728.77214191.12515884.94915029.38117839.09071478.251
ByteSumTraits_Args325.706744.51921591.46126073.82226028.37224511.02571714.983
ByteSumTraits_ArgsT311.284622.35620485.05520918.02117473.81420592.44870119.520
Int16SumBase_Basic262.677558.062564.900599.893584.054502.700779.558
Int16SumBase248.341540.558556.204605.246593.512501.510775.105
Int16SumTraits239.209558.1145683.8166581.9656700.7387620.08737391.696
Int16SumTraits_Args281.617559.99211638.05813238.99913545.55212500.39836420.577
Int16SumTraits_ArgsT261.851410.86710411.0329997.5599456.9059407.75737826.671
Int32SumBase_Basic198.312348.275353.172367.747357.773308.903492.810
Int32SumBase191.235336.581343.131368.362352.331315.974518.975
Int32SumTraits195.942346.7147304.3677885.9106948.8607046.24016615.500
Int32SumTraits_Args208.612353.2638449.77110713.37810380.91810909.32216363.912
Int32SumTraits_ArgsT160.571244.7936886.6886318.4485231.0695865.79315985.566
Int64SumBase_Basic124.441188.368191.286203.016190.671166.312257.693
Int64SumBase124.435188.868183.416191.652187.988176.683283.904
Int64SumTraits128.463186.2992806.8583304.0733102.7303224.0978778.706
Int64SumTraits_Args123.925186.0854587.7775516.0205302.7545455.5959174.376
Int64SumTraits_ArgsT97.554132.4433185.6183228.4872710.2072940.0199023.532

说明:

  • SumBase_Basic: 使用标量算法.
  • SumBase: 使用本库的基础方法(VectorTraitsBase.Statics.YShuffleX2Kernel). 它是通过组合使用BCL的向量方法来实现的, 能够利用硬件加速.
  • SumTraits: 使用本库的特征方法(Vectors.YShuffleX2Kernel). 它是通过内在函数来实现的, 能获得更佳硬件加速.
  • SumTraits_Args: 使用本库的 Core 后缀的方法来组合计算(Vectors.YShuffleX2Kernel_Args, Vectors.YShuffleX2Kernel_Core), 不使用ValueTuple, 而是用“out”关键字返回多个值.
  • SumTraits_ArgsT: 使用本库的 Core 后缀的方法来组合计算(Vectors.YShuffleX2Kernel_Args, Vectors.YShuffleX2Kernel_Core), 使用ValueTuple. 注意早期版本的 .NET 中运行时,SumTraits_ArgsT 一般比 SumTraits_Args 慢一些。
YShuffleX2Kernel - Arm - AWS Arm t4g.small
TypeMethod.NET Core 3.1.NET 6.0.NET 7.0.NET 8.0
ByteSumBase_Basic386.442382.735375.880472.929
ByteSumBase383.493381.257373.670473.065
ByteSumTraits384.1798557.7099853.45119777.508
ByteSumTraits_Args384.3609929.81611028.41319826.109
ByteSumTraits_ArgsT369.3204873.8779841.67219825.366
Int16SumBase_Basic250.954240.990257.083372.974
Int16SumBase250.149239.824258.794371.933
Int16SumTraits250.1923210.9044228.6829733.244
Int16SumTraits_Args250.3344413.4054972.6759736.750
Int16SumTraits_ArgsT242.4082251.1304965.8939734.258
Int32SumBase_Basic189.683174.949175.262285.014
Int32SumBase193.693171.892175.936284.895
Int32SumTraits193.5621796.5862121.6204781.900
Int32SumTraits_Args192.6252466.3352477.7554793.132
Int32SumTraits_ArgsT181.1941186.0552476.6044801.014
Int64SumBase_Basic118.550104.197100.764283.201
Int64SumBase116.596101.670101.495283.035
Int64SumTraits118.071887.114986.7642387.789
Int64SumTraits_Args116.0241234.1551404.8042423.836
Int64SumTraits_ArgsT108.289593.6401239.5612421.120

更多结果

详见: BenchmarkResults

附录

参考资料:

以前的发布日志:

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐