記憶體平衡¶
2000年1月由Kanoj Sarcar <kanoj@sgi.com>發起
對於!__GFP_HIGH和!__GFP_KSWAPD_RECLAIM以及非__GFP_IO分配,都需要記憶體平衡。
呼叫者避免回收的第一個原因是,由於持有自旋鎖或處於中斷上下文中,呼叫者無法睡眠。第二個原因是呼叫者願意在不產生頁面回收開銷的情況下使分配失敗。這可能發生在具有order-0後備選項的機會性高階分配請求中。在這種情況下,呼叫者可能還希望避免喚醒kswapd。
發出__GFP_IO分配請求是為了防止檔案系統死鎖。
在沒有不可睡眠的分配請求的情況下,進行平衡似乎是不利的。頁面回收可以延遲啟動,也就是說,只有在需要時(即區域可用記憶體為0時),而不是使其成為一個主動的過程。
也就是說,核心應該嘗試從直接對映池中滿足對直接對映頁面的請求,而不是退回到dma池,以便保持dma池為dma請求(原子與否)填充。類似的論點適用於highmem和直接對映頁面。另一方面,如果有大量空閒dma頁面,最好透過從dma池分配一個來滿足常規記憶體請求,而不是產生常規區域平衡的開銷。
在2.2中,記憶體平衡/頁面回收只有在空閒頁面_總_數低於總記憶體的1/64時才會啟動。使用適當的dma和常規記憶體比例,很可能即使dma區域完全為空,也不會進行平衡。2.2已經在各種記憶體大小的生產機器上執行,並且即使存在這個問題,似乎也執行良好。在2.3中,由於HIGHMEM,這個問題更加嚴重。
在2.3中,區域平衡可以透過兩種方式之一完成:根據區域大小(以及可能的較低類區域的大小),我們可以在初始化時決定在平衡任何區域時我們應該追求多少空閒頁面。好處是,在平衡時,我們不需要檢視較低類區域的大小,壞處是,由於忽略了較低類區域中可能較低的利用率,我們可能會過於頻繁地進行平衡。此外,透過對分配例程進行稍微修改,可以將memclass()宏簡化為一個簡單的相等性。
另一種可能的解決方案是,只有當一個區域_及其_所有較低類區域的空閒記憶體低於該區域及其較低類區域總記憶體的1/64時,我們才進行平衡。這解決了2.2的平衡問題,並且儘可能接近2.2的行為。此外,平衡演算法在具有不同數量和型別的區域的各種架構上以相同的方式工作。如果我們想要變得花哨,我們可以在未來為不同區域中的空閒頁面分配不同的權重。
請注意,如果常規區域的大小與dma區域相比很大,那麼在決定是否平衡常規區域時,考慮空閒dma頁面就變得不那麼重要了。第一個解決方案那時就更具吸引力了。
附加的補丁實現了第二個解決方案。它還“修復”了兩個問題:首先,正如2.2中那樣,在低記憶體條件下喚醒kswapd以進行不可睡眠的分配。其次,也平衡HIGHMEM區域,以便為replace_with_highmem()獲得HIGHMEM頁面提供一個機會,並確保HIGHMEM分配不會退回到常規區域。這也確保了HIGHMEM頁面不會洩漏(例如,在HIGHMEM頁面在交換快取中但未被任何人使用的情況下)
kswapd還需要知道它應該平衡的區域。kswapd主要是在無法進行平衡的情況下需要的,可能是因為所有分配請求都來自intr上下文,並且所有程序上下文都在休眠。對於2.3,kswapd實際上不需要平衡highmem區域,因為intr上下文不請求highmem頁面。kswapd檢視區域結構中的zone_wake_kswapd欄位以決定是否需要平衡區域。
如果從程序記憶體和shm竊取頁面會緩解頁面節點中任何已低於其水印的區域的記憶體壓力,則會執行頁面竊取。
watermark[WMARK_MIN/WMARK_LOW/WMARK_HIGH]/low_on_memory/zone_wake_kswapd:這些是每個區域的欄位,用於確定何時需要平衡區域。當頁面數量低於watermark[WMARK_MIN]時,滯後欄位low_on_memory將被設定。這會一直保持設定狀態,直到空閒頁面數變為watermark[WMARK_HIGH]。當設定了low_on_memory時,頁面分配請求將嘗試釋放該區域中的一些頁面(前提是在請求中設定了GFP_WAIT)。與此正交的是,決定觸發kswapd以釋放一些區域頁面。該決定不是基於滯後的,而是在空閒頁面數低於watermark[WMARK_LOW]時完成的;在這種情況下,zone_wake_kswapd也會被設定。
我聽到的(好的)想法
動態經驗應該影響平衡:可以跟蹤區域的失敗請求數並將其饋送到平衡方案中(jalvo@mbay.net)
實現一個類似replace_with_highmem()的replace_with_regular()來保留dma頁面。(lkd@tantalophile.demon.co.uk)