liveBook · Manning

Performance optimization

As explained in Modern C, Third Edition

Optimization is the transformation of a program's implementation to improve execution or compilation while preserving its required observable behavior.

A calculation the compiler may remove

Consider `double x = 5.0; double y = 3.0; x = (x * 1.5) - y; printf("x is %g\n", x);`. The output is `x is 4.5`. If `x` is never used again, the compiler may compute the result during compilation and replace the calculation with `printf("x is 4.5\n");`. The multiplication and subtraction need not occur in the executable: their intermediate results are not observed. section 5.1

Optimization changes how a program is carried out, not what its required observable behavior is. A C compiler need not follow every written step literally; it must produce an executable consistent with the abstract state machine’s observable states as execution proceeds. Those states include output and the contents of relevant variables. section 5.1 section 5.1.4

Combining additions

Suppose `x += 5;` is followed by work that does not use `x`, then by `x += 7;`. The compiler may be able to use a single `x += 12;`, placed before or after that intervening work. This is not permitted merely because the final arithmetic result looks right: printing or otherwise using the intermediate value would make the change observable. section 5.1.4

TAKEAWAY: Type determines optimization opportunities.

  • For an unsigned type, the combined addition remains consistent with the two separate additions even if the value wraps. section 5.1.4
  • For signed integer or floating-point types, an intermediate overflow may raise an exception and terminate execution. If the compiler cannot rule that out, it cannot discard the intermediate operation on the strength of the final value alone. section 5.1.4

A control-flow trap

After `setjmp`, a `longjmp` can return control to the saved position by an exceptional path. In a parser diagnostic, optimization can make a changed nesting-depth value appear as `0` rather than the expected `3`: the compiler analyzed the ordinary switch paths and assumed the value could not change. Objects modified across `longjmp` and needed on that path must be `volatile`; `unsigned volatile depth = 0;` is the shown repair. section 19.5

How Modern C, Third Edition covers it

How deep it goes
Works through eliminated calculations, reordered additions, overflow limits, and a long-jump hazard without detailing generated machine instructions.
Examples
Uses a printf calculation, two additions separated by unrelated work, and a parser diagnostic after longjmp.
What it assumes
Assumes familiarity with basic C expressions and types while introducing observable states through a small calculation.
What you can do after
Evaluate/understand whether proposed C transformations preserve observable behavior, including type-dependent overflow and long-jump cases.
How it connects
Connects optimization to the abstract state machine, observable behavior, overflow, types, setjmp, longjmp, and volatile.

Also explained in

Compare how 7 books explain performance 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.