5

如何在 C 中获取 CPU 的内存粒度

假设我想分配一个数组,其中所有元素都正确对齐内存。我可以将每个元素填充到一定大小 N 来实现这一点。我怎么知道N的值?

注意:我正在尝试创建一个内存池,其中每个插槽都是内存对齐的。任何建议将不胜感激。

4

3 回答 3

2

理论上

如何在 C 中获取 CPU 的内存粒度?

首先,您阅读指令集架构手册。它可以指定某些指令需要某些对齐,甚至某些指令中的寻址形式不能表示未对齐的地址。它可以指定有关对齐的其他属性。

其次,您阅读处理器手册。它可以指定性能特征(例如支持未对齐的加载或存储,但可能比对齐的加载或存储更慢或使用更多资源),并且可以指定指令集架构允许的各种选项。

第三,阅读操作系统文档。一些体系结构允许操作系统选择与对齐相关的功能,例如是否使未对齐的加载和存储失败或受支持,尽管性能比对齐的加载或存储慢。操作系统文档应包含此信息。

在实践中

对于许多编程情况,您需要知道的不是 CPU 的“内存粒度”,而是您使用的 C 实现(或您使用的任何语言)的对齐要求。而且,在大多数情况下,您不需要直接了解对齐要求,而只需要遵循有关管理对象的语言规则——使用具有声明类型的对象,不要使用强制转换在不兼容类型之间转换指针,超出特定规则允许的范围它,使用适当对齐的内存,malloc而不是调整你自己的字节指针,等等。遵循这些规则将为程序中的对象提供良好的对齐。

在 C 中,当您定义一个数组时,元素大小将自动成为 C 实现对其对齐所需的大小。例如,long double x[100];可以为每个数组元素使用 16 个字节,即使硬件仅使用 10 个字节来存储long double. 或者,对于struct foo您定义的任何内容,编译器将根据需要在结构中自动包含填充以提供所需的对齐方式,并且任何数组struct foo x[100];都已经包含该填充。sizeof(struct foo)将与 相同sizeof x[0],因为每个结构对象都有内置的填充,即使只是针对单个结构对象,而不仅仅是针对数组中的元素。

当您确实需要知道 C 实现对类型所需的对齐方式时,您可以使用 C 的_Alignof运算符。该表达式_Alignof(type)提供 所需的对齐方式type

其他

…正确的内存对齐。

正确对齐是度数问题:

  • 处理器支持的内容可能决定您的程序是否有效。不正确的对齐会导致您的程序陷入陷阱。
  • 对于单个加载和存储而言,什么是有效的可能会影响程序运行的速度。不正确的对齐会导致您的程序执行得更慢。
  • 在某些性能关键的情况下,缓存和内存映射特性的对齐也会影响性能。
于 2020-06-07T13:40:47.080 回答
1

简短的回答

使用 64 字节。

长答案

数据以称为高速缓存行的单元从内存中加载和存储。如果您的程序仅在缓存行中加载部分数据,则整行将被加载到 CPU 缓存中。也许更重要的是,用于在多核 CPU 中的核之间移动数据的算法在完整的高速缓存行上运行。将数据与缓存行对齐可以避免错误共享,即缓存行在内核之间反弹的情况,因为它包含由不同线程操作的数据。

过去,缓存行取决于架构,从 16 字节到 512 字节不等。但是,所有当前的处理器(Intel、AMD、ARM、MIPS)都使用 64 字节的高速缓存行。

于 2020-06-07T14:18:03.260 回答
0

这在很大程度上取决于您使用的 cpu 微架构。

在很多情况下,操作符的内存地址应该是操作数大小的倍数,否则执行会很慢(甚至可能抛出异常)。

但也有一些 CPU 根本不关心内存中操作数的特定对齐方式。

通常,C 编译器会为您关心这些细节。但是,您应该确保编译器采用正确的目标(微)架构,例如通过使用正确的编译器标志(-march=?在 gcc 上)指定它。

于 2020-06-07T13:21:52.013 回答