DPU网络开发SDK—DPDK(七)

13 篇文章 3 订阅

 rte_eal_init()

接上次内容继续对rte_eal_init()所做的工作进行分析。

24. 内存初始化

       24.2. 内存分配

       调用eal_memalloc_init()来处理内存分配,前半部分根据进程是primary还是secondary走不同的流程,后半部分两者相同。

       前后两个初始化过程中,用到了一个特殊的func,rte_memseg_list_walk(),该func的传入参数是一个rte_memseg_list_walk_t类型的函数指针及void *通用指针。在list_walk()中,会对rte_config.mem_config.memsegs列表中每一个memseg list依次调用函数指针指向的函数,且保证了整个过程中是在mem_config.memory_hotplug_lock锁的保护下进行的。

  • 以secondary方式

通过list_walk()来调用secondary_msl_create_walk()来为每个memseg list分配内存,该func中,根据primary的memseg list的大小,初始化一个local_memsegs结构,初始化还是调用rte_fbarray_init()来实现。primary的memseg list的大小从mem_config.memsegs获取到。

  • 以primary方式

该过程中,通过test_memfd_create执行memfd_create系统调用,测试当前系统是否支持创建匿名的内存共享,检查结果根据当前系统的一些配置情况决定是否以错误退出。

分primary和secondary之后,不管哪种方式初始化,都会执行fd_list_create_walk()。create_walk()对每个memseg list调用alloc_list(),alloc_list()会初始化文件描述符列表数组fd_list,每个memseg list对应一个数组项,数组项中会指向一块内存,用于存储文件描述符,这里的文件描述符即为匿名内存共享文件的描述符。

       24.3. 初始化大页

       初始化大页同样分primary和secondary

  • 以primary方式

调用rte_eal_hugepage_init(),如果internal_config设置了legacy_mem,那么调用eal_legacy_hugepage_init(),否则调用eal_dynmem_hugepage_init()。

      A. eal_dynmem_hugepage_init()

对于每一种大小类型的大页,确定好每个socket上页面的数量;统计出每个numa node上的内存大小;根据这些信息调用eal_dymem_calc_num_pages_per_socket()最终确定每种大小类型的页面的数量。

确定好这些信息之后,多次调用eal_memalloc_alloc_seg_bulk()来映射页面,该func通过list_walk()调用alloc_seg_walk()来完成这些工作。

      B. eal_legacy_hugepage_init()

分为两种情况执行,一种禁用hugetlbfs情况下,另一种是在启用情况下。

      a. 禁用hugetlbfs

此时允许的内存大小为64GB,页面大小为4KB,以此得出所需要的一个页面数量之后,调用eal_memseg_list_init_named()来重新初始化mem_config.memsegs[0]这个memseg list。然后通过eal_memseg_list_alloc()间接调用eal_get_virtual_area()为memseg分配虚拟地址,下一步通过mmap()系统调用创建匿名映射并获得匿名映射地址addr,接下来通过eal_memseg_list_populate()填充mem_config.memsegs[0]这个memseg list,以addr为基准计算出每个memseg的地址,填到相应的结构体中。

      b. 启用hugetlbfs

首先统计出用了哪几种大小类型的大页内存,并且计算出总得大页内存页面数量,分别存放在used_hp数组和nr_hugepages当中。接下来开辟一块内存tmp_hp,用于存放nr_hugepages个struct hugepage_file结构,hugepage_file结构用于存放一些信息,比如该大页被映射到进程地址空间的哪个虚拟地址,大页物理地址是多少,所属socket_id是多少。

接下来,对于每一种页面大小类型的大页,做如下操作:

1.调用map_all_hugepages()映射该大小类型的所有大页,具体做法是调用open()打开大页在/sys文件系统中的文件,然后mmap()之后获取一个虚拟地址,并记录在结构体当中。

2.如果启用了物理地址,且IOVA的模式不是VA,那么调用find_physaddrs()获取到每个大页的物理地址并保存下来,否则调用set_physaddrs()设定一个伪物理地址。

3.调用find_numasocket()确定每个大页所属的socket_id。

4.根据物理地址将tmp_hp进行排序。

接下来根据tmp_hp中的信息,统计出每个socket每种大小类型的大页的数量,更新这些信息更新到internal_config.hugepage_info结构体当中,并最终确定每个socket下大页的数量。

接下来调用create_shared_memory()创建一个共享文件,大小为nr_hugepages个struct hugepage_file结构体,路径为/var/run/dpdk/rte/hugepage_data;接下来调用copy_hugepages_to_shared_mem()将该进程中分配到的大页信息写入到该文件当中。需要指出的是,到此为止所需要分配的内存就分配完了,后续不会再根据需要再额外分配大页内存,即使在DPDK进程运行过程中遇到内存耗尽的情况,所以在最后的收尾工作中,会将一些不需要的memseg list做释放处理。

  • 以secondary方式

调用rte_eal_hugepage_attach()来实现,同样分为是否设置了lagacy_mem,分别调用eal_legacy_hugepage_attach()和eal_hugepage_attach()

      A. eal_legacy_hugepage_attach()

打开primary进程创建的文件/var/run/dpdk/rte/hugepage_data,并读取相应的信息,该文件的是多个hugepage_file结构体。对于每一个结构体中包含的信息,通过mmap()将大页内存还原到当前secondary进程当中,并以此初始化memseg list。

      B. eal_hugepage_attach()

调用eal_memalloc_sync_with_primary(),该func会调用sync_walk()。sync_walk()会根据primary进程中的memseg list信息初始化自己的memseg list。sync_walk()会调用sync_existing()去打开/sys文件系统中的大页文件去确认已经被primary分配的内存和未被primary分配的内存跟memseg list中的信息是一致的,在确保一致的情况下才可以进行后续工作。

未完待续…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值