【发布时间】:2014-05-06 10:56:15
【问题描述】:
我有一个程序几乎把他所有的时间都花在计算循环上,比如
for(int j = 0; j < BIGNUMBER; j++)
for(int i = 0; i < SMALLNUMBER; i++)
result += var[i] / sqrt((A[i].x-B[j].x)*(A[i].x-B[j].x)+(A[i].y-B[j].y)*(A[i].y-B[j].y)+(A[i].z-B[j].z)*(A[i].z-B[j].z));
其中1.0/sqrt(...) 计算两个向量A[i] = {A[i].x, A[i].y, A[i].z} 和B[j] = {B[j].x, B[j].y, B[j].z} 之差的范数的倒数,这也是循环中开销最大的部分。
有没有办法优化循环,即使有一些精度损失?
更新:
这里是非向量化循环步骤的汇编代码,每条指令的延迟都比较差。您清楚地看到平方根的倒数是瓶颈:
movsd A(%rip), %xmm0 1
movsd A+8(%rip), %xmm2 1
subsd B(%rip), %xmm0 3
subsd B+8(%rip), %xmm2 3
movsd A+16(%rip), %xmm1 1
mulsd %xmm0, %xmm0 5
subsd B+16(%rip), %xmm1 3
mulsd %xmm2, %xmm2 5
mulsd %xmm1, %xmm1 5
addsd %xmm2, %xmm0 3
addsd %xmm1, %xmm0 3
movsd .LC0(%rip), %xmm1 1
unpcklpd %xmm0, %xmm0 1
cvtpd2ps %xmm0, %xmm0 4
unpcklps %xmm0, %xmm0 3
cvtps2pd %xmm0, %xmm0 2
sqrtsd %xmm0, %xmm0 58
divsd %xmm0, %xmm1 32
mulsd var(%rip), %xmm1 5
addsd result(%rip), %xmm1 3
cvttsd2si %xmm1, %eax 3
movsd %xmm1, result(%rip) 1
(顺便说一句,我不明白它为什么会这样做unpcklpd cvtpd2ps unpcklps cvtps2pd。)
【问题讨论】:
-
你的问题应该移到math.stackexchange.com
-
@fluminis,你舒尔吗?
-
您确定
1./sqrt(x)是瓶颈吗?如果是这样,你能避免吗? (其余的计算可以通过使用一些线性代数来加速,但那部分不能。) -
好吧,假设我可以添加这些延迟,它们是 146 个周期,所以 33% 在
sqrtsd,22% 在divsd,45% 在其他所有东西中,所以可能在sqrtsd之外仍有改进的空间。 “瓶颈”这个词的问题在于它会让你倾向于只看一个地方,并且可能仅仅因为它是漫射的而忽略更大的东西。 -
很难判断您的数据类型是什么,但从生成的代码看来,您正在混合使用浮点数和双精度数。如果您可以将所有数据、计算和函数调用限制为单精度浮点数,那么您应该会获得更好的性能。
标签: math optimization assembly sse micro-optimization