Chandler Carruth在他的CppCon2015 talk中引入了兩個函數,可用於對優化器進行細粒度抑制。他們寫微觀基準是非常有用的,優化器不會簡單地導致無意義。MSVC中microbenchmarks的優化障礙:告訴優化器你有clobber內存?
void clobber() {
asm volatile("" : : : "memory");
}
void escape(void* p) {
asm volatile("" : : "g"(p) : "memory");
}
這些使用內聯彙編語句來更改優化器的假設。
clobber
中的彙編語句聲明其中的彙編代碼可以讀寫內存中的任何位置。實際彙編代碼是空的,但優化器不會查看它,因爲它是asm volatile
。它相信,當我們告訴它代碼可能在內存中的任何地方都可以讀寫。這有效地防止優化器在調用clobber
之前重新排序或丟棄內存寫入,並在調用clobber
†之後強制讀取內存。
escape
中的那個,另外使指針p
對組裝塊可見。同樣,由於優化器不會查看實際的內聯彙編代碼,因此代碼可能爲空,並且優化器仍然會假定該塊使用指針p
指向的地址。這有效地強制任何p
點在內存中,而不是在寄存器中,因爲程序集塊可能執行從該地址讀取。 (這很重要,因爲clobber
函數不會強制讀取或寫入編譯器決定放入寄存器的任何內容,因爲clobber
中的彙編語句沒有聲明任何特別的內容必須對於組裝)。
所有這些都是在沒有任何其他代碼直接由這些「障礙」生成的情況下發生的。它們純粹是編譯時的工件。
這些使用GCC和Clang支持的語言擴展。有沒有辦法在使用MSVC時有類似的行爲?
†爲了理解優化器爲什麼要這樣想,想象一下,如果程序集塊是一個循環,爲內存中的每個字節加1。
它看起來[象](http://stackoverflow.com/ a/8845503/786653)'_ReadWriteBarrier'可能是'clobber'的答案。雖然我不知道「逃跑」。也許'_ReadWriteBarrier'加上指針指向一些外部定義的函數。 – user786653
哦,我忘了提及這些的另一個特點:它們不生成任何代碼。優化器完成後,它們消失的任何效果都會消失。直到運行時纔會有什麼他們純粹是編譯時。 –
像@ user786653說的那樣,'_ReadWriteBarrier'(或者也許只是'_ReadBarrier' /'_WriteBarrier'如果這就是所需要的)在MSVC中會和'clobber'有相同的效果。對於'逃避',我在分析程序集輸出方面的經驗是,如果你只是標記變量'volatile',MSVC會做正確的事情。當然,在這裏有一些運行時間的開銷,因爲生成的代碼將*總是*保持變量在內存中更新。這不是一個完美的解決方案,但我還沒有找到更好的解決方案。 –