gpt4 book ai didi

assembly - 需要对我的 SSE/Assembly 尝试进行一些建设性的批评

转载 作者:行者123 更新时间:2023-12-04 14:20:08 25 4
gpt4 key购买 nike

我正在将一些代码转换为 SSE,虽然我有正确的输出,但结果证明它比标准 C++ 代码慢。

我需要执行此操作的代码位是:

float ox = p2x - (px * c - py * s)*m;
float oy = p2y - (px * s - py * c)*m;

我得到的 SSE 代码是:
void assemblycalc(vector4 &p, vector4 &sc, float &m, vector4 &xy)
{
vector4 r;
__m128 scale = _mm_set1_ps(m);

__asm
{
mov eax, p //Load into CPU reg
mov ebx, sc
movups xmm0, [eax] //move vectors to SSE regs
movups xmm1, [ebx]

mulps xmm0, xmm1 //Multiply the Elements

movaps xmm2, xmm0 //make a copy of the array
shufps xmm2, xmm0, 0x1B //shuffle the array

subps xmm0, xmm2 //subtract the elements

mulps xmm0, scale //multiply the vector by the scale

mov ecx, xy //load the variable into cpu reg
movups xmm3, [ecx] //move the vector to the SSE regs

subps xmm3, xmm0 //subtract xmm3 - xmm0

movups [r], xmm3 //Save the retun vector, and use elements 0 and 3
}
}

由于很难阅读代码,我将解释我所做的:

加载 vector4 , xmm0 _____ p = [px , py , px , py ]
多。由 vector4, xmm1 _ cs = [c , c , s , s ]
__________________________多----------------------------
结果,_____________ xmm0 = [pxc, pyc, pxs, pys]

重用结果,xmm0 = [pxc, pyc, pxs, pys]
洗牌结果,xmm2 = [pys, pxs, pyc, pxc]
_____________________减去 - - - - - - - - - - - - - -
结果,xmm0 = [pxc-pys,pyc-pxs,pxs-pyc,pys-pxc]

重用结果,xmm0 = [pxc-pys, pyc-pxs, pxs-pyc, pys-pxc]
加载 m vector4, scale = [m, m, m, m]
__________________________多----------------------------
结果,xmm0 = [(pxc-pys)m, (pyc-px*s)m, (pxs-py*c)m, (pys-px*c)m]

加载 xy vector4, xmm3 = [p2x, p2x, p2y, p2y]
重用, xmm0 = [(pxc-py*s)m, (pyc-px*s)m, (pxs-py*c)m, (pys-px*c)m]
_____________________减去 - - - - - - - - - - - - - -
结果,xmm3 = [p2x-(pxc-py*s)m, p2x-(pyc-px*s)m, p2y-(pxs-py*c)m, p2y-(pys-px*c)*m]

然后 ox = xmm3[0] 和 oy = xmm3[3],所以我基本上不使用 xmm3[1] 或 xmm3[4]

对于阅读本文的困难,我深表歉意,但我希望有人能够为我提供一些指导,因为标准 C++ 代码的运行时间为 0.001444 毫秒,而 SSE 代码的运行时间为 0.00198 毫秒。

如果我能做些什么来进一步解释/清理一下,请告诉我。我尝试使用 SSE 的原因是因为我运行了数百万次此计算,这是减慢我当前代码速度的一部分。

在此先感谢您的帮助!
布雷特

最佳答案

进行这种矢量化的通常方法是将问题“放在一边”。而不是计算 ox 的单个值和 oy ,你计算四个 ox值和四个 oy值同时进行。这最大限度地减少了浪费的计算和洗牌。

为了做到这一点,你捆绑了几个 x , y , p2xp2y值转换为连续数组(即,您可能有一个包含 x 的四个值的数组,一个包含四个 y 的值的数组,等等)。然后你可以这样做:

movups  %xmm0,  [x]
movups %xmm1, [y]
movaps %xmm2, %xmm0
mulps %xmm0, [c] // cx
movaps %xmm3, %xmm1
mulps %xmm1, [s] // sy
mulps %xmm2, [s] // sx
mulps %xmm3, [c] // cy
subps %xmm0, %xmm1 // cx - sy
subps %xmm2, %xmm3 // sx - cy
mulps %xmm0, scale // (cx - sy)*m
mulps %xmm2, scale // (sx - cy)*m
movaps %xmm1, [p2x]
movaps %xmm3, [p2y]
subps %xmm1, %xmm0 // p2x - (cx - sy)*m
subps %xmm3, %xmm2 // p2y - (sx - cy)*m
movups [ox], %xmm1
movups [oy], %xmm3

使用这种方法,我们在 18 条指令中同时计算 4 个结果,而使用您的方法在 13 条指令中计算单个结果。我们也没有浪费任何结果。

它仍然可以改进;因为无论如何您都必须重新排列数据结构才能使用这种方法,所以您应该对齐数组并使用对齐的加载和存储而不是未对齐的。您应该将 c 和 s 加载到寄存器中并使用它们来处理 x 和 y 的许多向量,而不是为每个向量重新加载它们。为了获得最佳性能,两个或多个向量值的计算应该交错,以确保处理器有足够的工作来防止流水线停顿。

(旁注:它应该是 cx + sy 而不是 cx - sy ?这会给你一个标准的旋转矩阵)

编辑

你对你在什么硬件上进行计时的评论几乎清除了一切:“奔腾 4 HT,2.79GHz”。这是一个非常古老的微架构,在该架构上未对齐的移动和洗牌非常缓慢;您在管道中没有足够的工作来隐藏算术运算的延迟,并且重新排序引擎并不像在较新的微体系结构上那样聪明。

我希望您的矢量代码将证明比 i7 上的标量代码更快,并且可能在 Core2 上也是如此。另一方面,如果可以的话,一次做四个会更快。

关于assembly - 需要对我的 SSE/Assembly 尝试进行一些建设性的批评,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2923458/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com