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