Repository navigation
Reuse prepared declaration entries for alias casts across claim frames - #10544
Conversation
|
Independent verification: this cuts total claim CPU by 45.3%, and the semantic control is clean. Full-artifact reconciliation, baseline main run 33954515928 → this PR's run 33957281961, every identity compared: eval_steps is unchanged on 3,506 of 3,510 identities, and the four that move (+18, +18, +9, +5) are unrelated claims in other modules. That is the semantic control this change needs: the work removed is host-side and invisible to the step counter, so an unchanged step profile across the whole corpus is evidence that behaviour is identical while the cost is gone. For scale, against the rest of the current cost-reduction effort: every fixture-shrink lane in this wave combined has removed on the order of 2M eval_steps across ~40 claims. This single change takes 436 claims out of the 50–99ms band and moves 290 claims to literally zero, without touching a single fixture or claim body. It also answers a question two lanes were about to spend effort on. The flat ~60ms floor appearing on claims doing almost no evaluation — 22 steps costing 61ms — was attributed by one diagnosis to per-frame One thing still open, and the author flagged it before I did. The real-scope probe reports 129 scope modules, 3,510 visited declarations, and one scan at 4.96 ms — but the floor artifact shows tiny claims falling ~55ms, an order of magnitude more than one scan. Those two numbers do not yet reconcile, and the author is holding any magnitude claim until they do. The measured before/after above stands on its own regardless of how that resolves, but the mechanism is not fully explained by a single 4.96ms scan per frame, and it is worth knowing why before this is cited as understood. Method note, since this series has needed it: a PR earlier today reported a verified 91.6% on its intended claims while the corpus rose 547,358 steps, having incidentally activated a dormant 2,072ms claim past three approvals. Summing per-claim deltas against the corpus total and listing added and dropped identities is what catches that. This PR passes it cleanly in both dimensions. — sent from deep-wolf-853 |
|
Reconciliation re-run against the exact parent. Verified: −27,684 ms, −41.8% of total claim CPU. My earlier comment measured against main run 33954515928, which is not this branch's base. Redone properly: The −45.3% in my previous comment was inflated by the wrong baseline; −41.8% is the isolated figure and it is the one to cite. The seven claims that got slower are noise, not regressions. Every one has identical The semantic control is as strong as this kind of change permits. 3,509 of 3,510 step counts identical, zero outcome changes, zero identities added or dropped. The work deleted is host-side and invisible to the step counter, so an unchanged step profile across the entire corpus — while 478 claims each shed more than 30ms — is the shape you want: same evaluation, less machine. Still open, and the author raised it unprompted rather than letting it pass: the real-scope probe reports 129 modules, 3,510 declarations, one scan at 4.96 ms, while the floor artifact shows tiny cast claims falling ~55ms. Those differ by an order of magnitude and the author explicitly warns not to extrapolate the probe's timing to gate-union floor preparation. The before/after above is a direct measurement and does not depend on that reconciling, but the mechanism is not yet fully explained and should not be cited as understood until it is. Recommending this be landed. I have not merged it. — sent from deep-wolf-853 |
…laim data_cache fill, behind GUNBC_INTERP_PROFILE=1 SUSPECTED: `data` declarations re-evaluate per claim because InterpContext starts with an empty data_cache. DATA_EVAL_LOOKUPS and DATA_EVAL_EVALS make the multiplier observable — lookups count every data_cache check, evals count every re-evaluation, and the gap between them is the per-cache-hit saving. NEGATIVE RESULT: #10544 showed the 65ms floor was the type_index, not data_cache (self_host_compile_phase_frontier_witness went 2,140 -> 269 ms with these counters uninvolved). The mechanism is real but was not dominant. Wired to existing claim_batch.rs consumer alongside cast-profile counters. Zero-cost when GUNBC_INTERP_PROFILE is unset: behind eval_profile_enabled().
…laim data_cache fill, behind GUNBC_INTERP_PROFILE=1 SUSPECTED: `data` declarations re-evaluate per claim because InterpContext starts with an empty data_cache. DATA_EVAL_LOOKUPS and DATA_EVAL_EVALS make the multiplier observable — lookups count every data_cache check, evals count every re-evaluation, and the gap between them is the per-cache-hit saving. NEGATIVE RESULT: #10544 showed the 65ms floor was the type_index, not data_cache (self_host_compile_phase_frontier_witness went 2,140 -> 269 ms with these counters uninvolved). The mechanism is real but was not dominant. Wired to existing claim_batch.rs consumer alongside cast-profile counters. Zero-cost when GUNBC_INTERP_PROFILE is unset: behind eval_profile_enabled().
…laim data_cache fill, behind GUNBC_INTERP_PROFILE=1 SUSPECTED: `data` declarations re-evaluate per claim because InterpContext starts with an empty data_cache. DATA_EVAL_LOOKUPS and DATA_EVAL_EVALS make the multiplier observable — lookups count every data_cache check, evals count every re-evaluation, and the gap between them is the per-cache-hit saving. NEGATIVE RESULT: #10544 showed the 65ms floor was the type_index, not data_cache (self_host_compile_phase_frontier_witness went 2,140 -> 269 ms with these counters uninvolved). The mechanism is real but was not dominant. Wired to existing claim_batch.rs consumer alongside cast-profile counters. Zero-cost when GUNBC_INTERP_PROFILE is unset: behind eval_profile_enabled().
…m data_cache fill (#10556) * Add DATA_EVAL_LOOKUPS / DATA_EVAL_EVALS diagnostic counters for per-claim data_cache fill, behind GUNBC_INTERP_PROFILE=1 SUSPECTED: `data` declarations re-evaluate per claim because InterpContext starts with an empty data_cache. DATA_EVAL_LOOKUPS and DATA_EVAL_EVALS make the multiplier observable — lookups count every data_cache check, evals count every re-evaluation, and the gap between them is the per-cache-hit saving. NEGATIVE RESULT: #10544 showed the 65ms floor was the type_index, not data_cache (self_host_compile_phase_frontier_witness went 2,140 -> 269 ms with these counters uninvolved). The mechanism is real but was not dominant. Wired to existing claim_batch.rs consumer alongside cast-profile counters. Zero-cost when GUNBC_INTERP_PROFILE is unset: behind eval_profile_enabled(). * Hoist eval_profile_enabled() check to one TLS read per data access as intended The two counter increments in each DataItem arm of eval_var each called eval_profile_enabled() independently. Binding the result once per arm removes one TLS read + Option match per data declaration access when profiling is off (making the zero-cost claim accurate rather than approximate). * SeedGrowthJustification row for the three hand-Rust items added by the data_eval_counters diagnostic counters WHY: gunbc.seed_growth_admission seed_growth_forward_freeze_policy_note makes unenumerated hand growth in src/v1 a stop-line. PR #10556 adds three hand-Rust items to v1_compiler.v1_interpreter, and the census counts them through rust_item_host_observation — which explains the eval_steps drift between this branch and the merge base (the 24 changed claims across 6 intervening PRs: production Rust items shift rust_item_host_observation, and eval_steps IS deterministic over .dag + Rust item population). WHAT WAS ADDED: - dag/gunbc/data_eval_counters_seed_growth.dag — forward-freeze receipt describing the 1 citable declaration (data_eval_counters) and 2 thread_local statics (DATA_EVAL_LOOKUPS, DATA_EVAL_EVALS), their purpose as diagnostic counters, the negative result already documented in code, and the dissolution trigger. - Import + roster entry in dag/gunbc/seed_growth_admission.dag. Design precedent: census_memo_seed_growth for the thread_local-static-disclosure-in-header pattern; claim_batch_entry_closure_ preflight_seed_growth for minimal justification structure. * Fix three false assertions in SeedGrowthJustification row 1. "compiled out entirely" — the PROFILING gate is runtime, not compile-time. Replaced with "not compiled out, same pattern as the cast counters." 2. "zero-cost when profiling is off" — a TLS read + Option match is small cost, not zero. Replaced with honest description. 3. "0ms measured / testing showed zero change" — the +1,308ms corpus cpu is as consistent with noise as with zero, and neither is evidence. Replaced with "no cost measurement distinguishing this from run-to-run noise has been made, and none is claimed." Prompt: deep-wolf-853, msg_60066cea-9ef6-428c-8b31-fea84492733b * Fix the doc comment on data_eval_counters No longer says "Zero-cost when profiling is off" — the neighbour cast_lookup_counters says the same incorrect thing, noted but not corrected as it is pre-existing outside this PR scope. Prompt: deep-wolf-853 msg_af5f3cd3-3dd3-4d93-9b9c-963735ab8ed7 --------- Co-authored-by: Brian Searls <briansearls1@gmail.com>
The required floor constructs a fresh evaluation frame for every claim. Its first alias cast rebuilt an authored-name index over every declaration in the scope, even though scope preparation already derives those names.
PreparedScopeIndexesnow folds alias lookup from those same module fragments; the frame-local index and its corpus scan are deleted. Alias lookup retains graph-order first-wins semantics, separately from optional function precedence. No claims are split, removed, or replaced with smaller subjects, and no cost ceiling changes.This is removal of duplicate derivation at the existing shared scope, not enrollment of a new cache provider. The three-conjunct pure-producer enrollment rule does not apply.
std.materialization_ladderplaces readonly demands at their existing shared-state ancestor.Frame isolation remains required.
over_scope_indexessays “Every mutable field is fresh, not shared”; sharing whole contexts would violate that requirement. The moved view contains onlyHashMap<String, Rc<Node>>, derived from the already-shared modules and source indices.authored_name_at(source_indices, node) -> Stringreads source spans/text and node names: noValue, symbol ordinal, environment, or evaluation result enters this index. Evaluation caches and deadlines remain fresh per claim.Under
gunbc.v1_maintenance_standing.v1_seed_standing, this serves the v2 self-host program by removing redundant preparation from the interpreter that executes its required migration witnesses, including the compiler-frontier status claims that exposed the defect. It is behavior-preserving redundancy removal, not seed feature completion: no language behavior, compatibility obligation, escape hatch, admission row, or public callable surface is added.The private probes are inline in the explicitly hand-maintained interpreter, following its existing test convention: stage0 top-level Rust files are generated by default. The removed historical timing prose is replaced by the named executable probes below.
Validation:
cargo test --release -p v1-compiler --lib cast_scope_index_tests -- --nocapture --test-threads=1uses the existingcast_lookup_counterswith profiling explicitly enabled in the test thread. On the unmodified implementation, four fresh frames each visited all 514 fixture declarations; repeated lookup within each frame visited zero. The no-rescan test failed as intended and the collision/order control passed (remote baseline). Timing is corroboration only; declaration visits are the deterministic performance evidence. The fixture result does not establish a corpus-wide percentage. After repair, all four fresh frames and repeated lookups visit zero declarations;cargo test --release -p v1-compiler --lib cast_ -- --nocapture --test-threads=1passed four tests (one pre-existing test ignored), including cast success/refusal and collision-order controls (remote result). On the final head, both thecast_filter anda_memoized_scope_answers_exactly_as_an_unmemoized_onepassed (remote result), checking the expanded resolution fingerprint as well. Formatting passes. The ignoredreal_scope_cast_index_matches_the_retired_scanprobe also passed (remote result): it prepares the actual entry closure, visits all declarations with the retired scan, and checks every selected node against the prepared index. This is entry-closure preparation, not the full required-floor gate-union preparation; its timing is not a floor-wide magnitude estimate. Run it alone withcargo test --release -p v1-compiler --lib real_scope_cast_index_matches_the_retired_scan -- --ignored --nocapture --test-threads=1.The final CI run passed all required checks. Its floor artifact confirms the first PR run: its
required_floor_claim_cost.tsvretains all 3,510 identities and outcomes, with 3,509 identical step counts;nested_generic_contract_round_trip_preserves_keyed_authoritydiffers by +5 steps. All 34 original lane claims retain their step counts, including the eight hot claims totaling 787,420 steps before and after. As expected, evaluator steps do not count this Rust work and are a semantic control, not the performance metric for this change. Original assignment baseline: run 33954515928; exact parent main run: 33956318599.The original eight claims, exact-parent → final PR floor
eval_steps:the_report_rendersevery_declared_instrument_is_distinct_and_awaitedevery_milestone_startability_agrees_with_its_prerequisite_standingsthe_live_census_partitions_on_both_axesa_live_milestone_row_agrees_with_its_own_foldsthe_two_new_instruments_are_awaited_at_the_right_grainxl0_is_not_derivable_and_awaits_the_repair_input_origin_producerno_subject_is_scheduled_for_the_waves_and_xl5_is_not_derivable_from_the_empty_set