DPDK17.02内存管理2 – rte_eal_memory_init

该函数用来配置物理地址连续的内存。如果是主进程,调用rte_eal_hugepage_init() 函数,如果是次进程,调用 rte_eal_hugepage_attach() 函数。

1、rte_eal_hugepage_init()

每个大页内存映射到挂载目录下的一个文件,文件前缀为 rtemap_XXX,每个大页的信息保存到结构体 struct hugepage_file 中,该结构定义如下:

函数针对每种大页的大小,都会做以下操作:

1.1 map_all_hugepages() 映射某尺寸的所有大页

第一次映射时,map_all_hugepages() 函数对每全大页文件做以下事情:

(1)初始化 hugepg_tbl[i] 成员变量信息

(2)打开大页文件

(3)映射大页文件

在每一次映射时,第一个页的 vma_addr 地址为NULL,之后每个大页增加 hugepage_sz 大小。

1.2 根据第一次映射的所有大页的虚拟地址,查找其物理地址

这一步调用函数 find_physaddrs(&tmp_hp[hp_offset], hpi),实现如下:

rte_mem_virt2phy() 函数会读取当前进程的 /proc/self/pagemap 文件,分析每个大页虚拟地址对应的物理地址,初始化每个大页的 hugepg_tbl[i].physaddr。

1.3 确认每个大页所在的 numa 结点

调用find_numasocket() 函数,通过当前进程的 /proc/self/numa_maps 文件,得到每个大页所在Numa 结点,并初始化每个大页对应结构的 hugepg_tbl[i].socket_id。

1.4 排序

调用 qsort 函数,对 tmp_hp[i] 表示的所有大页结构,按物理地址从小到大重新排序,

1.5 对所有大页重新映射

调用 map_all_hugepages(&tmp_hp[hp_offset], hpi, 0) 函数,对所有大页重新进行映射。

由于是重新映射,orig的值为0,所以映射第一个大页时,vma_len 的值为0,进入以下分支

之后是对这些连续的大页进行二次映射,并将映射到的虚拟地址保存到 hugepg_tbl[i].final_va 中,并且每映射完一个大页,就对 vma_len 减去 hugepage_sz 大小,并继续映射,直到把所有物理地址连续的大页映射完,vma_len 的值被减为0,再继续查找下一批物理地址连续的大页,并继续该过程。

1.6 将第一次映射的大页的虚拟内存unmap

调用 unmap_all_hugepages_orig(&tmp_hp[hp_offset], hpi) 函数,将第一次映射的大页的虚拟内存全部 unmap 掉。

1.7 计算所有大页的大小之和

调用函数计算所有大页的大小之和,并保存到 internal_config.memory 中。

实际上这时每种大小的大页还是保存在每个hpi的num_pages[0]上的。

1.8 清除每种大小的每个Numa结点上的大页数量

1.9 计算每种大小的大页,在每个Numa结点上各自有多少

1.10 计算最终需要的大页的数量

1.11 创建共享内存,用来保存这些大页的信息

eal_hugepage_info_path()函数得到映射文件为 /var/run/.rte_hugepage_info

1.12 将不需要的大页unmap掉

1.13 拷贝大页信息到共享内存

1.14 将连续的大页组成memseg

将每个 socket 上的连续的大页 组成一个 memseg[i],该变量结构如下:

判断一个大页是否需要组成一个新的memseg,需要以下几个判断条件:
(1)第一个大页,肯定是一个新的memseg;
(2)当前大页与前一个大页不在同一个socket_id上;
(3)当前大页与前一个大页的大小不同;
(4)当前大页与前一个大页的物理地址间隔,不等于当前大页的大小,说明物理地址不连续;
(5)当前大页与前一个大页的虚拟地址间隔,不等于当前大页的大小,说明映射的虚拟地址不连续;

2、rte_eal_hugepage_attach()

如果是次进程,则对主进程整理的各个 memseg 进行 attach 操作。

2.1 判断是否关闭aslr

如果没关闭则提示警告信息。

2.2 判断当前进程的 /proc/self/pagemap 是否可读

如果不可读则提示警告信息。

2.3 第一次映射 mcfg->memseg[i]

根据主进程中映射的每个 mcfg->memseg[i] 的虚拟地址与长度,在次进程中映射每一个memseg[i]。

2.4 映射/var/run/.rte_hugepage_info 文件

size = getFileSize(fd_hugepage); /* 得到文件的大小 */
hp = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd_hugepage, 0); /* 映射文件 */
if (hp == MAP_FAILED) {
RTE_LOG(ERR, EAL, “Could not mmap %s\n”, eal_hugepage_info_path());
goto error;
}
/* 计算需要的大页文件数 */
num_hp = size / sizeof(struct hugepage_file);
RTE_LOG(DEBUG, EAL, “Analysing %u files\n”, num_hp);

2.5 映射每个memseg[i] 中的每个大页

首先将刚刚映射的每个memseg[i] 的虚拟地址空间unmap掉,将该空间用作 memseg[i] 中每个大页的映射空间。

————————————————————

原创文章,转载请注明: 转载自孙希栋的博客

本文链接地址: 《DPDK17.02内存管理2 – rte_eal_memory_init》

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

Scroll Up