0

Let's say I have

void f(const bool condition) {
  if (condition) {
    f2();
  else {
    f3();
  }

  f4();

  if (condition) {
    f5();
  } else {
    f6();
  }
}

since condition never changes, the above can be simplied to the following

void f(const bool condition) {
  if (condition) {
    f2();
    f4();
    f5();
  } else {
    f3();
    f4();
    f5();
  }
}

note that f4() is duplicated in the second code but second code part has less if branches. I tried to profile the 2 code snippets but it seems to me that the performance is almost identical. Imagine in real life the above code snippets can have many more if with the same conditions. So I'm wondering for modern x86/64 processors:

  1. Is there any performance gain to have 2 giant if statements instead of many small ones that are based on the same condition?
  2. Will const keyword help compiler/processor generate better branch predictions ?
Monster Hunter
  • 846
  • 1
  • 12
  • 24
  • IMHO the first looks better and if you need to change `f4()` you only have to do it once instead of twice which could cause a bug. I program first for readability and maintainability. After profiling and I determine the code is a bottleneck then do I look at doing such optimizations. – NathanOliver Nov 28 '16 at 17:51
  • 2
    "Will const keyword help compiler/processor generate better branch predictions ?" probably is probably about the best answer, it depends on your compiler. – George Nov 28 '16 at 17:52
  • On a desktop computer with a multi-GHz processor, a single if-statement takes an extremely small amount of time. And an optimizing compiler may also see that the condition doesn't change, and do the transformation for you. It would likely be better to spend your time elsewhere, and then only if the program turns out not to be fast enough. – Bo Persson Nov 28 '16 at 17:58
  • The real question is - _do you really need it at the stage you are?_ Likely no, so who cares? – skypjack Nov 28 '16 at 18:07
  • Did you mean `f6` in the else block of the second snippet? –  Nov 28 '16 at 18:24
  • I like the first one better. Easier to spot the typo. – user4581301 Nov 28 '16 at 19:39

3 Answers3

2

First of all, to notice any difference, you need to run your snippets multiple times, like:

for (int i=0; i<100000000; ++i)
    f(true);

You need to select the number of iterations to make the overall running time 10-30 seconds. In this case you will see performance of the function itself and not various overheads like loading your application.

Second, what is the complexity of your functions f2 ... f6? If these functions are way more complex than the f itself, again you will not notice any difference.

Third, your second version will be slightly faster, although the difference will be tiny. Adding const will not help compiler in any way.

Finally, I would recommend to look at changes that will give noticeable performance gain.

Kirill Kobelev
  • 10,252
  • 6
  • 30
  • 51
2

First of all, your example is simple enough for any decent compiler to produce identical code for both cases.

To confuse it enough, you should do something more complex instead of simply calling f4, like so:

void f_seprate_ifs(const bool condition) {
  if (condition) {
    f2();
  } else {
    f3();
  }

  for ( int i = 0; i < 100; i++ ){
    f4();
  }

  if (condition) {
    f5();
  } else {
    f6();
  }
}

void f_duplicate_f4(const bool condition) {
  if (condition) {
    f2();
    for ( int i = 0; i < 100; i++ ){
      f4();
    }
    f5();
  } else {
    f3();
    for ( int i = 0; i < 100; i++ ){
      f4();
    } 
    f6();
  }
}

But then it is not a matter of style, but a clear trade-off between speed and space - your are duplicating code to eliminate branch (and IMO, it is not a good trade-off for my example at all). Compiler already doing this all the time with function inlining, and has very complex heuristics on when to inline. And for your example, it even did it for you.

To summarize, do not try to do such micro optimizations unless you are absolutely sure they are necessary. Especially when they hurt readability. Especially especially when they attract copy-paste errors.

As for const modifier, again, any decent compiler will notice that condition never changes, and is effectively const, speaking in Java terms. In C++, const is very rarely provides an additional optimization opportunities. It is here for programmer, not for the compiler.

For example, for:

void f(const bool& condition){

The condition is NOT constant - and compiler must assume that it can be changed by f4, so snippets are no longer semantically equivalent.

Community
  • 1
  • 1
0

In theory eliminating any conditional operation improves the performance. But in real world there can be no difference at all. In your particular case the compiler can easily do the proposed optimization for you, so there should be no difference, as you already have tested. One of valuable jobs of the optimizing compilers - branch elimination. They look for possibility to avoid unnecessary branching.

So, the answer to your question 1: In most cases on modern compilers there will be no difference.

Regarding const keyword: const itself does not help in branch prediction. The compilers can see if any variable was not modified and apply whatever they can to generate fast code. When the binary code is executed by a processor, there is no any indication that the value is constant. At least on x86 and x86-64 processors.

In any case "premature optimization is the root of all evil" (c) Donald Knuth. You need to avoid any low level optimization unless you have your profiling data that show the bottleneck. And for that you need a benchmark to analyze the performance.

Alan Milton
  • 374
  • 4
  • 13