我發現一個有趣的現象:#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編譯代碼,沒有進行任何優化。這是平均運行時間超過10倍: 還有其他人在其他Intel平臺上測試該案例并獲得相同的結果。 我將在這里發布由GCC生成的程序集。兩種匯編代碼之間的唯一區別是,在較快的一種匯編代碼之前,還有兩項操作:在此處輸入圖片說明addl $1, -12(%rbp)movl -44(%rbp), %eaxmovl %eax, -48(%rbp)那么,為什么用這樣的分配程序運行得更快?彼得的回答很有幫助。在AMD Phenom II X4 810和ARMv7處理器(BCM2835)上進行的測試顯示了相反的結果,該結果支持存儲轉發加速特定于某些Intel CPU。而BeeOnRope的評論和建議催著我重寫的問題。:) 這個問題的核心是與處理器架構和組裝相關的有趣現象。因此,我認為值得討論。
3 回答

慕桂英4014372
TA貢獻1871條經驗 獲得超13個贊
我認為這個問題沒有用。您開始時的一大不利之處是沒有優化就進行編譯,這對于“為什么Y的性能表現得像Z”已經是一個巨大的危險信號-但由于編譯器僅針對較慢的情況發出了額外的指令,因此事實證明這很有趣在組裝級別的問題。即,您幾乎可以刪除問題的C起源,以及您在不進行優化的情況下進行編譯的事實,并詢問程序集的行為,并且可能避免雪崩式的雪崩。

慕田峪9158850
TA貢獻1794條經驗 獲得超7個贊
請注意,call/ret
不會創建循環承載的依賴項,因為由推送的地址call
來自推測執行+分支預測。當存儲不依賴于數據時,多次存儲/重載到同一地址可以使每個時鐘維持一個時鐘。執行ret
指令可以每個時鐘執行一次,比call
指令落后5個周期。(當然,調用/ ret都是分支,因此它們彼此競爭執行資源,因此甚至沒有瓶頸。)可能是問題,是a push/pop rbp
或x=foo(x)
by ref。
添加回答
舉報
0/150
提交
取消