发布 VectorTraits v2.0(支持 x86的Sse系列指令集等)

这篇具有很好参考价值的文章主要介绍了发布 VectorTraits v2.0(支持 x86的Sse系列指令集等)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录
  • 支持 x86的Sse系列指令集
  • 为 Vector128/Vector256 补充全部的向量方法
  • 提供CPU型号信息
    • 结果范例1: X86 CPU on Windows
    • 结果范例2: Arm CPU on Linux
    • 结果范例3: Arm CPU on Mac OS
  • 提供所支持的指令集信息
    • 结果范例1: X86 CPU on Windows
    • 结果范例2: Arm CPU on Linux
    • 结果范例3: Arm CPU on Mac OS
  • 新增了向量方法
    • 位运算的向量方法
    • 浮点数判断的向量方法
    • 符号判断的向量方法
    • 限制的向量方法
    • 比较的向量方法
  • 增加目标框架 net8.0netstandard2.1
  • 提供固定长度的数组
    • “固定长度的数组”的范例
    • 备注:寻址方式说明
  • BitMath从静态类改为抽象类. 新增名称空间 Zyl.VectorTraits.Numerics
  • 基准测试程序增加命令行参数
  • 增加工具程序UpdateBenchmarkResults
  • 算法优化
  • 附录

VectorTraits已更新至 v2.0版。支持 x86的Sse系列指令集; 为 Vector128/Vector256 补充全部的向量方法; 还提供了 浮点数判断(YIsNaN, YIsinfinity)、符号判断(YCopySign, YSign) 等原创的向量方法。

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

变更日志如下。

  • Major: Support for the X86 Sse family instruction set; supplement all vector methods for Vector128/Vector256; also provides innovative vector methods such as check floating number (YIsNaN, YIsInfinity), sign (YCopySign, YSign) (支持 x86的Sse系列指令集; 为 Vector128/Vector256 补充全部的向量方法; 还提供了 浮点数判断(YIsNaN, YIsinfinity)、符号判断(YCopySign, YSign) 等原创的向量方法).
  • Provides the CPU model info (提供CPU型号信息). VectorEnvironment adds members: CpuModelName, CpuFlags, CpuDetectionCommand, CpuDetectionException, CpuDetectionResult .
  • Provides information about the supported instruction set (提供所支持的指令集信息). e.g. VectorEnvironment.SupportedInstructionSets, IBaseTraits.UsedInstructionSets
  • Supplement all vector methods for Vector128/Vector256 (为 Vector128/Vector256 补充全部的向量方法): Dot, Equals, EqualsAll, EqualsAny, GreaterThanAll, GreaterThanAny, GreaterThanOrEqual, GreaterThanOrEqualAll, GreaterThanOrEqualAny, LessThanAll, LessThanAny, LessThanOrEqual, LessThanOrEqualAll, LessThanOrEqualAny, Sqrt .
  • Provides the vector methods of bitwise operations (提供位运算的向量方法): YBitToByte, YBitToInt16, YBitToInt32, YBitToInt64, YOrNot .
  • Provides the vector methods of check floating number (提供浮点数判断的向量方法): YIsEvenInteger, YIsFinite, YIsInfinity, YIsInfinityOrNaN, YIsInteger, YIsNaN, YIsNegative, YIsNegativeZero, YIsNegativeInfinity, YIsNormal, YIsNotNaN, YIsOddInteger, YIsPositive, YIsPositiveInfinity, YIsSubnormal, YIsZero, YIsZeroOrSubnormal.
  • Provides the vector methods of check sign (提供符号判断的向量方法): YCopySign, YSign, YSignFloat .
  • Provides the vector methods of clamp (提供限制的向量方法): YMaxNumber, YMinNumber .
  • Provides the vector methods of compare (提供比较的向量方法): YIsAllTrue, YIsAnyTrue, YIsNotEquals.
  • VectorTraits.dll: Add TargetFrameworks net8.0 and netstandard2.1 (增加目标框架 net8.0netstandard2.1 ).
  • Provides arrays of fixed length (提供固定长度的数组). e.g. FixedArray2, FixedArray4 ...
  • BitMath changed from static to abstract class. Add namespace Zyl.VectorTraits.Numerics, add some math functions (BitMath从静态类改为抽象类. 新增名称空间 Zyl.VectorTraits.Numerics, 增加一些的数学函数).
  • Benchmark programs add command line parameter (基准测试程序增加命令行参数): -accelerated0 -allowFakeBenchmark -cpuDetection0 -fixedVector0 -test0
  • Add tool program (增加工具程序): UpdateBenchmarkResults.
  • Optimized hardware acceleration of ExtractMostSignificantBits methods in the Arm architecture (优化ExtractMostSignificantBits方法在Arm架构的硬件加速). For 8~64 bit types.

完整列表: ChangeLog

支持 x86的Sse系列指令集

本库已经支持了x86架构的Sse系列指令集。既:Sse, Sse2, Sse3, Ssse3, Sse41, Sse42。
在X86架构上使用128位向量(Vector128、128位时的Vector)时,现在能充分获得硬件加速。

为 Vector128/Vector256 补充全部的向量方法

