前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >VPP HugePages

VPP HugePages

作者头像
dpdk-vpp源码解读
发布2023-03-07 17:30:32
1.3K4
发布2023-03-07 17:30:32
举报
文章被收录于专栏:DPDK VPP源码分析DPDK VPP源码分析

以前经常遇到2C3G的vmware续集上环境上安装上vpp后,能直接运行,而每次当系统重启后总是报内存不足的问题。当把系统内存调整到4G后,就能正常运行了。一直也不清楚原因。最近工作中遇到一个问题在2c2g的环境上跑vpp,一段时间后,总是报内存不足。后来查询发现hugepage内存大小是1G,但是只使用了不到三分之一的大页内存。

下面虚拟机2C3G环境下启动vpp后使用大页内存的大小。Total-free=22*2M=44M的大页内存。下面是查询大页数量:

代码语言:javascript
复制
[root@learning_vpp2 vpp]# cat /proc/meminfo | grep Huge
AnonHugePages:      6144 kB
HugePages_Total:     1024  #是大页内存池中大页的总数量。
HugePages_Free:      1002  #大页内存池中尚未分配的大页面的数量
HugePages_Rsvd:        0  
#是“保留”的缩写,是已承诺从池中分配但尚未分配的大页面的数量。保留
#的大页面保证了应用程序能够在出错时从大页面池中分配大页面。
HugePages_Surp:        0
#大页池中超过/prov/sys/vm/nr_hugepages,最大不超过
# /proc/sys/vm/nr_overcommit_hugepages
Hugepagesize:       2048 kB #是单个大页内存大小(以Kb为单位)。

下面是查看vpp上使用大页内存的大小:

代码语言:javascript
复制
learning_vpp2# show physmem 
# 报文缓存区使用了40M大页内存。
 used-pages 20 reserved-pages 8192 default-page-size 2M lookup-page-size 2M
   arena 'buffers-numa-0' pages 20 subpage-size 2M numa-node 0 shared fd 10
#dpdk 使用了4M大页内存
learning_vpp2# show dpdk physmem 
Segment 2-0: IOVA:0x28c00000, len:2097152, virt:0xac0200000, socket_id:0, hugepage_sz:2097152, nchannel:0, nrank:0 fd:-95
Segment 2-1: IOVA:0x29200000, len:2097152, virt:0xac0400000, socket_id:0, hugepage_sz:2097152, nchannel:0, nrank:0 fd:-95
learning_vpp2# 

上述命令行来源于vpp dev邮件:https://lists.fd.io/g/vpp-dev/topic/30749806#12636

这里一直有个疑问,本地环境并没有配置大页内存,vpp安装后重启虚拟机时,查询已经分配了2G的(1024*2M)大页内存的。下面就看看vpp官方文档中的介绍。本文简单翻译了一下。在文档的结尾解答了文章开头的问题。

vpp Huge page翻译

VPP在运行期间需要大页内存。在VPP安装过程中,VPP将覆盖现有的巨页设置。缺省情况下,VPP将系统的大页数设置为1024*2m大页。这是系统上的大页面数量,而不仅仅是VPP使用的。 安装VPP后,会将vpp配置文件src/vpp/conf/80-vpp.conf拷贝到系统中/etc/sysctl.d/目录下。大页设置应用于VPP安装和系统重新启动时。使用下面的实例设置大页设置。

代码语言:javascript
复制
[root@learning_vpp2 vpp]# cat src/vpp/conf/80-vpp.conf 
# Number of 2MB hugepages desired
vm.nr_hugepages=1024

# Must be greater than or equal to (2 * vm.nr_hugepages).
vm.max_map_count=3096

# All groups allowed to access hugepages
vm.hugetlb_shm_group=0

