Chapter 16: Performance
The chapter introduction argues for safe, relevant performance work and explains how programmers can give C compilers useful optimization information.
After this chapter you will be able to
- Safety before performance. Explain why performance work should begin with safe code and a worthwhile performance problem, rather than clever changes made prematurely.
- Optimization information for compilers. Explain why C provides optimization-related annotations and describe, at the introductory level, what inline, restrict, and the function attributes communicate.
- Inlining and optimization opportunities. Explain why an ordinary function call can cost time and how inlining can both remove that overhead and reveal further optimizations.
- Inline definitions and emitted symbols. Describe what inline permits across translation units and how to ensure that a callable function symbol is emitted when needed.
- Exclusive access promise. Explain that restrict tells the compiler an object is accessed exclusively through the qualified pointer in the relevant code, and that the caller must ensure this is true.
- Copy function overlap contracts. Distinguish memcpy from memmove in terms of their pointer-access requirements and whether the source and destination may overlap.
- Unsequenced function contract. Explain what a function promises when marked [[unsequenced]] and why a verified promise helps optimize calls.
- Floating-point and errno limits. Explain why floating-point state and errno rule out [[unsequenced]] in general, and how the distance example establishes a local exception for sqrt.
- Reproducible state guarantees. Distinguish [[reproducible]] from [[unsequenced]] in terms of repeatable visible results, temporary state changes, and optimization.
- Local static state distinction. Distinguish the attributes' rules for modifying local static state using the caching hash example.
- Evidence for performance claims. Distinguish an algorithmic complexity assessment from a code performance assessment. Explain why the former calls for an argument or proof, while claims about actual run time require measurement rather than intuition.
- Measurement bias and repetition. Explain how timing instrumentation can change both compilation and execution, and describe why the example repeats code many times between timing calls.
- Statistical reliability of timings. Describe what the mean, relative standard deviation, and skew reveal about repeated timings. Explain why a performance difference smaller than the observed variability does not establish a gain.
- Loop overhead inspection. Explain why the example separately measures loop overhead and inspects generated assembler, including why an empty or volatile-counter loop can mislead.
What it builds on
- Access violations (chapter 15) · The risk of invalid memory access.
- Alignment (chapter 12) · The earlier discussion of alignas and alignment.
- Storage duration, lifetime, and visibility (chapter 13) · The earlier discussion of register.
- Simple functions (chapter 7) · Basic function calls and definitions.
- Declarations (chapter 2) · The distinction between declarations and definitions.
- Implementation (chapter 10) · The organization of implementation code.
- Definitions (chapter 2) · Function definitions.
- Pure functions (chapter 10) · Pure functions and the rat-structure example.
Section by section
Introduction
The chapter introduction argues for safe, relevant performance work and explains how programmers can give C compilers useful optimization information.
- Safety before performance: Explain why performance work should begin with safe code and a worthwhile performance problem, rather than clever changes made prematurely.
Why it matters: A faster program is not an improvement if it becomes unsafe or the speedup has no practical value. - Practices for safer code: Describe the coding practices the introduction recommends to reduce uninitialized-object and out-of-bounds errors while preserving optimization opportunities.
Why it matters: These practices address common failures without assuming that safer code must be slower. - Optimization information for compilers: Explain why C provides optimization-related annotations and describe, at the introductory level, what inline, restrict, and the function attributes communicate.
Why it matters: Optimization hints can enable better code generation, but their promises must be true for the program to remain valid.
Key terms: premature optimization, safety, performance, block-scope variables, calloc, static 1, static N, VLA notation, aliasing, inline
16.1 Inline functions
The section explains how inline function definitions can make functions available for compiler optimization across translation units, and the tradeoffs of using them.
- Inlining and optimization opportunities: Explain why an ordinary function call can cost time and how inlining can both remove that overhead and reveal further optimizations.
Why it matters: Inlining can improve more than the cost of the call itself. - Definition visibility across translation units: Explain why a compiler needs a function definition to inline it and compare the two described ways to make definitions visible without inline.
Why it matters: These limitations explain why C provides a dedicated inline mechanism. - Inline definitions and emitted symbols: Describe what inline permits across translation units and how to ensure that a callable function symbol is emitted when needed.
Why it matters: This arrangement makes the definition available for optimization while retaining a function symbol when the program needs one. - Compiler discretion over inlining: Explain why inline does not force inlining and how it can help an optimizing compiler with small or pure functions.
Why it matters: Making a definition available lets the compiler choose an optimization suited to its platform and build settings. - Header exposure and identifier hazards: Explain the rebuild and macro-name risks of exposing inline definitions in headers and the precautions the section recommends.
Why it matters: An inline header definition affects its users’ builds and can interact with names outside the function. - Translation-unit-local access restrictions: Describe the restrictions on naming or defining static entities inside inline functions and distinguish those restrictions from passing pointers.
Why it matters: The distinction between naming translation-unit-local state and receiving a pointer keeps inline-function designs within the rules described here.
Key terms: inlining, call overhead, caller, callee, definition, declaration, translation unit, static, inline, function symbol
16.2 Using restrict qualifiers
Explains how restrict-qualified pointers let compilers assume exclusive access, and how that promise affects callers and library functions.
- Exclusive access promise: Explain that restrict tells the compiler an object is accessed exclusively through the qualified pointer in the relevant code, and that the caller must ensure this is true.
Why it matters: The optimization opportunity depends on a promise the caller must actually keep. - Copy function overlap contracts: Distinguish memcpy from memmove in terms of their pointer-access requirements and whether the source and destination may overlap.
Why it matters: The distinction determines which copy function can handle overlapping memory. - String processing alias concerns: Describe why character-type aliasing can limit optimization of string-processing functions, and give the section’s printf format-argument restriction as an example of an aliasing concern.
Why it matters: Aliasing assumptions matter even in familiar string and formatted-output calls.
Key terms: restrict, exclusive access, alias, memcpy, memmove, overlap, character types, aliasing, string-processing functions, format parameter
16.3 Unsequenced and reproducible attributes
This section explains the guarantees required by [[unsequenced]] and [[reproducible]], and how those guarantees permit optimization.
- Unsequenced function contract: Explain what a function promises when marked [[unsequenced]] and why a verified promise helps optimize calls.
Why it matters: The attribute gives the compiler useful information only when the function actually keeps its promise. - Floating-point and errno limits: Explain why floating-point state and errno rule out [[unsequenced]] in general, and how the distance example establishes a local exception for sqrt.
Why it matters: A call that looks mathematical may still depend on or change state unless its context rules that out. - Reproducible state guarantees: Distinguish [[reproducible]] from [[unsequenced]] in terms of repeatable visible results, temporary state changes, and optimization.
Why it matters: The weaker attribute can describe useful functions that temporarily adjust state without leaving a visible change. - Attributed pointer parameters: Explain how the two attributes can apply to functions with pointer parameters or returns and why restrict remains a useful annotation.
Why it matters: A pointer argument does not automatically exclude these attributes, but it brings restrictions worth making visible. - Local static state distinction: Distinguish the attributes' rules for modifying local static state using the caching hash example.
Why it matters: An invisible cache can preserve repeatable outputs without allowing the freer call ordering promised by [[unsequenced]].
Key terms: [[unsequenced]], pure function, global variables, system state, floating-point rounding mode, errno, sqrt, FP_CONTRACT, FENV_ROUND, scope
16.4 Measurement and inspection
This section shows how to assess C code performance through measurement, statistical checks, and inspection of measurement overhead.
- Evidence for performance claims: Distinguish an algorithmic complexity assessment from a code performance assessment. Explain why the former calls for an argument or proof, while claims about actual run time require measurement rather than intuition.
Why it matters: It keeps a sound choice of algorithm from being confused with an untested claim about how fast its implementation runs. - Measurement bias and repetition: Explain how timing instrumentation can change both compilation and execution, and describe why the example repeats code many times between timing calls.
Why it matters: A benchmark can otherwise report the cost of observing the code as though it were the cost of the code itself. - Statistical reliability of timings: Describe what the mean, relative standard deviation, and skew reveal about repeated timings. Explain why a performance difference smaller than the observed variability does not establish a gain.
Why it matters: Variability tells you whether a reported speed difference is persuasive or merely noise in the measurements. - Incremental timing statistics: Describe how the example accumulates statistics as measurements arrive and why it uses the current mean rather than storing every sample.
Why it matters: The example shows that useful checks on timing variability can be collected without keeping every timing. - Loop overhead inspection: Explain why the example separately measures loop overhead and inspects generated assembler, including why an empty or volatile-counter loop can mislead.
Why it matters: Checking what the compiler actually emits helps separate the cost of the intended work from the benchmark loop's cost.
Key terms: complexity assessment, performance assessment, measurement, instrumentation, bias, timespec_get, iterations, mean, relative standard deviation, skew
16.5 Summary
Where this is used later
- (chapter intro) (chapter 17) · Assumes familiarity with inline functions.
- Argument checking (chapter 17) · The use of inline functions to limit call overhead.
- Variadic macros (chapter 17) · The use of inline functions.
- Generic selection (chapter 18) · Inline functions.
- Functions (chapter 19) · The idea of inspecting compiler optimizations
Concepts explained in this chapter
- performancePerformance is the measurable efficiency of a program or operation, commonly including execution time and resource consumption.
- inline functioninline is a C function specifier that permits a definition to suggest inline substitution of a function's body at call sites without requiring the compiler to perform that substitution.
- reproducible attributeThe reproducible attribute is a C23 function attribute declaring that a call produces consistent results and effects for given arguments while permitting limited temporary state changes.
- unsequenced attributeThe unsequenced attribute is a C function attribute indicating that calls to the function can be treated as unsequenced with respect to relevant evaluation and side-effect rules.
- measurementA measurement is an observed quantitative value obtained from a program execution or other empirical process.
- biasBias is a systematic deviation between an observed measurement and the property it is intended to represent.
- instrumentationInstrumentation is the addition of code or mechanisms that observe or record properties of program execution.
- meanA mean value is the arithmetic average of a collection of numeric values.
- optimizationAn optimizer is a compiler component that transforms program code to improve execution or compilation while preserving required behavior.
- performance analysisPerformance assessment is the evaluation of a program's execution behavior using analysis or empirical evidence.
- raw momentA raw moment is the sum of a specified power of each value in a sample.
- relative standard deviationRelative standard deviation is the standard deviation divided by the mean, expressing dispersion relative to the measured magnitude.
- skewSkew measures the asymmetry or lopsidedness of a distribution around its mean.
- standard deviationStandard deviation measures the typical dispersion of observed values around their mean.
- statistical sampleA statistical sample is a finite collection of observed values drawn from a phenomenon or experiment.
- timespec_gettimespec_get is a C standard-library function that obtains the current calendar time and stores it in a timespec object.
- volatile qualificationThe C volatile qualifier specifies that accesses to an object may have externally observable effects and must not be treated as freely eliminable or cacheable by the compiler.
- aliasingAliasing is the situation in which multiple pointer expressions or access paths designate the same object or overlapping storage.
- restrictrestrict is a C type qualifier that lets an implementation assume an object is accessed through a designated pointer-based access path during a relevant execution.
- inliningInlining is a compiler transformation that replaces a function call with the called function's implementation.
- translation unitA translation unit is the source-code unit produced after preprocessing a C source file and its included contents for compilation.
- pure functionA pure function is a function whose interactions with the rest of a program occur only through its interface and whose behavior has no other observable effects.
- memory boundA performance bottleneck is a program component or operation that substantially limits overall execution efficiency.
- register keywordregister is a C storage-class specifier that requests automatic storage for an object and permits implementation-specific restrictions on taking its address.
- floating-point arithmeticA floating-point value is a finite-precision numerical value represented by a sign, an exponent, and a sequence of significand bits.
- floating-point stateFloating-point state is execution state that controls or records the behavior of floating-point operations, including rounding and contraction.
- local static stateLocal static state is state held by objects with static storage duration that are declared within a function or local program region.
- stateHidden state is implementation or library state that affects program behavior without being directly represented by ordinary program values.
- observable stateObservable state is program state whose value or effects can be detected by code or users outside the component that maintains it.
These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.
