From: Ondřej Surý Date: Tue, 7 Jul 2026 15:02:23 +0000 (+0200) Subject: Add the struct-layout-analysis agent skill X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=e6f0ef56873c6b03107ebbc74367f1a397062e8b;p=thirdparty%2Fbind9.git Add the struct-layout-analysis agent skill Point agents at pahole on the developer build's DWARF instead of compiling throwaway sizeof programs, and document the cacheline-padding idiom (union arm with a plain ISC_OS_CACHELINE_SIZE multiplier plus a STATIC_ASSERT) over the enumerated-sizeof formula, which silently miscounts when members are added. --- diff --git a/.agents/skills/struct-layout-analysis/SKILL.md b/.agents/skills/struct-layout-analysis/SKILL.md new file mode 100644 index 00000000000..1008644a88a --- /dev/null +++ b/.agents/skills/struct-layout-analysis/SKILL.md @@ -0,0 +1,49 @@ +--- +name: struct-layout-analysis +description: Measure and fix C struct layout in BIND 9 — pahole on the build's DWARF for sizes, padding holes, and cacheline boundaries, plus the house cacheline-padding idiom. Use when asked about struct size, padding, false sharing, or when adding/reordering members in hot structures. +--- + +# Struct layout: measure with pahole, pad with a multiplier + +## Measuring — pahole, never throwaway sizeof programs + +The developer build (`-Og -ggdb`) already carries DWARF; read it +instead of compiling sizeof/offsetof snippets: + +```sh +pahole -C build/lib/dns/libdns*.so.p/.c.o +pahole --holes -C +``` + +pahole prints member offsets, padding holes, total size, and cacheline +boundaries — complete layout information the compiler already computed, +with no boilerplate to write. Any object file under `build/` or the +final binary works as input. + +## Padding to cachelines — union arm with a plain multiplier + +Pad a struct to a whole number of cache lines with a union arm sized by +a plain multiplier, always paired with a static assert: + +```c +struct foo { + union { + struct { + /* members */ + }; + uint8_t __padding[ISC_OS_CACHELINE_SIZE * 6]; + }; +}; +STATIC_ASSERT(sizeof(struct foo) % ISC_OS_CACHELINE_SIZE == 0, + "struct foo size must be a multiple of the cacheline size"); +``` + +Pick the smallest `n` that fits; when members outgrow the arm to a +non-multiple size, the STATIC_ASSERT fires and prompts a bump of `n`. + +Do NOT use the enumerated-sizeof trailing formula +`uint8_t __padding[CACHELINE - (sizeof(a) + sizeof(b) + ...) % CACHELINE]` +(the historical qpzone style): it must enumerate every member's sizeof, +so adding a member silently miscounts unless the formula is updated in +lockstep. The multiplier form has no such coupling and is easier to +read.