Skip to content

typing/perf 7: owning env meet — quadratic clone elimination (chains −22–28%) - #86

Open
Felipe705x wants to merge 1 commit into
tc-perf/06-desc-interningfrom
tc-perf/07-env-costs
Open

typing/perf 7: owning env meet — quadratic clone elimination (chains −22–28%)#86
Felipe705x wants to merge 1 commit into
tc-perf/06-desc-interningfrom
tc-perf/07-env-costs

Conversation

@Felipe705x

Copy link
Copy Markdown
Collaborator

Stacked on #85.

New lattice-op counters first localized the cost: chains do zero type meets — they were paying quadratic env cloning (272 String-key copies for chain_16, every Concat re-cloning the accumulator). Subquery/OPTIONAL shapes spend their time in genuine meet/join walks instead (44 for multi_optional); those are the next milestone's target and deliberately untouched here.

  • TypeEnvironment::meet_owned consumes the left env; scratch-staged merge keeps the error path's exact keep-previous-env behavior.
  • warn_for_collapsed_bindings now iterates only shared keys — provably the only keys that can collapse (the old walk's one-sided arms were unreachable); warnings byte-identical.
  • union gets an Rc::ptr_eq fast path (both arms usually hold the same refine-cache Rc; join(v,v) = v).

vs #85: chain_16 64 → 46 µs, chain_dir_16 73 → 55 µs, anydir_8 54 → 41 µs, union_8 59 → 50 µs; subq shapes unchanged by design. Chains now sit at 2.7–4.1× parse cost.

🤖 Generated with Claude Code

… fast path

New lattice-op counters (vt_meets, vt_joins, env_bindings_copied)
localized the remaining cost precisely:
- chains do ZERO VariableType meets — their cost was env cloning:
  every Concat cloned the accumulated environment, O(vars) String-key
  clones per hop, quadratic along a chain (272 copies for chain_16);
- subq/optional shapes spend their time in real meet/join walks over
  rich refined types (22–44 per check) — targeted next, not here.

Changes:
- TypeEnvironment::meet_owned consumes the left env (Concat/Join/
  match-chain/subquery folds own their accumulator). Merged bindings
  stage in a scratch Vec applied on success; the Err path hands the
  environment back untouched, preserving the exact
  keep-previous-env-on-error behavior. meet(&,&) remains as the
  cloning wrapper.
- warn_for_collapsed_bindings walked all merged keys; only SHARED keys
  can collapse (one-sided keys pass through meet untouched, so their
  "empty" was pre-existing and the old walk skipped them — its
  one-sided message arms were unreachable). Now takes the stashed
  shared bindings, warnings byte-identical.
- TypeEnvironment::union: Rc::ptr_eq fast path when both arms hold the
  same shared binding (join(v,v) collapses to v) — common since both
  arms get the same refine-cache Rc.

Idle-machine medians vs M06:
- chain_16    64.2 → 46.4 us (−28%)   chain_8   28.3 → 22.1 us (−22%)
- chain_dir_16 73.4 → 55.1 us (−25%)  anydir_8  54.1 → 40.5 us (−25%)
- union_8     59.0 → 50.0 us (−15%)
- subq_exists / multi_optional unchanged (their cost is the lattice
  meets; that is the next milestone)
- chk/parse: chains now 2.7–4.1×

Full sweep 80 targets green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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