蒙恩
一个睡不醒的老男孩儿

导航

 

build_all_zonelists

该函数在系统初始化阶段建立每个node下的zonelist结构

 函数第3行:设置初始化每一个node下zonelist的策略:举个例子说明:x86_64架构,64位系统下,假设系统中有node0和node1,node0中有DMA,DMA32,NORMAL,MOVABLE四个内存去,node1中有NORMAL,MOVABLE两个内存区。假设node0的初始化zonelist由一下两种方案:

第一种方案:[node0(MOVABLE),node0(NORMAL),node0(DMA32),node(DMA),node1(MAVABLE),node1(NORMAL)]

第二种方案:[node0(MOVABLE),node1(MOVABLE),node0(NORMAL),node1(NORMAL),node0(DMA32),node0(DMA)]

根据buddy系统的zone的fallback规则:

第一种方案考虑的时优先分配举例比较近的cpu,这样会加快cpu每次内存的访问速度;但是缺点是:会加快DMA32和DMA内存区的消耗,例如:当分buddy系统选中node0作为分配节点时,第一种方案对于要分配normal区和movable区的请求,如果node0上这两个区内存紧张,就会fallback到node0的DMA32和DMA区。如果DMA,DMA32内存去内存过渡消耗(本身这两个内存去空间就比较小DMA为固定16M,DMA32固定为4G)到真正必须要从DMA,DMA32分配内存时,就很容易出发OOM.

第二种方案优先考虑了减少内存分配请求对DMA,DMA32内存区的压力,次优先考虑了node节点之间的距离,这样会降低cpu每次访问内存的熟读。原因:还用上面的例子:如果node0上的movable和normal区紧张时,会优先分被fallback到node1上的movable和normal区,只有node0和node1上的normal,movable都紧张时,才会fallback到DMA和DMA32区。这样就减少了因”必须要申请DMA,DMA32内存去内存而失败的概率。

内核的做法:

1.默认由一个规则通过内核的内存现状选择上面的一种方案来初始化node的zonelist

2.导出了配置文件到proc文件系统或者通过sysctl命令来让用户自己设定使用种方案来初始化node的zonelist

第3行的逻辑:如果用户通过sysctl或者proc设置了zonelist初始化的策略,就用用户的设置,如果没有就根据系统种的内存情况选择两种方案种的一种(具体怎么选择看下文关于:default_zonelist_order的介绍

接下来重点说一下第15行到第26行的逻辑(TODO:补充完整对本函数的说明

第16行计算了所有zone中高于high内存水线的页数(举个例子:假设系统中只有两个zone,zone0总共由10个页,zone1总共由15个页,zone0的high水线时5,zone1的high水线时8,那么vm_total_pages就等于(10-5+15-8))第23行到第26行初始化了一个重要的全局变量:page_group_by_mobility_disabled,这个全局变量内核没有提供用户态接口,并且这里设置后,整个系统运行期间没有办法改变。也就是说如果系统中所有zone中高于内存水线的总页数如果小于pageblock_nr_pages*MIGRATE_TYPE那么就关闭按页的移动性分组的功能。相反则开启该功能。

【注】作者见过的所有生产环境中(通用服务器):vm_total_pages都远远大于pageblock_nr_pages*MIGRATE_TYPES,因此在通用服务器应用场景可以认为page_group_by_mobility_disabled始终等于0(可能有些嵌入式系统中内存比较少时,会为1)

void build_all_zonelists(void)
{
	set_zonelist_order();

	if (system_state == SYSTEM_BOOTING) {
		__build_all_zonelists(NULL);
		mminit_verify_zonelist();
		cpuset_init_current_mems_allowed();
	} else {
		/* we have to stop all cpus to guarantee there is no user
		   of zonelist */
		stop_machine(__build_all_zonelists, NULL, NULL);
		/* cpuset refresh routine should be here */
	}
	vm_total_pages = nr_free_pagecache_pages();
	/*
	 * Disable grouping by mobility if the number of pages in the
	 * system is too low to allow the mechanism to work. It would be
	 * more accurate, but expensive to check per-zone. This check is
	 * made on memory-hotadd so a system can start with mobility
	 * disabled and enable it later
	 */
	if (vm_total_pages < (pageblock_nr_pages * MIGRATE_TYPES))
		page_group_by_mobility_disabled = 1;
	else
		page_group_by_mobility_disabled = 0;

	printk("Built %i zonelists in %s order, mobility grouping %s.  "
		"Total pages: %ld\n",
			nr_online_nodes,
			zonelist_order_name[current_zonelist_order],
			page_group_by_mobility_disabled ? "off" : "on",
			vm_total_pages);
#ifdef CONFIG_NUMA
	printk("Policy zone: %s\n", zone_names[policy_zone]);
#endif
}

default_zonelist_order  

--------------------------------------------------------------------------------------------------

TODO1:

posted on 2019-01-09 22:54  DoOrDie  阅读(663)  评论(0编辑  收藏  举报