相关日志:

  • Supplement all vector methods for Vector128/Vector256 (为 Vector128/Vector256 补充全部的向量方法): Dot, Equals, EqualsAll, EqualsAny, GreaterThanAll, GreaterThanAny, GreaterThanOrEqual, GreaterThanOrEqualAll, GreaterThanOrEqualAny, LessThanAll, LessThanAny, LessThanOrEqual, LessThanOrEqualAll, LessThanOrEqualAny, Sqrt .

对于固定长度的向量类型(Vector128/Vector256),在v1.0版时只是提供了常用的向量方法。
而现在v2.0版,已经补充全部的向量方法。已经覆盖了 .NET 7.0中所有运算类的向量方法。例如 Dot, Equals, EqualsAll, EqualsAny 等.

这些向量方法的清单如下。

  • Dot①: Computes the dot product of two vectors (计算两个向量的点积).
    Mnemonic: rt := left[0]*right[0] + left[1]*right[1] + left[2]*right[2] + ... + left[Count-1]*right[Count-1] .
  • Equals: Compares two vectors to determine if they are equal on a per-element basis (比较两个向量,确定它们每个元素是否相等).
    Mnemonic: rt[i] := to_mask(left[i] == right[i]).
  • EqualsAll: Compares two vectors to determine if all elements are equal (比较两个向量以判定所有元素是否相等).
    Mnemonic: rt := (left[0] == right[0]) && (left[1] == right[1]) && ... && (left[Count-1] == right[Count-1]).
  • EqualsAny: Compares two vectors to determine if any elements are equal (比较两个向量以判定任一元素是否相等).
    Mnemonic: rt := (left[0] == right[0]) || (left[1] == right[1]) || ... || (left[Count-1] == right[Count-1]).
  • GreaterThanAll: Compares two vectors to determine if all elements are greater (比较两个向量以判定所有元素是否大于).
    Mnemonic: rt := (left[0] > right[0]) && (left[1] > right[1]) && ... && (left[Count-1] > right[Count-1]).
  • GreaterThanAny: Compares two vectors to determine if any elements are greater (比较两个向量以判定任一元素是否大于).
    Mnemonic: rt := (left[0] > right[0]) || (left[1] > right[1]) || ... || (left[Count-1] > right[Count-1]).
  • GreaterThanOrEqual: Compares two vectors to determine which is greater or equal on a per-element basis (比较两个向量,在每个元素的基础上确定哪个更大或等于).
    Mnemonic: rt[i] := to_mask(left[i] >= right[i]).
  • GreaterThanOrEqualAll: Compares two vectors to determine if all elements are greater or equal (比较两个向量以判定所有元素是否大于或等于).
    Mnemonic: rt := (left[0] >= right[0]) && (left[1] >= right[1]) && ... && (left[Count-1] >= right[Count-1]).
  • GreaterThanOrEqualAny: Compares two vectors to determine if any elements are greater or equal (比较两个向量以判定任一元素是否大于或等于).
    Mnemonic: rt := (left[0] >= right[0]) || (left[1] >= right[1]) || ... || (left[Count-1] >= right[Count-1]).
  • LessThanAll: Compares two vectors to determine if all elements are less (比较两个向量以判定所有元素是否小于).
    Mnemonic: rt := (left[0] < right[0]) && (left[1] < right[1]) && ... && (left[Count-1] < right[Count-1]).
  • LessThanAny: Compares two vectors to determine if any elements are less (比较两个向量以判定任一元素是否小于).
    Mnemonic: rt := (left[0] < right[0]) || (left[1] < right[1]) || ... || (left[Count-1] < right[Count-1]).
  • LessThanOrEqual: Compares two vectors to determine which is less or equal on a per-element basis (比较两个向量,在每个元素的基础上确定哪个更小或等于).
    Mnemonic: rt[i] := to_mask(left[i] <= right[i]).
  • LessThanOrEqualAll: Compares two vectors to determine if all elements are less or equal (比较两个向量以判定所有元素是否小于或等于).
    Mnemonic: rt := (left[0] <= right[0]) && (left[1] <= right[1]) && ... && (left[Count-1] <= right[Count-1]).
  • LessThanOrEqualAny: Compares two vectors to determine if any elements are less or equal (比较两个向量以判定任一元素是否小于或等于).
    Mnemonic: rt := (left[0] <= right[0]) || (left[1] <= right[1]) || ... || (left[Count-1] <= right[Count-1]).
  • Sqrt①: Computes the square root of a vector on a per-element basis (计算向量中每个元素的平方根).
    Mnemonic: rt[i] := sqrt(vector[i]) = pow(vector[i], 1.0/2). When x is less than 0, floating-point types return NaN, integer types return 0.

注:①表示这些方法也适用于不定长度的向量类型Vector. 因发现Vector的这些方法中, 部分元素类型没能提供硬件加速。

提供CPU型号信息

相关日志:

  • Provides the CPU model info (提供CPU型号信息). VectorEnvironment adds members: CpuModelName, CpuFlags, CpuDetectionCommand, CpuDetectionException, CpuDetectionResult .

在使用向量方法时,很多时候我们想知道CPU型号信息,但BCL未提供办法。于是v2.0版提供了查看CPU型号信息的属性,且支持 Windows/Linux/Mac 这3大主流操作系统。

