【发布时间】:2014-07-14 01:33:26
【问题描述】:
我正在尝试向量化一些对性能至关重要的代码。在高层次上,每次循环迭代从一个小数组中的非连续位置读取六个浮点数,然后将这些值转换为双精度并将它们添加到六个不同的双精度累加器中。这些累加器在迭代中是相同的,因此它们可以存在于寄存器中。由于算法的性质,使内存访问模式连续是不可行的。不过,该数组足够小以适合 L1 缓存,因此内存延迟/带宽不是瓶颈。
我愿意使用汇编语言或 SSE2 内在函数来并行化它。我知道我需要一次将两个浮点数加载到 XMM 寄存器的两个低位双字中,使用 cvtps2pd 将它们转换为两个双精度数,然后使用 addpd 一次将它们添加到两个累加器中。
我的问题是,如果它们在内存中不相邻,我如何将两个浮点数放入单个 XMM 寄存器的两个低位双字中?显然,任何速度太慢以至于违背并行化目的的技术都是没有用的。将不胜感激 ASM 或 Intel/GCC 内在函数的答案。
编辑:
严格来说,浮点数组的大小在编译时是未知的,但它几乎总是 256,所以这可以是特殊情况。
应读取的浮点数组元素是通过从字节数组中加载值来确定的。有六个字节数组,每个累加器一个。字节数组的读取是顺序的,每次循环迭代从每个数组读取一次,因此那里不应该有很多缓存未命中。
float 数组的访问模式实际上是随机的。
【问题讨论】:
-
您可能正在寻找
gather指令(那里有一个完整的系列,具体取决于您的 CPU 型号。Haswell 应该有一些不错的改进) -
@Leeor:我不认为
gather是 SSE2 指令集的一部分。不是AVX2吗? dsimcha,你的机器上有 AVX2 吗? -
@NathanFellman,啊,对不起,我错过了这个限制
-
从尝试
_mm_set_ps或_mm_set_pd开始,看看你的编译会生成什么代码(启用优化)——它可能会让你大吃一惊。 -
告诉我们更多关于这些浮点数在内存中的布局模式。如果它们是规则间隔的,也许交错处理是可能的?可以提供伪代码吗?
标签: performance optimization assembly sse simd