免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1183 | 回复: 5
打印 上一主题 下一主题

[内核入门] page_launder()函数疑问? [复制链接]

论坛徽章:
13
15-16赛季CBA联赛之八一
日期:2016-07-08 21:00:1415-16赛季CBA联赛之同曦
日期:2017-02-15 14:26:1515-16赛季CBA联赛之佛山
日期:2017-02-20 14:19:2615-16赛季CBA联赛之青岛
日期:2017-05-07 16:49:1115-16赛季CBA联赛之广夏
日期:2017-07-30 09:13:1215-16赛季CBA联赛之广东
日期:2018-07-05 22:34:3615-16赛季CBA联赛之江苏
日期:2018-09-03 12:10:2115-16赛季CBA联赛之上海
日期:2018-09-25 03:49:2215-16赛季CBA联赛之广东
日期:2018-09-25 04:09:12
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2016-02-22 16:31 |只看该作者 |倒序浏览
本帖最后由 _nosay 于 2016-02-22 17:30 编辑

Linux-2.4.0源码中的page_launder()函数:
我开始以为这个函数分2遍扫描,是在利用“第二次机会算法”,但看来不是,因为页面既然都到了inactive_dirty_list链表,就相当于被判了“死刑”,必须接受“死刑”往交换区写一次,才能变干净,也就没必要像“第二次机会算法”那样排个“你先死我后死”了。所以我猜测“第二次机会算法”应该是用于挑选将要移到inactive_dirty_list链表的页面,而不是用于挑选从inactive_dirty_list链表往交换区写的页面

这个函数的注释里面有这样一句话:
Since we want to refill those pages as soon as possible, we'll make two loops over the inactive list, one to move the already cleaned pages to the inactive_clean lists and one to (often asynchronously) clean the dirty inactive pages.

如果第1遍扫描之后,空闲页面还是短缺,这个函数会执行第2遍扫描,将链表中的页面全部写到交换区(即洗成干净页面),以后的一段时间,再执行到该函数,一般第1遍扫描就能解决空闲页面短缺的问题,而且只是将上次第2遍扫描过程洗干净的页面直接转移到page->zone->inactive_clean_list链表即可,所以保证了这个函数大部分时间执行很快。

这个函数我看了好久,现在终于感觉有点理解了,请问是我理解的这样吗

即使是这样,我还有疑问:
① 这种牺牲1次,提高大多次,好处体现在哪?反而有个缺点就是:在第2遍扫描时,如果inactive_dirty_list链表很长,内核不是会出现“卡顿”的现象吗?而且页面在链表中移来移去的,从整体上讲,性能也是有损失的(除非内核能保证,第2遍扫描大多数在CPU空闲的时候执行)。
② 第2遍扫描只是将链表中的页面都写到交换区,并没有顺便移到page->zone->inactive_clean_list链表,表示本次执行page_launder()洗净的页面数量cleaned_pages仍然是第1遍扫描的结果,这样不是可能会让后续的代码,由于洗净的页面还是满足不了需求而多走一些“弯路”吗?
③ 按照逻辑,难道不是干净页面在inactive_dirty_list链表最多只可能有1段区域,并且肯定在最前面吗?所以第1遍扫描如果遇到脏页面了,后面肯定都是脏页面,这样依次都移到inactive_dirty_list链表尾部,不是绕个圈又变成原来的形状了吗?而且第2遍扫描是将链表中剩下的页面全部洗干净,也不是从前往后扫一部分就不扫了,那即使“躲”到后面,又有什么意义呢,更别说由于大家都想“躲”,而造成恢复原来的队形了。

论坛徽章:
9
程序设计版块每日发帖之星
日期:2016-02-11 06:20:00程序设计版块每日发帖之星
日期:2016-02-14 06:20:00程序设计版块每日发帖之星
日期:2016-02-14 06:20:0015-16赛季CBA联赛之吉林
日期:2016-03-23 17:25:0015-16赛季CBA联赛之浙江
日期:2016-04-01 08:25:0615-16赛季CBA联赛之山西
日期:2016-04-01 10:09:1915-16赛季CBA联赛之广夏
日期:2016-06-03 15:58:212016科比退役纪念章
日期:2016-07-28 17:42:5215-16赛季CBA联赛之广东
日期:2017-02-20 23:32:43
2 [报告]
发表于 2016-02-22 17:29 |只看该作者
想帮您看看,可是我的内核代码里已经没有 page_launder() 这个函数了,楼主可以把这个函数贴出来看看吗....

