我有一个基本上循环的程序,并在每个循环中执行TON的添加。
所以像b + = .01在一个循环中可能发生了100次。
所以我希望计算(添加)与加载和存储指令的比率非常高。然而,出乎意料的是,我做的添加越多,我得到的内存读写次数越多。
int b = 0;
int i;
for (i = 0; i < 100000; i++){
b += .01 * (maybe 50 times)?)
}
我正在使用pin工具,内存读写量大幅上升。比增加快得多。而且我很困惑。我认为b是一个局部变量,因此,它不是存储在内存中,而是存储在堆栈中或缓存中。为什么会这样?
我看过这个组件,我看到没有任何地方使用lw或sw。
答案 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
不再存储在主存储器中,而是存储在寄存器中。