需要对我的 SSE/Assembly 尝试提出一些建设性的批评

2024-01-01

我正在努力将一些代码转换为 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
    }
}

由于阅读代码非常困难,我将解释一下我所做的:

加载的向量4,xmm0 _____ p = [px, py, px, py]
多。通过向量4,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 个向量4,scale = [m, m, m, m]
__________________________多----------------------------
结果,xmm0 = [(pxc-pys)m, (pyc-px*s)m, (pxs-py*c)m, (pys-px*c)m]


加载xy向量4,xmm3 = [p2x,p2x,p2y,p2y]
重用,xmm0 = [(px
c-py*s)m, (pyc-px*s)m, (pxs-py*c)m, (pys-px*c)m]
_____________________减去 - - - - - - - - - - - - - -
结果,xmm3 = [p2x-(px
c-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 and oy,你计算四ox价值观和四个oy同时值。这可以最大限度地减少浪费的计算和洗牌。

为了做到这一点,你捆绑了几个x, y, p2x and p2y值放入连续数组中(即您可能有一个包含四个值的数组x,四个值的数组y, ETC)。然后你可以这样做:

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 加载到寄存器中并使用它们来处理manyx 和 y 的向量,而不是为每个向量重新加载它们。为了获得最佳性能,两个或多个向量的计算量应交错,以确保处理器有足够的工作来防止管道停顿。

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

Edit

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

我希望你的矢量代码would事实证明比 i7 上的标量代码更快,也可能比 Core2 上的标量代码更快。另一方面,如果可以的话,一次做四个会更快。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

需要对我的 SSE/Assembly 尝试提出一些建设性的批评 的相关文章

随机推荐

  • 如何使用 R 以编程方式提取/解压 .7z (7-zip) 文件

    我正在尝试自动提取许多使用 7 zip 压缩的文件 我需要自动化这个过程 因为a 我想解锁很多年的数据 b 我想与其他人共享我的代码并防止他们手动重复该过程 我的计算机上安装了 WinRAR 和 7 zip 我可以使用任一程序轻松地单独打开
  • 构建和验证 Gigya 签名

    我编写了一个方法 根据 Gigya 的指定时间戳和 UID 来验证 gigya 签名构建签名的说明 http developers gigya com 030 Gigya Socialize API 2 0 010 Developer Gu
  • 可能是C# 4.0编译器错误,其他人可以验证吗?

    由于我不知道究竟是哪一部分触发了错误 所以我不完全确定如何更好地标记它 这个问题是SO问题的副产品C 代码似乎以无效的方式进行优化 导致对象值变为 null https stackoverflow com questions 3379894
  • 是否有解决方法可以在 Ruby 中打开包含下划线的 URL?

    我正在使用 open uri 来打开 URL resp open http sub domain domain com 如果它包含下划线 我会收到错误 URI InvalidURIError the scheme http does not
  • 如何在 C++/CLI 接口中声明默认索引属性

    如何在 C CLI 接口中声明默认索引属性 请原谅使用命名空间的重复 完全限定符号 因为我刚刚学习 C CLI 并且希望确保 C 和 C 之间不会发生语言原语的意外混淆 Code is public interface class ITes
  • 代码段的动态重定位

    只是出于好奇 我想知道是否可以在期间重新定位一段代码 程序的执行 例如 我有一个函数 这个函数应该 每次执行后都会在内存中进行替换 我们想到了一个想法 就是使用自修改代码来做到这一点 根据网上的一些资源 自行修改 代码可以在Linux上执行
  • DICOM StudyInstanceUID 对于患者来说应该是唯一的吗?

    在处理 DICOM 研究 系列和媒体概念时 我想知道这些值对于所有数据是否都是唯一的 或者仅对于它们所属的患者而言是唯一的 另有表述 我可以让 2 名患者的研究 系列 SOP 实例 uid 值相同吗 或者 DICOM 标准根本不关心这一点
  • python opencv如何分割血管

    我正在尝试使用 Python 和 OpenCV 分割视网膜图像中的血管 这是原始图像 理想情况下 我希望所有血管都像这样非常明显 不同的图像 这是我到目前为止所尝试过的 我拍摄了图像的绿色通道 img cv2 imread images H
  • 由初始值设定项列表初始化的数组存储在哪里?

    鉴于这段代码 void someFunction void int array 1 2 3 4 5 6 7 8 9 10 数组的值存储在哪里 Stack Heap 与那些字符串文字一起 是不是叫高频堆 别的地方 我问这个问题是因为我不确定这
  • 如何修改一个活动的另一活动的变量?

    比方说 头等舱 有一个变量 字符串当前值 红色 带有一个通往 Second class 一项活动 的按钮 First class Activity 在文本视图中显示变量 currentValue 的值 目前为红色 如果我们按下按钮 它将带我
  • 在 Excel 中调整单元格宽度

    我正在使用 xlsxwriter 写入 Excel 工作表 我面临的问题是 当文本大于单元格大小时 它就会被隐藏 import xlsxwriter workbook xlsxwriter Workbook file xlsx worksh
  • Crashlytics - Firebase 日志中的 Stacktrace 不可读

    我刚刚开始使用 React Native Firebase 和 Crashlytics 版本 6 当我打电话时firebase crashlytics recordError error 在JS中catch我在 Firebase Crash
  • Python 3.10 模式匹配 (PEP 634) - 字符串中的通配符

    我有一个很大的 JSON 对象列表 我想根据其中一个键的开头来解析这些对象 并使用通配符来处理其余的 很多键都是相似的 比如 matchme foo and matchme bar 有一个内置通配符 但它仅用于整个值 有点像else 我可能
  • 在struts2中使用tile

    我正在关注 Struts2 中的 Tile 教程 但遇到以下错误 SEVERE Error configuring application listener of class org apache struts2 tiles StrutsT
  • 自定义声音推送通知不起作用(Flutter)

    to XXXX notification title ASAP Alert body Please open your app data screen Nexpage1 sound alarm click action FLUTTER NO
  • 从文本文件中提取两个分隔符之间的文本

    我目前正在写关于首席执行官自恋的硕士论文 为了衡量它 我必须进行财报电话文本分析 我按照 python 中提供的答案编写了一段代码这个链接 https stackoverflow com questions 36559356 extract
  • Ruby on Rails:为什么我在 Rails 后收到有关 javascript 和 css 的消息?

    轨道 gt Started GET assets application css body 1 for 127 0 0 1 at 2011 10 11 03 37 03 0900 Served asset application css 3
  • JPA:如何覆盖@Embedded属性的列名

    Person class Embeddable public class Person Column public int code 嵌入在里面Event两个不同属性的两倍 manager and operator Entity publi
  • ICMP 是传输层协议吗?

    我正在观看有关网络的视频讲座 讲师提到 ICMP 作为传输层协议 然而 谷歌搜索它显示了各种论坛将其描述为网络层协议 这让我很困惑 有人可以澄清一下吗 传输层协议涉及端到端发送数据并确保 或明确不确保 可靠性 TCP 用于将数据从一台计算机
  • 需要对我的 SSE/Assembly 尝试提出一些建设性的批评

    我正在努力将一些代码转换为 SSE 虽然我有正确的输出 但它比标准 C 代码慢 我需要执行此操作的代码是 float ox p2x px c py s m float oy p2y px s py c m 我得到的 SSE 代码是 void