走进vpp物理内存管理的世界(1)

2023-03-07 17:29:55 浏览数 (1)

这篇文章标题已经写很久了,最近时间一直忙工作上事情,搁浅了很长一段时间。每次阅读到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

这篇是很久之前写的文章,只研究了一半吧,先发出来,有时间再继续研究。

0 人点赞