背景

  • Read the fucking source code! --By 鲁迅
  • A picture is worth a thousand words. --By 高尔基

说明:

  1. Kernel版本:4.14
  2. ARM64处理器,Contex-A53,双核
  3. 使用工具:Source Insight 3.5, Visio

1. 概述

本文将分析watermark

简单来说,在使用zoned page frame allocator分配页面时,会将可用的free pageszonewatermark进行比较,以便确定是否分配内存。

同时watermark也用来决定kswapd内核线程的睡眠与唤醒,以便对内存进行检索和压缩处理。

回忆一下之前提到过的struct zone结构体:

struct zone {
/* Read-mostly fields */ /* zone watermarks, access with *_wmark_pages(zone) macros */
unsigned long watermark[NR_WMARK]; unsigned long nr_reserved_highatomic; ....
} enum zone_watermarks {
WMARK_MIN,
WMARK_LOW,
WMARK_HIGH,
NR_WMARK
}; #define min_wmark_pages(z) (z->watermark[WMARK_MIN])
#define low_wmark_pages(z) (z->watermark[WMARK_LOW])
#define high_wmark_pages(z) (z->watermark[WMARK_HIGH])

可以看出,总共有三种水印,并且只能通过特定的宏来访问。

  • WMARK_MIN

    内存不足的最低点,如果计算出的可用页面低于该值,则无法进行页面计数;

  • WMARK_LOW

    默认情况下,该值为WMARK_MIN的125%,此时kswapd将被唤醒,可以通过修改watermark_scale_factor来改变比例值;

  • WMARK_HIGH

    默认情况下,该值为WMARK_MAX的150%,此时kswapd将睡眠,可以通过修改watermark_scale_factor来改变比例值;

图来了:

下边将对细节进一步分析。

1. watermark初始化

先看一下初始化的相关调用函数:

  • nr_free_buffer_pages:统计ZONE_DMAZONE_NORMAL中可用页面,managed_pages - high_pages

  • setup_per_zone_wmarks:根据min_free_kbytes来计算水印值,来一张图会比较清晰易懂:

  • refresh_zone_stat_thresholds

    先来回顾一下struct pglist_datastruct zone

typedef struct pglist_data {
...
struct per_cpu_nodestat __percpu *per_cpu_nodestats;
...
} pg_data_t; struct per_cpu_nodestat {
s8 stat_threshold;
s8 vm_node_stat_diff[NR_VM_NODE_STAT_ITEMS];
}; struct zone {
...
struct per_cpu_pageset __percpu *pageset;
...
} struct per_cpu_pageset {
struct per_cpu_pages pcp;
#ifdef CONFIG_NUMA
s8 expire;
u16 vm_numa_stat_diff[NR_VM_NUMA_STAT_ITEMS];
#endif
#ifdef CONFIG_SMP
s8 stat_threshold;
s8 vm_stat_diff[NR_VM_ZONE_STAT_ITEMS];
#endif
};

从数据结构中可以看出,针对NodeZone,都有一个Per-CPU的结构来存储信息,而refresh_zone_stat_thresholds就跟这两个结构相关,用于更新这两个结构中的stat_threshold字段,具体的计算方式就不表了,此外还计算了percpu_drift_mark,这个在水印判断的时候需要用到该值。阈值的作用就是用来进行判断,从而触发某个行为,比如内存压缩处理等。

  • setup_per_zone_lowmem_reserve

    设置每个zonelowmem_reserve大小,代码中的实现逻辑如下图所示。

  • calculate_totalreserve_pages

    计算各个zone的保留页面,以及系统的总的保留页面,其中会将high watermark看成保留页面。如图:

2. watermark判断

老规矩,先看看函数调用关系图:

  • __zone_watermark_ok

    watermark判断的关键函数,从图中的调用关系可以看出,最终的处理都是通过它来完成判断的。还是用图片来说明整体逻辑吧:

上图中左边判断是否有足够的空闲页面,右边直接查询free_area[]是否可以最终进行分配。

  • zone_watermark_ok:直接调用__zone_watermark_ok`,没有其他逻辑。

  • zone_watermark_fast

    从名字可以看出,这个是进行快速判断,快速的体现主要是在order = 0的时候进行判断决策,满足条件时直接返回true,否则调用__zone_watermark_ok

    贴个代码吧,清晰明了:

static inline bool zone_watermark_fast(struct zone *z, unsigned int order,
unsigned long mark, int classzone_idx, unsigned int alloc_flags)
{
long free_pages = zone_page_state(z, NR_FREE_PAGES);
long cma_pages = 0; #ifdef CONFIG_CMA
/* If allocation can't use CMA areas don't use free CMA pages */
if (!(alloc_flags & ALLOC_CMA))
cma_pages = zone_page_state(z, NR_FREE_CMA_PAGES);
#endif /*
* Fast check for order-0 only. If this fails then the reserves
* need to be calculated. There is a corner case where the check
* passes but only the high-order atomic reserve are free. If
* the caller is !atomic then it'll uselessly search the free
* list. That corner case is then slower but it is harmless.
*/
if (!order && (free_pages - cma_pages) > mark + z->lowmem_reserve[classzone_idx])
return true; return __zone_watermark_ok(z, order, mark, classzone_idx, alloc_flags,
free_pages);
}
  • zone_watermark_ok_safe

    zone_watermark_ok_safe函数中,主要增加了zone_page_state_snapshot的调用,用来计算free_pages,这个计算过程将比直接通过zone_page_state(z, NR_FREE_PAGES)更加精确。
bool zone_watermark_ok_safe(struct zone *z, unsigned int order,
unsigned long mark, int classzone_idx)
{
long free_pages = zone_page_state(z, NR_FREE_PAGES); if (z->percpu_drift_mark && free_pages < z->percpu_drift_mark)
free_pages = zone_page_state_snapshot(z, NR_FREE_PAGES); return __zone_watermark_ok(z, order, mark, classzone_idx, 0,
free_pages);
}

percpu_drift_maskrefresh_zone_stat_thresholds函数中设置的,这个在上文中已经讨论过了。

每个zone维护了三个字段用于页面的统计,如下:

struct zone {
...
struct per_cpu_pageset __percpu *pageset;
...
/*
* When free pages are below this point, additional steps are taken
* when reading the number of free pages to avoid per-cpu counter
* drift allowing watermarks to be breached
*/
unsigned long percpu_drift_mark;
...
/* Zone statistics */
atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];
}

内核在内存管理中,读取空闲页面与watermark值进行比较,要读取正确的空闲页面值,必须同时读取vm_stat[]__percpu *pageset计算器。如果每次都读取的话会降低效率,因此设定了percpu_drift_mark值,只有在低于这个值的时候,才触发更精确的计算来保持性能。

__percpu *pageset计数器的值更新时,当计数器值超过stat_threshold值,会更新到vm_stat[]中,如下图:

zone_watermark_ok_safe中调用了zone_page_state_snapshot,与zone_page_state的区别如下图所示:

watermark的分析到此为止,收工!

【原创】(八)Linux内存管理 - zoned page frame allocator - 3的更多相关文章

  1. 【原创】(六)Linux内存管理 - zoned page frame allocator - 1

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  2. 【原创】(七)Linux内存管理 - zoned page frame allocator - 2

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  3. 【原创】(九)Linux内存管理 - zoned page frame allocator - 4

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  4. 【原创】(十)Linux内存管理 - zoned page frame allocator - 5

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  5. Linux内存管理 (11)page引用计数

    专题:Linux内存管理专题 关键词:struct page._count._mapcount.PG_locked/PG_referenced/PG_active/PG_dirty等. Linux的内 ...

  6. 【原创】(十四)Linux内存管理之page fault处理

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  7. Linux内存管理6---伙伴算法与slab

    1.前言 本文所述关于内存管理的系列文章主要是对陈莉君老师所讲述的内存管理知识讲座的整理. 本讲座主要分三个主题展开对内存管理进行讲解:内存管理的硬件基础.虚拟地址空间的管理.物理地址空间的管理. 本 ...

  8. Linux内存描述之内存页面page–Linux内存管理(四)

    服务器体系与共享存储器架构 日期 内核版本 架构 作者 GitHub CSDN 2016-06-14 Linux-4.7 X86 & arm gatieme LinuxDeviceDriver ...

  9. [转帖]Linux分页机制之分页机制的演变--Linux内存管理(七)

    Linux分页机制之分页机制的演变--Linux内存管理(七) 2016年09月01日 20:01:31 JeanCheng 阅读数:4543 https://blog.csdn.net/gatiem ...

随机推荐

  1. 2019年全国新课标I卷文理科数学LaTeX排版试题与解析

    整体分析,没有偏怪难题之分,中等题偏多,题目较往年有题型改动变化,但难度还称不上很难.具体内容贴上链接! https://mp.weixin.qq.com/s/WKXhCKI_-z3UT-zUwI23 ...

  2. 手机端特有的meta标签有哪些?

    3.1 meta 语法 定义和用法:name 属性把 content 属性连接到 name. 语法:name=author|description|keywords|generator|revised ...

  3. Session的创建和设置

    1.Session的获取: (1)无参的方法: protected void doGet(HttpServletRequest request, HttpServletResponse respons ...

  4. 查看 Linux 系统版本信息

    博客地址:http://www.moonxy.com 一.前言 Linux 下如何查看内核信息.发行版信息,系统位数.CPU 信息等等,Windows 下我们可以通过各种图形化软件来查看,但是对于 L ...

  5. Java 中 Set、List 和 Map 的遍历

    java集合类的使用可以说是无处不在,总的我们可以将之分为三大块,分别是从Collection接口延伸出的List.Set和以键值对形式作存储的Map类型集合. package tup.lucene. ...

  6. [Code] 变态之人键合一

    目的也比较单纯,选一门语言,走向人键合一. 选了两本书作为操练场:<精通Python设计模式>.<Data Structure and Algorithm in Python> ...

  7. [Scala]集合中List元素转Tuple元素的函数迭代写法

    ____ 本文链接: https://www.cnblogs.com/senwren/p/Scala-Lis-2-Tuple.html —— Scala没有提供相应写法, 但迭代写法仍然可以做到. 有 ...

  8. 如何更规范化编写Java 代码

    如何更规范化编写Java 代码 Many of the happiest people are those who own the least. But are we really so happy ...

  9. 导出 mysql 数据到 redis

    决定你要导入到 redis 的数据类型 假设我的表 t_user 的结构为 列名 注释 类型 name 名称 varchar idcard 身份证号 varchar phone 手机号 varchar ...

  10. win10下安装FFmpeg步骤

    1.官方下载地址:https://ffmpeg.zeranoe.com/builds/ # 下载方式一,太慢 # 下载方式二,推荐 2.解压到D:\Program Files (x86),这个看个人喜 ...