在 Skylake 上展开 1 周期循环会使性能降低 25%。 uops调度问题?

2024-02-13

TL;DR我有一个循环需要 1 个周期才能在 Skylake 上执行(它执行 3 次加法 + 1 次增量/跳转)。

当我将其展开超过 2 次(无论多少次)时,我的程序运行速度会慢 25% 左右。这可能与对齐有关,但我不清楚是什么。

编辑:这个问题曾经询问为什么微指令是由 DSB 而不是 MITE 提供的。现在已移至这个问题 https://stackoverflow.com/q/59936512/4990392.


我试图对一个循环进行基准测试,该循环在我的 Skylake 上进行了 3 个添加。这个循环应该在一个周期内执行,因为3加+1增量与条件跳转融合在一起,一旦融合就可以在一个周期内执行。正如预期的那样。

然而,在某些时候,我的 C 编译器尝试展开该循环,从而产生更差的性能。我现在试图理解为什么展开的循环比未展开的循环具有更差的性能,因为我期望两者具有相同的性能,或者展开的循环可能小于慢 15% https://stackoverflow.com/a/39940932/4990392.

这是我的 C 代码:

int main() {
  int a, b, c, d;

  #pragma unroll(2)
  for (unsigned long i = 0; i < 2000000000; i++) {
    asm volatile("" : "+r" (a), "+r" (b), "+r" (c), "+r" (d));
    a = a + d;
    b = b + d;
    c = c + d;
  }

  // Prevent data from being optimized out
  asm volatile("" : "+r" (a), "+r" (b), "+r" (c));

}

使用 Clang 7.0.0 -O3 进行编译会生成以下(已清理的)程序集(称为v1今后):

    movl    $2000000000, %esi
    .p2align    4, 0x90
.LBB0_1:
    addl    %edi, %edx
    addl    %edi, %ecx
    addl    %edi, %eax
    addl    %edi, %edx
    addl    %edi, %ecx
    addl    %edi, %eax
    addq    $-2, %rsi
    jne .LBB0_1

并进行基准测试perf stat -e cycles表明每次迭代大约需要 2 个周期。

然而,用“新的 64 位寄存器”(r8 到 r15)替换任何寄存器会导致循环在 3 个周期内执行,而不是 2 个周期(我们称此代码为v2):

    movl    $2000000000, %esi
    .p2align    4, 0x90
.LBB0_1:
    addl    %edi, %r14d
    addl    %edi, %ecx
    addl    %edi, %eax
    addl    %edi, %r14d
    addl    %edi, %ecx
    addl    %edi, %eax
    addq    $-2, %rsi
    jne .LBB0_1

这不是一个随机的例子:如果我向程序添加一些东西并且运气不好,Clang 实际上会产生这个循环(我的初始版本是相同的 C 代码,带有额外的变量随机初始化、预热阶段和 rdtscp 来计时)循环,并使用了 Clangr14d在循环)。该循环大约执行 3 个周期/迭代。

进一步的测试表明,展开循环任意次数大于 2 次都会使程序执行 25 亿个周期(而不展开的循环为 20 亿个周期)。

一个循环中的uop数为3*n+1 (where n是展开因子,并且1代表融合的add/jne),这意味着展开3次的循环有10个uop; 4 乘以 13 微指令等。这些是相当少量的微指令,应该适合 DSB(微指令高速缓存)。我在 Skylake 上更新了微代码并修复了 SKL150,因此我的 LSD 循环缓冲区被禁用 https://stackoverflow.com/questions/45660139/how-exactly-do-partial-registers-on-haswell-skylake-perform-writing-al-seems-to/45660140#45660140.

此外,展开 3、4、10 或 50 次根本不会改变性能:我的代码始终运行 25 亿个周期(而非展开的代码运行 20 亿个周期)。这有点令人惊讶,因为 3 个加法应该总是在 1 个周期中执行,因此,如果由于某种原因在循环末尾丢失了一个额外的周期,则在展开增加时应摊销其开销,并且渐近(在展开中)因子)性能应接近 20 亿次循环。

