自然,我假设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;
}


使用带有-std = c11标志的GCC,可以编译它们并在Linux VirtualBox 3.19.0-18-通用#18-Ubuntu x86_64安装上运行。

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线或单个芯片可能始终显示出相反的趋势,相同的趋势或没有差异?

最佳答案

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

结果:
事实证明,默认优化设置将两个for循环都转换为同一程序集。实际上,这两个文件在组装形式上都是相同的。 (diff确认了这一点。)

先前观察到的时差的可能原因:
看来我运行二进制文件的顺序是造成运行时间差异的原因。


在给定的运行时间中,程序通常在每次连续执行时都更快地执行,大约执行3次后才达到稳定。
我在time ./lttime ./le之间来回切换,所以第一次跑步会偏向于平均时间的增加。
我通常先跑。
我做了几个单独的演练(增加了平均偏差)。


代码摘录:

        movl    $0, -4(%rbp)
        jmp     .L2
.L3:
        addl    $1, -4($rbp)
.L2
        cmpl    $1000000000, -4(%rbp)
        jle     .L3
        mol     $0, %eax
        pop     %rbp


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

关于c - 为什么<慢于<=? [C],我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31434458/

10-11 18:37