指令计数类型为什么有这么多数据操作?
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
不再存储在主内存中,而是存储在寄存器中。
我有一个基本上循环并在每个循环中执行大量添加的程序。
所以像 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
不再存储在主内存中,而是存储在寄存器中。