IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 关于hugetlbfs如何均匀的在各个numa节点上预留内存的探索 -> 正文阅读

[系统运维]关于hugetlbfs如何均匀的在各个numa节点上预留内存的探索

本文分析基于linux内核4.19.195.
在linux的实际使用中,使用hugetlbfs进行大页内存分配是一种常用的优化方法,而且我们知道,hugetlbfs能够根据需要,将不同numa节点上的内存分配给用户态程序。hugetlbfs常见的用法是,在内核启动完成后,通过写/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages接口预留适当数量的大页,然后通过hugetlbfs获得大页。那么,为了实现“将不同numa节点上的内存分配给用户态程序”,在写/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages接口预留大页的时候,均匀的在各个numa节点上预留内存,是一个比较合理的做法,当然内核也确实是这么干的。如下面步骤的输出所示(我的机器上有两个numa节点):

[root@localhost hugepages-2048kB]# cat nr_hugepages
0
[root@localhost hugepages-2048kB]# echo 1 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
[root@localhost node]# cat node0/hugepages/hugepages-2048kB/nr_hugepages
1
[root@localhost node]# cat node1/hugepages/hugepages-2048kB/nr_hugepages
0
[root@localhost hugepages-2048kB]# echo 2 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
[root@localhost node]# cat node0/hugepages/hugepages-2048kB/nr_hugepages
1
[root@localhost node]# cat node1/hugepages/hugepages-2048kB/nr_hugepages
1
[root@localhost node]# echo 10 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
[root@localhost node]# cat node0/hugepages/hugepages-2048kB/nr_hugepages
5
[root@localhost node]# cat node1/hugepages/hugepages-2048kB/nr_hugepages
5
[root@localhost node]# pwd
/sys/devices/system/node

可以看到,hugepage被均匀的分散到了2个numa节点中。但是,内核是怎么实现的呢?
我们知道,写/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages接口,最终会调用到内核的hugetlb_sysctl_handler函数。

int hugetlb_sysctl_handler(struct ctl_table *table, int write,
			  void __user *buffer, size_t *length, loff_t *ppos)
{
	return hugetlb_sysctl_handler_common(false, table, write,
							buffer, length, ppos);
}
static int hugetlb_sysctl_handler_common(bool obey_mempolicy,
			 struct ctl_table *table, int write,
			 void __user *buffer, size_t *length, loff_t *ppos)
{
	struct hstate *h = &default_hstate;
	unsigned long tmp = h->max_huge_pages;
	int ret;

	if (!hugepages_supported())
		return -EOPNOTSUPP;

	ret = proc_hugetlb_doulongvec_minmax(table, write, buffer, length, ppos,
					     &tmp);
	if (ret)
		goto out;

	if (write)
		ret = __nr_hugepages_store_common(obey_mempolicy, h,
						  NUMA_NO_NODE, tmp, *length);
out:
	return ret;
}

主要是在函数__nr_hugepages_store_common中实现的大页预留。

static ssize_t __nr_hugepages_store_common(bool obey_mempolicy,
					   struct hstate *h, int nid,
					   unsigned long count, size_t len)
{
	int err;
	NODEMASK_ALLOC(nodemask_t, nodes_allowed, GFP_KERNEL | __GFP_NORETRY);

	if (hstate_is_gigantic(h) && !gigantic_page_supported()) {
		err = -EINVAL;
		goto out;
	}

	if (nid == NUMA_NO_NODE) {
		/*
		 * global hstate attribute
		 */
		if (!(obey_mempolicy &&
				init_nodemask_of_mempolicy(nodes_allowed))) {
			NODEMASK_FREE(nodes_allowed);
			nodes_allowed = &node_states[N_MEMORY];
		}
	} else if (nodes_allowed) {
		/*
		 * per node hstate attribute: adjust count to global,
		 * but restrict alloc/free to the specified node.
		 */
		count += h->nr_huge_pages - h->nr_huge_pages_node[nid];
		init_nodemask_of_node(nodes_allowed, nid);
	} else
		nodes_allowed = &node_states[N_MEMORY];

	h->max_huge_pages = set_max_huge_pages(h, count, nodes_allowed);//增加或者减少永久巨型页数量

	if (nodes_allowed != &node_states[N_MEMORY])
		NODEMASK_FREE(nodes_allowed);

	return len;
out:
	NODEMASK_FREE(nodes_allowed);
	return err;
}

进入__nr_hugepages_store_common函数,首先是获取nodes_allowed这个nodemask_t,然后调用set_max_huge_pages函数完成大页的预留动作。按照调用流程分析,当我们通过写/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages接口完成大页的预留时,会走进if (nid == NUMA_NO_NODE) 分支并将nodes_allowed设置为&node_states[N_MEMORY],也就是说,会从所有有内存的numa节点分配内存。
接下来进入函数set_max_huge_pages。该函数会调用alloc_pool_huge_page(h, nodes_allowed);完成内存的分析,我们来看alloc_pool_huge_page函数。

#define for_each_node_mask_to_alloc(hs, nr_nodes, node, mask)		\
	for (nr_nodes = nodes_weight(*mask);				\
		nr_nodes > 0 &&						\
		((node = hstate_next_node_to_alloc(hs, mask)) || 1);	\
		nr_nodes--)

static int get_valid_node_allowed(int nid, nodemask_t *nodes_allowed)
{
	if (!node_isset(nid, *nodes_allowed))
		nid = next_node_allowed(nid, nodes_allowed);
	return nid;
}

static int hstate_next_node_to_alloc(struct hstate *h,
					nodemask_t *nodes_allowed)
{
	int nid;

	VM_BUG_ON(!nodes_allowed);

	nid = get_valid_node_allowed(h->next_nid_to_alloc, nodes_allowed);
	h->next_nid_to_alloc = next_node_allowed(nid, nodes_allowed);

	return nid;
}


static int alloc_pool_huge_page(struct hstate *h, nodemask_t *nodes_allowed)
{
	struct page *page;
	int nr_nodes, node;
	gfp_t gfp_mask = htlb_alloc_mask(h) | __GFP_THISNODE;

	for_each_node_mask_to_alloc(h, nr_nodes, node, nodes_allowed) { //注意这个函数
		page = alloc_fresh_huge_page(h, gfp_mask, node, nodes_allowed);
		if (page)
			break;
	}

	if (!page)
		return 0;

	put_page(page); /* free it into the hugepage allocator */

	return 1;
}

重点在for_each_node_mask_to_alloc宏定义。重点关注get_valid_node_allowed函数调用的第一个参数,传入的是h->next_nid_to_alloc,并且,在调用get_valid_node_allowed之后,立马更新了h->next_nid_to_alloc。也就是说,每次都是从h->next_nid_to_alloc这个numa节点开始去分配大页,每次分配之后,都会更新这个变量。依靠这个变量的不断更新,内核实现了从各个numa节点上均匀分配内存的功能。

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-03-13 22:13:16  更:2022-03-13 22:14:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 1:29:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码