为不同的处理器编译时,程序可以使用显着更少的内存吗?

问题描述

我有一个正在为 AMD64 编译的 C++ 程序。当然,不同的处理器,尽管是 AMD64,但支持不同的特性和指令,因为它们实现了不同的微体系结构。为自己的机器优化程序的一种简单方法是在 Clang 或 GCC 中仅使用 -march=native,但这对于分发来说不是很便携。更便携的解决方案是挑选特定的目标特征。

这显然会影响性能(有些处理器支持 AVX-512,有些不支持,有些支持 AVX2,有些不支持,等等),但是这会影响内存使用(堆/堆栈,而不是代码大小)吗?重要的方式?

解决方法

不同的对齐规则或类型宽度是获得差异的两种主要方式,但 -march= 不会改变这一点,在相同的 ISA 上为相同的 ABI 编译时不会改变。 (否则 -march=skylake-avx512 代码无法调用 -march=sandybridge 代码,反之亦然,如果它们在结构布局上存在分歧。)

针对不同的 ABI 进行编译可以节省空间,尤其是在大量指针的数据结构中。具体来说,像 Linux x32 这样的 ILP32 ABI 有 4 个字节的指针而不是 8 个,所以 struct foo { foo *next; int val; }; 是 8 个字节而不是 16 个(填充后使 sizeof(foo) 成为 alignof(foo)它继承自需要 8 字节对齐的指针)。但这不适用于您的 100GB 数据用例; 32 位指针将您限制为 4GiB 的地址空间。


在自动矢量化时,

-march= 可能会对 stack 空间产生一些小的影响。例如一个函数可能会将堆栈对齐 64,以便溢出/重新加载 ZMM 向量。 或者使用较旧的 GCC,即使最终的 asm 没有实际存储或加载任何向量到堆栈帧,也要对齐。但这最多是每级函数嵌套额外浪费 56 字节的堆栈空间,而 16 字节对齐可以作为调用约定的一部分免费使用。

GCC / clang 的优化器不会 AFAIK 做任何改变动态分配大小的优化。 Clang 有时可以完全在一个函数中优化掉动态分配,例如创建和销毁 std::vector<float> foo(100); 并且可以优化掉对它的所有访问。 (例如,将常量存储到向量中,然后将它们读回,它可以将其优化掉,然后也消除分配。或者甚至没有使用的 std::vector。)

如果您最终分配了一些内存页面但未完全使用,则可能是另一个更擅长减少内部碎片的分配器库可以节省空间。但这不是-march=影响的东西。