当为不同的处理器编译时,程序是否可以使用(显著)更少的内存



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

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

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

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


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

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

如果您最终分配了一些内存页但没有完全使用,那么一个更善于减少内部碎片的不同分配器库可能会节省空间。但-march=并没有影响到这一点。

相关内容

最新更新