VectorEnvironment类提供了这些成员。

  • CpuModelName: CPU型号名。例如 Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz, Neoverse-N1
  • CpuFlags: CPU特征标志。目前仅Linux操作系统上有值,它就是lscpu命令所返回的flags字段。例如Neoverse-N1的该属性为 fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp ssbs.
  • CpuDetectionCommand: CPU检测所用命令。不同操作系统(Windows/Linux/Mac)上,所用的命令不同。例如wmic
  • CpuDetectionException: CPU检测时的最新异常。
  • CpuDetectionResult: CPU检测的原始返回值. 它与 CpuDetectionCommand 有关。

一般情况下直接使用VectorEnvironment的属性就行。范例代码如下。

writer.WriteLine("CpuModelName: {0}", VectorEnvironment.CpuModelName);
writer.WriteLine("CpuFlags: {0}", VectorEnvironment.CpuFlags);
writer.WriteLine("CpuDetectionException: {0}", VectorEnvironment.CpuDetectionException);
writer.WriteLine("CpuDetectionCommand: {0}", VectorEnvironment.CpuDetectionCommand);
writer.Write("CpuDetectionResult:\t");
VectorTextUtil.WriteLines(writer, VectorEnvironment.CpuDetectionResult);
writer.WriteLine();

只有有一种情况需要特殊处理。就是在 .NET Framework 4.5等低版本(低于.NET Framework 4.6.1)程序里使用本库时,此时使用的是 netstandard1.1的库,而 netstandard1.1未提供 System.Diagnostics.Process 类,会导致无法获取CPU信息的情况。
解决办法是是提前将 System.Diagnostics.Process 的类型赋值给一个属性。随后本库便可通过反射来使用该类,从而能正常获取CPU信息了。范例代码如下。

#if NETSTANDARD1_3_OR_GREATER || NETCOREAPP2_0_OR_GREATER || NET461_OR_GREATER
    // No need to set up `ProcessUtil.TypeOfProcess` properties. 
#else
    Zyl.VectorTraits.Impl.Util.ProcessUtil.TypeOfProcess = typeof(System.Diagnostics.Process);
#endif

结果范例1: X86 CPU on Windows

CpuModelName: Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz
CpuFlags: 
CpuDetectionException:
CpuDetectionCommand: wmic


AddressWidth=64
Architecture=9
AssetTag=None
Availability=3
Caption=Intel64 Family 6 Model 142 Stepping 10
Characteristics=252
ConfigManagerErrorCode=
ConfigManagerUserConfig=
CpuStatus=1
CreationClassName=Win32_Processor
CurrentClockSpeed=1600
CurrentVoltage=11
DataWidth=64
Description=Intel64 Family 6 Model 142 Stepping 10
DeviceID=CPU0
ErrorCleared=
ErrorDescription=
ExtClock=100
Family=205
InstallDate=
L2CacheSize=1024
L2CacheSpeed=
L3CacheSize=6144
L3CacheSpeed=0
LastErrorCode=
Level=6
LoadPercentage=7
Manufacturer=GenuineIntel
MaxClockSpeed=1800
Name=Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz
NumberOfCores=4
NumberOfEnabledCore=4
NumberOfLogicalProcessors=8
OtherFamilyDescription=
PartNumber=None
PNPDeviceID=
PowerManagementCapabilities=
PowerManagementSupported=FALSE
ProcessorId=BFEBFBFF000806EA
ProcessorType=3
Revision=
Role=CPU
SecondLevelAddressTranslationExtensions=TRUE
SerialNumber=None
SocketDesignation=U3E1
Status=OK
StatusInfo=3
Stepping=
SystemCreationClassName=Win32_ComputerSystem
SystemName=THINK1621
ThreadCount=8
UniqueId=
UpgradeMethod=51
Version=
VirtualizationFirmwareEnabled=TRUE
VMMonitorModeExtensions=TRUE
VoltageCaps=

结果范例2: Arm CPU on Linux

CpuModelName: Neoverse-N1
CpuFlags: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp ssbs
CpuDetectionException: 
CpuDetectionCommand: lscpu
Architecture:                    aarch64
CPU op-mode(s):                  32-bit, 64-bit
Byte Order:                      Little Endian
CPU(s):                          2
On-line CPU(s) list:             0,1
Vendor ID:                       ARM
Model name:                      Neoverse-N1
Model:                           1
Thread(s) per core:              1
Core(s) per socket:              2
Socket(s):                       1
Stepping:                        r3p1
BogoMIPS:                        243.75
Flags:                           fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp ssbs
L1d cache:                       128 KiB (2 instances)
L1i cache:                       128 KiB (2 instances)
L2 cache:                        2 MiB (2 instances)
L3 cache:                        32 MiB (1 instance)
NUMA node(s):                    1
NUMA node0 CPU(s):               0,1
Vulnerability Itlb multihit:     Not affected
Vulnerability L1tf:              Not affected
Vulnerability Mds:               Not affected
Vulnerability Meltdown:          Not affected
Vulnerability Mmio stale data:   Not affected
Vulnerability Retbleed:          Not affected
Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:        Mitigation; __user pointer sanitization
Vulnerability Spectre v2:        Mitigation; CSV2, BHB
Vulnerability Srbds:             Not affected
Vulnerability Tsx async abort:   Not affected

结果范例3: Arm CPU on Mac OS

CpuModelName: Apple M2
CpuFlags: 
CpuDetectionException: 
CpuDetectionCommand: sysctl
kern.sched_rt_avoid_cpu0: 0
kern.cpu_checkin_interval: 4000
hw.ncpu: 8
hw.activecpu: 8
hw.perflevel0.physicalcpu: 4
hw.perflevel0.physicalcpu_max: 4
hw.perflevel0.logicalcpu: 4
hw.perflevel0.logicalcpu_max: 4
hw.perflevel0.cpusperl2: 4
hw.perflevel1.physicalcpu: 4
hw.perflevel1.physicalcpu_max: 4
hw.perflevel1.logicalcpu: 4
hw.perflevel1.logicalcpu_max: 4
hw.perflevel1.cpusperl2: 4
hw.physicalcpu: 8
hw.physicalcpu_max: 8
hw.logicalcpu: 8
hw.logicalcpu_max: 8
hw.cputype: 16777228
hw.cpusubtype: 2
hw.cpu64bit_capable: 1
hw.cpufamily: -634136515
hw.cpusubfamily: 2
machdep.cpu.cores_per_package: 8
machdep.cpu.core_count: 8
machdep.cpu.logical_per_package: 8
machdep.cpu.thread_count: 8
machdep.cpu.brand_string: Apple M2

提供所支持的指令集信息

相关日志:

  • Provides information about the supported instruction set (提供所支持的指令集信息). e.g. VectorEnvironment.SupportedInstructionSets, IBaseTraits.UsedInstructionSets

有了这些属性后,便能查看所支持的指令集了。

  • VectorEnvironment类提供了SupportedInstructionSets属性。用于获取本机所支持的指令。
  • 许多类型(Vectors、Vector128s、Vector256s与IBaseTraits的派生类)提供了UsedInstructionSets属性。用于获取该向量类型所使用的指令。

注:多个指令集时,会使用分隔符。分隔符是逗号 ','。

结果范例1: X86 CPU on Windows

VectorEnvironment.CpuModelName:	Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz
VectorEnvironment.SupportedInstructionSets:	Aes, Avx, Avx2, Bmi1, Bmi2, Fma, Lzcnt, Pclmulqdq, Popcnt, Sse, Sse2, Sse3, Ssse3, Sse41, Sse42, X86Base
Vector128s.Instance:	WVectorTraits128Avx2	// Sse, Sse2, Sse3, Ssse3, Sse41, Sse42, Avx, Avx2
Vector256s.Instance:	WVectorTraits256Avx2	// Avx, Avx2, Sse, Sse2
Vectors.Instance:	VectorTraits256Avx2	// Avx, Avx2, Sse, Sse2

注:“//” 后面的就是UsedInstructionSets属性的值。

结果范例2: Arm CPU on Linux

VectorEnvironment.CpuModelName:	Neoverse-N1
VectorEnvironment.CpuFlags:	fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp ssbs
VectorEnvironment.SupportedInstructionSets:	AdvSimd, Aes, ArmBase, Crc32, Sha1, Sha256
Vector128s.Instance:	WVectorTraits128AdvSimdB64	// AdvSimd
Vectors.Instance:	VectorTraits128AdvSimdB64	// AdvSimd

结果范例3: Arm CPU on Mac OS

VectorEnvironment.CpuModelName:	Apple M2
VectorEnvironment.SupportedInstructionSets:	AdvSimd, Aes, ArmBase, Crc32, Dp, Rdm, Sha1, Sha256
Vector128s.Instance:	WVectorTraits128AdvSimdB64	// AdvSimd
Vectors.Instance:	VectorTraits128AdvSimdB64	// AdvSimd

新增了向量方法

相关日志:

  • Provides the vector methods of bitwise operations (提供位运算的向量方法): YBitToByte, YBitToInt16, YBitToInt32, YBitToInt64, YOrNot .
  • Provides the vector methods of check floating number (提供浮点数判断的向量方法): YIsEvenInteger, YIsFinite, YIsInfinity, YIsInfinityOrNaN, YIsInteger, YIsNaN, YIsNegative, YIsNegativeZero, YIsNegativeInfinity, YIsNormal, YIsNotNaN, YIsOddInteger, YIsPositive, YIsPositiveInfinity, YIsSubnormal, YIsZero, YIsZeroOrSubnormal.
  • Provides the vector methods of check sign (提供符号判断的向量方法): YCopySign, YSign, YSignFloat .
  • Provides the vector methods of clamp (提供限制的向量方法): YMaxNumber, YMinNumber .
  • Provides the vector methods of compare (提供比较的向量方法): YIsAllTrue, YIsAnyTrue, YIsNotEquals.

位运算的向量方法

  • YBitToByte: Converts binary bits to each element of the Byte vector (将各个二进制位转换为 Byte 向量的每个元素). Bit 0 meaning is 0, bit 1 meaning is 1 for all bits (byte.MaxValue).
    Mnemonic: rt[i] := to_mask(0 != ((value>>i)&1)) .
  • YBitToInt16: Converts binary bits to each element of the Int16 vector (将各个二进制位转换为 Int16 向量的每个元素). Bit 0 meaning is 0, bit 1 meaning is 1 for all bits (-1).
    Mnemonic: rt[i] := to_mask(0 != ((value>>i)&1)) .
  • YBitToInt32: Converts binary bits to each element of the Int32 vector (将各个二进制位转换为 Int32 向量的每个元素). Bit 0 meaning is 0, bit 1 meaning is 1 for all bits (-1).
    Mnemonic: rt[i] := to_mask(0 != ((value>>i)&1)) .
  • YBitToInt64: Converts binary bits to each element of the Int64 vector (将各个二进制位转换为 Int64 向量的每个元素). Bit 0 meaning is 0, bit 1 meaning is 1 for all bits (-1).
    Mnemonic: rt[i] := to_mask(0 != ((value>>i)&1)) .

