views:

278

answers:

7

I have the following situation

bool user_set_flag;

getFlagFromUser(&user_set_flag);

while(1){

    if(user_set_flag){
        //do some computation and output

    }


    //do other computation
}

The variable user_set_flag is only set once and only once in the code, at the very start, its essentially the user selecting what he wants to do with the program. Say that the user selects user_set_flag = false then will the compiler compile the code in such a way such that the if(user_set_flag) statement will only be checked once, or will it be always checked. Can I give the compiler hints like setting the bool to a const?

The reason I ask this is because my application is time-critical and it processes frames as fast as possible. A branch that is always false should be able to be determined at run-time somehow?

+5  A: 

An alternative would be:

if(user_set_flag){
    while(1){
      ComputationAndOutput();
      OtherComputation();
    }
} else {
    while(1){
      OtherComputation();
    }
}

but as Smashery already said, this is micro-optimization and won't speed your program up as much as other optimizations you can surely do.

schnaader
Yeah, I was thinking about something like this - but I'd also wonder whether the extra effort of calling functions makes it not worth it
Smashery
Well, in that case you can copy your code instead of using a function - but once again, all this will only make your code a bit faster and is not really worth it.
schnaader
For example, calling a function or evaluating that if is perhaps 1-3 CPU cycles and I'm sure the remaining code you do in the loop will waste thousands of CPU cycles, so speedup by such optimizations will be less than 1%.
schnaader
@chnaader: what if you have a much much more complicated sequence of bools that need only be evaluated once and inflict a significant penalty on run time?
ldog
Then the optimization could be useful, but I doubt this case is very common (and if it is, there's an error in your coding technique which is not a case of optimization, but of writing good code).
schnaader
++ for your final comment.
Mike Dunlavey
+7  A: 

I don't think it's at all possible to optimize this any further. The compiler is smart enough to know that the value of user_set_flag is not going to change during the execution of the loop and will generate the most efficient machine code for that.

This is also somewhat in the realm of second-guessing the compiler. Unless you really really really know what you are doing its better to stick with the simplest solution.

As an exercise try to profile (time) the execution using both if (true) and if(user_set_flag). My guess would be that there is going to be zero difference in execution time.

Igor Zevaka
+2  A: 

You say that the user actually has a setting that can set this flag to true or false. That means that it's something that can change at runtime. Which means, it cannot be optimized away (usually).

In general, a compiler can only "optimize away" things it knows at compile time. Which means: at the moment you hit the "Build" item in your menu of your editor. If it can change, it - usually - cannot be optimized away.

However, it is rather easy (well, depending on the parts you didn't show) to optimize it away yourself. If you are bothered by the one assembly instruction this uses inside the loop, place the if-statement outside the loop. That way, it is only executed once for the call of the function.

Abel
+13  A: 

Firstly, processors have a capability called branch prediction. After a few runs of the loop, the processor will be able to notice that your if statement always goes one way. (It can even notice regular patterns, like true false true false.) It will then speculatively execute that branch, and so long as it able to predict correctly, the extra cost of the if statement is pretty much eliminated. If you think that the user is more likely to choose true rather than false, you can even tell this to the gcc compiler (gcc-specific extension).

However, you did mention in one of your comments that you have a 'much more complicated sequence of bools'. I think it is possible that the processor doesn't have the memory to pattern-match all those jumps -- by the time it comes back to the first if statement, the knowledge of which way that jump went has been displaced from its memory. But we could help it here...

The compiler has the ability to transform loops and if-statements into what it thinks are more optimal forms. E.g. it could possibly transform your code into the form given by schnaader. This is known as loop unswitching. You can help it along by doing Profile-Guided Optimization (PGO), letting the compiler know where the hotspots are. (Note: In gcc, -funswitch-loops is only turned on at -O3.)

You should profile your code at the instruction level (VTune would be a good tool for this) to see if the if-statements are really the bottleneck. If they really are, and if by looking at the generated assembly you think the compiler has got it wrong despite PGO, you can try hoisting out the if-statement yourself. Perhaps templated code would make it more convenient:

template<bool B> void innerLoop() {
    for (int i=0; i<10000; i++) {
        if (B) {
            // some stuff..
        } else {
            // some other stuff..
        }
    }
}
if (user_set_flag) innerLoop<true>();
else innerLoop<false>();
int3
Good point about branch prediction, people forget about that all the time, and yet it has a very huge effect on such things.
Pavel Minaev
excellent answer! Wow, I did not know gcc could do that :)
ldog
I would still expect the compiler to do the optimization here, if `user_set_flag` can be determined to be constant (local to the function, no handle passed to anything before the loop call and no modification within the loop for example), then I would expect the compiler to be able to generate 2 versions of the loop if it could be a significant speed up... (ie if the reduction of the number of instruction is worth it).
Matthieu M.
Yeah, I said that it could.. but on the off chance that it doesn't, we can encourage it by making it more explicit.
int3
It all depends on what `some stuff` or `some other stuff` actually are. They have to be almost nothing for any of this to matter.
Mike Dunlavey
A: 

If you know value of flag at compile time, you can add compilation flag for not including if statement as:

while(1){
   #ifdef user_set_flag
    {
        //do some computation and output

    }
   #endif


    //do other computation
}
Vivek
+3  A: 

Technically it is possible for the compiler to optimize situations like this.

For example:

#include <cstdio>

int main(int argc, char* [])
{
    while (true)
    {
        if (argc == 1) {
            puts("one");
        }
        puts("some more");
    }
}

main gets compiled to (G++ -O3):

    cmpl    $1, 8(%ebp)
    je  L9
    .p2align 4,,15
L2:
    movl    $LC1, (%esp)
    call    _puts
    jmp L2
L9:
    movl    $LC0, (%esp)
    call    _puts
    movl    $LC1, (%esp)
    call    _puts
    movl    $LC0, (%esp)
    call    _puts
    movl    $LC1, (%esp)
    call    _puts
    jmp L9

As you can see the condition is evaluated only once to determine which loop to run. And it has unrolled the true branch a bit :)

I would conclude that there is no reason to worry about these micro-optimizations, unless you determine that the compiler is not able to optimize away repeated evaluation of the unchanging boolean (e.g if it was global, how would the compiler know that it won't be modified by the function calls) and that it is indeed the bottleneck.

visitor
++ I always upvote newbies. You are right that there is no need to worry about these. Whenever optimizing a loop, look at the contents of the loop. In this case, `_puts` will consume orders of magnitude more time than the loop overhead, so the loop could be totally unoptimized and you'd never notice.
Mike Dunlavey
+1, this way you can comment :)
Matthieu M.
A: 

If you really want as-fast-as-possible, then you want to do aggressive performance tuning. So forget about trying to guess what the compiler might do to optimize your program.

That's being timid.

Instead, take charge. This shows you how.

Mike Dunlavey