【问题标题】:Why would < be slower than <=? [C]为什么 < 会比 <= 慢? [C]
【发布时间】: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 <=? 中的答案,&lt; 编译为jge&lt;= 编译为jg。那是处理 if 语句而不是 for 循环,但这仍然是原因吗? jge 的执行时间会比 jg 稍长吗? (我认为这很讽刺,因为这意味着从 C 转换到 ASM 会反转哪个是更复杂的指令,C 中的 lt 转换为 ASM 中的 gte,而 lte 转换为 gt。)
  • 或者,这只是特定于硬件,以至于不同的 x86 线或单个芯片可能始终显示相反的趋势、相同的趋势或没有差异?

【问题讨论】:

  • 你可能会要求编译器给你汇编代码并检查它。
  • 两个代码都编译成同一个程序集(都使用jle),即使使用-O0(gcc 4.9.2)也是如此。差异可能是不受控制的伪影。
  • 使用-O3编译器应该已经优化掉了循环,不使用优化是没有意义的。
  • 一般情况下,
  • 我也得到了相同的组件。不要假设&lt;&lt;= 编译为jgejg - 它们不在我的系统上(两个版本都使用jbe)。请注意jg 测试溢出、符号和零标志(OF=SFZF=0),而jge 仅测试溢出和符号标志(OF=SF)。这可能是在多次重复运行时差异的潜在来源。

标签: c performance assembly operators opcode


【解决方案1】:

在我的问题中,cmets 中有一些请求包括 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

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

【讨论】:

  • 现在您对 CPU 指令缓存机制及其作用有了更多了解 :)
【解决方案2】:

让我们在大会上发言。 (当然取决于架构) 比较时,您将使用 cmp 或 test 指令,然后 - 当您使用 here 但老实说,这甚至不是整个周期,所以......我认为在正常情况下差异是无法衡量的

【讨论】:

    猜你喜欢
    • 2012-02-19
    • 1970-01-01
    • 1970-01-01
    • 2011-03-23
    • 2013-04-27
    • 2021-04-03
    • 2011-03-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多