注:YBitToByte 等方法,是 ExtractMostSignificantBits 方法的逆运算。

浮点数判断的向量方法

  • YIsEvenInteger: Determines if a element represents an even integral number (确定元素是否为偶数整数).
    Mnemonic: rt[i] := to_mask(isEvenInteger(value[i])) .
  • YIsFinite: Determines if a element is finite. It contains zero, subnormal, and normal. It does not contain infinity, NaN (确定元素是否为有限值. 它包含 零、次正规数、正规数. 它不含无穷大、非数).
    Mnemonic: rt[i] := to_mask(isFinite(value[i])) .
  • YIsInfinity: Determines if a element is infinite (确定元素是否为无穷大).
    Mnemonic: rt[i] := to_mask(isInfinity(value[i])) .
  • YIsInfinityOrNaN: Determines if a element is infinite or NaN (确定元素是否为无穷大或非数).
    Mnemonic: rt[i] := to_mask(isInfinityOrNaN(value[i])) .
  • YIsInteger: Determines if a element represents an integral number (确定元素是否为整数).
    Mnemonic: rt[i] := to_mask(isInteger(value[i])) .
  • YIsNaN: Determines if a element is NaN (确定元素是否为非数).
    Mnemonic: rt[i] := to_mask(isNaN(value[i])) .
  • YIsNegative: Determines if a element represents a negative number or negative zero (确定元素是否为负数或负零).
    Mnemonic: rt[i] := to_mask(isNegative(value[i])) = to_mask((value[i]<0) || isNegativeZero(value[i])) .
  • YIsNegativeInfinity: Determines if a element is negative infinity (确定元素是否为负无穷大).
    Mnemonic: rt[i] := to_mask(isNegativeInfinity(value[i])) .
  • YIsNegativeZero: Determines if a element represents a negative zero (确定元素是否为负零).
    Mnemonic: rt[i] := to_mask(isNegativeZero(value[i])) .
  • YIsNormal: Determines if a element is normal (确定元素是否为正规数).
    Mnemonic: rt[i] := to_mask(isNormal(value[i])) .
  • YIsNotNaN: Determines if a element is not NaN (确定元素是否不为非数).
    Mnemonic: rt[i] := to_mask(isNotNaN(value[i])) = to_mask(!isNaN(value[i])) .
  • YIsOddInteger: Determines if a element represents an odd integral number (确定元素是否为奇数整数).
    Mnemonic: rt[i] := to_mask(isOddInteger(value[i])) .
  • YIsPositive: Determines if a element represents zero or a positive number (确定元素是否为零或正数).
    Mnemonic: rt[i] := to_mask(isPositive(value[i])) .
  • YIsPositiveInfinity: Determines if a element is positive infinity (确定元素是否为正无穷大).
    Mnemonic: rt[i] := to_mask(isPositiveInfinity(value[i])) .
  • YIsSubnormal: Determines if a element is subnormal (确定元素是否为次正规数).
    Mnemonic: rt[i] := to_mask(isSubnormal(value[i])) .
  • YIsZero: Determines if a element is zero (确定元素是否为零).
    Mnemonic: rt[i] := to_mask(0==value[i]) .
  • YIsZeroOrSubnormal: Determines if a element is zero or subnormal (确定元素是否为零或次正规数).
    Mnemonic: rt[i] := to_mask(isZeroOrSubnormal(value[i])) .

符号判断的向量方法

  • YCopySign: Copies the sign of a value to the sign of another value (将一个值的符号复制到另一个值).
    Mnemonic: rt[i] := copySign(value[i], sign[i]).
  • YSign: Determine the sign of each element (判断各个元素的符号). 其元素取决于value的对应元素的符号情况: 值为正数时返回1, 值为0或NaN时返回0, 值为负数时返回-1.
    Mnemonic: rt[i] := sign(value[i]).
  • YSignFloat: Determine the sign of each element and returns a floating point number (判断各个元素的符号并返回浮点数). 其元素取决于value的对应元素的符号情况: 值为正数时返回1, 值为0时返回0, 值为负数时返回-1, 值为NaN时返回NaN.
    Mnemonic: rt[i] := signFloat(value[i]).

限制的向量方法

  • YMaxNumber: Computes the maximum number of two vectors on a per-element basis (在每个元素的基础上计算两个向量的最大数值). The maxNumber method matches the IEEE 754:2019 maximumNumber function. This requires NaN inputs to not be propagated back to the caller and for -0.0 to be treated as less than +0.0 (maxNumber方法与 IEEE 754:2019 maximumNumber 函数匹配。 这要求 NaN 输入不传播回调用方,且 -0.0 被视为小于 +0.0).
    Mnemonic: `rt[i] := maxNumber(left[i], right[i]).
  • YMinNumber: Computes the minimum number of two vectors on a per-element basis (在每个元素的基础上计算两个向量的最小数值). The minNumber method matches the IEEE 754:2019 minimumNumber function. This requires NaN inputs to not be propagated back to the caller and for -0.0 to be treated as less than +0.0 (minNumber方法与 IEEE 754:2019 minimumNumber 函数匹配。 这要求 NaN 输入不传播回调用方,且 -0.0 被视为小于 +0.0).
    Mnemonic: `rt[i] := minNumber(left[i], right[i]).

