1 前言

DPDK将利用hugepage预留的物理内存统一的组织管理起来,然后以库的方式对外提供使用的接口。下图展示了DPDK中内存有关的模块的相互关系。

rte_eal            是统一的组织管理者(当然rte_eal不只是做内存的工作)

rte_malloc       对外提供分配释放内存的API,分配的内存都是rte_eal中管理的内存

rte_ring          提供无锁队列,他之间使用了rte_eal管理的内存

rte_mempool  利用rte_eal中的内存和rte_ring提供内存池的功能

ret_mbuf

2 rte_eal 对内存的组织与管理

这块是在rte_eal中实现的。有关的函数有:

rte_eal_init -> eal_hugepage_info_init

rte_eal_init -> rte_eal_memory_init

rte_eal_init -> rte_eal_memzone_init

rte_eal_init -> eal_check_mem_on_local_socket

预留的内存按页大小分类( i386 architecture supports 4K and 4M (2M in PAE mode) page sizes, ia64 architecture supports multiple page sizes 4K, 8K, 64K, 256K, 1M, 4M, 16M, 256M and ppc64 supports 4K and 16M. ),可能会有多类,DPDK会把这些信息全部读取,使用struct hugepage_info进行保存,每一类对应一个struct hugepage_info类型的对象,所有的这些对象保存在struct internal_config的数组中。DPDK有个internal_config的全局变量,记录这些信息。

struct hugepage_info {
size_t hugepage_sz; /**< size of a huge page */
const char *hugedir; /**< dir where hugetlbfs is mounted */
uint32_t num_pages[RTE_MAX_NUMA_NODES];
/**< number of hugepages of that size on each socket */
int lock_descriptor; /**< file descriptor for hugepage dir */
};
struct internal_config {
   ...
unsigned num_hugepage_sizes; /**< how many sizes on this system */
struct hugepage_info hugepage_info[MAX_HUGEPAGE_SIZES];
};

总结 eal_hugepage_info_init,就是获取了系统中预留的内存信息,有几类(相同页大小的是一类),将每一类的信息(页大小、页数、挂载点)存储在internal_config.hugepage_info数组中。hugepage_info数组也进行了排序,大页的信息放前面,小页的信息放后面。

每一类所有内存页,也分处在哪个 socket上(不明白的查看NUMA相关知识补齐)的,hugepage_info中统计内存页数会按属于处在哪个socket上进行统计,但在这一步(eal_hugepage_info_init)中,还区分不了每个页处在哪个socket上,因此这里还没有按socket统计页数,将内存页数直接记录到num_pages[0]里面了。

2.2 rte_eal_memory_init

int
rte_eal_memory_init(void)
{
RTE_LOG(INFO, EAL, "Setting up memory...\n");
const int retval = rte_eal_process_type() == RTE_PROC_PRIMARY ?
rte_eal_hugepage_init() :
rte_eal_hugepage_attach();
if (retval < )
return -; if (internal_config.no_shconf == && rte_eal_memdevice_init() < )
return -; return ;
}

DPDK多进程状态下,分为RTE_PROC_PRIMARY进程及RTE_PROC_SECONDARY进程,RTE_PROC_PRIMARY负责初始化内存,RTE_PROC_SECONDARY获取 RTE_PROC_PRIMARY 内存映射的信息,创建与RTE_PROC_PRIMARY一样的内存映射。这是DPDK多进程共享内存的方式。此处先不展开描述。随着流程的展开,自然会明白。

2.2.1 rte_eal_mem_init -> rte_eal_hugepage_init

DPDK有个全局变量

static struct rte_config rte_config

该变量的成员 struct rte_mem_config *mem_config;  保存了DPDK管理的内存的所有信息。DPDK将内存统一的管理,就是将所有内存保存到mem_config:memseg[]中。

struct rte_mem_config {
volatile uint32_t magic; /**< Magic number - Sanity check. */ /* memory topology */
uint32_t nchannel; /**< Number of channels (0 if unknown). */
uint32_t nrank; /**< Number of ranks (0 if unknown). */ /**
* current lock nest order
* - qlock->mlock (ring/hash/lpm)
* - mplock->qlock->mlock (mempool)
* Notice:
* *ALWAYS* obtain qlock first if having to obtain both qlock and mlock
*/
rte_rwlock_t mlock; /**< only used by memzone LIB for thread-safe. */
rte_rwlock_t qlock; /**< used for tailq operation for thread safe. */
rte_rwlock_t mplock; /**< only used by mempool LIB for thread-safe. */ uint32_t memzone_idx; /**< Index of memzone */ /* memory segments and zones */
struct rte_memseg memseg[RTE_MAX_MEMSEG]; /**< Physmem descriptors. */
struct rte_memzone memzone[RTE_MAX_MEMZONE]; /**< Memzone descriptors. */ /* Runtime Physmem descriptors. */
struct rte_memseg free_memseg[RTE_MAX_MEMSEG]; struct rte_tailq_head tailq_head[RTE_MAX_TAILQ]; /**< Tailqs for objects */ /* Heaps of Malloc per socket */
struct malloc_heap malloc_heaps[RTE_MAX_NUMA_NODES];
} __attribute__((__packed__));

