dpdk内存管理之内存初始化(内存收集)
来源:互联网 发布:中国经济数据网 编辑:程序博客网 时间:2024/04/30 12:14
初始化之前的内存layout
其中页a、a+1类似的表示连续的物理页。
dpdk通过事先申请的大页,mmap对应的大页dir获得内存。可以看出,程序mmap每个页时,虽然物理页可能连续,但返回的虚拟地址却不一定是连续的。而且,返回的内存不会固定在某个socket上。初始化之后的内存layout
为了高效的使用内存,需要重新组织内存,并对其进行管理。
组织的方式:
- 把物理地址连续的页映射到进程中时,对应的虚拟地址也连续。
- 把物理地址连续,并且在同一个socket node上的连续页,组织成一个段(segment)统一管理。
- 对于相同的物理页,每个进程映射的虚拟地址都相同。
组织内存用到的技术
dpdk使用linux提供的获取大页、页表、numa节点表、mmap功能重新组织内存。
大页:最多可以同时存在3中大页。一般只是用2M的大页。linux中获取大页相关信息是通过访问解析/sys/kernel/mm/hugepages、/proc/meminfo、/proc/mounts等内容得到的。
页表:linux中每个进程的页表对应的文件是/proc/pid/pagemap,本进程的页表是/proc/self/pagemap。/proc/pid/pagemap中的内容(每一个页表项有64位)如下:
* Bits 0-54 page framenumber (PFN) if present
* Bits 0-4 swap type ifswapped
* Bits5-54 swap offset if swapped
*Bit 55 pte is soft-dirty (see Documentation/vm/soft-dirty.txt)
*Bit 56 page exclusively mapped (since 4.2)
* Bits57-60 zero
*Bit 61 page is file-page or shared-anon (since 3.5)
*Bit 62 page swapped
* Bit 63 page present
注意:大页是不会被swap的,是常驻内存的,所以每个大页对应的页表项中PFN都对应物理内存,不会对应到swap区或者外设内存中。
numa节点表:linux中每个物理页所在的numa socket表对应的文件是/proc/pid/numa_maps,本进程的numa socket表是/proc/self/numa_maps。
/proc/pid/numa_maps中的内容大致如下:
address policy mapping details
00400000 defaultfile=/usr/local/bin/app mapped=1 active=0 N3=1 kernelpagesize_kB=4
00600000 defaultfile=/usr/local/bin/app anon=1 dirty=1 N3=1 kernelpagesize_kB=4
3206000000 default file=/lib64/ld-2.12.so mapped=26 mapmax=6 N0=24 N3=2kernelpagesize_kB=4
320621f000 default file=/lib64/ld-2.12.so anon=1 dirty=1 N3=1 kernelpagesize_kB=4
3206220000 default file=/lib64/ld-2.12.so anon=1 dirty=1 N3=1 kernelpagesize_kB=4
3206221000 default anon=1 dirty=1 N3=1 kernelpagesize_kB=4
3206800000 default file=/lib64/libc-2.12.so mapped=59 mapmax=21 active=55 N0=41 N3=18kernelpagesize_kB=4
320698b000 default file=/lib64/libc-2.12.so
3206b8a000 default file=/lib64/libc-2.12.so anon=2 dirty=2 N3=2 kernelpagesize_kB=4
3206b8e000 default file=/lib64/libc-2.12.so anon=1 dirty=1 N3=1 kernelpagesize_kB=4
3206b8f000 default anon=3 dirty=3 active=1 N3=3 kernelpagesize_kB=4
7f4dc10a2000 default anon=3 dirty=3 N3=3 kernelpagesize_kB=4
7f4dc10b4000 default anon=2 dirty=2 active=1 N3=2 kernelpagesize_kB=4
7f4dc1200000 default file=/anon_hugepage\040(deleted) huge anon=1 dirty=1 N3=1kernelpagesize_kB=2048
7fff335f0000 default stack anon=3 dirty=3 N3=3 kernelpagesize_kB=4
7fff3369d000 default mapped=1 mapmax=35 active=0 N3=1 kernelpagesize_kB=4
Where:"address" is the starting address for the mapping;
"policy"reports the NUMA memory policy set for the mapping (seevm/numa_memory_policy.txt);
"mapping details" summarizes mappingdata such as mapping type, page usage counters, node locality page counters (N0== node0, N1 == node1, ...) and the kernel page size, in KB, that is backingthe mapping up.主进程初始化内存流程
- 获取大页信息并存放在internal_config.hugepage_info[i]结构中
- 把所有可用的大页都映射进程中,并且每个大页对应一个文件(格式:mountdir/rtesmap_%d),后续可以通过open(hugedir),再mmap(fd)把大页映射进程中使用。
把每页信息都放到结构struct hugepage_file tmp_hp[]中。
/**
* Structure used to storeinformations about hugepages that we mapped
* through the files inhugetlbfs.
*/
struct hugepage_file {
void*orig_va; /**< virtual addr offirst mmap() */
void *final_va; /**< virtual addr of 2nd mmap() */
uint64_t physaddr; /**< physical addr */
size_t size; /**< the page size 页大小(多种大页)*/
int socket_id; /**< NUMA socket ID */
int file_id; /**< the '%d' in HUGEFILE_FMT每种大页都从0开始*/
int memseg_id; /**< the memory segment to which pagebelongs */
char filepath[MAX_HUGEPAGE_PATH]; /**< pathto backing file on filesystem */
}; - 通过find_physaddrs函数,根据映射得到的虚拟地址orig_va和/proc/self/pagemap中的信息,找到每个大页虚拟地址对应的物理地址,并添到struct hugepage_file结构中的physaddr字段。
- 通过find_numasocket函数,根据映射得到的虚拟地址orig_va和/proc/self/numa_maps中的信息,找到每个大页虚拟地址对应的numa_maps项,解析对应的numa socket节点,赋值到对应的页信息结构struct hugepage_file中的socket_id字段。
- 现在,得到了2M(假设使用2M大页)大页的所有可用页的信息,并放到tmp_hp数组中。然后,按物理地址physaddr从小到大排序每个大页。排序后tmp_hp数组中是按物理地址递增的顺序放置大页信息的。
- 再一次mmap所有的可用页。这次mmap,是把物理地址连续的页,映射成虚拟地址也连续的页(通过指定void*mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)函数的addr值)。并且,这次映射的虚拟地址放到final_va字段中。
- 解除第一次映射的va虚拟地址orig_va。munmap(orig_va)之后使orig_va对应的虚拟地址空间可用。
- dpdk默认是把所有的页平分到每个socket(根据每个socket上core的数量)上。
- 创建共享内存/var/run/.rte_hugepage_info,把重新组织的页信息struct hugepage_file数组放到.rte_hugepage_info中,以便其他进程共享。
- 最后,把物理地址连续(现在虚拟地址肯定也连续了)、同一个socket上的连续的页,组织成一个段memseg,放到rte_mem_config结构的memseg字段中。进程间共享。
次进程使用
次进程主要是把重新组织的内存映射到进程中。
- 根据共享的mem_config,获得memseg段信息。memseg中包括每个段的信息(段大小、虚拟和物理地址等)。再检查是否能获得每个段对应的虚拟地址空间。
- 然后,再根据共享的.rte_hugepage_info获得每个页信息。
- 根据.rte_hugepage_info中每个页的信息(dir、memseg_id),把每个页映射到次进程中,映射的虚拟地址和主进程中的一样。
- dpdk内存管理之内存初始化(内存收集)
- dpdk内存管理之内存分配器(堆分配)
- 内存管理之内存分配
- DPDK内存管理-----(一)初始化
- DPDK内存管理 -----(一)初始化
- C++内存管理之内存分配详解
- 内存管理之内存池的设计
- 内存管理之内存池的设计
- Java内存管理之内存分配
- linux内存管理总结之内存分配
- oc----内存管理之内存释放原则
- linux内存管理之内存映射
- iOS开发--内存管理之内存分配
- Linux 内存管理之内存零头
- 内存管理之内存池概述
- Android之内存泄露与内存管理
- JVM内存管理之内存结构
- JVM内存管理之内存回收策略
- Linux中关于init.d分析
- poj 2104 K-th Number (分桶法和平方分割)
- 什么是机器学习:一次权威定义之旅
- Java NIO笔记之Buffer
- 多线程2--毕向东基础视频教程学习笔记
- dpdk内存管理之内存初始化(内存收集)
- kernel32.dll函数介绍
- 动态内存分配:如何将两个字符串连接成单个字符串
- POJ3461:Oulipo(MP,KMP裸题)
- elasticsearch中doc_count为0,脚本失效?
- Ubuntu16.04下安装QT5.8
- Logistic Regression 逻辑回归算法
- 奶爸纪实--产房外等待的我们该做些什么?
- 买不到的数目