C/C++ - posix_memalign()

6
我做了一些缓存未命中优化的阅读,发现了这个stdlib函数。它对内存进行某种对齐以进行优化,但能否有人帮我解释一下这个函数究竟是做什么的呢?它需要三个参数:void* * memptr, size_t alignment, size_t size
我不明白的部分是文档中的下面这句话:

"allocated size byte aligned on a boundary specified by alignment..."

从阅读中我所理解的是,该函数会分配一个大小为size的内存块,但之后我不明白他们所说的"boundary"是什么意思……难道是将内存块分割成大小为alignment的小块吗?
以下是文档链接:http://www.opengroup.org/onlinepubs/9699919799/functions/posix_memalign.html
1个回答

10

我读了一些有关缓存未命中优化的内容,并了解到了这个stdlib函数。它做了一些内存对齐以进行优化,但是有没有人能帮我解释一下这个函数到底是干什么的?

这个函数的主要目的是分配一个按页面大小对齐的缓冲区。通常不是为了提高性能而做的,而是因为需要适用于设备驱动程序/直接硬件访问的缓冲区。

大部分性能与内存对齐问题已经被编译器自身解决了。例如,所有基本类型 - char、short、int、long - 已经按其“自然对齐”位置位于内存中(或在结构体内)。变量(或结构体字段)的地址可被该变量的大小整除以实现自然对齐。为此使用了填充(padding)。例如,在char a; int b;中,a之后会添加sizeof(char)-sizeof(int)字节,以确保b的地址对sizeof(b)进行了对齐。

我不懂他们所说的“边界”是什么意思...是将内存块划分为大小为对齐的块吗?

硬件设备(尤其是非PCI设备)通常将内存视为N字节的块,并且一次只能访问N字节。在这个上下文中,“边界”意味着块的开始,就像“块边界”一样。

现在,不情愿地提到对性能的影响。记住,过早地优化是万恶之源。这些技巧高度依赖于平台和CPU的特定性,因此通常不应该使用:

  • 在某些情况下,希望进行页面大小对齐以提高数据定位性。将虚拟地址转换为物理RAM位置的CPU维护缓存。代码访问的页面越少,对CPU产生的压力就越小(大多数操作系统已尝试优化应用程序的页面布局,以最小化虚拟到物理地址转换的开销)。如果您知道非常频繁访问的结构适合单个页面,则可能建议将其放入页面对齐的存储中,以确保它包含在单个页面内。 malloc()不提供保证,并且可能使结构体从一个页面开始,结束于另一个页面-跨越页面边界-因此占用两个TLB条目而不是所需的单个条目。如何查找页面大小

  • 缓存行对齐。虽然应用程序可以按字节寻址内存,但CPU实际上只能访问块状的物理RAM,通常称为“缓存行”。这是物理RAM的最小可寻址单元。通过利用结构的缓存行对齐,旨在最小化代码的缓存占用和缓存未命中。DRAM/DDR的缓存行大小为16字节。如果平台的内存控制器具有更宽的数据总线并且并行访问多个内存模块,则可以更大(32或64字节)。同样适用于页面对齐的逻辑也适用于此处:例如,如果您将经常作为一组访问的结构字段放在一起,并与缓存行大小对齐,则可以大大减少数据的缓存占用。最简单的例子是std::map<struct aaa*,void *>。如果struct aaa包含许多字段,则为了最小化缓存占用,人们会将所有用于比较(键字段)的字段放在结构的开头。如果关键字段分散在整个结构中,则比较最坏情况下会涉及每个关键字段一个缓存行。如果关键字段在结构的开头分组,则比较可能会触及更少的缓存行。数据需要较少的缓存行,留给应用程序余下的缓存就越多。但是,一般情况下,应用程序无法访问缓存行大小,尽管可以通过利用各种技巧找到它。

为了保持相对简短,我省略了许多细节。如果想了解更多信息,则建议阅读一些CPU手册。例如,英特尔有相当不错的开发者手册


1
@jaunt,是的,时间过得很快。只需谷歌“intel开发者手册”即可。当前版本似乎称为“Intel(R)64和IA-32体系结构开发人员手册”。 - Dummy00001
我不认为页面边界对齐是主要目的:缓存行对齐更为重要。它有助于矢量指令和预取流。 - Victor Eijkhout

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接