# Shared Memory Max must be greater or equal to the total size of hugepages.
# For 2MB pages, TotalHugepageSize = vm.nr_hugepages * 2 * 1024 * 1024
# If the existing kernel.shmmax setting  (cat /proc/sys/kernel/shmmax)
# is greater than the calculated TotalHugepageSize then set this parameter
# to current shmmax value.
kernel.shmmax=2147483648

可以看到vpp默认设置了2G的大页内存1024*2M,我们需要根据系统的内存的实际大小,来更新此配置文件,以调整系统上大页面数量。

如果VPP运行在虚拟机(VM)中,则虚拟机必须有大页支持。安装VPP后,它将尝试覆盖现有的巨页设置。如果虚拟机没有大页面支持,安装将失败,但失败可能不会被注意到。当虚拟机重启时,系统启动时,“VM .”nr_hugepages将被重新应用,并将失败,VM将中止内核引导,锁定VM。为了避免这种情况,请确保VM有足够的大页面支持。----可以解释开头的疑问了。

Huge page简介

现代的cpu支持不同的页面大小,例如4K、2M、1GB。在Linux中,所有页面大小(除了4K)都被称为“大页面”。这种名称约定的原因是历史原因,源于Linux最初只支持4K页面大小。 大页面大小有利于提高性能,因为虚拟地址和物理地址之间的转换较少,而且地址转换缓存缓冲区(Translation Lookaside Buffer, TLB)缓存是一种稀缺资源。

来源于blog:Learning DPDK : Huge pages: https://haryachyy.wordpress.com/2019/04/17/learning-dpdk-huge-pages/

代码语言:javascript
复制
使用HugePage的优点:
1、系统使用HugePage则内存页数量会减少,从而需要更少的页表,节约了页表所占用的内存数量。
2、所需的地址转化也减少了,TLB缓存失效的次数也减少了,从而提高内存访问的性能。
3、地址转换所需信息一般保存在CPU缓存中,HugePage使用让地址转换信息减少,减少了CPU缓存的使用。
4、HugePage页面是不支持swap的,所以没有page table lookups。所以大内存情况下,kswapd也不会频繁被调用。
 当然HugePage在某些场景下也存在缺点:
当申请一块大内存,但是使用内存并不多,比如:每个2MB,写4KB内容。
使用HugePage就会导致实际占用的物理内存相对于4KB页面大很多。

Linux 中有两种类型的大页面可用。透明(匿名)大页面和持久化大页面。

1、透明大页面

透明大页面是一个抽象层,可以自动化创建、管理和使用大页面的大多数方面。就性能和稳定性方面存在的一些问题而言,DPDK不依赖这种机制,而是使用持久化大页面。

2、持久化大页面

必须手动配置持久性大页面。Linux 内核永远不会交换持久性大页面。 Linux 中存在以下管理接口来分配持久性大页面。 1、使用shmget()共享内存 2、HugeTLBFS 是一个基于 RAM 的文件系统,可以使用mmap()、 read() 或 memfd_create()访问其文件 3、匿名mmap()通过指定标志MAP_ANONYMOUS和MAP_HUGETLB标志 4、libhugetlbfs API 5、自动支持内存区域 DPDK默认使用持久化大页面,自动发现挂载点,应用退出后释放页面。但如果用户需要手动调整某些内容,可以使用以下EAL 命令行参数。

--huge-dir使用指定的hugetlbfs目录而不是自动检测到的目录。 --huge-unlink 创建后取消链接大页面文件(意味着没有辅助进程支持)。 --in-memory 最近的 DPDK 版本添加了一个不依赖Hugetlbfs的选项 有多种方法可以设置持久性大页面。

在开机时,我们可以通过修改启动grub文件来设置。 修改/etc/default/grub 中的Linux 启动时间参数。大页内存将在所有 NUMA 套接字之间平均分布。

代码语言:javascript
复制
GRUB_CMDLINE_LINUX="default_hugepagesz=1G hugepagesz=1G hugepages=32"
#更新 grub 配置文件并重新启动。
grub2-mkconfig -o /boot/grub2/grub.cfg
reboot

