mmohab
mmohab

Reputation: 2373

C++ optimization if performance

consider these 2 situations of if statements:

if( error ==0 )
{
    // DO success stuff
}
else
{
    // DO error handling stuff
}

and this one:

if( error != 0 )
{
    // DO error handling stuff
}
else
{
    // DO success stuff
}

which one over performs the other, knowing that most of the time I come to the success code path.

Upvotes: 4

Views: 740

Answers (6)

learnvst
learnvst

Reputation: 16195

Any compiler should optimize the difference. Proof below. If error is set at runtime, then . . .

Using g++4.8 with -O3

This

int main(int argc, char **argv) {
    bool error=argv[1];
    if( error ){
        return 0;
    }else{
        return 1;
    }
}

makes . .

main:
    xorl    %eax, %eax
    cmpq    $0, 8(%rsi)
    setne   %al
    ret

and this...

int main(int argc, char **argv) {
    bool error=argv[1];
    if( !error ){
        return 1;
    }else{
        return 0;
    }
}

...makes...

main:
    xorl    %eax, %eax
    cmpq    $0, 8(%rsi)
    setne   %al
    ret

Same stuff to the CPU. Use the machine code when in doubt. http://gcc.godbolt.org/

Upvotes: 0

Mats Petersson
Mats Petersson

Reputation: 129314

It is quite unlikely that you will notice much of a difference between the two pieces of code. Comparing with 0 is the same operation whether the code later jumps if it's "true" or "false". So, use the form that expresses your "meaning" in the code best, rather than try to "outsmart the compiler" (unless you are REALLY good at it, you probably will just confuse things.

Since you have if ... else ... in both cases (most compilers will make a single return point, so even if you have a return in the middle of the function, it will still make a branch from the return to the bottom of the function, and if the condition is false, a branch to jump over it.

The only really beneficial way to solve this is to use hints that the branch is/isn't taken, which at least on some processors can be beneficial (and the compiler can turn the branches around so that the less likely conditions make the most branches). But it's also rather unportable, since the C and C++ languages don't have any features to allow such feedback to the compiler. But some compilers do implement such things.

Of course, the effect/result of this is VERY dependant on what the actual processor is (modern x86 has hints to the processor that feed into the branch prediction unit if there is no "history" for this particular branch - older x86, as used in some embedded systems, etc, won't have that. Other processors may or may not have the same feature - I believe ARM has a couple of bits to say "this is likely taken/not taken" as well). Ideally, for this, you want "profile driven optimisation", so the compiler can instrument and organise the code based on the most likely variants.

Always, use profiling and benchmarks to measure the results of any optimisation. It is often difficult to guess what is better just by looking at the code (even more so if you don't see the machine-code the compiler generates).

Upvotes: 0

Manuel Arwed Schmidt
Manuel Arwed Schmidt

Reputation: 3586

It depends.

When the code is run just one time, it would be statistically faster to use the more likely one at first - if and only if the cpu implementation of branch prediction is not "sharing counters" between many lines (e.g. every 16th statement shares same). However, this is not how most code will run. It will run multiple, dozen, a trillion times (e.g. in a while loop).

Multiple runs

None will perform better than the other. The reason is branch prediction. Everytime your program runs an if statement, the cpu will count up or down the amount of times this statement was true. This way it can now predict with high accuracy the next time, if code runs again. If you would test your code a billion times, you will see it won't matter if your if or else part gets executed. CPU will optimize for what it think is the most likely case to occur.

This is a simplified explaination, as CPU branch prediction is smart enough to also see when some code always flip-flops: true, false, true, false, true, false or even true, true, false, true, true, false...

You can learn alot on the wikipedia article about branch prediction

Upvotes: 2

Havenard
Havenard

Reputation: 27844

They will perform identically. You are just trading a instruction jz for a jnz observing from Assembly level. None of them executes more or complexier instructions than the other.

Upvotes: 0

xosp7tom
xosp7tom

Reputation: 2183

Gcc's default behavior is to optimize for true case of the if statement. Based on that, it will choose either je or jne should be used.

If you know and want to fine control which call path is more likely, use the following macro to find control.

#define likely(x)       __builtin_expect((x),1)
#define unlikely(x)     __builtin_expect((x),0)

Upvotes: 1

mrks
mrks

Reputation: 8333

Rather than worrying about this which might be a performance issue only in the rarest of cases, you should ask yourself which is more readable. For error checks, you could use a guard clause, which avoids too many indentations/brackets:

if( error != 0 )
{
    // DO error handling stuff
    return;
}

// DO success stuff

If you know that one path is more likely than the other and you are sure that this is really performance critical, you could let the compiler know (example for GCC):

if( _builtin_expect (error == 0, 1) )
{
    // DO success stuff
}
else
{
    // DO error handling stuff
}

Of course, this makes the code harder to read - only use it if really necessary.

Upvotes: 4

Related Questions