最近,我正在dpdk(dpdk.org)中阅读有关大页面的代码。我看到代码故意使虚拟地址在物理地址区域中连续。具体来说,它首先检查大页面中是否存在物理连续区域,然后将物理连续区域映射到连续虚拟地址。这如何提高性能?
要保留大量连续的内存,我们使用linux的巨大页面功能。为此,我们需要安装ugeltlbfs。此代码将在此目录中创建许多文件(每页一个),并将它们映射到虚拟内存中。对于每个页面,我们将检索其物理地址并对其进行重新映射,以拥有虚拟的连续区域和物理的连续区域。
为什么需要重新映射?
答案 0 :(得分:1)
将物理上连续的区域映射到连续的虚拟地址。这如何提高性能?
DPDK同时需要物理和虚拟地址。虚拟地址通常用于加载/存储一些数据。物理地址是用户空间驱动程序与设备之间进行数据传输所必需的。
例如,我们分配了几个mbuf
,它们的虚拟地址为0x41000
,0x42000
和0x43000
。然后,我们用一些数据填充它们,并将这些虚拟地址传递给PMD进行传输。
驱动程序必须将这些虚拟地址转换为物理地址。如果物理页面不连续地映射到虚拟地址空间,则要将虚拟地址转换为物理地址,我们需要搜索所有映射。例如,虚拟地址0x41000
可能对应于物理地址0x81000
,0x42000
对应于0x16000
,而0x43000
—对应于0x64000
。
这种搜索的最佳情况是读取一个内存,最坏的情况是每个缓冲区读取几个内存。
但是,如果我们确定存储区的虚拟地址和物理地址都是连续的,则只需在虚拟地址上添加一个偏移量即可获得物理地址,反之亦然。例如,虚拟0x41000
对应于0x81000
,虚拟0x42000
对应于物理0x82000
,以及0x43000
— 0x83000
。
我们从映射中知道的偏移量。这种转换的最坏情况是突发中每个缓冲区读取一个内存,这对于转换是一个巨大的改进。
为什么需要重新映射?
要将大型页面映射到虚拟地址空间,请使用mmap
系统调用。调用的API允许为要映射的大页面指定固定的虚拟地址。这样一来,就可以映射大页面,从而创建一个连续的虚拟内存区域。例如,我们可以在虚拟地址mmap
上0x200000
放置一个大页面,在虚拟地址0x400000
处下一个页面,依此类推。
不幸的是,在映射大页面之前,我们不知道它们的物理地址。因此,我们可以在虚拟地址0x200000
上映射物理地址0x800000
,并在虚拟地址0x400000
上映射物理0x600000
。
但是,当我们第一次映射那些大页面时,我们既知道物理地址又知道虚拟地址。因此,我们要做的就是以正确的顺序重新映射它们::在虚拟地址0x1200000
上,我们映射了物理0x600000
,而在0x1400000
上则映射了物理{{ 1}}。
现在,我们有一个虚拟和物理上连续的存储区,从虚拟地址0x800000
和物理地址0x1200000
开始。因此,要将虚拟地址转换为该存储区中的物理地址,我们只需如上所述从虚拟地址中减去偏移量0x600000
。
希望这可以澄清连续内存区域和重新映射的概念。