我正在查看版本Vector<T>
中 System.Numerics.Vectors 命名空间中的4.5.0-preview1-26216-02。 MSDN文档说:
Vector<T>
是一个不可变结构,表示指定数字类型的单个向量。Vector<T>
实例的计数已修复 ,但其上限取决于CPU注册。
https://docs.microsoft.com/en-us/dotnet/api/system.numerics.vector-1(强调补充)
即使忽略误导的措辞“计算 [sic。] of vector ”,这句话似乎也很不清楚,因为它意味着不同的Vector<T>
个实例可能有不同的 - 虽然“固定”到一些CPU限制 - “计数”(再次,所谓的“计数”,究竟是什么?)这里没有提到实际的Count
属性 - 或者事实上intro page)上的任何地方。
现在通常情况下,我认为“只读”或“不可变”比传统上用于描述实例属性或字段的“固定”更常用,但在此结果表明,Vector<T>.Count
属性虽然确实是只读的,但也是 静态 ,因此无法与任何{{1}相关联} 实例。相反,它的值仅根据泛型类型参数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
,但我认为这个库允许使用 很多 更广泛的硬件加速数据类型不仅仅是128位。我的HPSG解析引擎通常执行5,000+位的密集位计算向量。再次假设我没有忽略这一点,为什么不称它为SIMD
/ System.Int128
而不是System.UInt128
?使用通用基元类型对其进行参数化确实带来了一定的好处,但是我错误地认为它更像是一个有用的扩展数组(即,blittable elements Vector<T>
),而不是仅仅是一个双倍宽度的CPU注册,在我看来,就像你可以得到的那样是“标量”。
不要误解我的意思,128位寄存器是有趣的,有用的,令人兴奋的东西 - 如果这里只是有点超卖?例如,T
无论是什么,都会有16个元素,无论你是否需要或者全部使用它们,所以Vector<byte>
的精神在运行时期望因实例而异,似乎被误用了这里。
即使单个Count
不能直接处理我所描述的用例,我也希望更新我当前的实现(使用Vector<T>
数组对于每个N位向量,而是使用ulong[N >> 6]
数组?
...是的,那是“
Vector<ulong>[N >> 7]
的数组”,这对我来说似乎很奇怪;不应该在名称中使用“Vector”的类型充分或有用地扩展,而不必显式创建一个数组来包装多个实例吗?
Vector<ulong>
实际报告的SIMD位宽不同?答案 0 :(得分:8)
矢量大小并不总是16个字节,尽管这很常见。例如,在具有AVX2的平台上,以64位模式运行的程序获得32字节向量。通过这种方式,Count
属性也可以在同一台机器上变化(对于相同的T
),通过在不同模式下运行程序。原则上它不一定是这样,即使只支持AVX1,32位程序仍然可以使用256位操作,但这不是System.Numerics.Vectors的工作原理。 CPU的每个功能级别的不同大小是API设计的一个相当基本的部分,可能是为了实现某种形式的面向未来,尽管它可能导致shuffles的缺乏(这很难)指定非静态已知大小的矢量。
我认为这个库允许使用比128位
更宽的硬件加速数据类型
硬件中不存在,因此很难提供。顾名思义,AVX-512最多可达512位,但目前主流CPU的SIMD仍然存在。
为什么不称它为
System.Int128
/System.UInt128
我希望这些类型映射到实际的整数类型,而不是矢量类型。许多在128位整数上有意义的操作实际上并不作为CPU指令存在,并且几乎所有做的操作都在 2×64 上运行({{1 },Vector<long>
), 4×32 (long[2]
,Vector<int>
), 8×16 (int[4]
,Vector<short>
)或 16×8 (short[8]
,Vector<byte>
)位向量(或在支持它的平台上加倍宽度)。在byte[16]
上提供“逐字节添加”操作会很奇怪,不提供真正的128位添加会使它更加奇怪。除了前面提到的,大小不是128位,这很常见。
许多SIMD操作都非常快,但有一些例外。例如,32位乘法通常具有相当极端的延迟。 Int128
API还允许一些不存在的操作(必须缓慢模拟,例如整数除法或字节乘法),而不暗示存在问题。映射到实际存在的指令的操作通常很快。
虽然System.Numerics.Vectors
上的按位操作也很快,但从“每单位时间完成的总工作量”来看,它们的矢量版本甚至更好。例如,Skylake每个周期可以执行(最多)四个标量按位运算(但是额外的操作,如加法和比较/分支,以使循环在同一资源上竞争),但执行三个256位按位运算SIMD是同时工作量的3倍,它为标量操作或分支留下了执行端口。
所以是的,它可能值得使用。您可以保留ulong
数组并使用ulong
的{{3}}构造函数,这样您就不必处理任何地方的向量。例如,索引到具有变量索引的向量根本不是一个好的操作,导致分支,向量存储和标量重新加载。矢量的可变大小性质显然也使得直接使用它们的数组变得非常复杂,而不是使用基元类型的数组然后从它们进行向量加载。您可以轻松地将数组的长度向上舍入到向量计数的倍数,以消除对小数组循环的需要,以处理不完全适合向量的数组末尾的剩余项目。 / p>