System.Numerics.Vectors 'Vector<T>': 它基本上只是 System.UInt128 吗?
System.Numerics.Vectors 'Vector<T>': is it basically just System.UInt128?
我正在调查 Vector<T>
in the System.Numerics.Vectors namespace from version 4.5.0-preview1-26216-02。 MSDN 文档说:
Vector<T>
is an immutable structure that represents a single vector of a specified numeric type. The count of a Vector<T>
instance is fixed, but its upper limit is CPU-register dependent.
https://docs.microsoft.com/en-us/dotnet/api/system.numerics.vector-1 (emphasis added)
即使忽略了错误的措辞“count [sic.] of a Vector”,这句话似乎也很不清楚,因为它暗示不同的 Vector<T>
实例可能有不同——尽管 "fixed" 达到一些 CPU-limit--"counts"(再次,所谓的 'count' 什么,确切地说?)这里没有提到实际的 Count
属性——或者实际上 intro page 上的任何地方)。
现在一般来说,我觉得"read-only"或者"immutable"比[=88=更常用] 用于描述实例的属性或字段,但在这种情况下,事实证明 Vector<T>.Count
属性 虽然确实是只读的,但也是 static,因此与任何 Vector<T>
实例 没有任何关联。相反,它的值仅根据泛型类型参数 T
变化(然后可能是从机器到机器,如图所示):
bool hw = Vector.IsHardwareAccelerated; // --> true
var c = (Vector<sbyte>.Count, Vector<short>.Count, Vector<int>.Count, Vector<long>.Count);
Debug.WriteLine(c); // --> (16, 8, 4, 2)
哦。
那么它基本上是 System.Int128
伪装的吗?是这样吗?我的问题是:
- 我错过了什么吗?的确,我对
SIMD
little 一无所知,但我认为这个库将允许使用 much 比 128 位更宽的硬件加速数据类型。我的 HPSG 解析引擎经常对 5,000 位以上的向量执行密集的按位计算。
再次假设我没有漏掉重点,为什么不直接称它为 System.Int128
/ System.UInt128
而不是 Vector<T>
?使用通用基本类型对其进行参数化确实带来了某些好处,但让我错误地认为它是一个更有用的可扩展数组(即,可 blittable 元素 T
),而不仅仅是双宽度 CPU 注册,在我看来这大约是 "scalar" 你能得到的。
不要误会我的意思,128 位寄存器是有趣、有用且令人兴奋的东西——如果这里有点超卖?例如,Vector<byte>
无论如何都会有 16 个元素,无论您是否需要或全部使用它们,因此 Count
预期在运行时因实例而异的精神似乎被误用了这里.
即使单个 Vector<T>
不会直接处理我所希望描述的用例,是否值得更新我当前的实现(使用 ulong[N >> 6]
array for each N-bit vector) 改为使用 Vector<ulong>[N >> 7]
array?
...yes, that's "array of Vector<ulong>
", which again seems strange to me; shouldn't a type with "Vector" in its name be sufficiently or usefully extensible without having to explicitly create an array to wrap multiple instances?
- 除了每个 128 位 SIMD 按位运算处理两倍的数据这一事实之外,SIMD 按位运算在每个操作码的周期中是否也更快(或更慢)?
- 今天是否有其他常用或可用的硬件平台
System.Numerics.Vectors
实际上报告了不同的 SIMD 位宽?
矢量大小并不总是 16 字节,尽管这很常见。例如在具有 AVX2, programs run in 64bit mode get 32 byte vectors. In this way the Count
property can also vary on the same machine (for the same T
), by running the program in different modes. In principle it wouldn't have to be like that, a 32-bit program could still use 256-bit operations even with just AVX1 support, but that's not how System.Numerics.Vectors works. The varying size per feature-level of the CPU is a fairly fundamental part of the design of the API, presumably to enable some form of future-proofing, though it perhaps contributed to the lack of shuffles 的平台上(对于 not-statically-known 大小的向量很难指定)。
I thought this library would allow the use of much wider hardware-accelerated datatypes than just 128 bits
硬件中不存在,因此很难提供。 AVX-512 goes up to 512 bits as the name implies, but that's as far as SIMD 主流 CPU 现在可以了。
why not just call it System.Int128
/ System.UInt128
我希望这些类型映射到实际的整数类型,而不是向量类型。许多对 128 位整数有意义的操作实际上并不存在 CPU 指令,几乎所有 do 存在的操作都在 2 × 上运行64 (Vector<long>
, long[2]
), 4 × 32 (Vector<int>
, int[4]
), 8 × 16 (Vector<short>
, short[8]
) 或 16 × 8 (Vector<byte>
, byte[16]
)位向量(或在支持它的平台上加倍宽度)。在 Int128
上提供 "byte-wise add" 操作会很奇怪,而 而不是 提供真正的 128 位加法使它更奇怪。除了前面提到的,大小不是定义为 128 位,这很常见。
许多 SIMD 操作都非常快,但也有一些例外。例如,32 位乘法通常具有相当极端的延迟。 System.Numerics.Vectors
API 还允许一些 non-existent 操作(必须慢慢模拟,例如整数除法或字节乘法)而不暗示存在问题。映射到实际存在的指令的操作大多很快。
虽然 ulong
上的按位运算也很快,但从 "total work done per unit time." 的角度来看,它们的矢量版本甚至更好 例如,Skylake 可以执行(最多)四个标量每个周期的按位操作(但额外的操作,如加法和 compare/branch 进行循环会竞争相同的资源)但使用 SIMD 执行三个 256 位按位操作,这是同时工作量的 3 倍并为标量操作或分支保留一个执行端口。
所以是的,它可能值得使用。您可以保留 ulong
的数组并使用 Vector<T>
的 construct-from-array 构造函数,这样您就不必到处处理向量。例如,使用可变索引对向量进行索引根本不是一个好的操作,会导致分支、向量存储和标量重新加载。向量的 variable-size 性质显然也使直接使用它们的数组变得非常复杂,而不是使用原始类型数组然后从它们中 vector-loading 。不过,您可以轻松地将数组的长度四舍五入为向量计数的倍数,从而无需使用小标量循环来处理数组末尾不太适合向量的剩余项。
我正在调查 Vector<T>
in the System.Numerics.Vectors namespace from version 4.5.0-preview1-26216-02。 MSDN 文档说:
Vector<T>
is an immutable structure that represents a single vector of a specified numeric type. The count of aVector<T>
instance is fixed, but its upper limit is CPU-register dependent.
https://docs.microsoft.com/en-us/dotnet/api/system.numerics.vector-1 (emphasis added)
即使忽略了错误的措辞“count [sic.] of a Vector”,这句话似乎也很不清楚,因为它暗示不同的 Vector<T>
实例可能有不同——尽管 "fixed" 达到一些 CPU-limit--"counts"(再次,所谓的 'count' 什么,确切地说?)这里没有提到实际的 Count
属性——或者实际上 intro page 上的任何地方)。
现在一般来说,我觉得"read-only"或者"immutable"比[=88=更常用] 用于描述实例的属性或字段,但在这种情况下,事实证明 Vector<T>.Count
属性 虽然确实是只读的,但也是 static,因此与任何 Vector<T>
实例 没有任何关联。相反,它的值仅根据泛型类型参数 T
变化(然后可能是从机器到机器,如图所示):
bool hw = Vector.IsHardwareAccelerated; // --> true
var c = (Vector<sbyte>.Count, Vector<short>.Count, Vector<int>.Count, Vector<long>.Count);
Debug.WriteLine(c); // --> (16, 8, 4, 2)
哦。
那么它基本上是 System.Int128
伪装的吗?是这样吗?我的问题是:
- 我错过了什么吗?的确,我对
SIMD
little一无所知,但我认为这个库将允许使用 much 比 128 位更宽的硬件加速数据类型。我的 HPSG 解析引擎经常对 5,000 位以上的向量执行密集的按位计算。 再次假设我没有漏掉重点,为什么不直接称它为
System.Int128
/System.UInt128
而不是Vector<T>
?使用通用基本类型对其进行参数化确实带来了某些好处,但让我错误地认为它是一个更有用的可扩展数组(即,可 blittable 元素T
),而不仅仅是双宽度 CPU 注册,在我看来这大约是 "scalar" 你能得到的。不要误会我的意思,128 位寄存器是有趣、有用且令人兴奋的东西——如果这里有点超卖?例如,
Vector<byte>
无论如何都会有 16 个元素,无论您是否需要或全部使用它们,因此Count
预期在运行时因实例而异的精神似乎被误用了这里.即使单个
Vector<T>
不会直接处理我所希望描述的用例,是否值得更新我当前的实现(使用ulong[N >> 6]
array for each N-bit vector) 改为使用Vector<ulong>[N >> 7]
array?...yes, that's "array of
Vector<ulong>
", which again seems strange to me; shouldn't a type with "Vector" in its name be sufficiently or usefully extensible without having to explicitly create an array to wrap multiple instances?- 除了每个 128 位 SIMD 按位运算处理两倍的数据这一事实之外,SIMD 按位运算在每个操作码的周期中是否也更快(或更慢)?
- 今天是否有其他常用或可用的硬件平台
System.Numerics.Vectors
实际上报告了不同的 SIMD 位宽?
矢量大小并不总是 16 字节,尽管这很常见。例如在具有 AVX2, programs run in 64bit mode get 32 byte vectors. In this way the Count
property can also vary on the same machine (for the same T
), by running the program in different modes. In principle it wouldn't have to be like that, a 32-bit program could still use 256-bit operations even with just AVX1 support, but that's not how System.Numerics.Vectors works. The varying size per feature-level of the CPU is a fairly fundamental part of the design of the API, presumably to enable some form of future-proofing, though it perhaps contributed to the lack of shuffles 的平台上(对于 not-statically-known 大小的向量很难指定)。
I thought this library would allow the use of much wider hardware-accelerated datatypes than just 128 bits
硬件中不存在,因此很难提供。 AVX-512 goes up to 512 bits as the name implies, but that's as far as SIMD 主流 CPU 现在可以了。
why not just call it
System.Int128
/System.UInt128
我希望这些类型映射到实际的整数类型,而不是向量类型。许多对 128 位整数有意义的操作实际上并不存在 CPU 指令,几乎所有 do 存在的操作都在 2 × 上运行64 (Vector<long>
, long[2]
), 4 × 32 (Vector<int>
, int[4]
), 8 × 16 (Vector<short>
, short[8]
) 或 16 × 8 (Vector<byte>
, byte[16]
)位向量(或在支持它的平台上加倍宽度)。在 Int128
上提供 "byte-wise add" 操作会很奇怪,而 而不是 提供真正的 128 位加法使它更奇怪。除了前面提到的,大小不是定义为 128 位,这很常见。
许多 SIMD 操作都非常快,但也有一些例外。例如,32 位乘法通常具有相当极端的延迟。 System.Numerics.Vectors
API 还允许一些 non-existent 操作(必须慢慢模拟,例如整数除法或字节乘法)而不暗示存在问题。映射到实际存在的指令的操作大多很快。
虽然 ulong
上的按位运算也很快,但从 "total work done per unit time." 的角度来看,它们的矢量版本甚至更好 例如,Skylake 可以执行(最多)四个标量每个周期的按位操作(但额外的操作,如加法和 compare/branch 进行循环会竞争相同的资源)但使用 SIMD 执行三个 256 位按位操作,这是同时工作量的 3 倍并为标量操作或分支保留一个执行端口。
所以是的,它可能值得使用。您可以保留 ulong
的数组并使用 Vector<T>
的 construct-from-array 构造函数,这样您就不必到处处理向量。例如,使用可变索引对向量进行索引根本不是一个好的操作,会导致分支、向量存储和标量重新加载。向量的 variable-size 性质显然也使直接使用它们的数组变得非常复杂,而不是使用原始类型数组然后从它们中 vector-loading 。不过,您可以轻松地将数组的长度四舍五入为向量计数的倍数,从而无需使用小标量循环来处理数组末尾不太适合向量的剩余项。