函数先根据 struct hugepage_info hugepage_info[MAX_HUGEPAGE_SIZES]; (eal_hugepage_info_init中获取的信息)得到了内存页的总数。然后为struct hugepage_file *tmp_hp申请了内存,有多少个内存页,就分配了多少个hugepage_file。

struct hugepage_file {
void *orig_va; /**< virtual addr of first 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 */
int memseg_id; /**< the memory segment to which page belongs */
#ifdef RTE_EAL_SINGLE_FILE_SEGMENTS
int repeated; /**< number of times the page size is repeated */
#endif
char filepath[MAX_HUGEPAGE_PATH]; /**< path to backing file on filesystem */
};

接着针对每一类内存(相同页大小的内存算一类)进行处理,

for(每一类) {

  for(这一类的每一页) {

    每个页对应一个hugepage_file,file_id,size,filepath初始化。其中file_id是页的序号,这个序号是给filepath用的,是为了给每个页对应的文件起一个独立的文件名(与其他页不会重复)。

    建立文件<filepath>,这个文件是因为使用hugepage的内存必须按这样的方式(先建立文件,再mmap,得到内存虚拟地址使用)使用。

    执行mmap获得页的虚拟地址,赋给hugepage_file:orig_va。

  } (map_all_hugepages())

所有hugepage预留的物理内存都映射完成,可以根据hugepage_file:orig_va进行访问了。

  for(这一类的每一页) {

    获取物理地址,赋给hugepage_file:physaddr。

    获取物理地址的方式,是linux内核提供的功能,不了解的可以点击这里补齐。

  }(find_physaddrs())

  

  for(这一类的每一页) {

     获取每个页所在的socket,赋给hugepage_file:socket_id。 

     获取的方法也是linux内核提供的功能,具体不详述。

  }(find_numasocket())

  对这一类的页的hugepage_file[]按页物理地址进行排序。

  for(这一类的每一页) {

    重新执行mmap,并将获取的虚拟地址赋给hugepage_file:final_va。    

  }(map_all_hugepages())

  本次重新mmap,与第一次的不同是,会主动先申请一块足够映射本类所有内存页的虚拟地址空间,然后将本类的所有页连续的映射的该虚拟地址空间中。

  如果找不到这么大的虚拟地址空间,还是会一页一页的映射,让内核去决定虚拟地址空间。

  第二次映射用代码的注释解释 The second mapping tries to  map continguous physical blocks in contiguous virtual blocks.

  将第一次的映射unmap掉

继续

更新 internal_config.hugepage_info[].num_pages[],我们知道bugepage_info在eal_hugepage_info_init中初始化时,不知道每个页是属于哪个socket的,因此直接使用num_pages[0]记录了所有的页数,但在上一步中,已经知道了每个页属于哪个socket,因此这里更新了num_pages,准确的记录了哪个socket上有多少个页。

接下来,建立了共享内存,将hugepage_file拷贝到共享内存中,这样RTE_PROC_SECONDARY启动后可以在共享内存中读取这些信息,然后创建与RTE_PROC_PRIMARY一致的映射。

最后,使用mem_config->memseg[]将所有内存管理起来。

一个struct rte_memsg对象,保存一块相同socket的、相同页大小的、物理地址连续的、虚拟地址连续的内存。因此整个内存由多个memseg组成。

总结rte_eal_hugepage_init,它获取hugepge的方式预留的所有物理内存,统一的映射到虚拟地址空间中,保存到memseg中。至此,理论上可以通过memseg获取虚拟地址使用这些内存了。但DPDK提供了统一的方式来使用,不是谁用就可以来拿的。

DPDK内存管理(1)(转)的更多相关文章

  1. DPDK内存管理(1)

    1 前言 DPDK将利用hugepage预留的物理内存统一的组织管理起来,然后以库的方式对外提供使用的接口.下图展示了DPDK中内存有关的模块的相互关系. rte_eal            是统一 ...

  2. DPDK内存管理-----(二)rte_mempool内存管理

    DPDK以两种方式对外提供内存管理方法,一个是rte_mempool,主要用于网卡数据包的收发:一个是rte_malloc,主要为应用程序提供内存使用接口.本文讨论rte_mempool.rte_me ...

  3. DPDK内存管理-----(一)初始化

    1 前言 DPDK通过使用hugetlbfs,减少CPU TLB表的Miss次数,提高性能. 2 初始化 DPDK的内存初始化工作,主要是将hugetlbfs的配置的大内存页,根据其映射的物理地址是否 ...

  4. DPDK内存管理-----(三)rte_malloc内存管理

    rte_malloc()为程序运行过程中分配内存,模拟从堆中动态分配内存空间. void * rte_malloc(const char *type, size_t size, unsigned al ...

  5. DPDK内存管理-----rte_mbuf(转)

    本文主要介绍rte_mbuf与rte_mempool数据结构之间的组织关系.以及网卡接收到的数据是如何存储在rte_mbuf中的. 一.rte_mbuf.rte_mempool及网卡收到的数据包在内存 ...

  6. rte_mempool内存管理

    DPDK以两种方式对外提供内存管理方法,一个是rte_mempool,主要用于网卡数据包的收发:一个是rte_malloc,主要为应用程序提供内存使用接口.本文讨论rte_mempool.rte_me ...

  7. .NET基础拾遗(1)类型语法基础和内存管理基础

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开发基 ...

  8. PHP扩展-生命周期和内存管理

    1. PHP源码结构 PHP的内核子系统有两个,ZE(Zend Engine)和PHP Core.ZE负责将PHP脚本解析成机器码(也成为token符)后,在进程空间执行这些机器码:ZE还负责内存管理 ...

  9. linux2.6 内存管理——逻辑地址转换为线性地址(逻辑地址、线性地址、物理地址、虚拟地址)

    Linux系统中的物理存储空间和虚拟存储空间的地址范围分别都是从0x00000000到0xFFFFFFFF,共4GB,但物理存储空间与虚拟存储空间布局完全不同.Linux运行在虚拟存储空间,并负责把系 ...

随机推荐

  1. Springboot演示小Demo

    模拟数据库演示springboot小测试 1.编写一个实体类:user package com.wisezone.test; import java.io.Serializable; public c ...

  2. HIVE-如何查看执行日志

    HIVE既然是运行在hadoop上,最后又被翻译为MapReduce程序,通过yarn来执行.所以我们如果想解决HIVE中出现的错误,需要分成几个过程 HIVE自身翻译成为MR之前的解析错误 Hado ...

  3. Python学习笔记 - 用VSCode写python的正确姿势

    最近在学习python,之前一直用notepad++作为编辑器,偶然发现了VScode便被它的颜值吸引.用过之后发现它启动快速,插件丰富,下载安装后几乎不用怎么配置就可以直接使用,而且还支持markd ...

  4. [C++] 贪心算法之活动安排、背包问题

    一.贪心算法的基本思想 在求解过程中,依据某种贪心标准,从问题的初始状态出发,直接去求每一步的最优解,通过若干次的贪心选择,最终得出整个问题的最优解. 从贪心算法的定义可以看出,贪心算法不是从整体上考 ...

  5. [转] pip镜像升级报警 -trust-host问题解决方案

    pip升级到7.0以后,在使用http镜像进行包安装及升级的时候往往会有如下提示: Collecting beautifulsoup4The repository located at mirrors ...

  6. pushd,popd,dirs,cd -让切换目录更方便

    与linux cd命令相似,用pushd实现在不同目录间切换 在命令行模式下,当你工作在不同目录中,你将发现你有很多时间都浪费在重复输入上如果这些目录不在同一个根目录中,你不得不在转换时输入完整的路径 ...

  7. HDU 1863 畅通工程(Prim,Kruskal,邻接表模板)

    畅通工程 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  8. VisualGDB系列11:Linux C++项目中使用外部Linux库

    根据VisualGDB官网(https://visualgdb.com)的帮助文档大致翻译而成.主要是作为个人学习记录.有错误的地方,Robin欢迎大家指正. 在<使用VS创建Linux静态库和 ...

  9. [转]Missing MSS Settings in Security Options of Group Policy (GPO)

    I'm currently working on a new Windows Server 2012 and Windows 8 project. As part of that project is ...

  10. CPU, PSU, SPU的区别

    It all started in January 2005 with Critical Patch Updates (CPU).  Then Patch Set Updates (PSU) were ...