Both llvm-mca and iaca预测展开ntimes 将使循环执行n周期(这将使整个程序执行 20 亿个周期)。

总而言之,问题是:为什么我的循环一旦展开超过 2 次就会慢 25%?


None

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

在 Skylake 上展开 1 周期循环会使性能降低 25%。 uops调度问题? 的相关文章

  • 我可以在 pandas 中执行动态行累加吗?

    如果我有以下数据框 如下导出 df pd DataFrame np random randint 0 10 size 10 1 0 0 0 1 2 2 8 3 1 4 0 5 0 6 7 7 0 8 2 9 2 有没有有效的方法cumsum
  • 数百个空闲线程的影响

    我正在考虑使用可能数百个线程来实现通过网络管理设备的任务 这是一个在带有 Linux 内核的 powerpc 处理器上运行的 C 应用程序 在每个任务进行同步以将数据从设备复制到任务的初始阶段之后 任务变得空闲 并且仅在收到警报或需要更改一
  • 尝试使用 x86 程序集 GNU GAS 在数组索引处赋值时出现错误

    我在用x86GNU 与 GCC 的程序集 并尝试实现相当于以下内容的程序集c c int x 10 x 0 5 但是 当我尝试运行 使用命令 a out 我的汇编代码如下 第一次编译后gcc filename s 错误Segmentatio
  • Maven 依赖项更新报告需要数小时才能完成

    我有任务运行 Jenkins 工作女巫会报告新版本的库 我认为这些可以满足我的需要 org codehaus mojo versions maven plugin 2 5 plugin updates report org codehaus
  • 从汇编程序获取命令行参数

    通读 专业汇编语言书籍 似乎它提供了用于读取命令行参数的错误代码 我纠正了一点 现在它从段错误变成了读取参数计数 然后是段错误 这是完整的代码 data output1 asciz There are d params n output2
  • jQuery UI .buttonset() 太慢

    我的 HTML 页面上有几千个按钮 运行需要10多秒 buttonset buttonset 文件准备好 有没有更快的方法来做到这一点 或者是我以某种方式限制按钮数量的唯一解决方案 创建buttonset在第一次显示之前按需进行 我刚刚测试
  • 在Python中为什么ifrank:比ifrank!= 0更快:

    当我改变的时候 for i in range 0 100 rank ranks i if rank 0 pass to for i in range 0 100 rank ranks i if rank pass 我发现第二个代码效率更高
  • 在 Java 中加载和缓存图像的最佳方法是什么?

    我有超过一千个 16 x 16 像素图块图像的大量集合 我在 Java 中制作的游戏需要这些图像 在不耗尽 JVM 可用内存的情况下存储切片的最佳方法是什么 我认为生成 1000 BufferedImages 可能并不明智 保持图像准备就绪
  • 使用 Easy 68K (68000) 组装范围内的随机数

    我正在使用 Easy 68K 模拟器创建一个简单的黑杰克游戏 需要使用随机数来分配牌 我的牌必须在 2 到 11 的范围内 我似乎每次都得到相同的数字 但它不在我预期的范围内 我的卡值需要以 D3 结束 因此我有以下随机数代码 CLR L
  • 68HC11计算sin(x)的汇编代码

    68HC11 使用泰勒级数或查找表计算正弦值的汇编代码是什么 显示值只能是整数 查找表如何工作 在这种情况下 如何使用它来实现泰勒级数 http en wikipedia org wiki Taylor series 如果您正在寻找浮点解决
  • 寄存器寻址模式与直接寻址模式

    我在试卷中遇到过这个问题 它指出 哪种给定的寻址模式更快 为什么 寄存器寻址方式 直接寻址方式 现在根据我的说法 寄存器寻址模式应该更快 因为寄存器是计算机中最快的存储位置 这是正确答案吗 请帮忙 谢谢 两种寻址模式之间的区别是 地址的来源
  • “rep stos”x86 汇编指令序列有什么作用?

    我最近偶然发现了以下汇编指令序列 rep stos dword ptr edi For ecx重复 存储内容eax到哪里edi指向 递增或递减edi 取决于方向标志 每次 4 个字节 通常 这用于memset型操作 通常 该指令简单地写成r
  • HTML if 语句在 CDN 失败时加载本地 JS/CSS

    当从 CDN 或任何外部服务器加载 CSS JS 文件时 有可能 即使概率很低 由于外部故障而丢失该文件 在这种情况下 html 页面将因缺乏适当的 CSS 和 JS 而被损坏 有没有一种实用的方法可以在 CDN 故障时加载本地版本 IF
  • 如何知道寄存器是否是“通用寄存器”?

    我试图了解寄存器必须具备什么标准才能被称为 通用寄存器 我相信通用寄存器是一个可以用于任何用途的寄存器 用于计算 将数据移入 移出等 并且是一个没有特殊用途的寄存器 现在我读到了ESP寄存器是通用寄存器 我猜是ESP寄存器可以用于任何事情
  • 在 Pandas 中创建许多新列的最 Pythonic 方法

    我有一个大数据框df 约 100 列和约 700 万行 我需要创建约 50 个新变量 列 它们是当前变量的简单转换 一种方法是与许多人一起 apply声明 我只是使用transform 作为简单转换的占位符 例如max或平方 df new
  • 更改二维数组元素的值会更改整个列

    当我打印我的arrvalue 我得到了 2D 数组的正确值 但是当我退出 while 循环时 我的值都是错误的 我不确定我做错了什么 num runs n 4 x np linspace 1 1 n y np linspace 1 1 n
  • LINQ 函数的顺序重要吗?

    基本上 正如问题所述 LINQ 函数的顺序是否重要 表现 显然 结果仍然必须相同 Example myCollection OrderBy item gt item CreatedDate Where item gt item Code g
  • Java 基准测试 - 为什么第二个循环更快?

    我对此很好奇 我想检查哪个函数更快 所以我创建了一些代码并执行了很多次 public static void main String args long ts String c sgfrt34tdfg34 ts System current
  • 快速 log2(float x) 实现 C++

    我需要在 C 中非常快速地实现 log2 float x 函数 我发现了一个非常有趣的实现 而且速度非常快 include
  • ARMv8 A64 汇编中立即值的范围

    我的理解是 ARMv8 A64 汇编中的立即参数可以是 12 位长 如果是这样的话 为什么这行汇编代码是 AND X12 X10 0xFEF 产生此错误 使用 gcc 编译时 Error immediate out of range at