比较的向量方法

  • YIsAllTrue: Checks if all elements of the vector is true (检查向量中所有元素是不是都为true).
    Mnemonic: rt := value[0] && value[1] && value[2] && ... && value[Count-1] . The element of value must be 0 or AllBitsSet (Signed integer value -1).
  • YIsAnyTrue: Checks if any elements of the vector is true (检查向量中任一元素是不是为true).
    Mnemonic: rt := value[0] || value[1] || value[2] || ... || value[Count-1] . The element of value must be 0 or AllBitsSet (Signed integer value -1).
  • YIsNotEquals: Compares two vectors to determine if they are not equal on a per-element basis (比较两个向量,确定它们每个元素是否不相等).
    Mnemonic: rt[i] := to_mask(left[i] != right[i]).

增加目标框架 net8.0 与 netstandard2.1

相关日志:

  • VectorTraits.dll: Add TargetFrameworks net8.0 and netstandard2.1 (增加目标框架 net8.0netstandard2.1 ).

本库增加目标框架—— net8.0netstandard2.1。能更好的利用这些目标框架的一些新的方法来优化性能。
对于net8.0 新增的512位向量(Vector512)与Avx512指令集,本库的3.0版将支持它们。

提供固定长度的数组

相关日志:

  • Provides arrays of fixed length (提供固定长度的数组). e.g. FixedArray2, FixedArray4 ...

这一项功能主要是给本库使用的。Unsafe.Add的地址计算,存在写法繁琐,很难利用“寄存器相对寻址”、“相对基址变址寻址”指令问题。
使用“固定长度的数组”后,能解决这些问题,且具有编译时范围检查。
“固定长度的数组”的原理比较简单,就是利用值类型的结构体的一些特点。将数组下标寻址,换成访问结构体的成员。当数组下标是常数时,使用“固定长度的数组”会更方便。

“固定长度的数组”的范例

例如下面是一个计算float的256位向量相等(Vector256.Equals<float>)的函数。

public static Vector256<float> Equals_Basic(Vector256<float> left, Vector256<float> right) {
    UnsafeUtil.SkipInit(out Vector256<float> rt);
    ref int prt = ref Unsafe.As<Vector256<float>, int>(ref rt);
    ref float pleft = ref Unsafe.As<Vector256<float>, float>(ref left);
    ref float pright = ref Unsafe.As<Vector256<float>, float>(ref right);
    prt = BitMath.ToInt32Mask(pleft == pright);
    Unsafe.Add(ref prt, 1) = BitMath.ToInt32Mask(Unsafe.Add(ref pleft, 1) == Unsafe.Add(ref pright, 1));
    Unsafe.Add(ref prt, 2) = BitMath.ToInt32Mask(Unsafe.Add(ref pleft, 2) == Unsafe.Add(ref pright, 2));
    Unsafe.Add(ref prt, 3) = BitMath.ToInt32Mask(Unsafe.Add(ref pleft, 3) == Unsafe.Add(ref pright, 3));
    Unsafe.Add(ref prt, 4) = BitMath.ToInt32Mask(Unsafe.Add(ref pleft, 4) == Unsafe.Add(ref pright, 4));
    Unsafe.Add(ref prt, 5) = BitMath.ToInt32Mask(Unsafe.Add(ref pleft, 5) == Unsafe.Add(ref pright, 5));
    Unsafe.Add(ref prt, 6) = BitMath.ToInt32Mask(Unsafe.Add(ref pleft, 6) == Unsafe.Add(ref pright, 6));
    Unsafe.Add(ref prt, 7) = BitMath.ToInt32Mask(Unsafe.Add(ref pleft, 7) == Unsafe.Add(ref pright, 7));
    return rt;
}

说明一下,它是一个用标量算法实现函数,用于在不支持向量指令时进行回退。所以需要分别对每一个元素来做相等比较,并将比较结果转为掩码。
float是32位的,256位向量里能放下8个float。于是上面的代码使用Unsafe.Add,分别对8个元素进行了计算。

下面是使用“固定长度的数组”改写后的代码。

public static Vector256<float> Equals_Basic(Vector256<float> left, Vector256<float> right) {
    UnsafeUtil.SkipInit(out Vector256<float> rt);
    ref FixedArray8<int> p = ref Unsafe.As<Vector256<float>, FixedArray8<int>>(ref rt);
    ref FixedArray8<float> pleft = ref Unsafe.As<Vector256<float>, FixedArray8<float>>(ref left);
    ref FixedArray8<float> pright = ref Unsafe.As<Vector256<float>, FixedArray8<float>>(ref right);
    p.I0 = BitMath.ToInt32Mask(pleft.I0 == pright.I0);
    p.I1 = BitMath.ToInt32Mask(pleft.I1 == pright.I1);
    p.I2 = BitMath.ToInt32Mask(pleft.I2 == pright.I2);
    p.I3 = BitMath.ToInt32Mask(pleft.I3 == pright.I3);
    p.I4 = BitMath.ToInt32Mask(pleft.I4 == pright.I4);
    p.I5 = BitMath.ToInt32Mask(pleft.I5 == pright.I5);
    p.I6 = BitMath.ToInt32Mask(pleft.I6 == pright.I6);
    p.I7 = BitMath.ToInt32Mask(pleft.I7 == pright.I7);
    return rt;
}

