Chinaunix

标题: cache/buffer, anon, mmap 三类page的状态和生命周期转换。 [打印本页]

作者: embeddedlwp    时间: 2012-05-22 20:00
本帖最后由 embeddedlwp 于 2013-05-06 08:49 编辑

找到 fengguang童鞋的一个slides,share一下


作者: embeddedlwp    时间: 2012-05-23 18:54
本帖最后由 embeddedlwp 于 2012-05-23 18:57 编辑

回复 1# blake326


一般的情况,应该首先释放cache/buffer内存。
比如cat 一个文件,page只被引用了一次,所以状态是inactive,referenced。
第一次shrink_inactive_list会将这些page的referenced标志清除。
第二次shrink_inactive_list会将这些page释放。(二次机会)

=============================================================

    在我看的2.6.24的代码中,这个二次机会不一定总会有。shrink_page_list部分代码:

        referenced = page_referenced(page, 1);
                /* In active use or really unfreeable?  Activate it. */
                if (sc->order <= PAGE_ALLOC_COSTLY_ORDER &&
                                        referenced && page_mapping_inuse(page))
                        goto activate_locked;


/* Called without lock on whether page is mapped, so answer is unstable */
static inline int page_mapping_inuse(struct page *page)
{
        struct address_space *mapping;

        /* Page is in somebody's page tables. */
        if (page_mapped(page))
                return 1;

        /* Be more reluctant to reclaim swapcache than pagecache */
        if (PageSwapCache(page))
                return 1;

        mapping = page_mapping(page);
        if (!mapping)
                return 0;

        /* File is mmap'd by somebody? */
        return mapping_mapped(mapping);
}

也就是说只有被access过,而且这些条件都满足,才能拿到二次机会!
作者: blake326    时间: 2012-05-23 19:35
回复 3# embeddedlwp


    一般的情况,应该首先释放cache/buffer内存。
比如cat 一个文件,page只被引用了一次,所以状态是inactive,referenced。
第一次shrink_inactive_list会将这些page的referenced标志清除。
第二次shrink_inactive_list会将这些page释放。(二次机会)


在看了下page_check_references代码,发现这种情况page会被直接回收的。
buffer/cache并没有相应的pte对应它并是最近访问的pte。
        referenced_ptes = page_referenced(page, 1, sc->mem_cgroup, &vm_flags);
这个返回0,就应该被直接释放。所以说,buffer、cache很容易被释放,只要内存不够了,shrink_inactive_list第一次机会的时候就能够将这些只用了一次的buffer/cache给释放了。
当然,多次访问过的buffer/cache会通过mark_page_accessed从inactive的lru移动到active的lru。



作者: embeddedlwp    时间: 2012-05-23 20:14
本帖最后由 embeddedlwp 于 2012-05-23 20:16 编辑

回复 4# blake326


在看了下page_check_references代码,发现这种情况page会被直接回收的。
buffer/cache并没有相应的pte对应它并是最近访问的pte。
        referenced_ptes = page_referenced(page, 1, sc->mem_cgroup, &vm_flags);
这个返回0,就应该被直接释放。所以说,buffer、cache很容易被释放,只要内存不够了,shrink_inactive_list第一次机会的时候就能够将这些只用了一次的buffer/cache给释放了。
当然,多次访问过的buffer/cache会通过mark_page_accessed从inactive的lru移动到active的lru。

==============================================================

看了一下3.4的代码:

int page_referenced(struct page *page,
                    int is_locked,
                    struct mem_cgroup *memcg,
                    unsigned long *vm_flags)
{
        int referenced = 0;
        int we_locked = 0;

        *vm_flags = 0;
        if (page_mapped(page) && page_rmapping(page)) {
                if (!is_locked && (!PageAnon(page) || PageKsm(page))) {
                        we_locked = trylock_page(page);
                        if (!we_locked) {
                                referenced++;
                                goto out;
                        }
                }
                if (unlikely(PageKsm(page)))
                        referenced += page_referenced_ksm(page, memcg,
                                                                vm_flags);
                else if (PageAnon(page))
                        referenced += page_referenced_anon(page, memcg,
                                                                vm_flags);
                else if (page->mapping)
                        referenced += page_referenced_file(page, memcg,
                                                                vm_flags);
                if (we_locked)
                        unlock_page(page);

                if (page_test_and_clear_young(page_to_pfn(page)))
                        referenced++;
        }
out:
        return referenced;
}