论坛徽章:
13
15-16赛季CBA联赛之八一
日期:2016-07-08 21:00:1415-16赛季CBA联赛之同曦
日期:2017-02-15 14:26:1515-16赛季CBA联赛之佛山
日期:2017-02-20 14:19:2615-16赛季CBA联赛之青岛
日期:2017-05-07 16:49:1115-16赛季CBA联赛之广夏
日期:2017-07-30 09:13:1215-16赛季CBA联赛之广东
日期:2018-07-05 22:34:3615-16赛季CBA联赛之江苏
日期:2018-09-03 12:10:2115-16赛季CBA联赛之上海
日期:2018-09-25 03:49:2215-16赛季CBA联赛之广东
日期:2018-09-25 04:09:12
3 [报告]
发表于 2016-02-22 17:33 |只看该作者
回复 2# Buddy_Zhang1

我最近这样往论坛发代码,不知道会不会被公司抓起来 !我可是冒了好大危险的,你一定要帮我好好想想呀。

  1. /**
  2. * page_launder - clean dirty inactive pages, move to inactive_clean list
  3. * @gfp_mask: what operations we are allowed to do
  4. * @sync: should we wait synchronously for the cleaning of pages
  5. *
  6. * When this function is called, we are most likely low on free +
  7. * inactive_clean pages. Since we want to refill those pages as
  8. * soon as possible, we'll make two loops over the inactive list,
  9. * one to move the already cleaned pages to the inactive_clean lists
  10. * and one to (often asynchronously) clean the dirty inactive pages.
  11. *
  12. * In situations where kswapd cannot keep up, user processes will
  13. * end up calling this function. Since the user process needs to
  14. * have a page before it can continue with its allocation, we'll
  15. * do synchronous page flushing in that case.
  16. *
  17. * This code is heavily inspired by the FreeBSD source code. Thanks
  18. * go out to Matthew Dillon.
  19. */
  20. #define MAX_LAUNDER                 (4 * (1 << page_cluster))
  21. int page_launder(int gfp_mask, int sync)
  22. {
  23.         int launder_loop, maxscan, cleaned_pages, maxlaunder;
  24.         int can_get_io_locks;
  25.         struct list_head * page_lru;
  26.         struct page * page;

  27.         /*
  28.          * We can only grab the IO locks (eg. for flushing dirty
  29.          * buffers to disk) if __GFP_IO is set.
  30.          */
  31.         can_get_io_locks = gfp_mask & __GFP_IO;

  32.         launder_loop = 0;
  33.         maxlaunder = 0;
  34.         cleaned_pages = 0;

  35. dirty_page_rescan:
  36.         spin_lock(&pagemap_lru_lock);
  37.         maxscan = nr_inactive_dirty_pages;
  38.         while ((page_lru = inactive_dirty_list.prev) != &inactive_dirty_list &&
  39.                                 maxscan-- > 0) {
  40.                 page = list_entry(page_lru, struct page, lru);

  41.                 /* Wrong page on list?! (list corruption, should not happen) */
  42.                 if (!PageInactiveDirty(page)) {
  43.                         printk("VM: page_launder, wrong page on list.\n");
  44.                         list_del(page_lru);
  45.                         nr_inactive_dirty_pages--;
  46.                         page->zone->inactive_dirty_pages--;
  47.                         continue;
  48.                 }

  49.                 /* Page is or was in use?  Move it to the active list. */
  50.                 if (PageTestandClearReferenced(page) || page->age > 0 ||
  51.                                 (!page->buffers && page_count(page) > 1) ||
  52.                                 page_ramdisk(page)) {
  53.                         del_page_from_inactive_dirty_list(page);
  54.                         add_page_to_active_list(page);
  55.                         continue;
  56.                 }

  57.                 /*
  58.                  * The page is locked. IO in progress?
  59.                  * Move it to the back of the list.
  60.                  */
  61.                 if (TryLockPage(page)) {
  62.                         list_del(page_lru);
  63.                         list_add(page_lru, &inactive_dirty_list);
  64.                         continue;
  65.                 }

  66.                 /*
  67.                  * Dirty swap-cache page? Write it out if
  68.                  * last copy..
  69.                  */
  70.                 if (PageDirty(page)) {
  71.                         int (*writepage)(struct page *) = page->mapping->a_ops->writepage;
  72.                         int result;

  73.                         if (!writepage)
  74.                                 goto page_active;

  75.                         /* First time through? Move it to the back of the list */
  76.                         if (!launder_loop) {
  77.                                 list_del(page_lru);
  78.                                 list_add(page_lru, &inactive_dirty_list);
  79.                                 UnlockPage(page);
  80.                                 continue;
  81.                         }

  82.                         /* OK, do a physical asynchronous write to swap.  */
  83.                         ClearPageDirty(page);
  84.                         page_cache_get(page);
  85.                         spin_unlock(&pagemap_lru_lock);

  86.                         result = writepage(page);
  87.                         page_cache_release(page);

  88.                         /* And re-start the thing.. */
  89.                         spin_lock(&pagemap_lru_lock);
  90.                         if (result != 1)
  91.                                 continue;
  92.                         /* writepage refused to do anything */
  93.                         set_page_dirty(page);
  94.                         goto page_active;
  95.                 }

  96.                 /*
  97.                  * If the page has buffers, try to free the buffer mappings
  98.                  * associated with this page. If we succeed we either free
  99.                  * the page (in case it was a buffercache only page) or we
  100.                  * move the page to the inactive_clean list.
  101.                  *
  102.                  * On the first round, we should free all previously cleaned
  103.                  * buffer pages
  104.                  */
  105.                 if (page->buffers) {
  106.                         int wait, clearedbuf;
  107.                         int freed_page = 0;
  108.                         /*
  109.                          * Since we might be doing disk IO, we have to
  110.                          * drop the spinlock and take an extra reference
  111.                          * on the page so it doesn't go away from under us.
  112.                          */
  113.                         del_page_from_inactive_dirty_list(page);
  114.                         page_cache_get(page);
  115.                         spin_unlock(&pagemap_lru_lock);

  116.                         /* Will we do (asynchronous) IO? */
  117.                         if (launder_loop && maxlaunder == 0 && sync)
  118.                                 wait = 2;        /* Synchrounous IO */
  119.                         else if (launder_loop && maxlaunder-- > 0)
  120.                                 wait = 1;        /* Async IO */
  121.                         else
  122.                                 wait = 0;        /* No IO */

  123.                         /* Try to free the page buffers. */
  124.                         clearedbuf = try_to_free_buffers(page, wait);

  125.                         /*
  126.                          * Re-take the spinlock. Note that we cannot
  127.                          * unlock the page yet since we're still
  128.                          * accessing the page_struct here...
  129.                          */
  130.                         spin_lock(&pagemap_lru_lock);

  131.                         /* The buffers were not freed. */
  132.                         if (!clearedbuf) {
  133.                                 add_page_to_inactive_dirty_list(page);

  134.                         /* The page was only in the buffer cache. */
  135.                         } else if (!page->mapping) {
  136.                                 atomic_dec(&buffermem_pages);
  137.                                 freed_page = 1;
  138.                                 cleaned_pages++;

  139.                         /* The page has more users besides the cache and us. */
  140.                         } else if (page_count(page) > 2) {
  141.                                 add_page_to_active_list(page);

  142.                         /* OK, we "created" a freeable page. */
  143.                         } else /* page->mapping && page_count(page) == 2 */ {
  144.                                 add_page_to_inactive_clean_list(page);
  145.                                 cleaned_pages++;
  146.                         }

  147.                         /*
  148.                          * Unlock the page and drop the extra reference.
  149.                          * We can only do it here because we ar accessing
  150.                          * the page struct above.
  151.                          */
  152.                         UnlockPage(page);
  153.                         page_cache_release(page);

  154.                         /*
  155.                          * If we're freeing buffer cache pages, stop when
  156.                          * we've got enough free memory.
  157.                          */
  158.                         if (freed_page && !free_shortage())
  159.                                 break;
  160.                         continue;
  161.                 } else if (page->mapping && !PageDirty(page)) {
  162.                         /*
  163.                          * If a page had an extra reference in
  164.                          * deactivate_page(), we will find it here.
  165.                          * Now the page is really freeable, so we
  166.                          * move it to the inactive_clean list.
  167.                          */
  168.                         del_page_from_inactive_dirty_list(page);
  169.                         add_page_to_inactive_clean_list(page);
  170.                         UnlockPage(page);
  171.                         cleaned_pages++;
  172.                 } else {
  173. page_active:
  174.                         /*
  175.                          * OK, we don't know what to do with the page.
  176.                          * It's no use keeping it here, so we move it to
  177.                          * the active list.
  178.                          */
  179.                         del_page_from_inactive_dirty_list(page);
  180.                         add_page_to_active_list(page);
  181.                         UnlockPage(page);
  182.                 }
  183.         }
  184.         spin_unlock(&pagemap_lru_lock);

  185.         /*
  186.          * If we don't have enough free pages, we loop back once
  187.          * to queue the dirty pages for writeout. When we were called
  188.          * by a user process (that /needs/ a free page) and we didn't
  189.          * free anything yet, we wait synchronously on the writeout of
  190.          * MAX_SYNC_LAUNDER pages.
  191.          *
  192.          * We also wake up bdflush, since bdflush should, under most
  193.          * loads, flush out the dirty pages before we have to wait on
  194.          * IO.
  195.          */
  196.         if (can_get_io_locks && !launder_loop && free_shortage()) {
  197.                 launder_loop = 1;
  198.                 /* If we cleaned pages, never do synchronous IO. */
  199.                 if (cleaned_pages)
  200.                         sync = 0;
  201.                 /* We only do a few "out of order" flushes. */
  202.                 maxlaunder = MAX_LAUNDER;
  203.                 /* Kflushd takes care of the rest. */
  204.                 wakeup_bdflush(0);
  205.                 goto dirty_page_rescan;
  206.         }

  207.         /* Return the number of pages moved to the inactive_clean list. */
  208.         return cleaned_pages;
  209. }
复制代码

论坛徽章:
13
15-16赛季CBA联赛之八一
日期:2016-07-08 21:00:1415-16赛季CBA联赛之同曦
日期:2017-02-15 14:26:1515-16赛季CBA联赛之佛山
日期:2017-02-20 14:19:2615-16赛季CBA联赛之青岛
日期:2017-05-07 16:49:1115-16赛季CBA联赛之广夏
日期:2017-07-30 09:13:1215-16赛季CBA联赛之广东
日期:2018-07-05 22:34:3615-16赛季CBA联赛之江苏
日期:2018-09-03 12:10:2115-16赛季CBA联赛之上海
日期:2018-09-25 03:49:2215-16赛季CBA联赛之广东
日期:2018-09-25 04:09:12
4 [报告]
发表于 2016-02-22 18:04 |只看该作者
回复 2# Buddy_Zhang1

书上面说,这个函数是由多个线程执行的。


   

论坛徽章:
20
程序设计版块每日发帖之星
日期:2015-08-17 06:20:00程序设计版块每日发帖之星
日期:2016-07-16 06:20:00程序设计版块每日发帖之星
日期:2016-07-18 06:20:00每日论坛发贴之星
日期:2016-07-18 06:20:00黑曼巴
日期:2016-12-26 16:00:3215-16赛季CBA联赛之江苏
日期:2017-06-26 11:05:5615-16赛季CBA联赛之上海
日期:2017-07-21 18:12:5015-16赛季CBA联赛之青岛
日期:2017-09-04 17:32:0515-16赛季CBA联赛之吉林
日期:2018-03-26 10:02:16程序设计版块每日发帖之星
日期:2016-07-15 06:20:0015-16赛季CBA联赛之江苏
日期:2016-07-07 18:37:512015亚冠之萨济拖拉机
日期:2015-08-17 12:21:08
5 [报告]
发表于 2016-02-23 10:52 |只看该作者
如果不是私有代码,引用公开的lxr就可以了,不过现在2.4版本的应该不多了。

论坛徽章:
13
15-16赛季CBA联赛之八一
日期:2016-07-08 21:00:1415-16赛季CBA联赛之同曦
日期:2017-02-15 14:26:1515-16赛季CBA联赛之佛山
日期:2017-02-20 14:19:2615-16赛季CBA联赛之青岛
日期:2017-05-07 16:49:1115-16赛季CBA联赛之广夏
日期:2017-07-30 09:13:1215-16赛季CBA联赛之广东
日期:2018-07-05 22:34:3615-16赛季CBA联赛之江苏
日期:2018-09-03 12:10:2115-16赛季CBA联赛之上海
日期:2018-09-25 03:49:2215-16赛季CBA联赛之广东
日期:2018-09-25 04:09:12
6 [报告]
发表于 2016-02-23 14:07 |只看该作者
回复 5# nswcfd

我看的是《Linux内核源代码情景分析》,它对应的是2.4.0版本。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP