天天看點

巨頁的配置和修改巨頁

巨頁

背景知識

Linux中把頁面作為管理記憶體的基本機關,一個頁面為4KB。如果一個程式在運作過程中會用到很多的記憶體,那麼必然會導緻很多的TLB未命中和缺頁異常的情況,因為一個頁最大隻能是4KB是以也就造成了這種問題的發生。如果直接修改預設的頁面大小,那麼又容易造成記憶體浪費,顯然是不可取的。Linux引入了巨頁(Huge page)的概念。允許一個頁面的大小超過4KB,預設為2MB。

說到這裡其實你也應該知道為什麼預設為2MB了。 Linux的采取4級頁表管理虛拟位址到實體位址的轉換,32位系統中頁表項占4個位元組,64位中占8個位元組。4級頁表從高到低,依次為pgd,pud,pmd,pte,pte指向真正的4kb劃分的實體頁。倒數第二級為pmd,包含512個pte頁表項,指向的2MB的實體頁。采用大頁記憶體劃分時,核心頁表為三級,基本的分頁機關為2MB,此時pmd直接指向一個2MB的大頁面,作為最後一級頁表。

巨頁的配置和修改巨頁
巨頁的配置和修改巨頁

頁表項有标志位_PAGE_PSE,MMU以此來區分該頁表項映射的是4KB的小頁記憶體,還是2MB的大頁記憶體。

在系統啟動期間,你能用“大記憶體頁”為應用程式預留一部分記憶體。這部分記憶體,即被“大記憶體頁”占用的這些存儲器永遠不會被交換出記憶體。它會一直保留其中,除非你修改了配置。這會極大地提高像 Oracle 資料庫這樣的需要海量記憶體的應用程式的性能。

特點

大頁的優點

  • 減少頁表大小。每個Huge Page對應的是連續的2MB實體記憶體,這樣12GB的實體記憶體隻需要48KB的頁表,與原來的24MB相比減少很多。
  • Huge Page記憶體隻能鎖定在實體記憶體中,不能被交換到交換區,避免了交換引起的性能影響。
  • 由于頁表數量的減少,使得CPU中的TLB(可了解為CPU對頁表的CACHE)命中率大大提高。
  • Huge Page的頁表在各程序之間可以共享,也降低了Page Table的大小。

大頁的缺點

  • 要預先配置設定
  • 不夠靈活,需要重新開機主機生效
  • 如果配置設定過多,會造成浪費,不能被其他程式使用。

檢視巨頁資訊

grep Huge /proc/meminfo
           
巨頁的配置和修改巨頁
  • HugePages_Total表示大頁面池的大小
  • HugePages_Free表示池中尚未配置設定的大頁面數
  • HugePages_Rsvd表示保留的大頁面數,這些頁面尚未配置設定
  • HugePages_Surp是“盈餘”頁面,如果預設配置100,現在修改為80,則會顯示20

巨頁配置

配置有多種方式,可以修改啟動項重新啟動機器,也可以修改核心參數。這裡以後者為例。

修改檔案

HugePages_Total 對應核心參數 vm.nr_hugepages,也可以在運作中的系統上直接修改 /proc/sys/vm/nr_hugepages,修改的結果會立即影響空閑記憶體 MemFree的大小,因為HugePages在核心中獨立管理,隻要一經定義,無論是否被使用,都不再屬于free memory。如下:

巨頁的配置和修改巨頁
巨頁的配置和修改巨頁
巨頁的配置和修改巨頁
巨頁的配置和修改巨頁
巨頁的配置和修改巨頁

修改sysctl.conf

巨頁的配置和修改巨頁

大頁面缺頁中斷處理函數調用流程

巨頁的配置和修改巨頁
vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
			unsigned long address, unsigned int flags)
{
	...
	if (huge_pte_none(entry)) {
		ret = hugetlb_no_page(mm, vma, mapping, idx, address, ptep, flags);
		goto out_mutex;
	}

	...
}
           
static vm_fault_t hugetlb_no_page(struct mm_struct *mm,
			struct vm_area_struct *vma,
			struct address_space *mapping, pgoff_t idx,
			unsigned long address, pte_t *ptep, unsigned int flags)
{
	...

		page = alloc_huge_page(vma, haddr, 0);
		...
}
           

總體的流程其實是與普通的頁配置設定類似的。在程序通路到尚未建立虛實映射的大頁面記憶體區域時,就會産生缺頁中斷,缺頁中斷的處理函數是do_page_fault()函數。從do_page_fault()到函數handle_mm_fault()是缺頁中斷處理的公共流程,不是我們關注的重點,在此不作介紹。在函數handle_mm_fault()中首先會檢查産生缺頁中斷的記憶體區域是否是大頁面區域,即VM_HUGETLB标志是否設定,如果是,則調用函數hugetlb_fault()進行大頁面的映射,這是大頁面缺頁中斷處理的入口函數,其處理過程大緻如下:

​ hugetlb_fault()

  • 根據産生 Page Fault 的虛拟位址查找或配置設定相應的 PMD 表項;
  • 調用hugetlb_no_page()以配置設定實體記憶體、建立虛實映射;
  • 如果引發缺頁中斷的記憶體操作是寫操作,且該大頁面被設定為隻讀,則預先做一次 Copy on Write 操作,以避免因“違規操作”再次産生 Page Fault 而影響性能。

​ hugetlb_no_page()

  • 在産生 Page Fault 的虛存區域所映射的 hugetlb 特殊檔案的頁面緩存(PageCache)中查找引發中斷的虛拟位址所在的檔案頁面,如果找到則跳轉到第三部;
  • 配置設定大頁面,這是通過函數alloc_huge_page()完成的。配置設定成功後,将該頁面加入到該 hugetlb 檔案對應的 Page Cache 中,以便可以與其它程序共享該大頁面。
  • 設定相應的 PMD 表項,需要強調的是,為了區分大頁面與 4KB 頁面需要設定頁表項的_PAGE_PSE标志位,使得 MMU 在進行虛實位址轉換時能将此 PMD 表項作為最後一級映射,得到大頁面的實體位址。

​ alloc_huge_page()

​ 在前面提到,系統初始化時為每個 NUMA node 都初始化了相應的空閑大頁面連結清單——hugepage_freelists[],并配置設定了全部的大頁面,是以,在系統運作過程中配置設定大頁面的操作即為從該連結清單中擷取空閑大頁面的過程。至于大頁面的解除映射以及釋放,與配置設定與建立映射的過程相反,就不多說了。

總結

巨頁的出現滿足了很多對于大記憶體有需要的程序,對于不同的情況,作業系統會選擇不同的處理方式,不僅僅是固定的處理方式,采取更靈活的方法也是性能優化的目的。

參考

http://blog.chinaunix.net/uid-31410005-id-5783976.html

https://blog.csdn.net/niu91/article/details/116429354

繼續閱讀