【问题标题】:gcc optimizations while copying an array复制数组时的 gcc 优化
【发布时间】:2011-05-08 19:00:21
【问题描述】:

我需要分析一个执行大量数组副本的应用程序,所以我最终分析了这个非常简单的函数:

typedef unsigned char UChar;
void copy_mem(UChar *src, UChar *dst, unsigned int len) {
        UChar *end = src + len;
        while (src < end)
                *dst++ = *src++;
}

我正在使用 Intel VTune 进行实际分析,从那里我发现使用 gcc -O3 和“普通” gcc (4.4) 进行编译时存在显着差异。

为了理解为什么和如何,我得到了两个编译的汇编输出。

未优化的版本是这个:

.L3:
        movl    8(%ebp), %eax
        movzbl  (%eax), %edx
        movl    12(%ebp), %eax
        movb    %dl, (%eax)
        addl    $1, 12(%ebp)
        addl    $1, 8(%ebp)
.L2:
        movl    8(%ebp), %eax
        cmpl    -4(%ebp), %eax
        jb      .L3
        leave

所以我看到它首先从 *src 加载一个 dword 并将低字节放入 edx,然后将其存储到 *dst 并更新指针:很简单。

然后看到优化版,什么都不懂。

编辑here 有优化的程序集。

因此我的问题是:gcc 可以在这个函数中做什么样的优化?

【问题讨论】:

  • 使用 memcpy - 它应该比你的循环快得多。
  • 请将优化后的输出复制到您的问题中。
  • 我不能使用 memcpy,因为我可以有重叠。
  • @akappa:然后使用memmove。它可以处理重叠。

标签: c optimization compiler-construction assembly


【解决方案1】:

优化后的代码相当混乱,但我可以发现 3 个循环(靠近 L6、L13 和 L12)。我认为 gcc 做了@GJ 的建议(我支持他)。 L6 附近的循环每次移动 4 个字节,而循环 #2 只移动一个字节,并且有时仅在循环 #1 之后执行。我仍然无法获得循环 #3,因为它与循环 #2 相同。

【讨论】:

  • 是的,我认为这是唯一可以用它做的真正优化。谢谢!
【解决方案2】:

您的未优化函数逐字节移动!

如果您首先计算长度,则可以一次移动 4 个字节,其余 1..3 个字节手动移动。如果您可以确保正确的(4 字节)内存对齐,则复制功能也应该更快。 并且不需要在堆栈上增加指针,您可以使用寄存器。 这一切都认为将大大提高函数的速度。

或者使用memmove之类的专用内存移动功能!

【讨论】:

    【解决方案3】:

    优化的类型取决于函数及其属性,如果函数被标记为内联,并且足够小,它将变成MOV的展开循环,这比基于REP的循环更快变体(它可以避免寄存器溢出)。对于未知大小,您将获得 REP MOVS 系列指令(从最大字大小开始以减少恒定大小的循环数量,否则它将使用您复制的数据单元的大小)。

    如果启用 SSE,它很可能会使用长度允许的展开未对齐移动 (MOVDQU) 或循环未对齐移动(不知道是否会使用时间预取,其增益取决于块大小)如果长度足够大。如果源/目标正确对齐,它将尝试使用更快对齐的变体。

    就目前而言,当它没有被内联时,你能得到的最好的函数是MOVSB

    【讨论】:

      【解决方案4】:

      gcc 可以生成的最快的 x86 汇编指令是rep movsd,它一次会复制 4 个字节。 &lt;string.h&gt; 中的标准 libc 函数 memcpy 以及用于 memcpy 的特殊内联 gcc 以及 &lt;string.h&gt; 中的许多其他函数为您提供最快的结果。

      【讨论】:

      • 所以它只是循环展开的应用(每次展开4个副本)?
      • movpd/movps 会更快吗?
      • @akappa: `rep movsd' 确实循环展开,但它也包含循环本身,即它是一个用于复制大数据块的复合汇编指令。它应该比包含移动、比较和跳转指令的循环快一点。
      【解决方案5】:

      您还可以在此处使用restrict

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-12-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多