可见,摆脱了冗长的Unsafe.Add后,代码简洁了很多。
FixedArray8等“固定长度的数组”是结构体,且元素类型也是值类型,故它可以安全使用Unsafe.As来转换引用的类型,从而直接操作变量的内存。

备注:寻址方式说明

X86架构支持2种相对寻址。资料摘录如下。

寄存器相对寻址方式
格式:操作码 寄存器,DISP+基址或变址寄存器
有效地址=寄存器+8/16位相对值DISP
MOV AX, [SI+06H] ;AX←DS:[SI+06H]
MOV AX, 06H[SI] ;AX←DS:[SI+06H]

相对基址变址寻址方式
格式:操作码 寄存器,DISP+(基址寄存器)+(变址寄存器)
有效地址=BX/BP+SI/DI+8/16位相对值DISP
MOV AX, [BX+DI+6] ;AX←DS:[BX+DI+6]
MOV AX, 6[BX+DI] ; MOV AX, 6[BX][DI]

相对值DISP,是立即数(Immediate)。如上面范例里的6(或06H),它会直接编译到机器码里。
当使用这2种相对寻址时,能在同一指令内就能完成“地址计算”与实际的“数据搬运”。
而不使用它们时,得花3条指令才能达到同样的效果。分别是 “将立即数加载到寄存器”(相对值)、“加法”(基址+相对值)、“寄存器间接寻址”。
目前发现直至.NET8.0,Unsafe.Add的地址计算代码在JIT编译为机器码运行时,不会使用相对寻址。即原本1条指令就能寻址,但JIT只会编译为3条指令的,影响了性能。
于是本库使用“固定长度的数组”来解决这一性能问题。

BitMath从静态类改为抽象类. 新增名称空间 Zyl.VectorTraits.Numerics

相关日志:

  • BitMath changed from static to abstract class. Add namespace Zyl.VectorTraits.Numerics, add some math functions (BitMath从静态类改为抽象类. 新增名称空间 Zyl.VectorTraits.Numerics, 增加一些的数学函数).

这次改善了标量版数学函数的组织。向量方法是基于这些标量方法的。
原来的 BitMath 类太太了。且2.0版增加了浮点类型判断等多个函数,若仍然放在BitMath里,会使该类便的更大,不易维护。
看了一下 .NET 7.0 的泛型数学,感觉它的分类方案不错。于是新增名称空间 Zyl.VectorTraits.Numerics,随后按照泛型数学的分类,建立了各个静态类。目前有这些类。

  • BitMathCore: 本库新增的函数。例如 BitSelect 等。
  • MathBitConverter: BitConverter(位转换) 的数学函数。例如 SingleToInt32Bits 等。
  • MathIFloatingPoint: IFloatingPoint(浮点数接口) 的数学函数。例如 Truncate 等。
  • MathINumber: INumber(数字性接口) 的数学函数。例如 Clamp 等。
  • MathINumberBase: INumberBase(数字基本性接口) 的数学函数。例如 Abs 等。
  • MathIRootFunctions: IRootFunctions(根函数接口) 的数学函数。例如 Sqrt 等。
  • MathOperators: 运算符的数学函数。例如 BigMul 等。

目前BitMath是一个转发汇总的作用,便于简单的使用标量版数学函数。

基准测试程序增加命令行参数

相关日志:

  • Benchmark programs add command line parameter (基准测试程序增加命令行参数): -accelerated0 -allowFakeBenchmark -cpuDetection0 -fixedVector0 -test0

手动运行基准测试程序时,往往希望能显示更多的信息,便于分析数据。
而用脚本自动运行时,一般不希望显示次要信息。
于是用命令行参数来控制比较好。

  • accelerated[=n]: 是否显示各个向量方式的加速情况(例如 Ceiling_AcceleratedTypes 等)。
  • accelerated0: 相当于“accelerated=0”,禁止显示各个向量方式的加速情况。
  • allowFakeBenchmark[=n]: 是否对 FakeBenchmarkAttribute 特性的函数也进行基准测试。一般情况下无需使用它,仅在脚本自动测试时,有时会用到。
  • allowFakeBenchmark0: 相当于“allowFakeBenchmark=0”,禁止FakeBenchmarkAttribute的基准测试。
  • cpuDetection[=n]: 是否显示CPU检测信息(例如 CpuDetectionCommand 等)。
  • cpuDetection0: 相当于“cpuDetection=0”,禁止显示CPU检测信息。
  • fixedVector[=n]: 是否显示定长向量的信息(例如 Vector128/Vector256 等)。
  • fixedVector0: 相当于“fixedVector=0”,禁止显示定长向量的信息。
  • test[=n]: 是否进行特殊测试。详见AloneTestUtil类。
  • test0: 相当于“test=0”,禁止进行特殊测试。

增加工具程序UpdateBenchmarkResults

相关日志:

  • Add tool program (增加工具程序): UpdateBenchmarkResults.

