直接記憶體存取(DMA)
/ D-M-A /
假設來了一車一千個箱子,得有人把每個箱子從卡車搬進倉庫。執行長可以親自一次搬一個,什麼別的事都做不成——或者執行長可以告訴堆高機:「把這一千個箱子全搬到第 7 走道,搬完叫我一聲。」直接記憶體存取,也就是 DMA,就是那台堆高機。它是一種硬體機制,讓裝置自己把一整塊資料直接搬進或搬出主記憶體,不必 CPU 逐字複製——所以傳輸期間 CPU 可以去做真正的工作。
沒有 DMA 時,搬資料是程式化 I/O:對每一個字組,CPU 都要從裝置暫存器讀出再寫進記憶體,每字組燒掉一個以上的週期——幾個位元組還好,一個 MB 就要命了。有了 DMA,CPU 只需設定一次傳輸——告訴 DMA 控制器來源、目的記憶體位址和數量——然後說「開始」。DMA 引擎接著輪流使用匯流排或互連,自己把整塊資料串流進記憶體,並在整段傳輸完成時發出一個中斷。一次設定加一次中斷,取代了數千次 CPU 複製。
DMA 對任何高頻寬裝置都不可或缺——磁碟、固態硬碟、網路卡、GPU 全都仰賴它。兩個誠實的複雜之處。第一,因為 DMA 在 CPU 背後改寫記憶體,它可能留下過時的快取:若 CPU 快取著裝置剛覆寫的那塊區域的副本,系統必須維持兩者一致(清掉或監聽),否則軟體會讀到垃圾——這是臭蟲的經典來源。第二,DMA 仍與 CPU 爭奪記憶體頻寬;CPU 不被擋住,但一筆巨大傳輸會藉著偷走匯流排週期而拖慢它,有時稱為週期竊取。
讀一個 4 MB 的檔案:用程式化 I/O,CPU 要執行約百萬對載入-儲存而做不了別的事。用 DMA,驅動程式寫三個值(來源、目的、長度)和一個「開始」,接著去跑別的程式碼;DMA 引擎把整整 4 MB 串流進 RAM,完成時發出一個中斷。
設定一次、收一個中斷——DMA 用一個命令加一個通知,取代了百萬次 CPU 複製。
DMA 的經典陷阱是快取一致性:因為裝置在 CPU 不知情下改寫記憶體,過時的快取副本必須失效,否則 CPU 會讀到舊資料。「不用 DMA 沒事、用了就壞」往往就是這個臭蟲。