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

Instruction count type why so many data operations?

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

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

所以我预计计算(添加)与加载和存储指令的比率非常高。然而,没想到,我做的加法越多,我得到的内存读写次数就越大。

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

我用的是pin工具,内存读写上去了很多。比添加快得多。我很困惑。我认为 b 是一个局部变量,因此不存储在内存中,而只是堆栈或缓存中。为什么会出现这种情况?

我查看了程序集,没有发现任何地方使用 lw 或 sw。

默认情况下,编译器几乎总是将具有自动生命周期(例如 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   [=11=]x0,-0x4(%rbp)
  4004c1:       c7 45 f8 00 00 00 00    movl   [=11=]x0,-0x8(%rbp)
  4004c8:       eb 2c                   jmp    4004f6 <main+0x40>
  4004ca:       83 45 fc 01             addl   [=11=]x1,-0x4(%rbp)
  4004ce:       83 45 fc 01             addl   [=11=]x1,-0x4(%rbp)
  4004d2:       83 45 fc 01             addl   [=11=]x1,-0x4(%rbp)
  4004d6:       83 45 fc 01             addl   [=11=]x1,-0x4(%rbp)
  4004da:       83 45 fc 01             addl   [=11=]x1,-0x4(%rbp)
  4004de:       83 45 fc 01             addl   [=11=]x1,-0x4(%rbp)
  4004e2:       83 45 fc 01             addl   [=11=]x1,-0x4(%rbp)
  4004e6:       83 45 fc 01             addl   [=11=]x1,-0x4(%rbp)
  4004ea:       83 45 fc 01             addl   [=11=]x1,-0x4(%rbp)
  4004ee:       83 45 fc 01             addl   [=11=]x1,-0x4(%rbp)
  4004f2:       83 45 f8 01             addl   [=11=]x1,-0x8(%rbp)
  4004f6:       81 7d f8 9f 86 01 00    cmpl   [=11=]x1869f,-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 [=15=]x1,-0x4(%rbp) 指令,这些指令正在递增我们的变量,相当于源代码中的 b++。我们可以看到它在堆栈上 (-0x4(%rbp)),因此这些指令中的每一条都将算作一次加载和一次存储。这就是为什么您会看到如此多的 load/stores.

如果你不希望你的变量进入堆栈,你可以启用优化并希望编译器做正确的事情,或者你可以使用 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    [=13=]x0,%ebx
  4004c0:       c7 45 f4 00 00 00 00    movl   [=13=]x0,-0xc(%rbp)
  4004c7:       eb 22                   jmp    4004eb <main+0x35>
  4004c9:       83 c3 01                add    [=13=]x1,%ebx
  4004cc:       83 c3 01                add    [=13=]x1,%ebx
  4004cf:       83 c3 01                add    [=13=]x1,%ebx
  4004d2:       83 c3 01                add    [=13=]x1,%ebx
  4004d5:       83 c3 01                add    [=13=]x1,%ebx
  4004d8:       83 c3 01                add    [=13=]x1,%ebx
  4004db:       83 c3 01                add    [=13=]x1,%ebx
  4004de:       83 c3 01                add    [=13=]x1,%ebx
  4004e1:       83 c3 01                add    [=13=]x1,%ebx
  4004e4:       83 c3 01                add    [=13=]x1,%ebx
  4004e7:       83 45 f4 01             addl   [=13=]x1,-0xc(%rbp)
  4004eb:       81 7d f4 9f 86 01 00    cmpl   [=13=]x1869f,-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 [=19=]x1,%ebx,我们可以看到我们的变量确实按照要求存储在寄存器中(这里是ebx)。

I thought b was a local variable and as such, wasn't stored in memory but rather just the stack or in a cache. Why is this occurring?

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