Skip to content

perf: memoize type resolution; skip and source-generate JSON work - #51

Merged
kamronbatman merged 1 commit into
mainfrom
kb/generator_perf
Aug 22, 2026
Merged

perf: memoize type resolution; skip and source-generate JSON work#51
kamronbatman merged 1 commit into
mainfrom
kb/generator_perf

Conversation

@kamronbatman

Copy link
Copy Markdown
Member

Summary

Follow-up perf pass on the incremental pipeline, targeting the transform layer that #49 made the entire per-edit cost.

  • Per-compilation type-resolution memoization: GetTypeByMetadataName walks assemblies on every call, and the transforms resolve the same handful of names per field per class per compilation — tens of thousands of walks per keystroke at corpus scale. A ConditionalWeakTable<Compilation, ConcurrentDictionary<...>> cache collapses all 53 call sites to dictionary hits (weakly keyed so discarded compilations don't pin symbols). This also covers the migration augment stage's arbitrary schema type names for free.
  • Augment skip: the value-type fact only affects the nullable suffix on save-flagged content-struct fields, so properties without a save flag skip resolution entirely.
  • Source-generated JSON: migration parsing and schema writing go through a JsonSerializerContext, removing reflection-based serializer metadata construction from the analyzer process.

Numbers (150-class corpus with migrations)

Scenario #50 (main) this PR
Cold full run 29.9 ms 6.5 ms
Single-edit warm re-run 47.9 ms 19.6 ms
No-change re-run ~64 µs ~64 µs

The cold run is now 3.2× faster than even the pre-#49 pipeline (20.7 ms), erasing the cold-build trade-off #49 accepted; the per-edit cost drops another 2.4×.

Proof

89/89 tests green with every snapshot byte-identical; the 3,786-source real-corpus manifest is unchanged; the 150-class probe still shows SourceOutput: executed=0 after an inert edit.

🤖 Generated with Claude Code

…te JSON work

GetTypeByMetadataName walks assemblies on every call, and the transforms
resolved the same handful of names per field per class per compilation -
tens of thousands of walks per keystroke at corpus scale. A per-compilation
ConditionalWeakTable + ConcurrentDictionary cache collapses every call site
(53) to a dictionary hit, including the migration augment stage's arbitrary
schema type names.

The augment stage also skips resolution entirely for properties without a
save flag, since the value-type fact only affects the nullable suffix on
save-flagged content struct fields.

Migration JSON parsing and schema writing use a source-generated
JsonSerializerContext, removing reflection-based metadata construction from
the analyzer process.

Benchmarks (150 classes): cold full run 29.9ms -> 6.5ms (3.2x faster than
even the pre-#49 pipeline's 20.7ms), single-edit warm re-run 47.9ms ->
19.6ms, no-change re-run unchanged at ~64us. Output proven neutral: all
snapshots byte-identical and the 3,786-source corpus manifest is unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kamronbatman
kamronbatman merged commit 44704f9 into main Aug 22, 2026
2 checks passed
Sign up for free to 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