我發(fā)現(xiàn)一個有趣的現(xiàn)象:#include<stdio.h>#include<time.h>int main() { int p, q; clock_t s,e; s=clock(); for(int i = 1; i < 1000; i++){ for(int j = 1; j < 1000; j++){ for(int k = 1; k < 1000; k++){ p = i + j * k; q = p; //Removing this line can increase running time. } } } e = clock(); double t = (double)(e - s) / CLOCKS_PER_SEC; printf("%lf\n", t); return 0;}我在i5-5257U Mac OS上使用GCC 7.3.0編譯代碼,沒有進(jìn)行任何優(yōu)化。這是平均運(yùn)行時間超過10倍: 還有其他人在其他Intel平臺上測試該案例并獲得相同的結(jié)果。 我將在這里發(fā)布由GCC生成的程序集。兩種匯編代碼之間的唯一區(qū)別是,在較快的一種匯編代碼之前,還有兩項操作:在此處輸入圖片說明addl $1, -12(%rbp)movl -44(%rbp), %eaxmovl %eax, -48(%rbp)那么,為什么用這樣的分配程序運(yùn)行得更快?彼得的回答很有幫助。在AMD Phenom II X4 810和ARMv7處理器(BCM2835)上進(jìn)行的測試顯示了相反的結(jié)果,該結(jié)果支持存儲轉(zhuǎn)發(fā)加速特定于某些Intel CPU。而BeeOnRope的評論和建議催著我重寫的問題。:)這個問題的核心是與處理器架構(gòu)和組裝相關(guān)的有趣現(xiàn)象。因此,我認(rèn)為值得討論。
3 回答

慕娘9325324
TA貢獻(xiàn)1783條經(jīng)驗 獲得超4個贊
請注意,call/ret
不會創(chuàng)建循環(huán)承載的依賴項,因為由推送的地址call
來自推測執(zhí)行+分支預(yù)測。當(dāng)存儲不依賴于數(shù)據(jù)時,多次存儲/重載到同一地址可以使每個時鐘維持一個時鐘。執(zhí)行ret
指令可以每個時鐘執(zhí)行一次,比call
指令落后5個周期。(當(dāng)然,調(diào)用/ ret都是分支,因此它們彼此競爭執(zhí)行資源,因此甚至沒有瓶頸。)可能是問題,是a push/pop rbp
或x=foo(x)
by ref。

BIG陽
TA貢獻(xiàn)1859條經(jīng)驗 獲得超6個贊
我認(rèn)為這個問題沒有用。您開始時的一大不利之處是沒有優(yōu)化就進(jìn)行編譯,這對于“為什么Y的性能表現(xiàn)得像Z”已經(jīng)是一個巨大的危險信號-但由于編譯器僅針對較慢的情況發(fā)出了額外的指令,因此事實證明這很有趣在組裝級別的問題。即,您幾乎可以刪除問題的C起源,以及您在不進(jìn)行優(yōu)化的情況下進(jìn)行編譯的事實,并詢問程序集的行為,并且可能避免雪崩式的雪崩
- 3 回答
- 0 關(guān)注
- 503 瀏覽
添加回答
舉報
0/150
提交
取消