linux 復合頁( Compound Page )的介紹


1、復合頁的定義:

  復合頁(Compound Page)就是將物理上連續的兩個或多個頁看成一個獨立的大頁,它可以用來創建hugetlbfs中使用的大頁(hugepage),  也可以用來創建透明大頁(transparent huge page)子系統。但是它不能用在頁緩存(page cache)中,這是因為頁緩存中管理的都是單個頁。

 

2、復合頁的分配及標記:

  當__alloc_pages分配標志gfp_flags指定了__GFP_COMP,那么內核必須將這些頁組合成復合頁compound page。復合頁的尺寸要遠大於當前分頁系統支持的頁面大小。並且一定是2^order * PAGE_SIZE大小。復合頁主要用在HugeTLB相關的代碼。復合頁的引入是因為隨着計算機物理內存容量不斷增大,4G以上幾乎成了標配,幾十G的內存也很常見,而操作系統仍然使用4KB大小頁面的基本單位,顯得有些滯后。當采用4KB大小的頁面時,想像一下當應用程序分配2MB內存,並進行訪問時,共有512個頁面,操作系統會經歷512次TLB miss和512次缺頁中斷后,才可以把這2M地址空間全部映射到物理內存上;然而如果使用2MB大小的compand頁,那么只需要一次TLB miss和一次缺頁中斷。當頁面分配函數使用GFP_COMP進行頁面分配時,分配函數會為每一個增加標志PG_Compound,我們稱復合頁中的第一個4KB頁面為head page,后面的所有page 為tail page。每個page的private保存一個指針,head page的private指向本身,tail page的private指向head page。

  Page頁中的flag標記用來識別復合頁。在復合頁中,打頭的第一個普通頁成為“head page”,用PG_head標記,而后面的所有頁被稱為“tail pages”,用PG_tail標記。在64位系統中,可以有多余的標記來表示復合頁的頁頭和頁尾;但是在32位系統中卻沒有那么多的標記,因此采用了一種復用其他標記的方案,即將復合頁中的所有頁都用PG_compound標記,然后,對於尾頁同時也使用PG_reclaim標記,這是因為PG_reclaim只有在頁緩存中會用到,而復合頁根本就不會在頁緩存中使用。

 

 //32位系統中的標記實例: 
1
#define PG_head_mask ((1L << PG_compound)) 2 #define PG_head_tail_mask ((1L << PG_compound) | (1L << PG_reclaim)) 3 4 static inline int PageHead(struct page *page) 5 { 6 return ((page->flags & PG_head_tail_mask) == PG_head_mask); 7 } 8 9 10 static inline int PageTail(struct page *page) 11 { 12 return ((page->flags & PG_head_tail_mask) == PG_head_tail_mask); 13 }

 

3、復合頁的檢測:

  可以使用PageCompound函數來檢測一個頁是否是復合頁,另外函數PageHead和函數PageTail用來檢測一個頁是否是頁頭或者頁尾。在每個尾頁的page結構體中都包含一個指向頭頁的指針 - first_page,可以使用compound_head函數獲得。

 

4、復合頁的釋放:

  那么當一個復合頁不再被系統使用時,我們如何知道該復合頁包含多少個普通頁,又如何知道該復合頁的析構函數(destructor)存在哪里呢?首先,人們可能會認為這些信息存在於頭頁的page結構體中,但是很不幸,在這個結構體中已經沒有可用的空間了。因此,這些信息全部存儲在第一個尾頁的lru字段中,將該復合頁的大小(order)首先強制轉換為指針類型,然后存儲在lru.prev中,將析構函數存儲在lru.next中。

 1 static void free_compound_page(struct page *page)
 2 {
 3     __free_pages_ok(page, compound_order(page));
 4 }
 5 
 6 static inline int compound_order(struct page *page)
 7 {
 8     if (!PageHead(page))
 9         return 0;
10     return (unsigned long)page[1].lru.prev;
11 }

  這里就解釋了為什么復合頁必須至少是兩個頁。在內核中生成了兩個復合頁的析構函數,默認情況下會調用free_compound_page來將所有的頁返回給系統的頁框分配器,而hugetlbfs子系統會調用free_huge_page來做一些統計並釋放。使用復合頁的最經典的一個例子就是THP(transparent huge page),


免責聲明!

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



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