指令计数类型为什么这么多数据操作?

时间:2015-01-09 08:48:38

标签: assembly opcode

我有一个基本上循环的程序,并在每个循环中执行TON的添加。

所以像b + = .01在一个循环中可能发生了100次。

所以我希望计算(添加)与加载和存储指令的比率非常高。然而,出乎意料的是,我做的添加越多,我得到的内存读写次数越多。

int b = 0;
int i;
for (i = 0; i < 100000; i++){
b += .01 * (maybe 50 times)?)
}

我正在使用pin工具,内存读写量大幅上升。比增加快得多。而且我很困惑。我认为b是一个局部变量,因此,它不是存储在内存中,而是存储在堆栈中或缓存中。为什么会这样?

我看过这个组件,我看到没有任何地方使用lw或sw。

1 个答案:

答案 0 :(得分:1)

默认编译器几乎总是将具有自动生命周期的变量(例如int b=0;)放在堆栈上。

例如,如果我使用GCC编译这个片段,这与你写的很接近,但更正确一点:

int main()
{
    int b = 0;
    int i;
    for (i = 0; i < 100000; i++) {
        b++;
        b++;
        b++;
        b++;
        b++;
        b++;
        b++;
        b++;
        b++;
        b++;
    }
    return b;
}

我得到以下编译代码:

00000000004004b6 <main>:
  4004b6:       55                      push   %rbp
  4004b7:       48 89 e5                mov    %rsp,%rbp
  4004ba:       c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)
  4004c1:       c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%rbp)
  4004c8:       eb 2c                   jmp    4004f6 <main+0x40>
  4004ca:       83 45 fc 01             addl   $0x1,-0x4(%rbp)
  4004ce:       83 45 fc 01             addl   $0x1,-0x4(%rbp)
  4004d2:       83 45 fc 01             addl   $0x1,-0x4(%rbp)
  4004d6:       83 45 fc 01             addl   $0x1,-0x4(%rbp)
  4004da:       83 45 fc 01             addl   $0x1,-0x4(%rbp)
  4004de:       83 45 fc 01             addl   $0x1,-0x4(%rbp)
  4004e2:       83 45 fc 01             addl   $0x1,-0x4(%rbp)
  4004e6:       83 45 fc 01             addl   $0x1,-0x4(%rbp)
  4004ea:       83 45 fc 01             addl   $0x1,-0x4(%rbp)
  4004ee:       83 45 fc 01             addl   $0x1,-0x4(%rbp)
  4004f2:       83 45 f8 01             addl   $0x1,-0x8(%rbp)
  4004f6:       81 7d f8 9f 86 01 00    cmpl   $0x1869f,-0x8(%rbp)
  4004fd:       7e cb                   jle    4004ca <main+0x14>
  4004ff:       8b 45 fc                mov    -0x4(%rbp),%eax
  400502:       5d                      pop    %rbp
  400503:       c3                      retq   
  400504:       66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  40050b:       00 00 00 
  40050e:       66 90                   xchg   %ax,%ax

请注意addl $0x1,-0x4(%rbp)指令,这些指令正在递增我们的变量,相当于源中的b++。我们可以看到它位于堆栈(-0x4(%rbp))上,因此这些指令中的每一个都将计为加载和存储。这就是为什么你会看到如此高的加载/存储数量。

如果您不希望变量进入堆栈,您可以启用优化并希望编译器做正确的事情,或者您可以使用register关键字传递提示,如下所示:

int main()
{
    register int b = 0;
    int i;
    for (i = 0; i < 100000; i++) {
        b++;
        b++;
        b++;
        b++;
        b++;
        b++;
        b++;
        b++;
        b++;
        b++;
    }
    return b;
}

您将获得以下编译代码:

00000000004004b6 <main>:
  4004b6:       55                      push   %rbp
  4004b7:       48 89 e5                mov    %rsp,%rbp
  4004ba:       53                      push   %rbx
  4004bb:       bb 00 00 00 00          mov    $0x0,%ebx
  4004c0:       c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%rbp)
  4004c7:       eb 22                   jmp    4004eb <main+0x35>
  4004c9:       83 c3 01                add    $0x1,%ebx
  4004cc:       83 c3 01                add    $0x1,%ebx
  4004cf:       83 c3 01                add    $0x1,%ebx
  4004d2:       83 c3 01                add    $0x1,%ebx
  4004d5:       83 c3 01                add    $0x1,%ebx
  4004d8:       83 c3 01                add    $0x1,%ebx
  4004db:       83 c3 01                add    $0x1,%ebx
  4004de:       83 c3 01                add    $0x1,%ebx
  4004e1:       83 c3 01                add    $0x1,%ebx
  4004e4:       83 c3 01                add    $0x1,%ebx
  4004e7:       83 45 f4 01             addl   $0x1,-0xc(%rbp)
  4004eb:       81 7d f4 9f 86 01 00    cmpl   $0x1869f,-0xc(%rbp)
  4004f2:       7e d5                   jle    4004c9 <main+0x13>
  4004f4:       89 d8                   mov    %ebx,%eax
  4004f6:       5b                      pop    %rbx
  4004f7:       5d                      pop    %rbp
  4004f8:       c3                      retq   
  4004f9:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

请注意,递增指令现在是add $0x1,%ebx,我们可以看到我们的变量确实存储在寄存器(此处为ebx)中,如请求的那样。

  

我认为b是一个局部变量,因此没有存储在内存中,而只是存储在堆栈中或缓存中。为什么会这样?

局部变量通常存储在内存中(堆栈中)。但是你可以改变这种行为。在我发布的第二个片段中,您将看到更少的内存读/写操作,因为b不再存储在主存储器中,而是存储在寄存器中。