以前经常遇到2C3G的vmware续集上环境上安装上vpp后,能直接运行,而每次当系统重启后总是报内存不足的问题。当把系统内存调整到4G后,就能正常运行了。一直也不清楚原因。最近工作中遇到一个问题在2c2g的环境上跑vpp,一段时间后,总是报内存不足。后来查询发现hugepage内存大小是1G,但是只使用了不到三分之一的大页内存。
下面虚拟机2C3G环境下启动vpp后使用大页内存的大小。Total-free=22*2M=44M的大页内存。下面是查询大页数量:
[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上使用大页内存的大小:
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在运行期间需要大页内存。在VPP安装过程中,VPP将覆盖现有的巨页设置。缺省情况下,VPP将系统的大页数设置为1024*2m大页。这是系统上的大页面数量,而不仅仅是VPP使用的。 安装VPP后,会将vpp配置文件src/vpp/conf/80-vpp.conf拷贝到系统中/etc/sysctl.d/目录下。大页设置应用于VPP安装和系统重新启动时。使用下面的实例设置大页设置。
[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有足够的大页面支持。----可以解释开头的疑问了。
现代的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/
使用HugePage的优点:
1、系统使用HugePage则内存页数量会减少,从而需要更少的页表,节约了页表所占用的内存数量。
2、所需的地址转化也减少了,TLB缓存失效的次数也减少了,从而提高内存访问的性能。
3、地址转换所需信息一般保存在CPU缓存中,HugePage使用让地址转换信息减少,减少了CPU缓存的使用。
4、HugePage页面是不支持swap的,所以没有page table lookups。所以大内存情况下,kswapd也不会频繁被调用。
当然HugePage在某些场景下也存在缺点:
当申请一块大内存,但是使用内存并不多,比如:每个2MB,写4KB内容。
使用HugePage就会导致实际占用的物理内存相对于4KB页面大很多。
Linux 中有两种类型的大页面可用。透明(匿名)大页面和持久化大页面。
透明大页面是一个抽象层,可以自动化创建、管理和使用大页面的大多数方面。就性能和稳定性方面存在的一些问题而言,DPDK不依赖这种机制,而是使用持久化大页面。
必须手动配置持久性大页面。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 套接字之间平均分布。
GRUB_CMDLINE_LINUX="default_hugepagesz=1G hugepagesz=1G hugepages=32"
#更新 grub 配置文件并重新启动。
grub2-mkconfig -o /boot/grub2/grub.cfg
reboot
为hugetlbfs 的永久挂载点创建一个文件夹
mkdir /mnt/huge
#将以下行添加到 /etc/fstab 文件中:
nodev /mnt/huge hugetlbfs defaults 0 0
在运行时 更新每个 NUMA 节点的大页面数量。无法在运行时修改默认大页面大小。
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
可以通过命令查询大页内存挂载点
[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来管理内存的。可以通过命令行查询。
##默认会申请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
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页大小申请。
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内存使用情况
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
本文分享自 DPDK VPP源码分析 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!