随机推荐

  • Django - 如何从模型中选择特定列?

    我嗅了一下 找不到这个 但我确信它就在这里的某个地方 对这个潜在的双重帖子表示歉意 如果我有这个代码 return Story objects filter user request user id order by create date
  • Python 在 cv2.destroyWindow() 之后冻结

    我在 Mac OS X Lion 上的 Python 2 7 下使用 openCV 每当我运行代码来简单地显示相机源 来自 iSight 时 Python 就会冻结 看起来相机实际上并没有得到清理 我使用了相同代码的多个不同版本 如下 来自
  • Android EditText,在 numberDecimal 输入类型的情况下显示逗号和点作为可能的分隔符

    我需要让用户在输入十进制数时在两个变体之间进行选择 使用逗号 作为分隔符 使用点 作为分隔符 默认情况下 如果我使用inputType numberDecimal in the EditTextxml配置 EditText仅显示数字和逗号
  • R - 更改 corrplot 轴标签的大小

    我正在使用以下内容corrplot require corrplot needs the corrplot package corrplot cor lpp axis1 lpp axis2 method c number bg grey10
  • 如何将我的函数放入类中。Beginner

    我下面有一个 Json 函数 需要构造一个具有两个函数的类 我的第二个函数如何 知道 data这是第一个函数的响应 def results json request request get json data json loads json
  • Oracle SQL 循环遍历日期范围

    我正在尝试编写一个执行以下操作的查询 从 Visit 表中获取 Start Date 和 End Date 对于日期范围内包含的每个日期 搜索遭遇表 查看特定提供者在该日期是否看过患者 生成一个表格 显示每个日期以及谁在该日期见过该患者 日
  • 为什么我的 JFrame 没有显示?

    我很确定我以前已经这样做过 但由于某种原因 当我运行它时 JFrame 不会显示 JLabel originalString new JLabel Original String str getMutator JLabel currentS
  • 如何在 flutter/dart 中从购物车中删除商品

    当您有单独的列表小部件时 如何从 flutter 中的列表中删除购物车项目 我有三个包含以下代码的文件 carts dart gt 我在其中显示所有列表项 cart list item gt 我在其中创建了一个小部件 api service
  • 如何模拟任何未直接调用的函数?

    TL DR 我如何修补或模拟 任何未被直接调用 使用的函数 设想 我有一个简单的单元测试片段 utils functions py def get user agents sends requests to a private networ
  • 为什么我应该使用“->”而不是“.”在对象的指针中? [复制]

    这个问题在这里已经有答案了 我同意这可能是一个非常初学者的问题 但我不知道为什么我不能使用 访问对象指针的成员 e g JMP sum obj new JMP 0 JMP a sum obj gt number a number sum o
  • 从句子级别的旋转文本中取消旋转 PHP 中的文本

    我需要在 php 页面中整齐地输出旋转文本 我已经有了 hi hello greetings 格式的预旋转文本 我有一个在其他地方找到的 php 代码 但它不会在句子级别输出旋转文本 其中有两个 这是需要修复的代码
  • 如何在magento中提交表单后获取发布数据变量

    如何获取后变量的数据 就像如果我使用 post 方法发布表单 那么我可以使用 REQUEST 或 POST 获取它 我怎样才能在 mgento 中做到这一点 您可以使用以下命令读取值 this gt getRequest gt getPar
  • 在 Django 应用程序内对弹性搜索进行单元测试

    我有一个使用弹性搜索的 Django 应用程序 我想要 100 的代码测试覆盖率 因此我需要测试对 elasticsearch 在本地 安装 的 API 调用 所以我的问题是 模拟整个elasticsearch 更好还是我应该运行elast
  • cin.getline() 正在跳过 C++ 中的输入[重复]

    这个问题在这里已经有答案了 如果我使用以下代码 getline 不会采用最后一个输入 对于 for 循环的最后一次迭代 它只是跳过它 int main int n map
  • d3 sunburst 不使用内联 json 绘制

    我一直在尝试绘制内联旭日形 但结果始终是一个空块 有人可以看一下并提示我为什么吗 非常感谢你的帮助 基本上这是示例代码 我只是尝试将 json 加载更改为内联 json 这样我就可以更轻松地解析数据 function draw chart
  • 删除后未找到结果

    我有以下删除语句 delete s p o
  • 通过 jQuery AJAX 将数据发布到 Python CGI 脚本

    我正在尝试设置一个简单的脚本 其中使用 jQuery ajax 函数将一些数据发送到 Python CGI 脚本 Python 脚本只会将发布到其中的数据设为大写 然后将该数据返回到 HTML 文件 其中 div 将使用内容进行更新 我有如
  • iPhone 开发 - 限制用户与应用程序的交互并显示进度指示器

    我有一个案例 我从服务器获取信息 我的应用程序有一个选项卡栏和导航按钮 我希望应用程序显示进度指示器并禁用所有其他控件 以便用户在从服务器提取数据时无法跳转 我怎样才能做到这一点 我想到的一种方法是显示带有进度窗口的透明视图 很像消息警报窗
  • H2数据库:聚集索引支持

    我使用 H2 数据库来存储包含大量时间序列的环境数据 时间序列只是定期 例如每小时一次 记录在数据库中的传感器的测量值 表中存储的数据 CREATE TABLE hydr dt timestamp value double sensorid
  • 在 Skylake 上展开 1 周期循环会使性能降低 25%。 uops调度问题?

    TL DR我有一个循环需要 1 个周期才能在 Skylake 上执行 它执行 3 次加法 1 次增量 跳转 当我将其展开超过 2 次 无论多少次 时 我的程序运行速度会慢 25 左右 这可能与对齐有关 但我不清楚是什么 编辑 这个问题曾经询