总结:现代 FPU 硬件很难用定点击败,即使每个向量的元素数量是两倍。
现代 BLAS 库通常针对缓存性能(使用缓存阻塞/循环平铺)以及指令吞吐量进行了很好的调整。这让他们很难被击败。特别是 DGEMM 对这种优化有很大的空间,因为它对 O(N^2) 数据进行 O(N^3) 工作,因此值得只转置一个输入的缓存大小的块,以及类似的东西。
通过以 16 位半浮点格式存储浮点数可能有助于减少内存瓶颈。没有硬件支持以该格式对它们进行数学运算,只需在加载/存储时在该格式和普通 32 位元素浮点向量之间进行转换:VCVTPH2PS ( __m256 _mm256_cvtph_ps(__m128i)
)和VCVTPS2PH (__m128i _mm256_cvtps_ph(__m256 m1, const int imm8_rounding_control)
。这两条指令包含F16C 扩展,首先由 AMD Bulldozer 和 Intel IvyBridge 支持。
IDK 如果有任何 BLAS 库支持该格式。
固定点:
SSE/AVX 没有任何整数除法指令。但是,如果您只是除以常量,则可能不需要真正的 div 指令。所以这是固定点的一个主要绊脚石。
定点的另一个大缺点是在乘法后移动以纠正小数点(二进制?)的位置的额外成本。这将侵蚀您从每个向量中使用 16 位定点的两倍元素所获得的任何收益。
SSE/AVX 实际上有相当多的压缩 16 位乘法选择(比任何其他元素大小都好)。有压缩乘法产生低半部分、高半部分(有符号或无符号),甚至是从顶部以下 2 位中取 16 位,并带有舍入(PMULHRSW.html)。Skylake 每时钟运行两个,具有 5 个周期延迟。还有整数乘加指令,但它们在成对的乘法结果之间进行水平加法。(参见Agner Fog 的 insn 表,以及x86标记 wiki 以获得性能链接。)Haswell 和以前的没有那么多整数向量加法和乘法执行单元。通常是总 uop 吞吐量的代码瓶颈,而不是特定的执行端口。(但一个好的 BLAS 库甚至可能有手动调整的 asm。)
如果您的输入和输出是整数,则使用整数向量通常会更快,而不是转换为浮点数。(例如,请参阅我关于使用 SSE2(作为浮点数)缩放字节像素值 (y=ax+b) 的答案?,其中我使用 16 位定点来处理 8 位整数)。
但是如果你真的在使用浮点数,并且有很多乘法和除法要做,那就使用硬件 FPU。它们在现代 CPU 中非常强大,并且已经使定点对于许多任务来说已经过时了。正如@Iwill 指出的那样,FMA 指令是 FP 吞吐量(有时是延迟)的另一个巨大提升。
整数加/减/比较指令(但不是乘法)的延迟也低于其对应的 FP。