这篇文章标题已经写很久了,最近时间一直忙工作上事情,搁浅了很长一段时间。每次阅读到vpp对物理内存的管理这块都会绕过。终于鼓起勇气要来阅读一番。自己的理解也比较狭隘,比如通过/proc/pid/pagemap将虚拟地址查询到物理地址,本人也没有完全理解(参照其他人博客)。欢迎大家指正和交流。
物理内存命令行
这块也一直不知道从何入手,先介绍一下物理内存相关的命令行吧。 代码在src/vlib/physmem.c文件中。
代码语言:javascript复制show_physmem() /*src/vlib/physmem.c*/
| /*下面函数定义都在vppinfra/pmalloc.c文件中*/
| |---format_pmalloc /*对应命令行show physmem detail*/
| |---format_pmalloc_map /*对应命令行 show physmem map*/
1、show physmem detail 管理物理内存大小及使用情况
代码语言:javascript复制vpp# show physmem detail
#使用1个大页,预留大页16,缺省大页大小1G,
used-pages 1 reserved-pages 16 default-page-size 1GB lookup-page-size 1GB va-start 0x1000000000
#区域块使用情况:(这里就对应报文缓存区 vlib_buffer_t)
arena 'buffers-numa-0' pages 1 subpage-size 1GB numa-node 0 shared fd 6
#查询buffer缓存区使用情况:
vpp# show buffers
Pool Name Index NUMA Size Data Size Total Avail Cached Used
default-numa-0 0 0 2496 2048 430185 418824 1354 10007
2、show physmem map 虚拟内存物理内存的映射
代码语言:javascript复制vpp# show physmem map
virtual-addr physical-addr size
0x7b00000000 0x40000000 1GB
物理内存相关结构体描述
1、pmalloc 管理结构体
代码语言:javascript复制typedef struct
{
/* flags */
u32 flags;
#define CLIB_PMALLOC_F_NO_PAGEMAP (1 << 0)
/* base VA address 虚拟地址基址*/
u8 *base;
/* default page size - typically 2M 缺省页大小 2M或1G*/
u32 def_log2_page_sz;
/* system page size - typically 4K 系统页大小,4K*/
u32 sys_log2_page_sz;
/* 最大页数,受VA预分配大小限制*/
u32 max_pages;
/* vector结构页表——每个页面都有自己的alloc池,它可以被分割成子页面: (比如 2M page 被分割为 512 4K pages) */
clib_pmalloc_page_t *pages;
/* hash结构 <va, chunk_index>*/
uword *chunk_index_by_va;
/* */
clib_pmalloc_arena_t *arenas;
/* vector结构,每个numa节点都有自己的默认私有内存arena*/
u32 *default_arena_for_numa_node;
/* VA to PA lookup table */
uword *lookup_table;
/* lookup page size - equals to smalles subpage used */
u32 lookup_log2_page_sz;
/* last error */
clib_error_t *error;
} clib_pmalloc_main_t;
2、pmalloc 内存区域结构
代码语言:javascript复制typedef struct
{
u32 index;/**/
u32 flags;/**/
#define CLIB_PMALLOC_ARENA_F_SHARED_MEM (1 << 0)
int fd;/**/
u32 numa_node;/**/
u32 first_page_index;/**/
u32 log2_subpage_sz;/**/
u32 subpages_per_page;/**/
u32 n_pages;/**/
u8 *name; /**/
u32 *page_indices;/**/
} clib_pmalloc_arena_t;
3、pmalloc_page 结构体
代码语言:javascript复制/**
typedef struct
{/*
*
**/
u32 start, prev, next;
u32 size:31;/**/
u32 used:1;/**/
} clib_pmalloc_chunk_t;
typedef struct
{
u32 index;/**/
u32 arena_index;/**/
clib_pmalloc_chunk_t *chunks;/**/
u32 first_chunk_index;/**/
u32 n_free_chunks;/**/
u32 n_free_blocks;/**/
} clib_pmalloc_page_t;
4、物理内存管理结构体
代码语言:javascript复制typedef struct
{
int index;
int fd;
void *base; /*基地址大小,会根据页表大小进行对齐后大小*/
u32 n_pages; /**/
uword *page_table;/**/
u32 log2_page_size;/**/
u32 numa_node;/**/
} vlib_physmem_map_t;
typedef struct
{
u32 flags; /*标识字段*/
uword base_addr; /*虚拟内存基地址*/
uword max_size; /*内存大小*/
#define VLIB_PHYSMEM_MAIN_F_HAVE_PAGEMAP (1 << 0)
#define VLIB_PHYSMEM_MAIN_F_HAVE_IOMMU (1 << 1)
vlib_physmem_map_t *maps;/**/
clib_pmalloc_main_t *pmalloc_main;/**/
} vlib_physmem_main_t;
GDB调试打印信息
gdb 调试打印数据大小。当前环境大页大小是1G。
代码语言:javascript复制/*startup.conf 设置物理基地址和内存大小设置*/
physmem {
base-addr 0x7af0000000
max-size 8G
}
/* gdb 调试打印信息如下*/
(gdb) p/x vlib_global_main.physmem_main
$2 = {
flags = 0x1,
base_addr = 0x7b00000000,/*基地址需要做页大小对齐 和配置不一致*/
max_size = 0x200000000, /*8G内存*/
maps = 0x7fe2c5710d28,
pmalloc_main = 0x7fe2c56f1b40
}
(gdb) p vlib_global_main.physmem_main.pmalloc_main[0]
$3 = {
flags = 0,
base = 0x7b00000000 "",
def_log2_page_sz = 30, /*大页大小 1G*/
sys_log2_page_sz = 12, /*系统默认页表大小 4K*/
max_pages = 8, /*最大页表数量*/
pages = 0x7fe2c581ade0,
chunk_index_by_va = 0x0,
arenas = 0x7fe2c59b4878,
default_arena_for_numa_node = 0x0,
lookup_table = 0x7fe2c5fbd400,
lookup_log2_page_sz = 30,
error = 0x0
}
(gdb) p vlib_global_main.physmem_main.pmalloc_main[0].pages[0]
$4 = {
index = 0,
arena_index = 0,
chunks = 0x0,
first_chunk_index = 0,
n_free_chunks = 0,
n_free_blocks = 16777216 /*16M*/
}
(gdb) p vlib_global_main.physmem_main.pmalloc_main[0].arenas[0]
$5 = {
index = 0,
flags = 1,
fd = 6,
numa_node = 0,
first_page_index = 0,
log2_subpage_sz = 30,
subpages_per_page = 1,
n_pages = 1,
name = 0x7fe2c63c1c30 "buffers-numa-0",
page_indices = 0x7fe2c58a1250
}
查询当前进程报文缓存区虚拟内存使用情况:
代码语言:javascript复制cat /proc/`pidof vpp`/maps | grep buffer
7b00000000-7b40000000 rw-s 00000000 00:0e 82841 /memfd:buffers-numa-0 (deleted)
查询虚拟地址对应的物理地址:
代码语言:javascript复制[13:46:11]root:get_pa_by_va$ ./a.out `pidof vpp` 7b00000000
Big endian? 0
Vaddr: 0x7b00000000, Page_size: 1000, Entry_size: 8
Reading /proc/15878/pagemap at 0x3d800000
[0]0x0 [1]0x0 [2]0x4 [3]0x0 [4]0x0 [5]0x0 [6]0x80 [7]0xa1
Result: 0xa180000000040000
PFN: 0x40000 0x40000000 /*物理地址和 命令行show physmem maps 显示一样*/
DBGvpp# show physmem maps
virtual-addr physical-addr size
0x7b00000000 0x40000000 1GB
查询虚拟地址对应物理地址相关代码已上传到 github:https://github.com/jin13417/dpdk-vpp-learning。 代码来源于网站:http://fivelinesofcode.blogspot.com/2014/03/how-to-translate-virtual-to-physical.html
这篇是很久之前写的文章,只研究了一半吧,先发出来,有时间再继续研究。