2

As far as I understand the concept, CC is determined by how many nested branched logic the given method have. It can be refactored to checking the opposite of original predicate and calling return. For example:

void Foo()
{
  if (predcate0)
  {
    if (predicate1)
    {
      // some code
    }
  }
}

can be refactored to

void Foo()
{
  if (!predicate0) return;

  if (!predicate1) return;

  // some code
}

but the thing is, following the branch predicate0 && predicate1 will generate less cache misses in C++ if this path will be taken much more frequently.

Obviously I intentionally simplifying the code. For example there can be dozens of predicates and things like one predicate dependency on another predicate.

What to do in this case? Should I throw away performance for better readability?

  • 4
    Note that in your example, both versions have the same cyclomatic complexity of 3. The CC is the number of independent paths through a procedure. Though I still agree that early returns / guards improve readability. – amon Oct 21 '16 at 11:28
  • 4
    An even remotely competent optimizing compiler, even for the utterly brain-dead x86 instruction set architecture, will generate identical code for your two examples. Read Wulf's "Design of an Optimizing Compiler" for more information. – John R. Strohm Oct 21 '16 at 12:33
  • This has nothing to do with cyclomatic complexity, as both examples have exactly the same cyclomatic complexity. – David Hammen Oct 21 '16 at 16:51
8

Unless you really need that performance, always prefer better readability.

The biggest performance wins do not come from micro-optimizations, but from algorithmic complexity improvements, and from other ways to avoid doing unnecessary work. Not doing something is always faster than doing something as fast as possible. Cleaner code makes it easier to spot such opportunities.

If you do need that performance, and can prove with a profiler & benchmarking tools that this change will give you that performance, then of course go for it. But you are still at the mercy of your compiler to get machine code that is branch prediction friendly. The compiler might suddenly deduce that a branch that it previously considered unlikely is in fact likely, or vice versa. To get around this, try to look into profile-guided optimization and/or annotations and compiler hints that let you unambiguously mark a branch as likely or unlikely.

  • Isn't it always preached by people of C++ community? To pursue data localization, since most of the algorithms fall apart if you have lots of cache misses. I remember Stroustrup's talk about liner vector beating more sophisticated algorithms which supposed to have far better O. – GuardianX Oct 21 '16 at 12:54
  • 4
    @GuardianX Big-O analysis discusses how the resource usage (time, memory) of an algorithm scales with input size. An algo with a better Big-O class will always beat other algorithms, regardless of effects like caching – but only for large input sizes. But many inputs aren't large. In terms of absolute performance, algorithms with worse scaling behaviour might be better for small inputs. This doesn't mean “worse is better”. This means “use a profiler to discover hot spots, and choose appropriate algorithms for your specific use case, input structure, and environment.” – amon Oct 21 '16 at 13:13
  • 3
    @GuardianX: Looking at your code change, your assumption that they will in any way influence the number of cache misses is completely unwarranted. Your change will produce more and slower code with a non-optimising compiler, and the exact same code with a good compiler. You are not doing any data localisation. – gnasher729 Oct 21 '16 at 19:00
3

If you don't already know for sure that you should throw away readability for performance because you have a performance problem and you have profiler data proving that the problem lies here, then definitely throw away performance.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.