• 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)

    from: https://www.cnblogs.com/penglcool/p/13293558.html

  • 相关阅读:
    数据结构学习笔记(特殊的线性表:栈与队列)
    数据结构学习笔记(线性表)
    使用U盘安装 OS X 的坑
    chrome插件推荐
    Mac下安装oh-my-zsh
    sublime下让代码居中
    Mac上关于shell使用Python3和C++11声明
    github学习(三)
    github学习(二)
    github学习(一)
  • 原文地址:https://www.cnblogs.com/aspirs/p/13899609.html
Copyright © 2020-2023  润新知