【问题标题】:Counting overhead due to packing in C (gcc/g++)由于在 C (gcc/g++) 中打包导致的计算开销
【发布时间】:2011-07-12 06:53:36
【问题描述】:

我想计算/总结由于打包导致的目标文件中的开销(理想情况下,让 gcc 为我将其最小化)。

例如,考虑以下结构(32 位 x86,gcc):

struct a { 
    uint8_t a_char;
    uint32_t an_integer
    uint8_t another_letter;
};

虽然实际数据只占用 6 个字节,但该结构在内存中占用 12 个字节,因为两个字符后面都跟着 3 个填充字节。通过重新排序结构如下:

struct b { 
    uint32_t an_integer
    uint8_t a_char;
    uint8_t another_letter;
};

该结构将只有 sizeof(struct b) == 8(仍然是 4 个字节的开销)。

(1) 理想情况下,我希望 gcc 将 struct a 重新排列为 struct b 并节省空间,但我的版本 (4.2) 似乎没有针对任何优化级别执行此操作。

(2) 或者,给定struct a,我想(自动)获得数字6(总开销)或4(最小开销,如果成员按“理想情况下”排序”)。这样做的目的是确定手动重新排序结构是否值得花时间(可能不值得)。

gcc 有没有办法执行 (1),是否有工具可以执行 (2)?对于(1),我能想到的最接近的事情是#pragma pack(1),但是(我猜)它会通过使大多数/所有内存访问不对齐而对性能产生严重影响。对于(2),我认为解析调试符号的 Perl 脚本可能能够做到这一点,但我对 DWARF 不够熟悉,无法确定。

【问题讨论】:

  • AFAIK 未对齐内存访问与对齐访问一样快;只是编译器没有对它们进行一些优化。
  • 未对齐的内存访问会导致 SIGBUS 具有 4 或 8 字节类型 - 它们很重要。
  • @Mehrdad:某些架构对未对齐的内存访问零容忍,并且在发生这种情况时会抛出硬件异常。在这种情况下,操作系统会拦截它们并在软件中模拟未对齐的内存访问,这比对齐的访问要慢得多。即使在 x86 等“未对齐访问容忍”架构上,未对齐访问也较慢,并且某些指令(例如 SIMD)具有严格的对齐要求。
  • @Mehrdad,在 x86 上 is 尽管是相同的指令,但对齐与未对齐的性能差异(这取决于您的代码)。 CPU 只是有更多的工作要做——尤其是当您跨越缓存线边界时。更重要的是,关于原子性的某些保证仅适用于对齐值。
  • 真的,有多难?一个天真的解决方案是只编写所有结构,其元素按尺寸递减排序......您实际上并不需要工具来为您执行此操作。

标签: c++ c gcc alignment packing


【解决方案1】:

对于#1,未完成的原因是 C 和 C++ 标准都禁止结构成员重新排序。

是的,结构打包通常会降低性能。而且,正如评论中提到的,在某些情况下,在非 x86 架构上,如果您尝试对成员进行操作,您可以获得 SIGBUS。

对于#2,是的,一个 perl 脚本可能能够做到这一点。除了解析 DWARF 信息之外,您还可以尝试扫描源代码中的结构定义,并可能生成一些小型测试程序来检查结构和成员的 sizeof() 等等。

【讨论】:

  • 1 - 你说得对,我找到了。 “在结构对象中,非位域成员和位域所在的单元的地址按照声明的顺序增加。” -open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf。叹。谢谢。
  • 可以补充一点,即使它可以重新排序也可能无济于事,因为它必须每个成员在放入数组时仍然必须满足对齐要求,以及堆栈上的各种顺序。
  • 另一个需要考虑的性能问题是,在某些情况下,对结构元素重新排序可能会导致缓存/内存访问模式不太理想,从而导致性能更差,即使总共使用了更少的内存.
【解决方案2】:

在 linux 中有一个名为 pahole 的工具,它可以解析带有调试信息的 ELF 文件,并为每个结构打印输出每个成员的对齐方式以及编译器完成了多少填充。如果您发现开销过多,可以使用该信息来指导您手动打包。

【讨论】:

    【解决方案3】:

    这并不总是可以做到,问题是所有架构都不允许访问未对齐的内存。这也简化了编译器的一些代码,允许优化对内存本身的某些访问。此外,重组结构可能不值得您花时间,因为每个结构 4-8 字节的开销并不是什么大问题,除非您正在运行对内存非常敏感的软件。至于您的问题,我不确定是否有办法,但我确定是否有人知道他们会通知您(也许具有最高优化标志的 gcc-4.6 可以吗?)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-20
      • 1970-01-01
      • 2021-03-10
      • 1970-01-01
      • 2012-07-18
      • 1970-01-01
      相关资源
      最近更新 更多