为什么 < 会比 <= 慢? [C]

Why would < be slower than <=? [C]

当然,我假设 < 和 <= 运算符 运行 的速度相同 (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[=49 上编译和 运行 =] 安装,使用带有 -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运行slating 到 ASM 中的 gte 和 lte 到 gt。 )
  • 或者,这是否只是硬件特定,以至于不同的 x86 线或单个芯片可能始终显示相反的趋势、相同的趋势或没有差异?

让我们在集会上发言。 (当然取决于架构) 比较时,您将使用 cmp 或测试指令,然后 - 当您使用 < 时,等于指令将是 jl,它检查 SF 和 OF 是否不相同(一些特殊标志称为符号和溢出) - 当您使用 <= 时,等于指令是 jle,它不仅检查 SF != OF,而且检查 ZF == 1(零标志) 等等,更多 here 但老实说,这甚至不是整个周期所以......我认为在正常情况下差异是无法衡量的

我的问题的评论中有一些要求包括 GCC 为我生成的程序集。到编译器弹出每个文件的汇编版本后,我检查了一下。

结果:
事实证明,默认优化设置将两个 for 循环变成了同一个程序集。实际上,这两个文件的汇编形式是相同的。 (diff 证实了这一点。)

之前观察到的时间差的可能原因:
似乎我 运行 二进制文件的顺序是造成 运行 时差的原因。

  • 在给定的 运行through 中,程序通常在每次连续执行时执行得更快,然后在大约 3 次执行后稳定下来。
  • 我在 time ./lttime ./le 之间来回切换,所以第一个 运行 的平均值会偏向于加时赛。
  • 我通常运行先。
  • 我做了几个单独的 运行throughs(增加平均偏差)。

代码摘录:

        movl    [=10=], -4(%rbp)
        jmp     .L2
.L3:
        addl    , -4($rbp)
.L2
        cmpl    00000000, -4(%rbp)
        jle     .L3
        mol     [=10=], %eax
        pop     %rbp

... * 遮住脸 * ...继续....