对rte_config->mem_config->memsegs 数组进行配置。primary进程调用memseg_primary_init。
struct rte_mem_config {
struct rte_memseg_list memsegs[RTE_MAX_MEMSEG_LISTS]; /**< list of dynamic arrays holding memsegs */
} __attribute__((__packed__));
#define RTE_MAX_MEMSEG_LISTS 128
/**
* memseg list is a special case as we need to store a bunch of other data
* together with the array itself.
*/
struct rte_memseg_list {
RTE_STD_C11
union {
void *base_va; /**< Base virtual address for this memseg list. */
uint64_t addr_64; /**< Makes sure addr is always 64-bits */
};
uint64_t page_sz; /**< Page size for all memsegs in this list. */ //每个大页的字节数2048*1024
int socket_id; /**< Socket ID for all memsegs in this list. */
volatile uint32_t version; /**< version number for multiprocess sync. */
size_t len; /**< Length of memory area covered by this memseg list. */ //这里是以字节为单位,本文例子中为 8192*2048*1024(memseg个数*2MB)
unsigned int external; /**< 1 if this list points to external memory */
struct rte_fbarray memseg_arr; //(这里存储着memseg个数,也就是页面的数目,本例中为8192)
};
1. gdb
1.1 n_memtype由internal_config.num_hugepage_sizes * rte_socket_count()得到,这里是1。
1.2 计算每个memtype中, seg_list个数和每个list里面的segs个数。
1.3 在每一个memtype中,根据上面的n_seglists = 4,分别创建每一个memseg list。分为两步,第一步alloc_memseg_list,第二步alloc_va_space。
1.3.1 第一步alloc_memseg_list
主要内容是通过rte_fbarray_init函数对rte_memseg_list中的memseg_arr进行赋值,fbarray中的每个element对应一个大页,element个数(即大页个数len)为8192个,每个element的大小(elt_sz)为48字节,每个element结构为
struct rte_memseg {
RTE_STD_C11
union {
phys_addr_t phys_addr; /**< deprecated - Start physical address. */
rte_iova_t iova; /**< Start IO address. */
};
RTE_STD_C11
union {
void *addr; /**< Start virtual address. */
uint64_t addr_64; /**< Makes sure addr is always 64 bits */
};
size_t len; /**< Length of the segment. */
uint64_t hugepage_sz; /**< The pagesize of underlying memory */
int32_t socket_id; /**< NUMA socket ID. */
uint32_t nchannel; /**< Number of channels. */
uint32_t nrank; /**< Number of ranks. */
uint32_t flags; /**< Memseg-specific flags */
} __rte_packed;
最后获得的memseg_arr中,data地址为0x10002e000,是紧接着memzones地址之后。
1.3.2 第二步alloc_va_space
memseg_arr仅仅是保存rte_memseg结构的管理内存,真正的大页内存是申请到rte_memseg_list的base_va下面,这个地址需要以2MB对齐,所以最终的地址是0x100200000,这个地址开始需要占用的内存即为len中的字节数:81922MB = 8192210241024 = 17,179,869,184 = 0x400000000。所以此时next_baseaddr全局变量应该为 0x100200000+0x400000000 = 0x500200000。
从0x10002e000到0x100200000,memseg_arr用不了那么多内存,后面很大一段是为了对齐浪费的。
1.4 所有4个memseg list分别创建之后,rte_config->mem_config->memsegs下的最终结果如下:
2. 总结
rte_eal_memseg_init对rte_config->mem_config->memsegs进行了初始化配置,是按照不同的socket和不同的page size,管理了多个memtype,每个memtype中再初始化多个memseg list,每个memseg list再初始化多个memsegs。其中,memtype个数是准确的(socket个数 乘以 page_size个数),而memseg list个数和memsegs个数,是按照最大数目来初始化的。我这里大页只配置了512个memsegs,实际上却初始化了4 乘以 8192个memsegs。