【发布时间】:2020-09-18 12:59:46
【问题描述】:
主要来自 Python 背景,我现在正在学习 C 和 x86-64 汇编。我以前通过 Cython 间接使用过 C,但现在除了汇编之外,我还在学习 C。
我的基本问题是,在优化编译器时,我应该把自己放在什么样的心态上。我应该让编译器完成它的工作,但是一旦我足够精通汇编,就开始检查并确认汇编输出吗?这就是想要编写高性能代码的负责任的 C 程序员所做的吗?
问题被触发是因为我想检查gcc 7.5.0 将优化下面的代码。特别是,我运行了objdump 来了解如何在不同级别上优化在同一索引处访问一个数组两次。
- 在
-O3上有一些我还没有学过的指令,例如movaps XMMWORD PTR [rsp+0x10],xmm0 -
-O2和-O1的关卡比较清晰,但我还是没有完全理解 - 在
-O0级别我相信我可以看到代码的相当简单的翻译,我认为messages[idx]确实被访问了两次
我的问题不是什么时候应该使用这些级别。我只是问更有经验的程序员,如果这就是你所做的,运行高度优化的代码并检查汇编输出以确保一切都符合预期?对于想要真正了解编译器生成什么机器代码的人来说,这是自然的工作流程吗?
我知道下面的示例是一种微不足道的优化机会,但您是否刚刚了解到某些优化肯定会发生并且您不再考虑它们?关于可以进行什么样的转换和优化的信息并不多,更不用说编译器没有留下任何注释或消息让程序员了解优化的内容和原因,所以我无法想象除了简单的其他方式在实践中学习这一切。谢谢。
#include <stddef.h>
#include <stdio.h>
int main(int argc, char ** argv)
{
size_t len_messages = 9;
int messages[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
for(size_t idx=0; idx < len_messages; idx++) {
printf("Accessing here %d and there %d\n", messages[idx], messages[idx]);
}
return 0;
}
【问题讨论】:
-
我认为这取决于你工作的环境。我根本不考虑优化——我只是说
-O3并让编译器做它的事情——除非有似乎是个问题。而且在我的领域中很少有——编译器通常会生成非常好的代码。在许多领域,我怀疑你必须更加积极主动。老实说,我怀疑你会对此发表意见,但没有明确的答案。 -
我很少看汇编代码,尽管我非常关心优化。看两块汇编代码并说:这比那快——现代处理器非常复杂,这绝非易事。此外,性能的一个关键决定因素是程序与内存系统(所有这些缓存!)的配合程度,这通常更容易从更高级别的视图中看到。对我来说,我怀疑其他许多人,优化的时间都花在查看分析器输出和尝试更高级别的“算法”上
-
您应该首先通过探查器运行代码,而不是手动检查程序集。寻找热点,然后首先关注这些领域的算法复杂性、缓存一致性等。只有在您确信您的设计是最佳的之后,您才应该查看装配(如果那时仍然需要)。
-
只有疯狂(或不幸)的人才会查看他们编写的所有高级语言代码的程序集。
-
阅读this draft report。与您的问题相关的十几页