2015-01-09 18 views
1

我有一個程序,基本上循環並做每個循環中添加噸。指令計數類型爲什麼這麼多的數據操作?

所以像b + = .01在一個循環中可能發生100次。

所以我期望計算(增加)與加載和存儲指令的比率非常高。然而,出乎意料的是,我做的更多的增加,我得到更大的內存讀寫次數。

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

我正在使用pin工具,並且內存讀寫增加很多。比添加要快得多。我很困惑。我以爲b是一個局部變量,因此,不是存儲在內存中,而是存儲在堆棧中或緩存中。爲什麼會發生?

我已經看過裝配,我看不到任何地方的lw或sw的用法。

+1

「只是堆棧」,不在內存中?你的計算機上是否有一個不需要內存的魔術「附加組件」? –

+1

嘗試將'b'更改爲'double'。 –

回答

1

默認情況下,編譯器幾乎總是在堆棧上放置自動生存期的變量(例如int b=0;)。

例如,如果我與海灣合作委員會這個片段中,這是接近你寫的編譯,但多一點點正確的:

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 

請注意0​​指令,這些指令正在遞增我們的變量,相當於源代碼中的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),作爲reque STED。

我以爲b是一個局部變量,因此,沒有存儲在內存中,而是存儲在堆棧中或緩存中。爲什麼會發生?

局部變量通常存儲在內存中(在堆棧上)。但是你可以改變這種行爲。隨着我發佈的第二個片段,您會看到更少的內存讀取/寫入操作,因爲b不再存儲在主內存中,而是存儲在寄存器中。

+0

美麗,謝謝! – user3340037