liveBook · Manning

Optimization

As explained in Modern C, Third Edition

An optimizer is a compiler component that transforms program code to improve execution or compilation while preserving required behavior.

An optimizer can remove an empty C loop whose execution has no effect. That is useful in production code, but it makes the loop impossible to time as written. A measurement must preserve the work it intends to measure. section 16.4

Three loop designs resist elimination, but measure different work:

  • A volatile loop counter forces operations on the counter; GCC and Clang emit repeated loads and stores. section 16.4
  • A nonvolatile counter with a volatile store preserves the loop with less overhead. section 16.4
  • An index calculation whose result is opaque to the compiler preserves a loop closer to the measured computation. section 16.4
Listing 16.7 Instrumenting three for loops with struct timespec
    timespec_get(&t[0], TIME_UTC);
    /* Volatile for i ensures that the loop is effected */
    for (uint64_t volatile i = 0; i < iterations; ++i) {
      /* do nothing */
    }
    timespec_get(&t[1], TIME_UTC);
    /* s must be volatile to ensure that the loop is effected */
    for (uint64_t i = 0; i < iterations; ++i) {
      s = i;
    }
    timespec_get(&t[2], TIME_UTC);
    /* Opaque computation ensures that the loop is effected */
    for (uint64_t i = 1; accu0 < upper; i += 2) {
      accu0 += i;
    }
    timespec_get(&t[3], TIME_UTC);
    

Compare the three timed C loops: counter qualification, a volatile store, and an opaque accumulation each prevent elimination differently. section 16.4

TAKEAWAY: Inspect generated instructions as well as timings. The volatile-store loop measured about 81% less time per iteration than the volatile-counter loop; their overhead is not interchangeable. section 16.4

How Modern C, Third Edition covers it

How deep it goes
Works through three loop designs, generated assembly, and timing differences without describing optimizer internals.
Examples
Compares an empty loop with a volatile counter, a volatile store, and opaque accumulation.
What it assumes
Assumes familiarity with C for loops and variables; introduces volatile through its effect on generated instructions.
What you can do after
Diagnose/debug with it whether optimization invalidates a loop benchmark or changes its overhead.
How it connects
Connects optimization to volatile qualification, compiler-generated assembly, and performance measurement.

Also explained in

Compare how 30 books explain optimization →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Modern C, Third Edition. The section links point to the parts of the book it draws on.