You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
HermitCrab engine: share frozen Shapes on internal Word clones (clone 36% to 9% of profile; peak memory 11 GB to 6 GB) #593
Internal Word clones deep-copy the whole Shape (every node, feature structure and annotation), but three of the four clone sites never use the copy. The change adds Word.CloneForEngine, which shares a frozen source shape and marks it shared. EnsureOwnShape copies on demand before in-place mutation, and is called in AnalysisStratumRule and SynthesisStratumRule. ResetShape and Shape.CreateEmptyLike replace clone-then-clear at the four GenerateShape sites. Public Word.Clone() still returns a deep copy. A missed mutation throws because the shared shape is frozen. This is sharing, not a cache. CloneForEngine, EnsureOwnShape, ResetShape and CreateEmptyLike are on the archived branch only.
Measured. Profile on the heaviest Sena word: Word clone 36% to 9% of wall time, Shape.CopyTo 28.6% to 13%, ReplayOnto 21.7% to 6.5%. Peak working set 11 GB to 6 GB. Wall-time attribution is unreliable on that machine. Counts are unchanged by construction.
What a revival must do first. The disposition says to reopen only if memory becomes the constraint, because the aliasing rules are subtle. Re-measure with a gloss, allomorph-index and feature-structure signature, since the old parity signature checked only morph counts.
Archived from docs/hc-optimization-ledger @ 2eba2f5 (docs/optimizations/shape-sharing-on-clone.md), which is being deleted:
Copy-on-write Shape sharing in Word.Clone
Status: retained on perf/hc-optimization-archive, not merged (Word.CloneForEngine, EnsureOwnShape, ResetShape, Shape.CreateEmptyLike). Portable: partly. The observation (three of four clone sites
never use the copied shape) is engine-independent; the mechanism (shared reference to an immutable
structure) is how a Rust port would naturally write it already.
The observation
A CPU profile of the heaviest Sena word (60 s sampled, memoized path) put Word cloning at 36% of wall,
of which Shape.CopyTo was 28%: every clone deep-copied every ShapeNode, every node's feature
structure (SimpleFeatureValue.CloneImpl 22%), every annotation, and built a node-mapping dictionary.
The callers: Word.ReplayOnto 15% (memo replay; never mutates the shape), Word.ExpandAlternatives 9%
(immediately replaces_shape), AnalysisAffixProcessAllomorphRuleSpec.ApplyRhs 5% (GenerateShape
immediately Clear()s the copy), non-head clones 2.5%, LexicalLookup (the RootAllomorph setter
replaces _shape).
The change
Internal engine clone: if the source shape is frozen, share the reference and mark _shapeShared; otherwise
deep-copy it. Public Word.Clone() always returns a deep, independently mutable shape.
EnsureOwnShape(): clone once, on demand, before in-place mutation. Called in AnalysisStratumRule and SynthesisStratumRule before phonological rules are applied to a fresh clone (rewrite specs insert
nodes and hold node references obtained by matching, so the un-share must precede the match).
ResetShape(): replace with a new empty shape of the same configuration. Used by the four GenerateShape/rebuild sites (analysis affix, analysis compounding subrule, synthesis affix, synthesis
compounding) instead of clone-then-clear.
ExpandAlternatives marks the adopted shape as shared; the RootAllomorph setter and constructors mark
their fresh clones as owned.
The safety net is that a shared shape is frozen: any mutation through a missed site throws
(Shape.CheckFrozen, frozen node feature structures; a missing guard on Annotation.Range was added).
During development the first full test run threw at exactly the two stratum sites, which is how they
were found; no other site surfaced across 122 HermitCrab tests, 464 fixture words and 45 Sena words.
Measured
Profile after the change: Word clone 36% → 9% of wall, Shape.CopyTo 28.6% → 13% (the remainder is
the stratum's EnsureOwnShape and part copying inside GenerateShape), ReplayOnto 21.7% → 6.5%. Peak
working set on the heaviest word 11 GB → 6 GB. Wall-time attribution is unreliable on this machine (see
the round document); counts are unchanged by construction.
WordShapeSharingTests covers public-clone independence, copy-on-write, reset paths, and missed-mutation
guards. The final conformance-inclusive run passed 603 tests with one expected host-privilege skip.
Activity
johnml1135 commentedon Nov 7, 2026
Archived from
docs/hc-optimization-ledger@ 2eba2f5 (docs/optimizations/shape-sharing-on-clone.md), which is being deleted:Copy-on-write Shape sharing in
Word.CloneStatus: retained on
perf/hc-optimization-archive, not merged (Word.CloneForEngine,EnsureOwnShape,ResetShape,Shape.CreateEmptyLike). Portable: partly. The observation (three of four clone sitesnever use the copied shape) is engine-independent; the mechanism (shared reference to an immutable
structure) is how a Rust port would naturally write it already.
The observation
A CPU profile of the heaviest Sena word (60 s sampled, memoized path) put
Wordcloning at 36% of wall,of which
Shape.CopyTowas 28%: every clone deep-copied everyShapeNode, every node's featurestructure (
SimpleFeatureValue.CloneImpl22%), every annotation, and built a node-mapping dictionary.The callers:
Word.ReplayOnto15% (memo replay; never mutates the shape),Word.ExpandAlternatives9%(immediately replaces
_shape),AnalysisAffixProcessAllomorphRuleSpec.ApplyRhs5% (GenerateShapeimmediately
Clear()s the copy), non-head clones 2.5%,LexicalLookup(theRootAllomorphsetterreplaces
_shape).The change
_shapeShared; otherwisedeep-copy it. Public
Word.Clone()always returns a deep, independently mutable shape.EnsureOwnShape(): clone once, on demand, before in-place mutation. Called inAnalysisStratumRuleandSynthesisStratumRulebefore phonological rules are applied to a fresh clone (rewrite specs insertnodes and hold node references obtained by matching, so the un-share must precede the match).
ResetShape(): replace with a new empty shape of the same configuration. Used by the fourGenerateShape/rebuild sites (analysis affix, analysis compounding subrule, synthesis affix, synthesiscompounding) instead of clone-then-clear.
ExpandAlternativesmarks the adopted shape as shared; theRootAllomorphsetter and constructors marktheir fresh clones as owned.
The safety net is that a shared shape is frozen: any mutation through a missed site throws
(
Shape.CheckFrozen, frozen node feature structures; a missing guard onAnnotation.Rangewas added).During development the first full test run threw at exactly the two stratum sites, which is how they
were found; no other site surfaced across 122 HermitCrab tests, 464 fixture words and 45 Sena words.
Measured
Profile after the change:
Wordclone 36% → 9% of wall,Shape.CopyTo28.6% → 13% (the remainder isthe stratum's
EnsureOwnShapeand part copying insideGenerateShape),ReplayOnto21.7% → 6.5%. Peakworking set on the heaviest word 11 GB → 6 GB. Wall-time attribution is unreliable on this machine (see
the round document); counts are unchanged by construction.
WordShapeSharingTestscovers public-clone independence, copy-on-write, reset paths, and missed-mutationguards. The final conformance-inclusive run passed 603 tests with one expected host-privilege skip.