程式設計師的 CPU 微架構

快取寫入策略(write-back 與 write-through)

從快取讀取很容易想像,但當中央處理器「寫入」時該發生什麼?你改動了一個同時存在於快取、以及(過時版本)存在於 DRAM 的值。於是冒出兩個問題:你何時把這個改動往下推到記憶體?以及,如果你要寫的位址根本還沒被快取,你該怎麼辦?快取寫入策略就是這些答案,而它多半由硬體決定、不由你選——但了解它能解釋真實的效能行為。

關於「何時」這個問題:寫透(write-through)快取把每一次寫入立刻送往下一層,讓記憶體永遠是最新的,卻製造沉重的寫入流量。寫回(write-back)快取(幾乎所有現代 L1/L2/L3 快取所用的)則只更新快取列並把它標記為髒(dirty);這個列要到被擠出時才懶惰地寫回記憶體。這把對同一列的許多次寫入收攏成最終單一的一次記憶體寫入,正是寫回成為效能預設值的原因。關於第二個問題——寫一個目前未被快取的位址——寫入配置(write-allocate)策略會先把該列載入快取(讓這次寫入、以及很可能在附近的未來寫入,都變成快速的快取寫入),而非寫入配置(no-write-allocate)策略則直接越過、寫到記憶體而不快取。常見的搭配是寫回加寫入配置。

這在實務上會在哪裡浮現:因為寫回快取裡握著髒資料,DRAM 的內容可能落後於中央處理器實際算出的結果,直到擠出為止——這正是為何記憶體映射的裝置暫存器與 DMA 緩衝區必須小心處理(常被標記為不可快取、或被明確清刷)。它也解釋了為何在寫入配置下,去寫一個全新、從未被讀過的緩衝區可能很浪費:硬體把每一列的舊內容載入進來,只為了把它們覆寫掉,這正是為何存在批量儲存與非暫存(non-temporal)儲存指令,好在你明知短期內不會把資料讀回時繞過快取。

把一個你接著要 DMA 送出的巨大緩衝區清零:在寫回加寫入配置下,每次儲存都會先抓取舊的列。改用非暫存儲存(例如 _mm_stream_si128 內建函式)會直接寫到記憶體,跳過那次毫無意義的「為了取得所有權而讀取」。

寫入配置會貼心地把你將重用的資料快取起來——卻浪費地抓取你只打算覆寫的那些列。

在一般程式裡你很少能選擇策略;它主要在裝置驅動程式、DMA 與高吞吐串流寫入時才要緊。別把非暫存儲存當常規來用——它們繞過快取,所以若你確實很快又把資料讀回,反而會受害。

又称
write-backwrite-throughwrite-allocateno-write-allocate快取寫回/寫透