为hugetlbfs 的永久挂载点创建一个文件夹

代码语言:javascript
复制
mkdir /mnt/huge
#将以下行添加到 /etc/fstab 文件中:
nodev /mnt/huge hugetlbfs defaults 0 0

在运行时 更新每个 NUMA 节点的大页面数量。无法在运行时修改默认大页面大小。

代码语言:javascript
复制
echo 16 > /sys/devices/system/node/node0/hugepages/hugepages-1048576kB/nr_hugepages
echo 16 > /sys/devices/system/node/node1/hugepages/hugepages-1048576kB/nr_hugepages

#创建挂载点。
mkdir /mnt/huge
#挂载Hugetlbfs 
mount -t hugetlbfs nodev /mnt/huge

可以通过命令查询大页内存挂载点

代码语言:javascript
复制
[root@learning_vpp2 vpp]# cat /proc/mounts | grep huge
cgroup /sys/fs/cgroup/hugetlb cgroup rw,nosuid,nodev,noexec,relatime,hugetlb 0 0
nodev /mnt/huge hugetlbfs rw,relatime 0 0

大页内存只有设置挂载点以后,才能被应用程序使用。

内存分配 虽然有多种分配持久性大页面的方法,但 DPDK 使用以下方法。 mmap()使用Hugetlbfs挂载点调用。 mmap()调用带有 MAP_HUGETLB标志。 memfd_create()调用带有MFD_HUGETLB标志。

透明大页和持久化大内存页具体有什么不同支持,我也没有分清楚?

vpp目前使用内存模式,纯属于个人理解:vpp目前支持三种内存管理模式:

1、大页内存:主要是报文缓存区buffer和dpdk 内存管理使用到。 2、main_heap内存:vppinfra基础库中很多数据结构(vector、pool、hash、heap等)都是从main_heap申请的内存,底层是使用pmalloc来管理内存的。可以通过命令行查询。

代码语言:javascript
复制
##默认会申请1G,pagesize=4K
learning_vpp2# show memory main-heap
Thread 0 vpp_main
  base 0x7fffb5ada000, size 1g, locked, unmap-on-destroy, name 'main heap'
    page stats: page-size 4K, total 262144, mapped 40122, not-mapped 0, unknown 222022
      numa 0: 40122 pages, 156.73m bytes
    total: 1023.99M, used: 83.58M, free: 940.42M, trimmable: 939.91M
Thread 1 vpp_wk_0
  base 0x7fffb5ada000, size 1g, locked, unmap-on-destroy, name 'main heap'
    page stats: page-size 4K, total 262144, mapped 40122, not-mapped 0, unknown 222022
      numa 0: 40122 pages, 156.73m bytes
    total: 1023.99M, used: 83.58M, free: 940.42M, trimmable: 939.91M

默认情况的main heap内存申请大小是1G,pagesize=4K,我们可以在startup.config文件中指定。比如下面main heap 500M,pagesize=2M

代码语言:javascript
复制
memory {
main-heap-size 500m #设置heap大小
main-heap-page-size default-hugepage #页大小:这里使用大页内存
}
learning_vpp2# show memory main-heap
Thread 0 vpp_main
  base 0x7fffd6600000, size 500m, locked, unmap-on-destroy, name 'main heap'
    page stats: page-size 2M, total 250, mapped 250, not-mapped 0
      numa 0: 250 pages, 500m bytes
    total: 499.99M, used: 83.60M, free: 416.39M, trimmable: 416.26M

Thread 1 vpp_wk_0
  base 0x7fffd6600000, size 500m, locked, unmap-on-destroy, name 'main heap'
    page stats: page-size 2M, total 250, mapped 250, not-mapped 0
      numa 0: 250 pages, 500m bytes
    total: 499.99M, used: 83.60M, free: 416.39M, trimmable: 416.26M

3、mmap函数直接申请内存。 类似api-segment, stats-segment等,目前bihash支持2中方式, 1、从main heap上申请,2、通过mmap直接映射,优先从大页内存上申请,申请失败,再系统默认4K页大小申请。

代码语言:javascript
复制
static inline void *BV (alloc_aligned) (BVT (clib_bihash) * h, uword nbytes)
{
    if (BIHASH_USE_HEAP)
    {

    }
    else
    {
       if (alloc_arena_next (h) > alloc_arena_mapped (h))
    {
      void *base, *rv;
      uword alloc = alloc_arena_next (h) - alloc_arena_mapped (h);
      int mmap_flags = MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS;
      int mmap_flags_huge = (mmap_flags | MAP_HUGETLB | MAP_LOCKED |
                 BIHASH_LOG2_HUGEPAGE_SIZE << MAP_HUGE_SHIFT);

      /* new allocation is 25% of existing one */
      if (alloc_arena_mapped (h) >> 2 > alloc)
    alloc = alloc_arena_mapped (h) >> 2;

      /* round allocation to page size */
      alloc = round_pow2 (alloc, 1 << BIHASH_LOG2_HUGEPAGE_SIZE);

      base = (void *) (uword) (alloc_arena (h) + alloc_arena_mapped (h));
       /*先尝试从大页内存申请*/
      rv = mmap (base, alloc, PROT_READ | PROT_WRITE, mmap_flags_huge, -1, 0);

      /* fallback - maybe we are still able to allocate normal pages 
      * 申请失败,从系统页大小申请*/
      if (rv == MAP_FAILED || mlock (base, alloc) != 0)
    rv = mmap (base, alloc, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
....

    }
}

我们可以通过show memory map查询vpp内存使用情况

代码语言:javascript
复制
learning_vpp2# show memory map

StartAddr          size   FD PageSz  Pages Numa0 NotMap Name
00007ffff5adb000     1m          4K    256     2      0 main heap
00007fffd6600000   500m          2M    250   250      0 main heap
00007fffccc0d000     2m          4K    512     7      0 thread stack: thread 0
00007fffcac0c000    32m    9     4K   8192   430      0 stat segment
00007fffcabeb000   128k          4K     32     2      0 process stack: vrrp-periodic-process
00007fffcabda000    64k          4K     16     2      0 process stack: rtnl-process
00007fffcabc9000    64k          4K     16     2      0 process stack: nsh-md2-ioam-export-process
00007fffcabb8000    64k          4K     16     2      0 process stack: nat44-ei-ha-process
00007fffcaba7000    64k          4K     16     2      0 process stack: memif-process
00007fffcab96000    64k          4K     16     3      0 process stack: lldp-process
00007fffcab85000    64k          4K     16     2      0 process stack: linux-cp-itf-process
00007fffcab74000    64k          4K     16     2      0 process stack: udp-ping-process
00007fffcab63000    64k          4K     16     2      0 process stack: vxlan-gpe-ioam-export-process
00007fffcab52000    64k          4K     16     2      0 process stack: ioam-export-process
00007fffcab41000    64k          4K     16     2      0 process stack: ikev2-manager-process
00007fffcab30000    64k          4K     16     2      0 process stack: igmp-timer-process
00007fffcab1f000    64k          4K     16     1      0 process stack: static-http-server-process
00007fffcab0e000    64k          4K     16     1      0 process stack: http-server-process
00007fffcaafd000    64k          4K     16     2      0 process stack: gbp-scanner
00007fffcaaec000    64k          4K     16     2      0 process stack: flowprobe-timer-process
00007fffcaacb000   128k          4K     32     5      0 process stack: dpdk-process
00007fffcaaaa000   128k          4K     32     2      0 process stack: admin-up-down-process
00007fffcaa99000    64k          4K     16     2      0 process stack: send-dhcp6-pd-client-message-process
00007fffcaa88000    64k          4K     16     2      0 process stack: dhcp6-pd-client-cp-process
00007fffcaa77000    64k          4K     16     2      0 process stack: dhcp6-client-cp-process
00007fffcaa66000    64k          4K     16     2      0 process stack: send-dhcp6-client-message-process
00007fffcaa55000    64k          4K     16     2      0 process stack: dhcp6-pd-reply-publisher-process
00007fffcaa44000    64k          4K     16     2      0 process stack: dhcp6-reply-publisher-process
00007fffcaa33000    64k          4K     16     2      0 process stack: dhcp-client-process
00007fffcaa22000    64k          4K     16     2      0 process stack: cnat-scanner-process
00007fffcaa11000    64k          4K     16     2      0 process stack: avf-process
00007fffcaa00000    64k          4K     16     2      0 process stack: acl-plugin-fa-cleaner-process
00007fffca9ef000    64k          4K     16     3      0 process stack: statseg-collector-process
00007fffca9ae000   256k          4K     64     4      0 process stack: api-rx-from-ring
00007fffca99d000    64k          4K     16     2      0 process stack: rd-cp-process
00007fffca98c000    64k          4K     16     2      0 process stack: ip6-ra-process
00007fffca97b000    64k          4K     16     2      0 process stack: ip6-rs-process
00007fffca96a000    64k          4K     16     2      0 process stack: ip6-mld-process
00007fffca959000    64k          4K     16     2      0 process stack: fib-walk
00007fffca948000    64k          4K     16     1      0 process stack: session-queue-process
00007fffca937000    64k          4K     16     2      0 process stack: virtio-send-interrupt-process
00007fffca926000    64k          4K     16     2      0 process stack: vhost-user-process
00007fffca915000    64k          4K     16     2      0 process stack: vhost-user-send-interrupt-process
00007fffca904000    64k          4K     16     2      0 process stack: flow-report-process
00007fffca8f3000    64k          4K     16     2      0 process stack: bfd-process
00007fffca8e2000    64k          4K     16     2      0 process stack: ip-neighbor-event
00007fffca8d1000    64k          4K     16     2      0 process stack: ip6-neighbor-age-process
00007fffca8c0000    64k          4K     16     2      0 process stack: ip4-neighbor-age-process
00007fffca8af000    64k          4K     16     2      0 process stack: ip6-sv-reassembly-expire-walk
00007fffca89e000    64k          4K     16     2      0 process stack: ip6-full-reassembly-expire-walk
00007fffca88d000    64k          4K     16     2      0 process stack: ip4-sv-reassembly-expire-walk
00007fffca87c000    64k          4K     16     2      0 process stack: ip4-full-reassembly-expire-walk
00007fffca86b000    64k          4K     16     2      0 process stack: bond-process
00007fffca85a000    64k          4K     16     2      0 process stack: l2fib-mac-age-scanner-process
00007fffca849000    64k          4K     16     2      0 process stack: l2-arp-term-publisher
00007fffca838000    64k          4K     16     2      0 process stack: vpe-link-state-process
00007fffca7f7000   256k          4K     64     4      0 process stack: startup-config-process
00007fffc95f4000     2m          4K    512     2      0 thread stack: thread 1
00007fffc9420000   256k          4K     64     4      0 process stack: unix-cli-127.0.0.1:38944
00007fffc940f000    64k          4K     16     3      0 process stack: unix-cli-new-session

参考文章:

1、HugePage介绍、实现分析、配置和使用 https://www.cnblogs.com/arnoldlu/p/14028825.html 2、Learning DPDK : Huge pages https://haryachyy.wordpress.com/2019/04/17/learning-dpdk-huge-pages/ 3、Hugepages你用了吗?--原理概念篇 https://blog.51cto.com/hsbxxl/1075166

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-06-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DPDK VPP源码分析 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • vpp Huge page翻译
  • Huge page简介
    • 1、透明大页面
      • 2、持久化大页面
      • 参考文章:
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档