37

DPDK内存篇(三):17.11及早期版本

 3 years ago
source link: https://www.sdnlab.com/24517.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

导读

这是关于数据面开发套件(DPDK)内存管理功能系列文章的第三篇。本系列的第一篇文章描述了DPDK基础的基本概念。第二篇文章深入介绍了输入输出虚拟地址(IOVA)和适用于所有DPDK版本的内核驱动程序。本文概述了DPDK版本中可用的内存管理工具,包括17.11版本。

DPDK17.11是(目前)仍然支持的最早的长期支持(LTS)版本。因此,描述DPDK 17.11提供的内存管理功能不仅为DPDK内存管理功能的发展提供了宝贵的历史视角,而且对许多使用这些较旧但仍受支持的版本的DPDK消费者有所帮助。

从内存管理的角度来看,18.11之前的LTS版本表现完全相同,因此,除非另有说明,否则关于17.11版本的所有内容也适用于任何早期DPDK版本。本文中涉及的一些概念已在本系列的第1篇和第2篇文章中介绍过,因此也请阅读这些文章。

作者简介

Anatoly Burakov:英特尔软件工程师,目前在维护DPDK中的VFIO和内存子系统。

为DPDK提供标准大页内存

为了使应用程序访问大页内存,Linux*使用了一个特殊的hugetlbfs文件系统。因此,为了利用标准大页,DPDK 17.11必须使用hugetlbfs文件系统挂载点。因为大页可以有不同的大小,hugetlbfs 挂载点可以提供对不同大小页面的访问,具体取决于它的配置方式。如果未明确指定特定hugetlbfs挂载点的大页大小,则它使用默认的大页大小,该大小通过内核命令行设置(或者是如果在启动时未指定默认的大页大小,则设置为某个默认值)。

在许多当前发行版中,默认情况下通过systemd可以使用hugetlbfs挂载点,在少数情况下(例如开发或调试),只有一个默认挂载点就足够了。用户也可以选择通过编辑/etc/fstab创建自己的hugetlbfs挂载点。如何设置hugetlbfs挂载点,设置默认大页大小以及保留标准大页超出了本系列文章的范围,但是有关如何执行这些操作的相关指南可以在DPDK文档以及Linux发行版文档中找到。

使用DPDK管理大页内存

一旦系统被设置为为应用程序使用保留大页,DPDK就可以使用它。默认情况下,如果没有指定与内存相关的环境抽象层(EAL)命令行参数,DPDK应用程序将占用任何它可以从系统中获得的标准大页。这是一个很好的默认设置,因为它可以令DPDK很容易地开始使用,

而且使用所有可用的大页内存可能对开发环境和提升场景有利。但这可能不适用于多个应用程序可能需要大页的生产环境。要解决此问题,可以使用-m EAL命令行开关指定DPDK应用程序被允许使用多少大页内存:

./app -m 64

此EAL参数将DPDK的内存使用限制为64MB(向上舍入到最小可用页面大小)。对于具有非统一内存访问(NUMA)支持的系统,提供此参数会尝试将所请求的内存量分散在所有可用的NUMA节点上。例如,给定双插槽系统,上述命令将在NUMA节点0和1上各保留32 MB。

但是,内存并不总是平均分配到所有NUMA节点上;实际上,分配给每个NUMA节点的内存量是按照coremask中特定NUMA节点上的CPU核心数量成比例计算的。默认coremask包括所有可用内核,每个NUMA节点上的内核数通常是相等的,因此在默认情况下内存将平均分配。如果coremask在NUMA节点0上有六个核心而在NUMA节点1上有两个核心,那么内存的分配方式会有所不同:NUMA节点0上有48MB和NUMA节点1上有16MB。类似地,如果coremask中的NUMA节点0上没有核,则上述命令将所有64 MB 分配在NUMA节点1上。

如果每个NUMA节点分配需要更精细的控制,怎么办?DPDK有另一个EAL命令行标志专用于这个用例— socket-mem标志:

./app —socket-mem 0,64

使用此标志,可以指定任何每NUMA节点内存要求。如果未指定特定NUMA节点的内存量,则假定该值为0; 例如,在双插槽系统上,提供—socket-mem64将在NUMA节点0上保留64 MB,而在NUMA节点1上不保留任何内容。

要预留多少内存

使用DPDK库17.11版本或更早版本的任何应用程序必须事先知道其内存要求。这是因为,对于这些版本的DPDK,在初始化之后不可能再申请额外的大页内存,或者将其释放回系统。因此,DPDK应用程序可能使用的任何内存都必须在应用程序初始化时预留,并在应用程序的整个生命周期都由DPDK保留。

在决定要保留的内存量时,留出一些余量通常是个好主意。在各种内部分配中,某些DPDK内存将在不同的内部分配中被“浪费”,数量会因您的配置而异(DPDK将使用的设备数量,启用功能等)。

此外,DPDK17.11中的大多数API都需要大量的IOVA连续内存。这是因为在DPDK 17.11中,虚拟内存布局总是与物理内存布局相匹配。换句话说,如果内存区域是VA连续的,它也会是IOVA连续的。这是DPDK17.11内存管理中众所周知的问题之一:实际上很少有应用程序需要IOVA连续内存,但是没有它也无法使用VA连续内存,由于缺少足够的IOVA连续内存,分配大量内存可能会失败。

1.webp

图1. IOVA模式的比较

上述限制当然仅适用于作为物理地址(PA)模式的IOVA,因为在该模式下,DPDK的虚拟地址(VA)空间遵循PA空间的布局。在PA模式的IOVA中,可用IOVA连续内存量取决于DPDK控制之外的许多因素,尽管DPDK将尝试保留尽可能多的IOVA连续内存,具体取决于可用内存量和系统配置,可能没有足够的IOVA连续内存来满足所有分配。

在VA模式的IOVA中,这不是问题,因为在这种情况下,IOVA空间布局将与VA空间的布局相匹配(而不是相反),并且所有物理内存都被重新映射为IOVA连续到硬件。

DPDK中的大页内存使用

一旦DPDK启动,有许多方法可以在用户应用程序中使用DPDK提供的内存。在DPDK中,大多数情况下,可用内存将固定到NUMA节点。然后,用户可以选择在特定NUMA节点上分配内存(通过在分配时指定NUMA节点ID作为API参数),或者让DPDK自己决定使用特殊值作为NUMA节点ID来分配内存。

为了分配DPDK提供的数据结构,例如哈希表,Mempool,环形缓存等,API会自动使用适当的内存分配方法。例如,对一个rte_ring数据结构分配的调用,API会调用适当的内存分配过程,因此在这种情况下不需要显式调用任何内存分配API。

对于一般的内存申请,DPDK提供了自己的一组API,这些API反映了glibc malloc()函数。还有这些API的NUMA感知版本。C程序员应该对这些API非常熟悉。使用DPDK内存管理的所有好处(例如显式NUMA节点局部性,更少的TLB查询失败,对齐等),将适用于使用这些API分配的任何内存。

除此之外,DPDK还提供了rte_memzone系列API,允许分配满足大小,对齐和边界以及NUMA节点和页面大小要求的原始内存区域。内存区域也必须具有独一无二的名称,因为可以通过它们的名称进行查找。这些API主要由数据结构,驱动程序等在内部使用,通常不在应用程序代码中使用。

2.webp

表1.分配API的决策图

DPDK数据结构,相应的数据结构分配API(如果存在),否则为rte_malloc

在DPDK 17.11及更早版本中,所有DPDK内存分配,无论它们如何执行,都是VA和IOVA连续的。所有内存分配API也是线程安全的,并且因为内存也在所有主进程和辅助进程之间共享,在进程之间传递指针,以及在不同进程中分配或释放内存,是非常安全的。

其他与内存相关的功能

除上述内容外,EAL还提供了一些专门性功能,在一般情况下无用,但在某些情况下可以派上用场。

(1) 在没有标准大页支持的情况下运行DPDK

EAL提供的功能之一是一个非庞大的模式,可通过指定—no-huge EAL命令行标志来实现。这使得DPDK不需要(或使用)大页内存初始化,而是使用常规内存。这通常仅用于调试目的(例如运行某些单元测试),因为除非使用VA模式的IOVA,否则数据包IO将无法工作。—socket-mem开关在此模式下无效,但是-m开关仍指定DPDK在启动时应保留多少内存。

(2)设置自定义大页文件系统挂载点

EAL提供的另一个功能是使用—huge-dir命令行参数设置自定义hugetlbfs挂载点。如果用户具有相同页面大小的hugetlbfs的多个挂载点,则结果可能是不可预测的,因为这不是DPDK操作的预期环境。指定DPDK的一个特定挂载点以解决该问题,尽管一次只有一个这样的挂载点可以使用。

(3)从文件系统中删除大页

最后,最有用的选项是—huge-unlink。默认情况下,只要DPDK初始化,它就会在hugetlbfs挂载点中创建并存储所有大页文件,并且不会在退出时删除它们。因此,当DPDK应用程序退出时,那些大页在内核方面仍然使用(即使DPDK已经关闭),并且为了将它们释放回系统,需要从文件系统中删除这些文件。这种行为是有意的,因为它允许在主DPDK进程退出后,辅助进程也能初始化并附加到内存(并继续正常工作)。

—huge-unlink选项使得在初始化时,hugetlbfs挂载点中的大页文件被创建,映射,然后立即被删。DPDK将继续保留分配的大页,但在hugetlbfs文件系统中不再有文件遗留,因此在DPDK应用程序退出后没有任何东西可以清理。不言而喻,这个选项牺牲了辅助进程支持(因为没有可以在初始化时发现的共享内存),但也有许多DPDK用例乐于使用该选项。

结论

本文概述了DPDK 17.11及更早版本中可用的内存管理功能,并提供了可使特定用例充分利用DPDK的各种选项。

这是DPDK内存管理系列文章的第三篇文章。第一篇文章概述了DPDK内存管理子系统基础中的关键原则。第二篇文章深入介绍了DPDK如何处理物理地址。下一篇也即最后一篇文章将概述DPDK 18.11或更高版本中可用的新内存管理功能。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK