Skip to content

HermitCrab engine: share frozen Shapes on internal Word clones (clone 36% to 9% of profile; peak memory 11 GB to 6 GB) #593

Open

Description

@johnml1135

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.

Record: see the archived write-up below
Ledger: #490 (comment); disposition: #490 (comment)
From #490 (closed).

Activity

  1. johnml1135 commented on Nov 7, 2026

    @johnml1135
    CollaboratorAuthor

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    • Status
      🆕 New

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions