将物理上连续的区域映射到连续的虚拟地址。这如何提高性能?
DPDK 需要物理地址和虚拟地址。虚拟地址通常用于加载/存储一些数据。物理地址是用户空间驱动程序向/从设备传输数据所必需的。
例如,我们分配了几个mbuf
带有虚拟地址的0x41000
s0x42000
和0x43000
。然后我们用一些数据填充它们并将这些虚拟地址传递给 PMD 进行传输。
驱动程序必须将这些虚拟地址转换为物理地址。如果物理页面映射到不连续的虚拟地址空间,要将虚拟地址转换为物理地址,我们需要搜索所有映射。例如,虚拟地址0x41000
可能对应于物理地址0x81000
、0x42000
对应于0x16000
和0x43000
- 到0x64000
。
这种搜索的最好情况是一次内存读取,最坏的情况是每个缓冲区读取几次内存。
但是如果我们确定内存区域的虚拟地址和物理地址都是连续的,我们只需在虚拟地址上添加一个偏移量即可获得物理地址,反之亦然。例如,virtual0x41000
对应于0x81000
, virtual 对应0x42000
于 physical 0x82000
,以及0x43000
- 0x83000
。
我们从映射中知道的偏移量。这种翻译的最坏情况是突发中每个缓冲区读取一个内存,这对翻译来说是一个巨大的改进。
为什么需要重新映射?
要将大页面映射到虚拟地址空间,需要mmap
使用系统调用。调用的 API 允许为要映射的大页面指定固定的虚拟地址。这允许一个接一个地映射大页面,创建一个连续的虚拟内存区域。例如,我们可以mmap
在虚拟地址处创建一个大页面,在虚拟地址处创建0x200000
下一个页面0x400000
,以此类推。
不幸的是,我们不知道大页面的物理地址,直到它们被映射。所以在虚拟地址0x200000
我们可以映射物理地址0x800000
,在虚拟地址0x400000
——物理地址0x600000
。
但是一旦我们第一次映射这些大页面,我们就知道物理地址和虚拟地址。所以我们需要做的就是以正确的顺序重新映射它们:在虚拟地址0x1200000
我们映射物理地址0x600000
,在0x1400000
物理地址0x800000
。
0x1200000
现在我们有一个从虚拟地址和物理地址开始的虚拟和物理连续的内存区域0x600000
。因此,要将这个内存区域中的虚拟地址转换为物理地址,我们只需0x600000
要从虚拟地址中减去偏移量,如前所述。
希望这能澄清一下连续内存区域和重新映射的想法。