现代cpus如何处理跨页不对齐访问?

Iva*_*ves 6 linux arm x86-64 memory-alignment mmu

我试图理解未对齐的内存访问(UMA)如何在现代处理器(即x86-64和ARM体系结构)上工作.我知道我可能遇到UMA问题,从性能下降到CPU故障.我阅读posix_memalign并缓存行.

我找不到的是当我的请求超出页面边界时,现代系统/硬件如何处理这种情况?

这是一个例子:

  1. malloc()是一块8KB的内存.
  2. 假设malloc()没有足够的内存和sbrk()8KB的话.
  3. 内核获取两个内存页(每个4KB)并将它们映射到我的进程的虚拟地址空间(假设这两个页面在内存中不是一个接一个)
  4. movq (offset + $0xffc), %rax 我从第4092字节开始请求8个字节,这意味着我需要从第一页末尾开始的4个字节和从第二页开始开始的4个字节.

物理内存:

---|---------------|---------------|-->
   |... 4b|        |        |4b ...|-->
Run Code Online (Sandbox Code Playgroud)

我需要在页面边界分割的8个字节.

x86-64和ARM上的MMU如何处理这个问题?内核MM中是否有任何机制以某种方式为这种请求做准备?是否有某种保护malloc?处理器做什么?他们取两页吗?

我的意思是完成这样的请求MMU必须将一个虚拟地址转换为两个物理地址.它如何处理这样的请求?

如果我是软件程序员,我应该关心这些事情吗?为什么?

我正在阅读谷歌,SO,drepper的cpumemory.pdf和gorman的Linux VMM书中的很多链接.但它是一个信息的海洋.如果您至少向我提供一些我可以使用的指针或关键字,那将会很棒.

Not*_*hat 5

我不太熟悉 Intel 架构的内部结构,但 ARM 架构在“未对齐的数据访问限制”下用一个要点总结了这一具体细节:

  • 执行未对齐访问的操作可以在其进行的任何内存访问中中止,并且可以在多个访问中中止。这意味着跨页边界发生的未对齐访问可能会在边界的任一侧生成中止。

因此,除了可能从单个操作生成两个页面错误之外,这只是另一个未对齐的访问。当然,这仍然假设“只是另一个未对齐的访问”的所有警告 - 即它仅在正常(而非设备)内存上有效,仅适用于某些加载/存储指令,无法保证原子性并且可能很慢 - 微体系结构将可能会从多个对齐访问中合成一个未对齐访问1,这意味着多个 MMU 转换,如果跨越行边界,则可能会发生多个缓存未命中等。

从另一个角度来看,如果未对齐的访问不会跨越页面边界,则意味着如果第一个“子访问”的对齐地址转换正常,则任何后续部分的对齐地址肯定会命中在 TLB 中。MMU 本身并不关心——它只是转换处理器提供给它的一些地址。除非 MMU 引发页面错误,否则内核甚至不会参与进来,即使如此,它也与任何其他页面错误没有什么不同。

我快速浏览了一下英特尔手册,他们的答案并没有跳出来——但是在“数据类型”一章中他们确实指出:

[...]处理器需要两次内存访问才能进行未对齐的访问;对齐访问仅需要一次内存访问。

因此,如果不是大致相同(即每个对齐访问一个翻译),我会感到惊讶。

现在,这是大多数应用程序级程序员不必担心的事情,只要他们自己表现良好 - 在汇编语言之外,实际上很难发生未对齐的访问。可能的罪魁祸首是类型双关指针和混乱的结构打包,这两件事在 99% 的情况下没有理由接近,而对于另外 1% 的情况来说,几乎肯定仍然是错误的做法。


[1] ARM 架构伪代码实际上将未对齐访问指定为一系列单独的字节访问,但我希望实现实际上在适当的情况下将其优化为更大的对齐访问。