2

I have a function, which is executed hundreds of millions of times in a typical program run. This function performs a certain main task, but, if the user so desires, it should perform some slight variations of that main task. The obvious way to implement this would be something like this:

void f(bool do_option)
{
    // Do the first part

    if (do_option)
    {
        // Optional extra code
    }

    // Continue normal execution
}

However, this is not very elegant, since the value of do_option does not change during a program run. The if statement is unnecessarily being performed very often.

I solved it by turning do_option into a template parameter. I recompile the program every time I want to change it. Right now, this workflow is acceptable: I don't change these options very often and I am the sole user/developer. In the future though, both these things will change, so I want a single binary with command-line switches.

Question is: what is the best or most elegant way to deal with this situation? I don't mind having a large binary with many copies of f. I could create a map from a set of command-line parameters to a function to execute, or perhaps use a switch. But I don't want to maintain that map by hand -- there will probably be more than five such parameters.

By the way, I know somebody is going to say that I'm prematurely optimizing. That is correct, I tested it. In my specific case, the performance of runtime ifs is not much worse than my template construction. That doesn't mean I'm not interested if nicer solutions are possible.

Kessel
  • 136
  • 6
  • 6
    With branch prediction, I don't think there will be much slowdown at all. – AndyG Jul 11 '17 at 18:19
  • 2
    Have you profiled your code to confirm that simply checking `do_option` is a performance bottleneck? I'd be willing to bet [branch prediction](https://stackoverflow.com/questions/11227809/why-is-it-faster-to-process-a-sorted-array-than-an-unsorted-array) would make that very fast since it never changes. Don't make your life more difficult just based on speculation, just focus your time optimizing code that is *actually* slow. – Cory Kramer Jul 11 '17 at 18:19
  • If your if statement was more complicated than just checking a boolean flag, then you could use a std::function<> variable or a base class with a pure virtual function or ... But all these solutions have a runtime overhead, so in your case I would not use that. – Rene Jul 11 '17 at 18:24
  • 1
    @AndyG, @CoryKramer: I agree with both of you. As I mentioned, I tested my code and the "runtime if statements" perform very well no matter the value of `do_option`. I'm happy to go with that, actually. But I'm just curious if there is a "proper" C++ way to do this. – Kessel Jul 11 '17 at 18:26
  • 5
    An `if` statement seems quite "proper" to me. Don't over-design or over-complicate things unless you *have to*. – Jesper Juhl Jul 11 '17 at 18:29
  • 2
    @Kessel: Fair question but yes this looks fine. a C++ program describes what the program should _mean_, not what operations the physical computer should perform – Lightness Races in Orbit Jul 11 '17 at 18:33
  • @AndyG: There's still opportunity cost, considering optimizations that would have been possible if the block were either present or absent rather than conditional. – Ben Voigt Jul 11 '17 at 18:40
  • @BenVoigt: You mean tying up issue slots if the block is large? Fair point. Without knowing more I don't think that we can refactor OP's code to refactor it to remove the `if` altogether more effectively. – AndyG Jul 11 '17 at 19:13
  • @AndyG: I meant compiler optimizations, things like common subexpression recognition between the code above the conditional and below it, which can be optimized when generating code for the (condition is false) case. Or elimination of code above the conditional when generating code for the true case, if its side effect is superceded by code in the conditional. – Ben Voigt Jul 11 '17 at 21:05

1 Answers1

1

On a modern (non-embedded) CPU, the branch predictor will be smart enough to recognize that the same path is taken every time, so an if statement is a perfectly acceptable (and readable) way of handling your situation.

On an embedded processor, compiler optimizations should be smart enough to get rid of most of the overhead of the if statement.

If you're really picky, you can use the template method that you mentioned earlier, and have an if statement select which version of the function to execute.

kingtux
  • 64
  • 4