本文根據 https://lwn.net/Articles/712467/ 翻譯改編而來。
隨著3DX POINT相關技術的逐漸普及和推廣,我們可以預見很快持久化記憶體(Persistent Memory)將會被使用得越來越多,同時也催生了Linux核心很多方面的革新,Matthew Wilcox的DAX就是其中非常著名的一個,這個東東可以讓使用者對於基於持久化記憶體的檔案系統跳過頁面快取(Page Cache)直接訪問檔案系統,而Dave Chinner甚至預測有了DAX,我們將不再需要頁面快取了。這個從1995年開始存在於Linux核心並造福無數蒼生的玩意難道要壽終正寢了麼?作為DAX的始作俑者,Matthew Wilcox又是怎麼認為的?讓我們一起去聽聽他在今年linux.conf.au上的演講。
快取的重要性
首先計算機就是快取的世界,君不見體系結構領域裡面關於cache相關的paper一直是層出不窮,此起彼伏。Wilcox甚至回過頭查閱了1975年發行的Unix第六版,併在那裡找到了使用緩衝區快取的例子。同時Wilcox舉例說只要快取都命中,他的新電腦每秒可以執行100億條指令。但是記憶體每秒只能跑5億3千萬條cache line,因此快取未命中就會嚴重影響效能。如果資料沒有快取到主存,需要從儲存裝置讀, 即使是快速的SSD,也會變得很慢。 PDP-11會因快取未命中而顯著變慢,幾十年過去了,這個問題反而惡化了。因為CPU的發展速度比記憶體快,而同時記憶體的發展速度相比儲存也更快,所以快取未命中的帶來的效能損失也會越來越嚴重。
什麼是Linux的頁面快取
如前文所述,很久以來,Unix系統都有緩衝區快取(Buffer Cache),位於檔案系統與磁碟之間,目的是為了快取磁碟塊到記憶體中。Linux從一開始就有個緩衝區快取。在1995年發行的1.3.50版本中,Linus Torvald做了一個重大創新——頁面快取。頁面快取與緩衝區快取的區別在於,它是位於虛擬檔案系統(VFS)與檔案系統本身之間。有了頁面快取,如果所需的頁面已經存在,則根本無需呼叫檔案系統的程式碼。起初,頁面快取和緩衝區快取是完全獨立的,在1999年,Ingo Molnar統一了它們。現在,緩衝區快取仍然存在,但是內容是指向頁面快取。
頁面快取有許多非常重要的功能,比如可以透過給定的索引查詢頁面。如果頁面不存在,則建立並從磁碟填充相應的內容。臟頁可以刷回磁碟,頁面可以被鎖定,解鎖,以及從快取中刪除。執行緒可以等待頁面狀態的變化,也可以透過介面對給定狀態的頁面進行搜尋,頁面快取還能夠追蹤與外部儲存相關的錯誤等等。
另外頁面快取還需要有一套手段來對未來的使用進行預測。當快取增長太大時,各種啟發演演算法開始決策哪些頁面應當被移除。僅使用了一次的頁面很可能不會被再使用,因此它們將保留在“不活躍”連結串列(inactive list)並相對較快的換出。第二次使用將會把頁面從不活躍連結串列轉移到活躍連結串列(active list),活躍連結串列的頁也會因為超時而被移到不活躍串列。 有一個例外,“影子”條目用於追蹤已脫離不活躍連結串列並已回收的頁面,這些條目可以延長相對遙遠的過去使用過的頁的生命週期。
隨著記憶體變大,大頁和透明大頁也開始普及起來。不過透明大頁(THP)特性最初只能用於匿名(非檔案後端)記憶體,把大頁在頁面快取中使用同樣也會有很多優點。不過由於radix tree的限制,將大頁作為頁面快取是Linux內核的一個挑戰。最早的一個嘗試是簡單地往頁面快取中增加了大量單頁條目,以對應於單個大頁。Wilcox認為這種方法是“愚蠢的”,他增強了用於追蹤頁面快取中頁面的radix tree程式碼,使得頁面快取可以使用單個條目來表示對應的大頁,從而使radix tree能夠直接處理大頁的條目。
是否仍然需要頁面快取?
介紹完頁面快取光輝的歷史和強大的功能以後,我們回到開頭的問題,現在Linux內核是否還需要頁面快取呢?由於Wilcox的DAX實現,Dave Chinner預測我們將不再需要頁面快取。當然同樣也有其他人不同意Chinner,Linus Torvalds也是其中之一。Torvalds在一個單獨的論壇中指出頁面快取很重要,因為在資料訪問的關鍵路徑上,好的東西從來不是出自低層的檔案系統程式碼(譯者作為一個檔案系統開發者,表示很受傷,附上文中Torvalds的原話:the page cache is important because good things don’t come from having low-level filesystem code in the critical path for data access)。
對於是否需要頁面快取,DAX的作者Wilcox是咋想的呢?他說“沒有什麼比你的同事懷疑你的整個動機更糟糕的了”,所以貌似他也不是想幹掉頁面快取。但是等等,為啥Dave Chinner會得出與之相反的結論呢?
原來Wilcox在設計他的DAX程式碼的時候,其實真的沒有使用頁面快取。當一個應用使用類似於read()的系統呼叫從儲存在持久化記憶體中的檔案中讀取資料時,DAX會介入。由於請求的資料不存在於頁面快取中,VFS層呼叫檔案系統特定的read_iter()函式。這反過來呼叫到DAX程式碼,它將回呼到檔案系統將檔案偏移轉換為塊號,然後查詢塊層以獲取持久化記憶體塊的位置(如果需要,將其對映到核心地址空間),最終使得塊內容可以被複製回應用。
但是現在Wilcox覺得當初他的這個設計是錯誤的,read()應該以另外一種方式工作,初始的步驟是相同的,因為read_iter()函式仍將被呼叫,同時它將呼叫到DAX程式碼。但是,DAX不是回呼到檔案系統,而是應當呼叫到頁面快取以獲取檔案中所需偏移關聯的物理地址,然後資料從該地址複製到使用者空間。這樣的邏輯就和現在頁面快取的工作原理完全一致了,而且如果資訊已經存在頁面快取中的情況下,低層檔案系統的程式碼完全無需介入。
Wilcox在這裡又再次取用了Torvalds關於頁面快取的帖子:
從鎖的角度來看,這也是一個重大的災難:相信我,如果你認為你的檔案系統可以進行細粒度的鎖,當諸如併發路徑查詢的事情到來時,你會生活在一個夢幻世界。
Torvalds先生的話是“如此正確”,Wilcox說。DAX中的鎖實現的確是災難性的。他最初認為可能用相對簡單的鎖來解決,但複雜性在每個新發現的邊緣場景蔓延。DAX的鎖實現現在“實在醜陋”,他很抱歉他犯了一個錯誤,認為可以繞過頁面快取。現在,他說他必須去彌補這個錯誤。
未來的工作
Wilcox同時總結了圍繞DAX和頁面快取的一系列增強。前文提到的大頁支援最佳化是其中之一,這已經在mm樹中,應該很快就可以完成。使用頁框數而不是頁面也已經討論了一段時間,因為讓核心為這些大型持久化記憶體保持大量的頁面結構體(struct page)是完全沒有必要的。
另外他想重新考慮檔案系統塊尺寸大於系統頁面尺寸的想法,這是人們多年想要的東西。現在既然頁面快取可以處理多個頁面大小,這個想法應該已經有希望了。不過他自己沒時間折騰這個,所以他正在找尋其他感興趣的開發人員一起來做這個專案。
交換大頁也是一個不錯的領域。我們已經在記憶體中使用了大頁,但當這些大頁被換出時,他們又被分解成普通尺寸的頁面。針對這一問題,目前已經有一些提升交換效能的工作在進行,但是這個解法從根上來看可能就是不對的,正確的解法應該是讓交換出去的大頁保持在一起。相應的,這同樣也有助於我們將記憶體交換到持久化記憶體。因為使用持久化記憶體的交換空間中的資料仍然可以被訪問,因此將其留在那可能是有意義的,尤其是當資料沒有被大量修改的時候。
最後附上Wilcox的演講影片,影片中還包含了頁面快取鎖的相關分析和討論。
結論
所以貌似即使我們有了持久化記憶體,頁面快取還會繼續存在下去。但是譯者覺得隨著持久化記憶體速度越來越快,價格越來越便宜,也許核心社群會有一些新的想法也說不定,讓我們拭目以待吧。