红的部分在测PG_referenced是否置位,也就是说即使是访问过一次的cache/buffer,这里也会返回1而不是0啊!所以你说的那个红色的部分应该不成立吧!嘿嘿!
当内存紧缺的时候,swap tendency 会 >= 100,此时会从 buffer/cache 和 用户地址空间的页 同时回收!


   
作者: blake326    时间: 2012-05-24 08:40
本帖最后由 blake326 于 2012-05-24 11:11 编辑

回复 5# embeddedlwp


    38的代码跟3.4的差不多。
    我有个疑问:
        if (page_mapped(page) && page_rmapping(page)) {
    对于这个条件,buffer/cache page一般不可能成立吧。

//buffer/cache page一般没有pte指向的。在内核一般kmap,然后拷贝到用户的anon,然后再内核kumap了。
static inline int page_mapped(struct page *page)
{
        return atomic_read(&(page)->_mapcount) >= 0;
}
//反向映射,anon或者文件映射。buffer/cache不可能有这个吧。-----更正一下,这个明显是文件映射的!晕了
static inline void *page_rmapping(struct page *page)
{
        return (void *)((unsigned long)page->mapping & ~PAGE_MAPPING_FLAGS);
}

   更重要的一个问题:
                if (page_test_and_clear_young(page_to_pfn(page)))
                        referenced++;
这个page_test_and_clear_young方法我查了下只有s390上才有定义的。其他架构上都是noop。英文我不太看的懂,你可以看下,貌似说s390的pte跟一般的不一样什么的。还请看了之后,指教指教我啊。



作者: embeddedlwp    时间: 2012-05-24 17:05
本帖最后由 embeddedlwp 于 2012-05-24 17:11 编辑

回复 6# blake326

//buffer/cache page一般没有pte指向的。在内核一般kmap,然后拷贝到用户的anon,然后再内核kumap了。
static inline int page_mapped(struct page *page)
{
        return atomic_read(&(page)->_mapcount) >= 0;
}

=====================================
buffer/cache page为什么没有pte指向的呢,buffer cache是用来contain meta data的,page cache使用来contain file data的。
那么mmap把一个文件映射到进程的地址空间,当需要访问文件数据的时候,正是由于这个pte的Present标志位没有设置,所以
会触发page fault,然后到page cache中这个page对应的file对应的radix tree里去找.....
你说的“在内核一般kmap,然后拷贝到用户的anon,然后再内核kumap了。”在哪里看到的啊?


更重要的一个问题:
                if (page_test_and_clear_young(page_to_pfn(page)))
                        referenced++;
这个page_test_and_clear_young方法我查了下只有s390上才有定义的。其他架构上都是noop。英文我不太看的懂,你可以看下,貌似说s390的pte跟一般的不一样什么的。还请看了之后,指教指教我啊。

=====================================
什么英文,怎么没找到啊,不过在x上这个应该为空了哈。那么是不是还差这段我们没有分析?

if (!is_locked && (!PageAnon(page) || PageKsm(page))) {
                        we_locked = trylock_page(page);
                        if (!we_locked) {
                                referenced++;
                                goto out;
                        }
                }


BTW:

既然cache/buffer是文件映射,那么会执行下边这个啦:

else if (page->mapping)
                        referenced += page_referenced_file(page, memcg,
                                                                vm_flags);
作者: blake326    时间: 2012-05-24 17:16
本帖最后由 blake326 于 2012-05-24 17:20 编辑

回复 7# embeddedlwp


    我说的buffer/cache 是指的cat 一个文件,通过系统调用read,而产生的page。并没有包括mmap的文件映射page。虽然这两种page都属于buffer/cache。

因为我说的直接read系统调用的buffer/cache page是最多的。比如说grep xxx . -rn 查找字符串什么的。通过free命令会发现cache会急速的增长。


所以我根据page的回收机制和重要性重新分了下,buffer/cache, annon, mmap三种。

read系统调用涉及到两种 buffer/cache, anon.

对于kernel来说,我说的buffer/cache, mmap 的page都是cache。但是,它们的重要性却不同。回收内存时有点区别。

-------------------------------------------------------------------------------------------------
int page_referenced(struct page *page,
                    int is_locked,
                    struct mem_cgroup *mem_cont,
                    unsigned long *vm_flags)
{
        int referenced = 0;
        int we_locked = 0;

        *vm_flags = 0;
        if (page_mapped(page) && page_rmapping(page)) { //下面都没用了。对于read系统调用产生的cache.buffer
                if (!is_locked && (!PageAnon(page) || PageKsm(page))) {
                        we_locked = trylock_page(page);
                        if (!we_locked) {
                                referenced++;
                                goto out;
                        }
                }
                if (unlikely(PageKsm(page)))
                        referenced += page_referenced_ksm(page, mem_cont,
                                                                vm_flags);
                else if (PageAnon(page))
                        referenced += page_referenced_anon(page, mem_cont,
                                                                vm_flags);
                else if (page->mapping) //我说的read系统调用出来的buffer/cache, page_mapped(page)都没有成立,肯定不会走了。
                        referenced += page_referenced_file(page, mem_cont,
                                                                vm_flags);
                if (we_locked)
                        unlock_page(page);
        }
out:
        if (page_test_and_clear_young(page))
                referenced++;

        return referenced;
}
作者: embeddedlwp    时间: 2012-05-24 17:47
本帖最后由 embeddedlwp 于 2012-05-24 17:47 编辑

回复 8# blake326



int page_referenced(struct page *page,
                    int is_locked,
                    struct mem_cgroup *mem_cont,
                    unsigned long *vm_flags)
{
        int referenced = 0;
        int we_locked = 0;




        *vm_flags = 0;
        if (page_mapped(page) && page_rmapping(page)) { //下面都没用了。对于read系统调用产生的cache.buffer
        //这两个条件都成立啊,前者判断引用计数,后者判断是不是反向映射,从page_rmapping的实现来看,它判断的是page->mapping,即相应的
          address_space或anon_vma是否存在,既然是文件映射,那么address_space object肯定存在啦,所以怎么说不会往下执行呢,嘿嘿!


                if (!is_locked && (!PageAnon(page) || PageKsm(page))) { 
                        we_locked = trylock_page(page);
                        if (!we_locked) {
                                referenced++;
                                goto out;
                        }
                }
                if (unlikely(PageKsm(page)))
                        referenced += page_referenced_ksm(page, mem_cont,
                                                                vm_flags);
                else if (PageAnon(page))
                        referenced += page_referenced_anon(page, mem_cont,
                                                                vm_flags);
                else if (page->mapping) //我说的read系统调用出来的buffer/cache, page_mapped(page)都没有成立,肯定不会走了。
                        referenced += page_referenced_file(page, mem_cont,
                                                                vm_flags);
                if (we_locked)
                        unlock_page(page);
        }
out:
        if (page_test_and_clear_young(page))
                referenced++;




        return referenced;
}
   
作者: embeddedlwp    时间: 2012-05-24 17:50
回复 1# blake326



mmap page:
1. do_linear_fault(),filemap_fault()加入到inactive file lru中。pte accessed被置位.
由于mmap经常存在一次然后读取写入之后就不用的情况。所以page重要性不如anon的page,加入到inactive file lru中。

============================================================

我感觉还有个原因,anon主要是 堆栈这类的,所以回收的时候得swap out到swap area.
如果是file map这类的,直接写回就行啦,如果不脏还不用写。


   
作者: blake326    时间: 2012-05-24 18:09
回复 9# embeddedlwp


          if (page_mapped(page) && page_rmapping(page)) { //下面都没用了。对于read系统调用产生的cache.buffer
        //这两个条件都成立啊,前者判断引用计数,后者判断是不是反向映射,从page_rmapping的实现来看,它判断的是page->mapping,即相应的
          address_space或anon_vma是否存在,既然是文件映射,那么address_space object肯定存在啦,所以怎么说不会往下执行呢,嘿嘿!

>>>>>>>>
       read系统调用产生的buffer/cache page
       page_mapped返回0. page->_mapcount=-1




-----------------------------------------------------------------------
我感觉还有个原因,anon主要是 堆栈这类的,所以回收的时候得swap out到swap area.
如果是file map这类的,直接写回就行啦,如果不脏还不用写。

>>>>>>
必须的
作者: embeddedlwp    时间: 2012-05-24 20:25
回复 11# blake326



read系统调用产生的buffer/cache page
       page_mapped返回0. page->_mapcount=-1

===========================

那你找到在mmap的时候,哪里增加的这个_mapcount值没有?

再一个就是不知fengguang这张图中pte_young是个啥?



   
作者: blake326    时间: 2012-05-24 21:37
回复 12# embeddedlwp




    do_linear_fault
__do_fault
                        page_add_file_rmap(page);


void page_add_file_rmap(struct page *page)
{
        if (atomic_inc_and_test(&page->_mapcount)) {
                __inc_zone_page_state(page, NR_FILE_MAPPED);
                mem_cgroup_inc_page_stat(page, MEMCG_NR_FILE_MAPPED);
        }
}
作者: blake326    时间: 2012-05-25 09:33
本帖最后由 blake326 于 2012-05-25 09:33 编辑

回复 12# embeddedlwp



pte关联的地址被访问时自动置为。pte_young检测pte是否最近被access过。
    static inline int pte_young(pte_t pte)
{
        return pte_flags(pte) & _PAGE_ACCESSED;
}

filemap,anon的page相关的pte被access过,那么就不会释放,然后kernel 清除access位。下次再来释放该page的时候,如果access还是清除的话,那么久真的释放了。
作者: embeddedlwp    时间: 2012-05-25 12:04
分享清磁盘高速缓存的方法


To free pagecache:

# echo 1 > /proc/sys/vm/drop_caches
To free dentries and inodes:

# echo 2 > /proc/sys/vm/drop_caches
To free pagecache, dentries and inodes:

echo 3 > /proc/sys/vm/drop_caches
作者: embeddedlwp    时间: 2012-05-27 17:49
回复 1# blake326



从这张图来看貌似read/write的page在第二次access的时候为active
而mapped pages第一次就active吧?

再比如在页换入的时候,在read_swap_cache_async函数中,页直接就添加的active,而不是从先加到inactive,然后mark_page_accessed


   
作者: blake326    时间: 2012-05-28 09:12
回复 16# embeddedlwp


   最新的代码(至少38以后肯定是的)filemap的page在缺页异常时没有mark_page_accessed, PG_referenced也没有置为。

   所以shrink_page_list的时候,会KEEP在inactive list中。
作者: embeddedlwp    时间: 2012-05-28 19:48
回复 17# blake326

为什么filemap的page一次就active,而read/write得两次
这样read/write的page比filemap更容易被回收掉
为什么对filemap的这样保护?


   
作者: blake326    时间: 2012-05-28 20:23
embeddedlwp 发表于 2012-05-28 19:48
回复 17# blake326

为什么filemap的page一次就active,而read/write得两次


anon 最重要
filemap 其次
buffer/cache 最不重要

具体的表现:
buffer/cache 只mark_page_accessed一次的话(一般至少一次),shrink_inactive_list会直接释放它。
filemap只访问一次的话,第一次shrink_inactive_list会把他keep在inactive list中,第二次shrink_inactive_list就会释放它。
anon page只访问一次的话,第一次shrink_active_list会把他移到inactive list中,然后下次shrink_inactive_list就会释放它。

anon page直接就在 active list中,一般系统比较少才能调用到shrink_active_list,更突出了它的重要性。
你的帖子ubuntu为什么free内存这么少,其实就是buffer/cache很多,加进来的释放的主要都是cache,shrink_active_list调用比较少。




作者: 瀚海书香    时间: 2012-05-29 10:07
本帖最后由 瀚海书香 于 2012-05-29 10:07 编辑

多谢分享!
对page cache这块了解的更清楚了

   
作者: embeddedlwp    时间: 2012-05-29 11:41
回复 19# blake326


anon page直接就在 active list中,一般系统比较少才能调用到shrink_active_list,更突出了它的重要性。
你的帖子ubuntu为什么free内存这么少,其实就是buffer/cache很多,加进来的释放的主要都是cache,shrink_active_list调用比较少。

=============================================================

红色的部分怎么看出来的,貌似是swap tendency >= 100也就是你说的系统内存紧张时,从lump reclaim回收的page更有可能被
放到inactive。调不调用shrink_active_list与系统的紧张程度有关,进而影响回收的priority,那么紧张的话shrink_active_list和shrink_inactive_list
都会调用到。如果系统不是很紧张,而且要扫描的page数没有超过threshold sc->swap_cluster_max,那么就不会往下执行啊,接着在direct page reclaim path
和swap daemon path都会调用shrink_slab从icache,dcahce回收
  1. static unsigned long shrink_zone(int priority, struct zone *zone,
  2.                                 struct scan_control *sc)
  3. {
  4.         unsigned long nr_active;
  5.         unsigned long nr_inactive;
  6.         unsigned long nr_to_scan;
  7.         unsigned long nr_reclaimed = 0;

  8.         /*
  9.          * Add one to `nr_to_scan' just to make sure that the kernel will
  10.          * slowly sift through the active list.
  11.          */
  12.         zone->nr_scan_active +=
  13.                 (zone_page_state(zone, NR_ACTIVE) >> priority) + 1;
  14.         nr_active = zone->nr_scan_active;
  15.         if (nr_active >= sc->swap_cluster_max)
  16.                 zone->nr_scan_active = 0;
  17.         else
  18.                 nr_active = 0;

  19.         zone->nr_scan_inactive +=
  20.                 (zone_page_state(zone, NR_INACTIVE) >> priority) + 1;
  21.         nr_inactive = zone->nr_scan_inactive;
  22.         if (nr_inactive >= sc->swap_cluster_max)
  23.                 zone->nr_scan_inactive = 0;
  24.         else
  25.                 nr_inactive = 0;

  26.         while (nr_active || nr_inactive) {
  27.                 if (nr_active) {
  28.                         nr_to_scan = min(nr_active,
  29.                                         (unsigned long)sc->swap_cluster_max);
  30.                         nr_active -= nr_to_scan;
  31.                         shrink_active_list(nr_to_scan, zone, sc, priority);
  32.                 }

  33.                 if (nr_inactive) {
  34.                         nr_to_scan = min(nr_inactive,
  35.                                         (unsigned long)sc->swap_cluster_max);
  36.                         nr_inactive -= nr_to_scan;
  37.                         nr_reclaimed += shrink_inactive_list(nr_to_scan, zone,
  38.                                                                 sc);
  39.                 }
  40.         }

  41.         throttle_vm_writeout(sc->gfp_mask);
  42.         return nr_reclaimed;
  43. }
复制代码

作者: embeddedlwp    时间: 2012-05-29 11:45
回复 19# blake326


anon 最重要
filemap 其次
buffer/cache 最不重要

=======================

你这里的disk cache可以再细分一下讨论:

filemap 的page cache
read/write 的page cache
icache/dcache的page cache

   
作者: chishanmingshen    时间: 2012-06-03 22:23
回复 1# blake326


    请教一下,single mmap具体是什么意思?
作者: blake326    时间: 2012-06-04 09:16
回复 23# chishanmingshen


    只用一次的mmap。
    比如应用程序mmap一个文件,读取一遍就不用了。
作者: blake326    时间: 2012-09-21 14:39
回复 1# embeddedlwp


    这个不是我的发的帖子吗,怎么1楼变了。本来打算回忆一下这方面的东西的,怎么回事???
作者: embeddedlwp    时间: 2012-09-21 14:45
回复 24# blake326


是啊,不知你的总结哪里去了。最近这部分代码我又仔细看了看,有什么问题可以多多讨论!


   
作者: blake326    时间: 2012-09-21 14:46
回复 25# embeddedlwp


    尴尬了,莫非又要总结一遍。{:3_186:}  看来下次我得存到自己的电脑上比较保险。
作者: embeddedlwp    时间: 2012-09-21 14:48
回复 26# blake326


你可以在总结一下啊,然后我们讨论讨论,最好是最近的代码,貌似某些东西已经变化了!


   
作者: omycle    时间: 2013-02-22 16:41
blake326 发表于 2012-05-28 20:23
anon 最重要
filemap 其次
buffer/cache 最不重要


总结的好,受教了!
作者: chishanmingshen    时间: 2013-05-04 13:02
本帖最后由 chishanmingshen 于 2013-05-04 13:06 编辑

回复 18# blake326

我看了下3.9的,filemap没有加任何标志,就是说一次shrink就释放了啊。。。?





欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2