7 routes42 sections324 units

Unit 7.3 · about 5 h

44 / 324

Struct layout, alignment, strides and locality

A dtype or stride mismatch changes which bytes native code reads. The same layout choices also decide how much useful data each memory access brings into the computation.

  • derive
  • measure

You can now

  • Compute field offsets, padding and array strides for a measured native layout.
  • Derive a byte offset from a base address, index, stride and field offset.
  • Compare AoS and SoA for a controlled access pattern without assuming either layout must be faster.

Covers

  • Struct and class layout, padding, alignment and strides
  • Contiguous layout, locality, array of structures and structure of arrays

Study, in this order

4 steps

  1. Objects, representation and alignment
    cppreference

    Object representation and value representation; Size; Alignment, including the S and X examples

    Depth · Skip implicit object creation and polymorphic layout. Use simple standard-layout structs for offset checks.

  2. Predictable memory access
    C++ Core Guidelines

    Per.19: Access memory predictably, including the two matrix traversal orders

  3. AoS and SoA trade-offs
    Memory Layout Transformations

    Overview; Topics; AOS Form (Array of Structs); SOA Form (Struct of Arrays)

    Depth · Read the layouts, not the Intel-specific array-notation syntax. Stop before AOSOA and the LIBOR example. Treat performance statements as hypotheses for your own access pattern.

  4. When AoS wins: whole-record access
    Algorithmica - AoS and SoA

    AoS and SoA: Experiment

    Depth · Read the Experiment section only; the associativity and huge-page effects after it are beyond this unit. Its pointer chase reads every field of a randomly chosen record, the opposite of the Reproduce's single-field scan.

Focus on

  • sizeof includes padding. Alignment constrains legal object addresses, and trailing padding keeps successive array elements suitably aligned.
  • For a standard-layout record array, a field's byte offset is index * sizeof(record) + offsetof(record, field). For a strided view, use the supplied byte strides instead.
  • AoS groups fields of one record; SoA groups one field across records. Field-wise scans and whole-record access can favor different layouts.
  • Keep allocation, initialization and layout conversion outside a kernel-only timing. Preserve results so the compiler cannot discard the work, and do not infer cache misses from wall time alone.

Reproduce closed-book

On Linux x86-64 with g++ 15.2, -std=c++20 -O0, define struct Row { char tag; std::int32_t count; char flag; }; print offsetof for all fields, sizeof and alignof. The observed values are offsets 0, 4, 8, size 12 and alignment 4. Thus rows[2].flag is at byte offset 2 * 12 + 8 = 32 from a three-element array's base. These are observations for that toolchain, not universal layout constants. Then compare summing x in vector<Point> where Point has uint64_t x,y,z against a separate vector<uint64_t> x: initialize both with x[i] = i % 100, use 1,048,576 records, g++ 15.2 -std=c++20 -O2, one warmup and seven timed scans per layout in alternating order, and consume each checksum. On your machine, record all timings and their medians with the CPU model, sizeof(Point) and allocated bytes. Python is not involved. Both checksums must be 51,903,600; no speed ranking is promised.

Traps

  • Summing member sizes misses internal and trailing padding. Packing a struct is not a free optimization and can create unaligned accesses.
  • Assuming an array of pointers stores the pointed-to objects contiguously.
  • Declaring SoA faster from one timing, or comparing different data, access patterns or conversion costs.

Practice

The section mini-project covers this: document field offsets and strides, then preserve a controlled AoS/SoA comparison with equal checksums and a reproducible measurement setup.

Self-test

  1. Why can sizeof(Row) exceed the sum of its members' sizes?

  2. A view has byte strides (40, 8). What is the offset of element [2,3]?

  3. Why might SoA help a scan that reads only x, but not a workload consuming every field of scattered records?

Completion criterion

Stop when

Your offset predictions match the measured layout, both scan checksums match, and your seven-repeat report separates measured timings from untested cache explanations.

Mark passed, then open 7.4 Only mark this when you can do it without notes.

Leads to

Comes after

Resources for this unit

  • C++ Core Guidelines
    Standard C++ Foundation communityrequiredreference
    Use the Philosophy, Interfaces, Resource management, Expressions, Containers and concurrency rule groups to review ownership and safety decisions in the native component.
  • cppreference
    cppreference communitysupportreference
    Consult language lifetime, object model, value categories, memory model, atomics, containers and iterator invalidation while reading or modifying code.
  • Algorithmica - AoS and SoA
    Sergey Slotinsupportapplication
    Read the AoS and SoA experiment for a measured case where keeping each record together wins, the counterpart to a single-field scan.
  • Memory Layout Transformations
    Intelsupportreference
    Read Overview and Topics through AOS Form and SOA Form for field-wise access and locality trade-offs. Skip Intel array-notation syntax and the LIBOR example.

Also in this section

  • AlgoMaster C++
    AlgoMasterprimarycourse
    Use the sections on compilation, pointers and references, memory, RAII and smart pointers, copy and move, STL containers, templates, errors, concurrency and paired exercises. Skip competitive-programming breadth already covered in Algorithms.
  • Clang AddressSanitizer and UndefinedBehaviorSanitizer
    LLVMrequiredimplementation
    Compile seeded memory defects with AddressSanitizer and UndefinedBehaviorSanitizer, preserve the reports, repair the root cause and keep regression tests.
  • pybind11 documentation
    pybind11 projectrequiredimplementation
    Follow First steps and NumPy support to expose one small native function with explicit shape, dtype, stride, ownership, GIL and exception behavior.
  • CMake tutorial
    CMakesupportimplementation
    Use the introductory steps for targets, libraries, testing and install rules. Produce one clean debug build and one optimized build without copied one-off commands.
  • `ld.so`: dynamic linker/loader
    Linux man-pages projectsupportreference
    Read DESCRIPTION, Dynamic string tokens and LD_DEBUG to distinguish link-time symbols from runtime shared-library discovery on Linux.
  • GDB manual: Backtraces
    GNU Projectsupportreference
    Use section 8.2 for frame numbers, bt, bt -full and optimized-out arguments when inspecting a native failure.

Quick find

Search Michi

Type to search every route, section, unit, topic and resource.

Enter opens the first result Esc closes

Reference

Keyboard shortcuts

n
Continue to the first unit not passed
j / k
Next / previous unit
1 2 3
Toggle learned, practised, passed
/
Open search
?
Show this help
Esc
Close open panels