阿裏內核月報:2017年04月
1. Gregg: perf sched for Linux CPU scheduler analysis
隨著 Linux 4.10 perf sched timehist 新特性的推出,Linux 的 perf 工具又增加了一個新的 CPU 調度器性能分析的子命令。
perf sched timehist 可以按照調度事件表示調度延遲,其中包括了重要的調度相關的時間信息:
- 任務等待被喚醒的時間 (waiting for sleep)
- 任務從被喚醒之後到運行態的調度延遲 (waiting on per-cpu run-queue)
- 任務在CPU上實際執行的時間 (running on the cpu)
由於 timehist 子命令隸屬於 perf sched 子命令,Brendan Gregg 同學特意為此寫了一篇博客(譯文) 總結了 perf sched 子命令的基本使用。
對急於了解這篇文章是否對自己有用的同學,可以快速瀏覽一下博客裏的 perf sched 例子裏的輸出.
2. Proactive compaction
Vlastimil Babka 是 kcomactd 的作者,他在 LSF&MM 2017 的內存管理討論上提到,這個工具的一個目的是騰出更多可用的連續物理頁,用於分配高階內存,這在THP等特性中會有大用處。目前內存壓縮的實現在內核中是一個按需執行的機製,他打算讓這個機製稍微做點兒預測的工作。
他目前的想法是,讓內存壓縮在後台進行,不與任何進程上下文關聯。 kswapd 內核線程會在內存分配的慢路徑中喚醒,然後回收一個特定數目的頁麵;然後它再喚醒 kcompactd 線程來壓縮內存,直到給出的一個預期order的頁麵可用,或者掃完整個內存zone都騰不出空間為止。不過這樣最後最多也就分出一個高階的頁,所以這是遠遠不夠的。(感覺這個是已經在 upstream 裏的 kcompactd 的實現呀)
他拋出一個問題,怎麼才能讓這個機製更牛逼一些。Michal Hocko 建議,加一個配置選項,可以設置水位(watermark)和時間周期(time period),壓縮線程可以反複喚醒去確保預期的N個頁麵可以被騰出來。不過 Babka 反駁說,把參數暴露給係統管理員不太靠譜,THP 的 allocation rate 或者網絡的吞吐量這種場景,是很難量化出要多少個可用的空閑頁麵的。所以最好還是讓係統智能一點,自己調。
那如果是個自動調節的方案,我們對這個實現的輸入是什麼呢?首先應該是最近每個order的頁麵的需求量,當然以後靠譜了可以帶點兒預測功能,預測將來各階內存各需要多少頁麵,在此之前,隻能以過去的需求量來預測將來。當然可以跟蹤一下請求頁麵分配的來源的重要程度,比如說THP和SLUB分配高階內存相比,後者對高階可用內存的需求就更要緊。另外一個輸入就是,最近的內存壓縮的成功率是多少。如果成功率過低,就不用再嚐試壓縮了。此外,Mel Gorman 還建議,記錄一下壓縮線程本身在執行的時候,有多少壓縮請求發過來。
Andrea Arcangeli 指出,壓縮後創建的大頁要重點保護一下,要不然,內核辛辛苦苦拚出一塊連續大頁,剛分配完,就可能被打碎去回應一些小頁的分配,太不值當了。當然如果這個壓縮本身就是來自一個分配請求觸發的,這個問題不會出現,因為大頁分出來馬上就被用了。綜合考慮,保護大頁這個事情,還是要好好跟進一下。
Babka 介紹了一下當前這個預測特性的進度,還處於 RFC 階段,最近剛發出一係列 RFC 補丁。他係列嚐試記錄用更多的 kcompactd 活動而成功分配的數字,當然這個數字是在內存不緊張的情況下得出的;另外一點,這個patch現在還沒有記錄前麵提到的分配請求的重要程度,或許GFP標記可以用來幹這事;還有一點,它現在隻是一直不停運行壓縮,直到足夠多的高階內存可用為止。
還有一個工作就是評估這項工作的價值:他說現有的 benchmark 顯示,基本都能跑到上限,沒什麼性能損失。
對於這項工作,大家也有一些顧慮。比如說,後台壓縮會不會增加係統的電源消耗。Hocko 說,正因為有這種風險,所以要讓SA自主配置。Babka 說,這不是大問題,內存壓縮是按需啟動的,平時空著的時候基本上不會增加係統電源消耗。
最後,Ancangeli 建議那些需要大頁場景的子係統可以注冊到壓縮代碼中,標明他們需要多少大頁以方便後續壓縮。Babka 說他不想加那麼多可調的參數。Johannes Weiner 說可以添加一個開關,因為任何預測係統都有可能帶來資源浪費的風險,當然其他接口就不用加了。大體上,大家認為這個工作是有價值的,不過特性剛開始的實現可以盡可能簡單,以後再來按需複雜化這個特性。
3. Cpusets and memory policies
“cpusets”控製著給定進程運行哪些處理器上。而內存的(或“mempolicy”)機製控製了如何在NUMA節點之間分配內存。正如Vlastimil Babka在2017年LSFMM上解釋的那樣,這兩種機製一起使用配合的不好,會出現一些想不到的問題。
cpusets是一個特權控製機製;非特權進程通常不能更改其CPU分配。相反,Mempolicies是進程本身控製。這兩種機製一起使用時希望可以在cpuset和mempolicy的交集定義的節點上分配內存。而如果這個交集的節點為空的話,則對係統不會產生影響,但實際上並不是這樣。
Babka介紹了可能發生以下情況:想象一個進程運行在4個節點的係統上;首先將cpuset和mempolicy都設置為節點0和1。在這種情況下,內存將會在這兩個節點中分配。如果cpuset更改為節點1和2,同時內存分配也會到這兩個節點。但是,如果cpuset修改為單個節點(比如節點2),然後再恢複到原來的0和1,則結果是進程將僅僅從節點0上分配了;內核將失去mempolicy配置的兩個節點的信息。
這個問題在2.6.26內核通過在set_mempolicy()係統調用中添加幾個標誌解決掉了。如果進程設置mempolicy時使用MPOL_F_STATIC_NODES標誌,則在更改cpuset時內存策略不會更改。而MPOL_F_RELATIVE_NODES會使得內存策略與cpuset更改保持一致,同時會記住原始策略,因此這樣不會出現上述單節點分配的情況。但如果cpuset和mempolicy之間沒有交集會怎樣,特別是有MPOL_F_STATIC_NODES時?答案是會從cpuset節點分配內存。Kirill Shutemov認為這樣可能會存在內存分配失敗,但是如果不這樣做則會破壞ABI。最好方式是能在其他不同節點上分配內存,而不是殺死一個工作的任務,特別是如果該任務在運行在老內核上。一般如果這個處理方式能確定,set_mempolicy()接口ABI會被破壞
當前這種實現中問題是cpuset被改變時mempolicy也被改變,如果出現一個空節點列表時會導致內核OOM,這時OOM killer會被調用,對用戶來說這是不公平的。要解決這個問題顯得必要而緊迫。mempolicy隨著cpusets更改而更新這種方式已經確定。在這種情況下,對於靜態情況,解決方法簡單,因為節點不會改變。相反,動態情況下重新映射需要在運行時完成; 這是要解決的起來比較複雜,默認情況下可能沒有可行的修複方法。
這次討論的重點是如何修複動態的情況。它可能涉及將可以使用內存區域列表移到cpusets中,這是多年前mempolicies的一個實現方式,計劃看看這個補丁在當時是怎麼解決的。
4. Slab reclaim
”回收“是一個尋找係統內存的過程,它會將當前不在使用且能在被回收後恢複的內存回收。Michal Hocko 在 2017 Linux Storage, Filesystem, and Memory-Management 峰會提及:從slab分配器中回收對象的機製還遠遠不夠完美。他同Christoph Lameter 一起瀏覽幾個改善現狀的途徑。
Slab 回收時會調用”收縮回調“;當係統需要更多內存時,收縮器被調用並開始釋放一些對象。使用者希望收縮器在這個過程中能提供更多有用的功能,但這裏最大的問題是,不存在對象與頁表的對應關係。如果內核要釋放一個頁表,那麼頁表內的所有對象都將被釋放,並沒有一種機製可以讓收縮器對指定頁表中的對象進行收縮操作。
Hocko 說道,幾年前,Dave Chinner 提出了一個有趣的想法:可以依賴slab分配器來加強回收。如果分配器維護一個LRU(最近使用過)列表,他們就可以更好地回收這些對象。但是,因為沒有人關心實現那個提議,所以至今這個提議仍然是一個想法而已
其後,Lameter 介紹了一個截然不同的思路,並且他為此努力了一段時間。這個思路通過在slab分配器上添加幾個回調,這些回調可以在頁被釋放時向子係統要求重新定位對象。第一個回調類似如下
void *isolate_object(struct kmem_cache *cache, void **objs, int nr, int node);
這個方法準備重新分配**objs指向的對象;除此之外,它會保證這些對象直到整個操作完成前是穩定不可變。一旦這個操作完成,第二個回調將被調用
void migrate_objects(struct kmem_cache *cache, void **objs, int nr, int node, void *private);
這個回調將嚐試把objs移動一個新的內存位置;當然也可以釋放objs。一旦一個slab頁裏麵的對象都完成移動操作,就可以釋放這個頁了。
上述機製的第一個實現版本已經在2007年完成,Lameter 暗示合並該實現並開始使用它的實際可能馬上就到了。隨著內存發展,容量越來越大,對更好的slab分配器的需求也會更加緊迫
Andrea Arcangeli 提議了一個不同的方法:從虛擬映射的頁中分配slab對象,這樣一來,如果這個頁需要被重新定位時,隻要修改該頁的映射。通過這個方式,能方便在節點之間移動已分配的slab對象,卻又能避免追蹤該對象指針。這避免了上述Lameter方法中的一個主要缺陷————需要針對每一個slab類型增加移動接口
Rik van Riel 指出這個方法的問題在於不能將slab對象移動到碎片的頁表中。而這種需求恰恰是最重要的使用場景,他看到過許多係統用在slab的內存有95%是空的。 Arcangeli 回應道,這個機製有三種使用場景:內存熱插入,內存整理和避免內存不足。他說,他的虛擬映射方案解決了最重要的這三個問題,而且可以很好的兼容搭配kmalloc()工作,否則兼容上也是一個問題
本次會話就此到已段落,並沒有達成一個最終的決議。會話會在郵件列表中繼續,也許基於特定的補丁繼續討論
5. Huge pages in the ext4 filesystem
透明大頁特性加入內核時僅支持匿名內存(非文件後端)。2016年,頁緩存支持大頁功能加入進來,但僅支持tmpfs。由於在某些負載下大頁將顯著地提升性能,這使得擴展支持其他文件係統受到歡迎。LSF/MM 2017會議上,Kirill Shutemov領導了僅有的一個文件係統和內存管理聯合議題,討論在ext4文件係統中支持大頁。
他開始提到tmpfs目前支持得很好,是時候進入下一階段支持一個真正的文件係統了。複合頁用於在係統內存映射中表示大頁,開始的一係列小頁組成大頁頭頁,餘下的則是尾頁。大多數重要的元數據存儲在頭頁中。使用複合頁允許大頁在LRU鏈表中以單個條目表示,同時所有緩衝區頭部與頭頁綁定。不同於DAX的是,透明大頁沒有任何文件磁盤布局的限製。
使用tmpfs,創建一個大頁導致基樹中額外增加512個條目,這將不能在ext4中工作。同樣需要添加DAX支持以保持一致。還存在一些其他的問題,例如,預讀當前不能在大頁下工作。最大的預讀窗口是128KB,遠小於大頁的大小。他不確定這是否是個大問題,但如果是則需要解決。大頁也導致任何頁緩存中的影子條目被忽略,這將使得係統的頁回收決策變得越來越糟。
他強調大頁需要避免打破現有的語義,這意味著有時需要回退到小頁。頁遷移是可能發生的一種場景。一個相關的問題是,很多係統調用提供4KB精度,這將妨礙大頁的使用。使用ext4加密同樣將強製回退到小頁。
鑒於以上所述,他問到是否有理由不再繼續ext4的大頁支持?他的補丁已經有一段時間了,目前計劃變更基線到當前的頁緩存工作上並重新發出。
Jan Kara問到是否有必要每個文件係統都感知大頁,這會增加複雜度,或者說文件係統是否可能一直使用小頁。Shutemov回複這不會永遠都是個選擇。比如整個複合頁的單個最新標識。更清晰的抽象並在任何可能時候隱藏差異是有意義的,他一直在致力這方麵的工作,但解決方案並非總是顯著。
Kara繼續說,這需要某些合適的數據結構以追蹤子頁狀態。目前內核使用緩衝區頭部鏈表,但可能需要修改。更細粒度的追蹤將會有優勢。但他重申他看不到文件係統需要知道頁緩存中頁大小的理由,且讓每個文件係統了解可變大小的頁緩存將會是個重大的工作。Shutemov同意這個擔憂,但他說正確的途徑是先實現單個文件係統,使之工作後,再嚐試抽象。
Matthew Wilcox則抱怨到當前的工作僅支持兩種頁大小,而他更想能夠處理任何複合頁大小。抽象出代碼將使得整個事情更為清晰。一開始代碼無需真正能處理每個頁大小,但應當為此做好準備。
Trond Myklebust說想要在頁緩存中合適地支持大頁。NFS代碼中,他需要很多的循環和聚集以迎合合理的塊大小。Ted Ts'o問到是否已經是時候分離也大小(PAGE_SIZE)概念和頁緩存中存儲數據大小(PAGE_CACHE_SIZE)。過去內核曾區別對待這兩者,但不久前該區分又被移除了,導致更清晰的代碼。Wilcox回複過去從來沒有明確定義過PAGE_CACHE_SIZE的含義,同時抽象處理頁緩存大小不是代碼清理,而是性能更好。他建議ext4支持多種塊大小將使得該工作變得更容易,但Shutemov很快補充到他無法對此承諾。
Ts’o說大塊的問題在於,當一個進程遇到4KB頁缺頁時,文件係統需要引入一個大塊,這從來都不是一件容易的事情。文件係統的人認為這是內存管理的問題,而內存管理的人則指向文件係統,這種狀況持續了很長時間。Wilcox認為這是內存管理的問題,他在頁緩存中支持可變頁大小的工作應當能處理其中的大部分。
Andrea Arcangeli說當大頁無法分配時將發生問題。透明大頁代碼不需要這種分配,而是總回退到小頁。他不想看到這種修改。相反,真正的解決方案是增加頁大小基數。Rik van Riel回答到,如果頁緩存包含多個大頁,將可用於回收,同時應當比現在更容易分配。
議題結束時,Ts'o注意到相比ext4,內存管理將需要更大的修改。如果大家樂意這個工作,可能是時候合並這些想法,相關遺留問題可以接下來再解決。或者,嚐試先進一步衍生出接口。他說,這更大程度是內存管理的決策,因此他將服從內存管理組。Shutemov說頁緩存接口是最難的部分,他將著眼於使得該接口和文件係統更加清晰。但是,他提醒到,一開始嚐試抽象一切毫無意義。
6. Fast memory allocation for networking
在2016年Linux存儲、文件係統和內存管理(LSFMM)峰會上,Jesper Dangaard Brouer提出用一種新的內存管理API來滿足內核網絡協議棧對性能越來越高的要求。2017年,他重回LSFMM峰會內存管理組分會場像社區介紹他最近在這一方向上的已經做的以及還需要做的工作。
網絡數據包處理速度驚人,一個10GB的以太網鏈路每秒可以處理近1百50萬個包。也就意味著在目前的硬件環境上,每個數據包留給操作係統的處理時間隻有大約200個 CPU時鍾周期,而且隨著鏈路帶寬的提升留著操作係統的CPU時鍾周期變得更少。
解決這個問題主要的方法在於對多個數據包盡量批處理。但批處理並不是什麼靈丹妙藥,批量處理10個包並不意味著會有10倍的性能提升。但是它仍然會有很大的幫助,因此必須這麼做。多種多樣的kernel-bypass方案(如DPDK)已經顯示以如此高的速率處理包是可能的。他們采用批處理和特殊的內存分配器;另外,他們同時還采用polling的技術,通過浪費CPU來減少喚醒。Brouer認為內核可以做得比那個更好。
目前已經在嚐試的一個技術是express data path(XDP),大約在4.9內核的開發周期中。通過使用XDP,並且避免使用內核的內存管理層,就有可能可以在內核實現線速。這就意味著需要把數據包放在緩存中,並且保持他們為DMA操作連續映射。當這些操作完成後,一個使用XDP的"drop every packet"的簡單應用可以達到17Mpps,而另一個重傳每個到達這個設備接口的每一個數據包的應用可以達到10Mpps的處理速率。這些benchmarks可能看起來太理想化,但是他們卻可以解決現實世界中的問題:譬如防範DOS攻擊以及做負載均衡。Facebook目前正在使用XDP做這些任務。
目前XDP還沒有完成的工作是真實數據包的轉發,因為目前這依賴內存管理層。而目前內核中頁分配器對於這種場景顯得太慢了,因此當前的以太網驅動的工作方式是重用他們申請的這些頁,現在每個高性能的驅動都自己實現了一些這類的技術,因此,把這些技術挪到通用代碼庫會更好。
這個問題的實質是設備驅動程序需要獲取到DMA-mapped的頁並且一直保留著他們以便重複使用。內存管理層可以通過提供更快的per-CPU的頁cache來幫助實現這點,但它仍然不能通過簡單的在驅動中複用頁來實現。因此,Brouer提出另一個方案,為DMA-mapped的頁創建一個per-device的分配器。通過將這些頁映射給這個設備,這種分配器可以大幅減少內存管理的開銷。
Matthew Wilcox問道現有的DMA pool API是否可以用來實現這個目的。Brouer說,現有的DMA pools是為coherent DMA操作(長生命周期的緩存可以同時被CPU和設備訪問)操作設計的,而網絡數據包使用streaming DMA操作(短生命周期的緩存同一時刻隻能被CPU或者設備訪問)。
Brouer說,他真正想要的其實是,在page結構體中帶一個destrutor的回調函數,當這個頁的引用計數降到0時,destructor能夠被調用。有了這個回調函數就可以實現“偷用”這個頁了,從而使這個頁對於同一個設備一直可用。其實,這種回調機製在內核裏已經存在了,但隻對高階內存可用,而想把這種機製帶到單個頁上需要從已經相當擁擠的page結構體中再找地方,而這並不簡單。帶destructor回調的頁可能還需要一個flag來標記他們,而這又是一個問題,因為目前這些flags空間已經緊缺。在一些討論中,已經有一些tricky的方法來把所需的信息放到struct page結構體中,因此,看起來是可以找到一些方案來解決這個問題的。
Brouer總結中提到一些benchmark表明在4.11內核中,性能會更好,這要感謝4.11內核中Mel Gorman所做的page-caching的提升。但這些開銷仍然有點大,而這些開銷的大部分是維護內存區的統計信息所帶來的。這些統計信息對於內存管理子係統本身的運作並不是必須的,但是有一些其他內核模塊會使用這些統計信息來進行優化。
因此,這些統計信息確實需要保留著,但是在生產係統中禁用它們是可能的,這些統計的代碼可以在他們不需要的地方通過宏的方式注釋掉。
最後,Brouer問大家是否對DMA-page pool機製有反對意見,現場沒有人馬上提出反對意見,但是現場的開發者表示在提出確定的結論之前會先去看看patch。
7. The next steps for swap
在內核的內存管理子係統中, swap不是主流. 通常來說, 如果係統開始做swapping了, 性能就已經開始下降了, 所以優化swapping沒多大意義. 現在ssd用得很廣泛, 改變了格局, swapping又有了新的用處. 2017 linux 存儲, 文件係統, 內存管理會議上, Tim Chen領導了一個議題, 看看swapping的性能是否還能提升.
以前Tim Chen就是幹這個的, 最開始的swap scalability patch已經被合並了, 下一步就是提升swap預讀性能. 現在機製發生了變化, 現在的預讀是按照它們被換出的順序讀取頁麵, 要提升的是在預期需要之前預讀頁麵. 他強調, 最有順序和混合訪問模式沒必要一起用, 不然性能會很差。
最近提交的基於vma swap預讀的patch嚐試通過監控每個vma區域的page in的行為提升預讀的性能, 如果出現某個vma區域會串行訪問, 他的預讀窗口就會增加, 以至於更多的頁在需要之前可以被預讀, 對於隨機訪問的情況, 預讀就沒什麼意義, 所以預讀窗口就會變小。
Rik van Riel指出現在的預讀機製是為了多媒體而設計的, 那麼基於vma的預讀機製如何在這上麵工作呢? Tim Chen尷尬了一下, 表示沒做過這方麵的嚐試. Rik van Riel接著補充道, 對於旋轉設備, 讀一個block能把相鄰的一堆block都順便讀出來, 所以就應該多讀一些數據, 但是對ssd就不一樣了, 他建議對於預讀, 不同的設備應該有不同的行為來與之對應。
Matthew Wilcox指出, 相對於預讀, 換出時間才是真正的問題, page是根據LRU列表被換出的, 但是LRU不能反映下次什麼時候再次需要, 還有可能的是向swap寫有可能被緩衝. 被交換的頁麵會進入victim cache, 在寫入存儲設備之前被排序. 這種方法的價值在座的都不太清楚, 雖然鑒於訪問模式可能隨時間而改變。
下一個主題是對大頁的交換, 現在的情況是, 第一步, 把大頁分成單頁, 然後把他們單獨交換出去, 這樣效率不高, Tim Chen和他的小夥伴們打算對這個過程改進一下. 第一步是推辭分割大頁直到swap空間被申請出來為止, 預期的結果是申請了一個頁麵集合, 然後一次性的完成寫入, https://lwn.net/Articles/702159/ 這個patch實現了這個修改, 測試的結果是swap-out性能又了14%的提升.
下一步是推遲分割大頁, 直到換出操作完成. 這個功能的patch還在開發中, 標準測試顯示對於swap out性能有了37%的提升。
Tim Chen說, 最後, 直接將大頁換進是個好主意, 不過還需要再想一想, 這並不是一個絕對的優化窗口, 如果一個應用程序隻需要一部分頁, 沒理由要把整個大頁都換進來. 一種有可能的實現是如果這個頁被標記了MADV_HUGEPAGE , 並且還有一個大的預讀窗口, 就可以把整個大頁都換進來。
還有一點剩餘的討論是如何驗證這些patch是可以工作的. 標準測試的結果是最好的激勵. 有一點要注意的是, 隻要沒有拖慢kernel的編譯, Linus Torvalds是不喜歡卡著這些patch的. Michal Hocko說這些patch有意思,但是他們在優化一個不太容易發生的事情, 當前的code假設我們不想要swap. 但是Johannes Weiner說swap-out有新的合理的內容, 大頁的批量換出操作方式可以提升性能.
下一個討論是使用DAX直接訪問機製來交換頁麵. 如果交換道持久內存陣列, 那些頁仍然可以被直接訪問而不需要再讀回到ram中, 這個是swap永遠可以工作的摸下. 這種情況下, 最難的部分是要決定什麼時候把這些頁讀回道內存. 那就是內存被經常訪問, 特使是寫訪問的情況下, 讀回來會更好。
Wilcox說要不要讀回來取決於內存和持續內存之間的性能差異, 在某些情況下, 永遠都不用讀回來, 有些時候, 比如, 持久內存其實就是hypervisor下的DRAM, 有一些討論是關於使用係統PMU來追蹤頁訪問, 但是這個思路也沒下文了. 內核開發者不喜歡用PMU, 因為存在性能損失, 而且結果也並不總是有用。
在一些討論結束之後, 最終達成的結論是內核應該預讀隨機大小的一些頁到內存, 運氣好的話, 頻繁訪問的頁會在那裏, 剩下的就回到swap空間去。
最後, 有一個簡短的討論是將來關於交換設備鎖的優化, 看起來仍然有很多爭論, 即使最近關於scalability提升之後。
8. HMM and CDM
2017 LSF/MM的第一個內存管理的topic是關於device memory不可尋址的問題,這裏並非指CPU不可訪問,而是指system memory與device memory缺乏cache-coherent語義,在使用的時候存在諸多不同以及由此引發了很多問題(比如DMA前需要pin住system memory)。目前有兩個嚐試的解決方案:異構內存管理(HMM) 與 cache-coherent設備(CDM)。
HMM開發已持續了幾年,目前已經是v20版本,不過離真正進入主線還有一段距離,相關patch見:git://people.freedesktop.org/~glisse/linux。首先簡單介紹一下HMM的功能,主要包括兩類:(a). address space mirroring, 即保證CPU page table(即CPU側mmu)與 device page table(即device側mmu,邏輯上的概念,比如set_pte()與clear_pte()兩個操作可以解釋為dma_map_page()與dma_unmap_page())同步。底層同步的機製則依賴於kernel已有的mmu notifier特性,帶來的好處之一就是DMA 與 page migration可以同時存在(此前需要pin住內存,然後DMA)。目前HMM實現了一套框架,update device page table具體實現則需要相應的device driver負責填充ops(參考例子:hmm_dmirror字符設備)。(b). migration to and from device memory,即在system memory與device memory間無縫地進行頁遷移,流程與普通的swap類似:CPU訪問內存時觸發page fault,進而將數據從device memory DMA至system memory。
本次會議討論的幾個點:(1). HMM對硬件feature的依賴,目前明確的是硬件需要能設置頁表的訪問權限,比如允許CPU或GPU(但不能同時)擁有excute權限;(2). HMM與IOMMU的異同:IOMMU對I/O設備進行了安全隔離,保護係統,HMM則需要捕獲write fault,CPU與device觸發時執行的處理邏輯也不一樣;(3). 基於KSM機製,正在開發的一個write protection特性允許同一個係統上的多個GPU設備訪問相同的數據區域。這裏引入了一個問題:傳統的寫異常將觸發COW,而HMM則是保證寫者擁有唯一的寫權限。fork()係統調用基於COW來複製地址空間,在HMM裏則是先觸發page fault的進程(child或parent)將取得page的所有權,這將依賴於觸發的時間點,引入不確定性。為了避免該問題,Gorman建議強製進程通過madavise()係統調用設置MAD_DONTFORK來避免該問題,這樣所有的內存都將屬於父進程。(4).Dan Williams提到HMM將GPU內存放置到ZONE_DEVICE區域,目前persistent memory也使用了該區域,二者共用邏輯的話容易導致一些bug,目前隻能通過仔細review來避免錯誤。(5). 目前還沒有具體的driver使用了HMM,NVIDIA GPU的Nouveau-based驅動有希望在4.12的合並窗口中提交,HMM的相關patch仍然暫時保留在-mm分支。
CDM是IBM提出的另一個思路,主要通過硬件來解決目前所遇到的問題。在一些嵌入式係統中,device memory可以看成是一個沒有CPU的NUMA節點,且提供cache-coherent語義。目前仍在開發中:https://lwn.net/Articles/713035/ 。本次會議討論的幾個點:(1). 如何在Linux中使用這些設備?預期是提供給用戶可選擇的內存分配機製:用戶決定申請CDM內存或者普通內存。NUMA balance需要關閉,因為直接在CDM內存與普通內存間進行頁遷移存在問題。如果一定要頁遷移,可通過DMA來加速。(2). 已有patch通過cpuset機製來隔離CDM;整個係統由於缺乏對完整的內存信息,無法實現內存均衡。zone鏈表將CDM隔離開來。THP頁遷移的功能還有待進一步討論。
9. Stack and driver testing
LSF/MM 2017會議上一個存儲和文件係統聯合議題中,Chaitanya Kulkarni領導了一個關於測試存儲設備驅動和存儲棧其他部分的討論。他想以一個內核緊耦合的測試驅動框架作為起步。目前已有相關的零散測試套件,他想收集一些關於統一測試框架的想法和反饋。
Hannes Reinecke問到Kulkarni想要測試目標類型是什麼?功能,性能,亦或其他?Kulkarni說,第一步是功能測試,但最終目標將轉向更複雜的測試集。
James Bottomley說硬件和內核是否都正確實現刷緩存並沒有得到有效驗證。確保驅動在這方麵正確是最難測試的。但Jens Axboe提出存在諸如fio等工具可以用於記錄寫入設備的數據,然後斷電再驗證所有記錄的寫是否已真正地寫入到設備。但Chris Mason指出將需要大量的係統來實施這種測試。
Kulkarni想知道任何時候塊層有新的提交時都能測試整個塊層是否可行。他問到:是否存在這種方法,且這種類型的測試是否有必要?Bottomley引導Dave Chinner說,如果存在該類型的測試,應該被加到xfstests。這樣做的原因是,文件係統開發者定期運行xfstests,測試比較充分(pool of willing guinea pigs)。另外,參會者建議不同的測試/測試套可以作為統一測試的一部分運行。
但是Mason建議將事情細分。雖然文件係統開發者一直運行xfstests,但是他們並沒有Kulkarni感興趣的硬件(Kulkarni在WD工作)。文件係統開發者可以使用device mapper創建硬件模擬器來運行xfstests。因此問題將變成需要確保模擬器能真實反映硬件。
Ted Ts'o同意該觀點,指出SMR設備是一個需要測試的領域,但對文件係統開發者來說並不容易。如果device mapper模擬器提供寫指針和其他SMR功能,將使xfstests和其他測試得以運行。這對打開文件係統和SMR的交互局麵將起到很大作用。“我們可以後續再考慮邊緣案例”。
一個參會者提出:測試device mapper模擬器固然對文件係統來說很好,但諸如塊層IO調度器同樣需要被測試。Axboe說,這種類型的測試可以訓練多隊列調度器,但仍然需要塊層的測試。類似於xfstests,塊層開發者可以運行和測試塊層和存儲層部分棧。它可包含不同類型的設備如SMR,也可包含內核特性如熱插拔。如果有人構建框架,測試將會隨之而來。
實際上,他旨在幫助將框架組合在一起。Josef Bacik同樣推薦將其加入xfstests,Axboe對此並不反對。Bacik說xfstests框架已經有許多需要的測試,但Bottomley提醒將需要將xfstests改造成不再依賴文件係統。
一位觀眾提出,測試到的代碼路徑也需要展示出來,但另外一位指出內核支持gcov,可以用來查看測試代碼覆蓋。
一位參會者關心目前沒有熱插拔的測試,但Bacik說部分Btrfs測試使用到了。他擔心xfstests不支持設備級測試,因此需要新增。Ts‘o想確保開發者可以在無需訪問特殊硬件的前提下運行各種測試,因此需要創建device mapper模擬器。
Bottomley說一旦xfstests修改成不再需要掛載文件係統來作為測試的一部分,一些子係統特定的測試可以加入進來,如SCSI,NVMe,RDMA等。Bacik同意該觀點,xfstests目前工作良好,除非你想測試塊層。該討論額外得出,塊層測試應當加入到不再依賴文件係統的xfstests,然後新增子係統特定的測試。
Mason補充到無需持久化的測試應當成為該努力的一部分,如設備可用性和模擬。Axboe說,當新bug出現,檢測該問題的測試應當同樣新增進來。他不想對假定測試用例是什麼樣。可能存在特定類型硬件的測試用例。任何人做該工作將選擇測試框架運行的形式。
Kulkarni想知道一些存儲子係統特定的測試是否可以在諸如SCSI,NVMe等之間共享。Bottomley說可能,但重要的是持續聚焦於內核關心的特性。多樣的硬件設備可以確保和提供Linux不使用的特性,因此測試這些對內核社區並沒有價值。覆蓋地圖將指導哪些地方需要更多的測試。議題時間耗盡,但看來已經在正確的道路上達成了較強的一致。
最後更新:2017-06-08 10:01:27