使物理地址区域中的虚拟地址连续如何提高性能?

How does making the virtual address contiguous in physical address zone improve performance?

最近在看dpdk(dpdk.org)中关于hugepage的代码。我看到代码故意使虚拟地址在物理地址区域中连续。具体来说,它首先检查hugepages中是否存在物理上连续的zone,并将物理上连续的zone映射到连续的虚拟地址上。这如何提高性能?

source code 说:

To reserve a big contiguous amount of memory, we use the hugepage feature of linux. For that, we need to have hugetlbfs mounted. This code will create many files in this directory (one per page) and map them in virtual memory. For each page, we will retrieve its physical address and remap it in order to have a virtual contiguous zone as well as a physical contiguous zone.

为什么需要重新映射?

map the physically contiguous zone into contiguous virtual address. How does this improve the performance?

DPDK 需要物理地址和虚拟地址。虚拟地址正常使用,到load/store一些数据。用户space 驱动程序传输数据 to/from 设备需要物理地址。

比如我们分配几个mbuf,虚拟地址为0x410000x420000x43000。然后我们用一些数据填充它们并将这些虚拟地址传递给PMD进行传输。

驱动程序必须将这些虚拟地址转换为物理地址。如果物理页面映射到虚拟地址 space 不连续,要将虚拟地址转换为物理地址,我们需要搜索所有映射。例如,虚拟地址 0x41000 可能对应于物理地址 0x810000x42000 对应于 0x16000,而 0x43000 — 对应于 0x64000.

这种搜索的最佳情况是一次内存读取,最坏的情况是 — 每个缓冲区读取几次内存

但是如果我们确定内存区域的虚拟地址和物理地址是连续的,我们只需在虚拟地址上加上一个偏移量就可以得到物理地址,反之亦然。例如,虚拟 0x41000 对应 0x81000,虚拟 0x42000 对应物理 0x82000,并且 0x430000x83000.

我们从映射中知道的偏移量。这种翻译的最坏情况是突发中每个缓冲区读取一次内存,这对翻译来说是一个巨大的改进。

Why is this remapping necessary?

要将大页面映射到虚拟地址 space,需要使用 mmap 系统调用。调用的 API 允许指定要映射的大页面的固定虚拟地址。这允许一个接一个地映射大页面,创建一个 连续的虚拟内存区域 。例如,我们可以mmap虚拟地址0x200000的一个大页面,下一个虚拟地址0x400000的大页面等等。

不幸的是,在映射之前我们不知道大页面的物理地址。因此,在虚拟地址 0x200000 处,我们可以映射物理地址 0x800000,并在虚拟地址 0x400000 处映射物理地址 0x600000.

但是一旦我们第一次映射了那些大页面,我们就知道了物理地址和虚拟地址。所以我们 需要做的就是以正确的顺序重新映射它们: 在虚拟地址 0x1200000 我们映射物理地址 0x600000,在 0x1400000 —物理 0x800000.

现在我们有一个虚拟和物理连续的内存区域,从虚拟地址 0x1200000 和物理地址 0x600000 开始。因此,要将此内存区域中的虚拟地址转换为物理地址,我们只需要从虚拟地址中减去偏移量 0x600000,如前所述。

希望这能稍微阐明连续内存区域和重新映射的概念。