cpuset


本文屬於內核文檔翻譯,翻譯時沒有遵照原文,添加了一些作者的理解,目的不是為了替代內核文檔,可以作為閱讀內核文檔的引子,作者鼓勵讀者閱讀原有的內核文檔。原文參考3.10.514內核文檔cpuset.txt

 

內容
1.cpuset
  1.1:什么是cpuset?
  1.2:為什么需要cpuset?
  1.3:cpuset是如何實現的?
  1.4:什么是互斥cpuset?
  1.5:mem_pressure是什么意思?
  1.6:什么是memory spead?
  1.7:什么是sched_load_balance?
  1.8:什么是sched_relax_domain_level?
  1.9:如何用cpuset?
2.使用舉例,以及語法
  2.1:基本用法
  2.2:添加刪除cpu
  2.3:設置標志位
  2.4:進程綁定

 

1.Cpusets
==========

1.1 什么是cpuset?

cpuset基本功能是限制某一組進程只運行在某些cpu和內存節點上,舉個簡單例子:系統中有4個進程,4個內節點,4個cpu.利用cpuset可以讓第1,2個進程只運行在第1,2顆cpu上並且只在第1,2個內存節點上分配內存。cpuset是基於cgroup子系統實現(關於cgroup子系統可以參考內核文檔 Documentation/cgroups/cgroups.txt.)使用cpuset上述功能可以讓系統管理員動態調整進程運行所在的cpu和內存節點。

linux提供的如下三個系統調用完成類似的功能:

sched_setaffinity(俗稱進程親核性)系統調用,設置某進程(或線程)只能運行在某些cpu上。

mbind(內存綁定)和set_mempolicy(內存策略)系統調用,設置進程只能在某些內存節點上分配內存。

那親核性,內存綁定,內存策略和cpuset是什么關系呢?

如果一個進程即設置了親核性,內存綁定,內存策略,又設置了cpuset,那么進程運行需要的內存和cpu就會是前后兩者的交集。例如:進程1通過親核性設置只能跑在1,2兩個cpu上,並且通過mbind或者set_mempolicy限制只能在內存節點1,2上分配內存;接着又用cpuset限制其只能在1,3核心上運行,並且只能在內存節點1,3上分配內存,那么結果是:進程1只能運行在1核心上,並且只能在內存節點1上分配內存。

cpuset使用sysfs提供用戶態接口,可以通過普通文件讀寫,將某顆cpu動態的加入到cpuset從而允許cpuset中的所有進程使用這顆cpu,也可以將某個進程加入到cpuset,從而讓該進程接受cpuset的限制。可以將某個進程從一個cpuset移動到另一個cpuset。可以動態的創建,刪除cpuset,修改cpuset的屬性。

遺留問題:

1.mbind和set_mempolicy對用戶態內存和內核態內存限制,表現的特性是不是一樣?如果不一樣都有哪些差異呢?

 

1.2 為什么需要cpuset?

大型的服務器中,有上百顆cpu,若干內存節點。尤其在NUMA架構下,cpu訪問不同內存節點的速度不同,這種情況增加了進程調度和進程內存分配目標node管理的難度。比較新的小型系統使用linux內核自帶的調度功能和內存管理方案就能得到很好表現,但是在比較大的系統中如果精心調整不同應用所在的cpu和內存節點會大大提高服務器性能表現。

cpuset在一下應用場合會顯得特別有價值

1.對於跑了很多相同的應用實例的大型web server
2.對於跑了不同應用的大型server(例如:同時跑了web server相關應用,又跑了數據庫應用)
3.大型NUMA系統

cpuset必須允許動態調整,並且不影響服務器上其他不相關cpuset中運行的進程。比如:可以將某個cpu動態的加入到某個cpuset,可以從某個cpuset中將某個cpu移除,可以將進程加入到cpuset,也可以將某個進程從一個cpuset遷移到另一個cpuset。內核的cpuset補丁,提供了最基本的實現上述功能的機制,在實現上最大限度使用原有的cpu和內存節點分配機制,盡可能避免影響現有的調度器,以及內存分配核心功能的代碼。

個人覺得相對於親核性,內存綁定,內存策略幾個系統調用,cpuset的優勢在於:前者必須通過系統調用,而系統調用的目標是進程,也就是說系統調用是面向單個進程。而cpuset則是另一種思路是先將幾個cpu和幾個內存節點放到cpuset中,在將相關的進程放到cpuset中 從而達到進程接受cpuset的限制,cpuset面向的系統資源和進程集合。

 

1.3 cpuset是如何實現的?

在內核引入cpuset之前,已經有一些其他的機制來限制某個進程只能被調度到某些cpu上運行(sched_setaffinity),限制某些進程的內存申請只能在某些內存節點上分配(mbind,set_mempolicy)

cpuset在如下幾個方面對sched_setaffinity,mbind,set_mempolicy做了擴展

1.cpuset從概念上可以理解成一組cpu和一組內存節點的集合
2.進程描述符中有一個指針指向了cgroup數據結構(cpuset是cgroup的一個子系統),通過這個指針,可以將進程添加到具體的cpuset
3.對於在某個cpuset中的進程,調用sched_setaffinity那么親核性設置的cpu集合會經過cpuset的過濾,也就是說親核性最后設置的結果一定是seched_setaffinity和cpuset的交集。

4.mbind和set_mempolicy設置的node節點也要經過cpuset的過濾,內存綁定,內存策略設置的node也要經過cpuset規則設置的node的限制

5.根cpuset中包含了系統中所有的內存節點和cpu

6.針對任何的cpuset,用戶可以定義該cpuset的子cpuset,子cpuset中包含的cpu和內存節點是該cpuset(父親cpuset)的子集

7.cpuset的層級可以被掛在在/dev/cpuset,也就是一個偽文件系統,通過操作該文件系統的文件來動態管理cpuset

8.一個cpuset可以被標志位“互斥”的,一個被標志位互斥的cpuset,該cpuset的兄弟cpuset中包含的cpu和內存節點不能和該cpuset中的cpu和內存節點有交集

9.可以找到一個cpuset中所有進程的pid

cpuset實現需要在現有的內核代碼流程中實現些鈎子函數,但是這些鈎子函數都不在內核控制路徑的的關鍵(熱點)路徑上。

1.在init/main.c中需要在系統初始化的時候初始化根cpuset

2.在fork和exit流程中需要將某個進程放入cpuset或者將進程從cpuset中拿出來

3.在sched.c的調度或者進程遷移中,確保進程遷移的目標cpu在cpuset中

4.在mbind和set_mempolicy中用cpuset的內存節點對這兩個系統調用的內存節點過濾

5.在page_alloc.c中限制內存分配只能在cpuset中的內存節點上分配內存

6.在vmscan.c中限制page回復到當前的cpuset(不知道啥意思)

如果想對cpuset操作,就必須掛在cgroup文件系統,內核沒有提供額外的系統調用對cpuset做修改,維護。所有的修改維護操作都是通過修改該文件系統中的文件來完整。

在/proc/#pid/status中添加了如下幾行來說明一個進程運行必須在某些cpu上,並且進程分配內存必須在某些內存節點上

  Cpus_allowed:   ffffffff,ffffffff,ffffffff,ffffffff
  Cpus_allowed_list:      0-127
  Mems_allowed:   ffffffff,ffffffff
  Mems_allowed_list:      0-63

 

每一個cpuset對應cgroup文件系統中的一個目錄,目錄下有些文件,用來描述cpuset的屬性。對應的文件里列表如下:

1.cpuset.cpus cpuset中的cpu列表

2.cpuset.mems cpuset中的內存節點列表

3.cpuset.memory_migrate

4.cpuset.cpu_exclusive cpuset是否是cpu互斥的(參考1.4節)

5.cpuset.mem_exclusive cpuset是否是內存互斥的(參考1.4節)

6.cpuset.mem_hardwall cpuset是否是hardwalled的(參考1.4節)

7.cpuset.memory_pressure

8.cpuset.memory_spread_page 如果被設置了,將該cpuset中進程上下文申請的page cache平均分布到cpuset中的各個節點

9.cpuset.memory_spread_slab 如果被設置了,將該cpuset中進程上下文申請到的slab對象平均分布到cpuset中的各個內存節點

10.cpuset.sched_load_balance

