【发布时间】:2021-02-24 19:50:16
【问题描述】:
以下两个代码 sn-ps 中哪一个通常会运行得更快(没有编译器优化)?这段代码只是一个例子——我知道有更快的方法来做同样的计算。
// arr points to the following array: [1,2,4,8,16,32,64]
// assume that it has already been created, so that the
// array creation does not cause a time penalty
int result = 0;
for (int i = 0; i < 7; i++) {
result += arr[i];
}
int result = 0;
for (int i = 0; i < 7; i++) {
result += (1 << i);
}
我很确定内存访问会更慢,但我想确认一下。
编辑:为了澄清这个问题,我对此代码的未优化版本特别感兴趣。不是因为我真的打算在生产中使用这段代码,而是因为我对内存访问或算术是否更快的概念感兴趣。也许我应该用汇编语言而不是 C/C++ 编写代码,以进一步说明我对代码的编译器优化不感兴趣。
一些回复说在大多数情况下内存访问速度较慢,而其他人则说我应该进行基准测试,这取决于我的处理器和系统。
感兴趣的架构是 x86 或 x86-64 - 您可以在 2021 年在现代笔记本电脑或台式计算机中找到这些架构。一旦我在未优化和优化版本上运行了一些基准测试,我将再次编辑这个问题代码。感谢到目前为止所有回复的人。
编辑 2:我在上面两个代码 sn-ps 的变体上运行 gprof,发现平均(经过数十亿次运行后),使用内存访问的计算版本大约需要 2.4 纳秒,而使用内存访问的版本大约需要 2.4 纳秒。使用算术大约需要 1.1 纳秒。这是在 64 位 Linux 计算机上。
运行未优化 (-O0) 并使用 GCC 版本 10.2.0。我还尝试使用 clang 版本 10.0.1,结果如下:内存版本平均为 2.45 纳秒(与 GCC 没有显着差异),算术版本为 1.63 纳秒(明显比 GCC 差,尽管这种差异可能有其他原因......我的基准并不严格,因为它只是为了给出一个粗略的估计)。
我用于基准测试的变体将循环替换为一系列 7 行重复的代码(result += arr[0]; ...、result += (1 << 0); ...),因为我发现循环本身比两种情况下的计算花费的时间要多得多。
我没有为优化运行而烦恼,因为我知道算术版本将优化为单个常量(127 或 0x7F),它实际上只是测试编译器是否足够聪明以优化内存版本。
【问题讨论】:
-
如果您想知道 X 是否比 Y 快,请使用 benchmarker
-
在任何现代处理器上(1990 年左右之后),几乎可以肯定的是,内存访问会比移位慢得多。
-
"...没有编译器优化" - 谁在乎未优化的代码?
-
“没有编译器优化”不仅无趣,而且毫无意义。对于“最佳”的某些特定定义,至少可以将优化的代码视为编译器知道如何生成的最佳代码,但谁能说这与同一编译器可能生成的代码有何不同?。
-
@Agent008 如果您的原始代码无法以相同的方式进行优化,那么对这个问题的任何回答对您来说都是无用的。您必须同时衡量问题、编译器和系统的组合才能得到答案。
标签: c++ c optimization