Skip to content

perf(build): unity + /MP for analyzer compiles (16x), guard three kbm headers - #719

Merged
ddehilster merged 1 commit into
masterfrom
perf/analyzer-build-speed
Aug 25, 2026
Merged

perf(build): unity + /MP for analyzer compiles (16x), guard three kbm headers#719
ddehilster merged 1 commit into
masterfrom
perf/analyzer-build-speed

Conversation

@ddehilster

Copy link
Copy Markdown
Member

Compiling a generated analyzer is dominated by re-parsing the same headers. parse-en-us emits 520 kb/*.cpp (57 MB) plus 139 run/*.cpp, and an 80 KB generated source expands to 4.5 MB of engine headers — roughly 45% of each TU's compile time is that header block, paid 520 times.

Two fixes

1. UNITY_BUILD batches the generated sources so the header block is parsed once per batch instead of once per file.

0.71 s/file -> 0.039 s/file (batch 65)

2. /MP. This one is a plain bug. cmake --build --parallel N with the Visual Studio generator becomes msbuild /m:N, which parallelises projects — there is one project, so without /MP the sources compile serially regardless of what --parallel says. Measured on 20 files with --parallel 4 on a 22-core box:

NO /MP 15.08s (0.754 s/file -- the serial rate)
WITH /MP 4.29s (0.214 s/file)

Results

Clean 100-file CMake build, current config vs proposed: 61.79s → 3.87s (16x), with identical exported symbol sets (115 in both, diffed).

A full parse-en-us kb + run build (528 files, 57 MB) now takes ~30s where it used to take 10–15 minutes — the figure the compile-analyzer.yml comment refers to when it says "long builds (10+ min for large analyzers like parse-en-us) look hung".

Batch size is derived from the core count (~2 batches per core, clamped to [8,64]) so small analyzers still spread across cores and large ones don't build one enormous TU. -DNLP_UNITY_BUILD=OFF falls back to one TU per file.

Why the header guards are in here

UNITY_BUILD does not compile at all without them. kbm/sym_s.h, kbm/con_s.h and kbm/ptr_s.h had no include guards, so a second inclusion inside one TU fails with C2011: 'sym': 'struct' type redefinition.

These headers ship inside nlpengine-compile-libs, so the cloud compile service needs a release carrying this commit before it can turn unity on at its end. Companion PRs for nlp-compile-service and vscode-nlp follow — all three generate the same CMakeLists and have to move together.

Version

Assumes #718 (3.8.6) lands first. If it doesn't, this should be 3.8.6.

🤖 Generated with Claude Code

…eaders
Compiling a generated analyzer is dominated by re-parsing the same
headers. parse-en-us emits 520 kb/*.cpp (57 MB) plus 139 run/*.cpp, and
an 80 KB generated source expands to ~4.5 MB of engine headers -- about
45% of each translation unit's compile time is that header block, paid
520 times.
Two fixes, both measured on parse-en-us:
1. UNITY_BUILD batches the generated sources so the header block is
parsed once per batch instead of once per file. 0.71 s/file -> 0.039
s/file at batch 65.
2. /MP. `cmake --build --parallel N` with the Visual Studio generator
becomes msbuild /m:N, which parallelises PROJECTS -- there is one
project, so without /MP the sources compile serially no matter what
--parallel says. Measured on 20 files with --parallel 4:
15.08s without /MP, 4.29s with.
End to end, a clean 100-file CMake build went 61.79s -> 3.87s (16x) with
identical exported symbol sets, and a full parse-en-us kb+run build
(528 files, 57 MB) takes ~30s where it used to take 10-15 minutes.
Batch size is derived from the core count (~2 batches per core, clamped
to [8,64]) so small analyzers still spread across cores and large ones
do not build one enormous TU. -DNLP_UNITY_BUILD=OFF falls back to one TU
per file.
UNITY_BUILD needs the include guards: kbm/sym_s.h, kbm/con_s.h and
kbm/ptr_s.h had none, so a second inclusion inside one TU fails with
C2011 'sym': 'struct' type redefinition. These headers ship in
nlpengine-compile-libs, so the cloud compile service needs a release
carrying this commit before it can turn unity on at its end.
Version note: assumes #718 (3.8.6) lands first. If it does not, this
should be 3.8.6.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@ddehilster