11.cpuset.sched_relax_domain_level

下面文件只有在根cpuset中才有:

12.cpuset.memory_pressure_enabled

可以通過mkdir 命令在shell環境下創建cpuset,而新創建的cpuset的屬性,可以通過普通的文件讀寫修改(具體文件就是上面提到的12個文件)。而通過在一個cpuset對一個的目錄下創建子目錄可以創建子cpuset,通過這個層級模型可以把一個大型系統從軟件上切分成若干個小型的系統

【未完待續】

 

1.4 什么是互斥cpuset

每個cpuset有兩個bool類型的參數cpuset.mem_exclusive,cpuset.cpu_exclusive,分別表示當前的cpuset是否是內存互斥和cpu互斥的。為了理解這個概念必須理解cgroup層級樹的概念:其實cpuset做為cgroup一個子系統實現,也遵循了cgroup層級樹的概念。舉個例子,例如:有一個cpuset0,可以在cpuset0下再建立若干個cpuset。比如:建立cpuset0-0,cpuset0-1兩個孩子cpuset。cpuset0-0和cpuset0-1互稱位兄弟,cpuset0屬於父親。孩子cpuset中的cpu和node節點集合必須是父親cpuset中cpu和內存節點集合的子集。理解了層級樹的概念,再來看cpu互斥的概念:如果某個cpuset是cpu互斥的那么該cpuset中的cpu是不能被該cpuset的兄弟cpuset共享的,當然該cpuset中的cpu是能夠和該cpuset的祖先cpuset和子孫cpuset共享的。理解了cpu互斥的概念,要理解內存互斥的概念,將上述cpu互斥概念中的cpu替換成內存節點就可以了。

下面特別說明下關於內存互斥cpuset

cpuset還有一個bool類型的參數cpuset.mem_hardwall,如果一個cpuset被設置成內存互斥或者被設置了cpuset.mem_hardwall,那么都認為這個cpuset是mem_hardwalled。一個mem_hardwalled的cpuset其中的進程在內核態申請的內存(主要有直接申請的頁,以及通過slab系統分配的內存,還有文件系統page cache)會受到cpuset的限制,進而在該cpuset內的內存節點中分配內存。最為對比:不管cpuset是否是mem_haardwalled,cpuset中的進程在用戶態申請的內存都會受到cpuset中內存節點的限制。另外從上面的闡述也可以得到一個總要結論:其實cpuset.headwall是一個相對獨立的概念:它限制了cpuset中進程在內核態申請的內存來至於cpuset中的node節點。而mem_exclusive除了提供了內存互斥的功能,還隱含了cpuset.mem_hardwall的功能。

通過上面闡述得到如下兩個重要結論:

1.如果一個cpuset 是hardwalled的,那么這個cpuset中的進程的內存分配(不管是用戶態的還是內核態的)都要接受cpuset中內存節點的限制。

2.如果一個cpuset不是hardwalled的,那么這個cpuset中的進程的內核態內存分配不受cpuset中內存節點的限制,而用戶態內存分配受到cpuset中內存節點的限制。

 

這么來說就有一個非常有用的場景:

比如又一個文件服務器,有5個內存節點,其中有兩組業務進程在大量的讀寫文件,我們需要將一組進程用戶態內存分配限制在內存節點1,2上,而另一組用戶態內存分配限制在內存節點3,4上,而所有兩組進程需要共同訪問的page cache限制在1,2,3,4內存節點上。剩下一個內存節點(5)給其他進程用。而除去這兩組進程,不允許其他進程內存分配(不管是和心態還是用戶態)落到1,2,3,4上。我們就可以先建立一個cpuset0標記mem_exclusive,並將1,2,3,4節點添加到cpuset0,並在cpuset0下創建一個cpuset0-0 不設置mem_exclusive,將第一組進程添加到其中,並將1,2節點添加到其中,同樣建立cpuset0-1,不設置mem_exclusive,並將第二組進程添加到其中,同時將內存節點3,4添加到其中。再建立一個cpuset1 設置mem_exclusive 並將系統中剩余的進程加入到cpuset1中,並將內存節點5放入其中。

 

1.5什么是mem_pressure?

【未完待續】

1.6什么是memory spread?

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM