简体   繁体   中英

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

Naturally, I've assumed the < and <= operators run at the same speed ( per Jonathon Reinhart's logic, here ). Recently, I decided to test that assumption, and I was a little surprised by my results.

I know, for most modern hardware, this question is purely academic, so had to write test programs that looped about 1 billion times (to get any minuscule difference to add up to more acceptable levels). The programs were as basic as possible (to cut out all possible sources of interference).

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;
}

They were compiled and run on a Linux VirtualBox 3.19.0-18-generic #18-Ubuntu x86_64 installation, using GCC with the -std=c11 flag set.

The average time for lt.c's binary was:

real    0m2.404s
user    0m2.389s
sys 0m0.000s

The average time for le.c was:

real    0m2.397s
user    0m2.384s
sys 0m0.000s

The difference is small, but I couldn't get it to go away or reverse no matter how many times I ran the binaries.

  • I made the comparison value in the for-loop of lt.c one larger than le.c (so they'd both loop the same number of times). Was this somehow a mistake?
  • According the answer in Is < faster than <=? , < compiles to jge and <= compiles to jg . That was dealing with if statements rather than a for-loop, but could this still be the reason? Could the execution of jge take slightly longer than jg ? (I think this would be ironic since that would mean moving from C to ASM inverts which one is the more complicated instruction, with lt in C translating to gte in ASM and lte to gt.)
  • Or, is this just so hardware specific that different x86 lines or individual chips may consistently show the reverse trend, the same trend, or no difference?

There were a few requests in the comments to my question to include the assembly being generated for me by GCC. After getting to compiler to pop out the assembly versions of each file, I checked it.

Result:
It turns out the default optimization setting turned both for-loops into the same assembly. Both files were identical in assembly-form, actually. ( diff confirmed this.)

Possible reason for the previously observed time difference:
It seems the order in which I ran the binaries was the cause for the run time difference.

  • On a given runthrough, the programs generally were executed quicker with each successive execution, before plateauing after about 3 executions.
  • I alternated back and forth between time ./lt and time ./le , so the one run first would have a bias towards extra time in its average.
  • I usually ran lt first.
  • I did several separate runthroughs (increasing the averaged bias).

Code excerpt:

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

... * covers face * ...carry on....

Let's speak in assembly. (depends on the architecture of course) When comparing you'll use cmp or test instruction and then - when you use < the equal instruction would be jl which checks if SF and OF are not the same (some special flags called sign and overflow) - when you use <= the equal instruction is jle which checks not only SF != OF but also ZF == 1 (zero flag) and so one, more here but honestly it's not even the whole cycle so...I think the difference is unmeasurable under normal circumstances

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM