【问题标题】:C++ GCC Optimization Speed slows down when local variable is copied to global variable将局部变量复制到全局变量时,C ++ GCC优化速度变慢
【发布时间】:2016-05-13 10:54:16
【问题描述】:

我对 GCC 的优化标志及其工作方式有疑问。

我有一段很长的代码,它使用了所有本地数组和变量。在代码的最后,我将本地数组的内容复制到一个全局数组中。这是我的代码的一个非常精简的示例:

uint8_t globalArray[16]={0};
void func()
{ 
    unsigned char localArray[16]={0};
    for (int r=0; r<1000000; r++)
    {    
        **manipulate localArray with a lot of calculations**
    }
    memcpy(&globalArray,localArray,16);
}    

以下是三种不同场景下代码的大致速度:

  1. “-O3”优化:3.203s

  2. 使用“-O3”优化:1.457s

  3. “-O3”优化和没有最后的memcpy(&amp;globalArray,localArray,16);语句:0.015s

无需将本地数组复制到全局数组中,代码运行速度几乎快了 100 倍。我知道全局数组存储在内存中,本地数组存储在寄存器中。我的问题是:

  1. 为什么仅将本地数组的 16 个元素复制到全局数组会导致执行速度降低 100 倍?我已经搜索了这个论坛和在线,我找不到我的这个特定场景的明确答案。

  2. 有什么方法可以在不损失速度的情况下提取局部变量的内容?

提前感谢任何可以帮助我解决此问题的人。

【问题讨论】:

  • 在情况 3 中,编译器可能删除了所有计算,因为它们不会导致可观察到的行为。您可以通过检查汇编代码来验证这一点
  • 您还可以从函数返回 localArray 指针,这也将阻止编译器优化函数的全部内容。这将提供更好的比较。
  • @Conor 这是未定义的行为。
  • @TartanLama,是的,你当然是对的,也许更好地传入 GlobalArray 并填充它?这样你就可以看到有没有 memcpy 的区别
  • @TartanLlama 不,不是。使用返回的指针将是 UB,但仅返回它不会。我怀疑它会禁用优化。

标签: c++ arrays performance gcc compiler-optimization


【解决方案1】:

如果没有memcpy,您的编译器可能会看到永远不会读取localArray,因此它不需要在循环体中进行任何计算。

以这段代码为例:

uint8_t globalArray[16]={0};
void func()
{ 
    unsigned char localArray[16]={0};
    for (int r=0; r<1000000; r++)
    {
        localArray[r%16] = r;
    }
    memcpy(&globalArray,localArray,16);
} 

带有-O3 的Clang 3.7.1 输出此程序集:

func():                               # @func()
# BB#0:
        xorps   %xmm0, %xmm0
        movaps  %xmm0, -24(%rsp)
        #DEBUG_VALUE: r <- 0
        xorl    %eax, %eax
.LBB0_1:                                # =>This Inner Loop Header: Depth=1
        #DEBUG_VALUE: r <- 0
        movl    %eax, %ecx
        sarl    $31, %ecx
        shrl    $28, %ecx
        leal    (%rcx,%rax), %ecx
        andl    $-16, %ecx
        movl    %eax, %edx
        subl    %ecx, %edx
        movslq  %edx, %rcx
        movb    %al, -24(%rsp,%rcx)
        leal    1(%rax), %ecx
        #DEBUG_VALUE: r <- ECX
        movl    %ecx, %edx
        sarl    $31, %edx
        shrl    $28, %edx
        leal    1(%rax,%rdx), %edx
        andl    $-16, %edx
        negl    %edx
        leal    1(%rax,%rdx), %edx
        movslq  %edx, %rdx
        movb    %cl, -24(%rsp,%rdx)
        leal    2(%rax), %ecx
        movl    %ecx, %edx
        sarl    $31, %edx
        shrl    $28, %edx
        leal    2(%rax,%rdx), %edx
        andl    $-16, %edx
        negl    %edx
        leal    2(%rax,%rdx), %edx
        movslq  %edx, %rdx
        movb    %cl, -24(%rsp,%rdx)
        leal    3(%rax), %ecx
        movl    %ecx, %edx
        sarl    $31, %edx
        shrl    $28, %edx
        leal    3(%rax,%rdx), %edx
        andl    $-16, %edx
        negl    %edx
        leal    3(%rax,%rdx), %edx
        movslq  %edx, %rdx
        movb    %cl, -24(%rsp,%rdx)
        leal    4(%rax), %ecx
        movl    %ecx, %edx
        sarl    $31, %edx
        shrl    $28, %edx
        leal    4(%rax,%rdx), %edx
        andl    $-16, %edx
        negl    %edx
        leal    4(%rax,%rdx), %edx
        movslq  %edx, %rdx
        movb    %cl, -24(%rsp,%rdx)
        addl    $5, %eax
        cmpl    $1000000, %eax          # imm = 0xF4240
        jne     .LBB0_1
# BB#2:
        movaps  -24(%rsp), %xmm0
        movaps  %xmm0, globalArray(%rip)
        retq

对于没有memcpy 的相同代码,它会输出:

func():                               # @func()
# BB#0:
        #DEBUG_VALUE: r <- 0
        retq

即使你对汇编一无所知,很明显后者什么也不做。

【讨论】:

  • 谢谢。完美回答。
猜你喜欢
  • 1970-01-01
  • 2011-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-08
  • 2017-09-20
  • 2019-06-05
  • 2013-01-06
相关资源
最近更新 更多