为了能将基准测试结果进行自动归类与更新,开发了这一工具程序。
编译好的程序已放在 /tools/build/ 文件夹,可以这样使用。

  1. 在各台计算机上运行基准测试的脚本,并将结果分别放到 /articles/BenchmarkResultsRaw文件夹。
  2. 运行脚本 /tools/build/UpdateBenchmarkResults.bat。它会对评测数据进行汇总, 随后更新到 /articles/BenchmarkResults文件夹。

该工具程序的源代码在 /tools/UpdateBenchmarkResults 文件夹。

算法优化

相关日志:

  • Optimized hardware acceleration of ExtractMostSignificantBits methods in the Arm architecture (优化ExtractMostSignificantBits方法在Arm架构的硬件加速). For 8~64 bit types.

附录

以前的发布日志:文章来源地址https://www.toymoban.com/news/detail-840920.html

  • 发布 VectorTraits v1.0, 它是C#下增强SIMD向量运算的类库

到了这里,关于发布 VectorTraits v2.0(支持 x86的Sse系列指令集等)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • x86汇编_MUL/IMUL乘法指令_笔记52

    32位模式下整数乘法可以实现32、16或8位的操作,64位下还可以使用64位操作数。MUL执行无符号乘法,IMUL执行有符号乘法。 MUL指令:无符号数乘法 32 位模式下,MUL(无符号数乘法)指令有三种类型: 执行 8 位操作数与 AL 寄存器的乘法; 执行 16 位操作数与 AX 寄存器的乘法;

    2024年02月07日
    浏览(40)
  • 【架构】探索计算机处理器的世界:ARM和x86架构解析及指令集

    计算机处理器是数字化时代的核心引擎,而在众多处理器架构中,ARM和x86是备受关注的三个。本文将带您深入探索这三个架构,介绍它们的特点、公司背景以及应用领域。让我们一起揭开计算机处理器的神秘面纱吧! ARM(Advanced RISC Machines)是一种计算机指令集架构(ISA),

    2024年02月11日
    浏览(44)
  • 模板管理支持批量操作,DataEase开源数据可视化分析平台v2.2.0发布

    2024年1月8日,DataEase开源数据可视化分析平台正式发布v2.2.0版本。 这一版本的功能升级包括:在“模板管理”页面中,用户可以通过模板管理的批量操作功能,对已有模板进行快速重新分类、删除等维护操作;数据大屏中,支持多个组件构成的分组中某一组件的快速重新定位

    2024年01月20日
    浏览(46)
  • 发布 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编程存

    2024年02月09日
    浏览(41)
  • fetch-github-hosts间隔一年大更新v2.6发布,多端支持

    前言 fetch-github-hosts是一款同步 github hosts 的工具,用于帮助您解决github时而无法访问的问题。在间隔了一年之久的时间,最近抽空将fetch-github-hosts的依赖及UI进行了一波大更新,同时也增加了一些实用的功能。 主要更新 更新了基础依赖:包括界面依赖和对于windows和macos申请管

    2024年02月14日
    浏览(32)
  • ARM和X86、X86和X64、Intel和AMD、CPU和GPU介绍

    X86 和 ARM 都是CPU设计的一个架构。X86 用的是复杂指令集。ARM用的是精简指令集。 指令集其实就是机器码,机器码上是汇编,汇编之上是程序语言例如java、c、c#。 复杂指令集是在硬件层面上设计了很多指令,所以编程会简单些。 精简指令集是在硬件层面上设计的指令比较少

    2024年02月04日
    浏览(41)
  • 安装Android x86

    一台电脑(需要预装Windows) 一块U盘 Phoenix OS 或 Bliss OS 有关的文件,取决于你想安装谁 UltraISO【可选】 提到安卓系统,大家首先想到的应该是手机吧。市面上卖的手机,除了苹果系统就是安卓系统(虽然也会有很少很少一部分手机安装的是Linux或Windows)。但如果我希望在电

    2024年02月08日
    浏览(41)
  • 在windows内使用virtualbox搭建安卓x86,以及所遇到的问题解决--2.virtualbox上安卓x86的配置

    目录: 简要说明: 1.配置vesa驱动: 2.启用网络连接并配置adb: 3.增强性能的方法: 简要说明: 先进行说明一点个人直接通过vbox VMware这些软件,并不能超越专业的安卓模拟器,大部分模拟器实际也是基于vbox(腾讯傲引擎和网易星云比较特殊,使用了aow),但是仍然存在不同。

    2023年04月16日
    浏览(50)
  • X86和arm的区别

    硬件上的区别 x86 系统中的硬件组件(如声卡、显卡、内存、存储器和 CPU)都是相互独立的。大多数组件都有单独的芯片,称为控制器。我们可以对这些组件进行更改或扩展,而不会影响连接性或整个硬件平台。 ARM 处理器没有单独的 CPU。相反,处理单元与其他硬件控制器位

    2024年02月03日
    浏览(43)
  • 电脑刷x86点心云教程

    准备工作 1.0工具与安装包 镜像下载地址: https://cdn.linkfog.cn/product/terminal/edgexos/LW/small/1.1.100.58.3/x86/zfs/2023-11-28-1701154557/LW-small-S-zfs-A03-other-edgexos-1.1.100.58.3.iso 启动u盘制作工具下载地址: https://cdn.linkfog.cn/image/backtools/balenaEtcher-Setup-1.7.3.exe 1.1 需要用到的工具: ① EdgeXOS设备(

    2024年02月03日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包