docs(build): record the thin-binary layout and its measured effect

Replace the 'known remaining inefficiency' section with the layout that
now exists, plus the measured before/after (clean release build: 2m14s
-> 1m46s wall, keydr units 61.0s -> 32.4s, peak ~2.0 GB unchanged).

Add a maintenance note: new modules go in src/lib.rs, not src/main.rs.
Re-declaring them in the binary would silently restore the double
compile this refactor removed.
This commit is contained in:
2026-08-07 01:08:44 +00:00
parent 0a74fe3143
commit f8d3bb5b2b
+28 -24
View File
@@ -9,8 +9,9 @@ cargo build --release
``` ```
Plain cargo. No wrapper, no memory ceiling, no reduced optimisation. Plain cargo. No wrapper, no memory ceiling, no reduced optimisation.
A clean release build peaks at **1.92 GB** and takes **2m17s** on a A clean release build peaks at **~2.0 GB** and takes **1m46s** on a
4-core / 7.6 GB VM. 4-core / 7.6 GB VM; an incremental rebuild after touching one file is a
few seconds.
If that's not what you're seeing, read on. If that's not what you're seeing, read on.
@@ -87,35 +88,38 @@ Nothing there reduces the optimisation of shipped code.
--- ---
## Known remaining inefficiency ## Project layout
`src/main.rs` re-declares the whole module tree (`mod app; mod config; All application code lives in the **library** (`src/lib.rs``src/run.rs`
...`) instead of depending on the `keydr` lib target, so **every module and the module tree). `src/main.rs` is a 10-line entry point that calls
compiles twice** — once for the lib, once for the bin. The `i18n!` macro `keydr::run()`.
must therefore be invoked in both crate roots (`t!()` expands to
`crate::_rust_i18n_t`, so it must exist in each crate).
Measured with `cargo build --release --timings` on a clean tree, the two This matters for build time. `main.rs` used to re-declare the whole module
duplicated units are the slowest in the whole graph: tree (`mod app; mod config; ...`), which made the binary a *second
independent crate*: every module — and the entire rust-i18n translation
table — was compiled twice, and 281 unit tests ran twice.
Measured effect of consolidating it, clean release build:
``` ```
33.7s keydr (bin) before after
26.0s keydr (lib) keydr (bin) 33.7s 0.3s
1.4s generate_test_profiles (bin) keydr (lib) 26.0s 31.0s
------ keydr total 61.0s 32.4s (-28.6s)
61.0s of 292.2s total unit-seconds (21%) total unit-seconds 292.2s 264.5s
wall clock 2m14s 1m46s (-28s, -21%)
``` ```
So restructuring `main.rs` to `use keydr::...` would save roughly 26s of Test coverage is unchanged — 341 unique tests before and after. The
compile work — real, but nowhere near half the build. Wall-clock saving is execution count dropping from 622 to 340 is the duplicate run disappearing.
smaller still, since those units partly overlap with dependency
compilation across 3 parallel jobs (292s of unit-work compressed into
~2m15s wall). Worth doing for code hygiene; not a build-performance
emergency.
Note the remaining ~79% is dependency compilation (`reqwest` 12.7s, **Keep it this way:** if you add a module, declare it in `src/lib.rs`, not
`clap_builder` 11.4s, `toml_edit` 9.3s, `tokio` 8.0s...), which is `src/main.rs`. Re-declaring modules in the binary would silently restore
one-time work that incremental builds skip entirely. the double compile.
The remaining ~79% of build time is dependency compilation (`reqwest`
12.7s, `clap_builder` 11.4s, `toml_edit` 9.3s, `tokio` 8.0s...), which
incremental builds skip entirely.
--- ---