【发布时间】:2015-10-04 17:35:44
【问题描述】:
当然,我假设 per Jonathon Reinhart's logic, here)。最近,我决定测试这个假设,结果让我有点惊讶。
我知道,对于大多数现代硬件来说,这个问题纯粹是学术性的,因此必须编写循环约 10 亿次的测试程序(以获取任何微小的差异以达到更可接受的水平)。这些程序尽可能基本(以消除所有可能的干扰源)。
lt.c:
int main() {
for (int i = 0; i < 1000000001; i++);
return 0;
}
le.c:
int main() {
for (int i = 0; i <= 1000000000; i++);
return 0;
}
它们是在 Linux VirtualBox 3.19.0-18-generic #18-Ubuntu x86_64 安装上编译和运行的,使用带有 -std=c11 标志集的 GCC .
lt.c 的二进制文件的平均时间是:
real 0m2.404s
user 0m2.389s
sys 0m0.000s
le.c 的平均时间是:
real 0m2.397s
user 0m2.384s
sys 0m0.000s
差异很小,但无论我运行多少次二进制文件,我都无法让它消失或反转。
- 我在 lt.c 的 for 循环中将比较值设置为比 le.c 大一(因此它们都会循环相同的次数)。这是不是一个错误?
- 根据Is < faster than <=? 中的答案,
<编译为jge,<=编译为jg。那是处理 if 语句而不是 for 循环,但这仍然是原因吗?jge的执行时间会比jg稍长吗? (我认为这很讽刺,因为这意味着从 C 转换到 ASM 会反转哪个是更复杂的指令,C 中的 lt 转换为 ASM 中的 gte,而 lte 转换为 gt。) - 或者,这只是特定于硬件,以至于不同的 x86 线或单个芯片可能始终显示相反的趋势、相同的趋势或没有差异?
【问题讨论】:
-
你可能会要求编译器给你汇编代码并检查它。
-
两个代码都编译成同一个程序集(都使用
jle),即使使用-O0(gcc 4.9.2)也是如此。差异可能是不受控制的伪影。 -
使用
-O3编译器应该已经优化掉了循环,不使用优化是没有意义的。 -
一般情况下,
-
我也得到了相同的组件。不要假设
<和<=编译为jge和jg- 它们不在我的系统上(两个版本都使用jbe)。请注意jg测试溢出、符号和零标志(OF=SF和ZF=0),而jge仅测试溢出和符号标志(OF=SF)。这可能是在多次重复运行时差异的潜在来源。
标签: c performance assembly operators opcode