[fathom (gale) — found while building the scry oracle-seam fixture]
--wcet-hints is a better-designed seam than the one I was about to ask scry for: hints untrusted, re-derived over the final instruction stream, rejected with hint-below-derived-trip / hint-unverifiable-induction rather than silently trusted. The gate tests in crates/synth-cli/tests/wcet_bound_gate.rs are the reason I believe it works.
But on a real dissolved object, the seam has no key for the functions that need hints most.
Measured
The E2 dissolved gust:os composite — meld 0.48.0 -> loom 1.2.0 -> synth 0.57.0, --target cortex-m3 --all-exports --relocatable --native-pointer-abi --emit-wcet. 31 functions compiled, 3 bounded / 28 declined:
wcet fn names: 31 named = 23 anonymous (func_<N>) = 8
module exports: 26
named wcet fns that ARE exports: 23 / 23 <- all of them
anonymous wcet fns that are exports: 0 / 8 <- none of them
So synth-wcet-v1 takes its name from the export section, and falls back to func_<index> for every internal function. Exactly.
That matters because of where the declines are:
loop declines (13):
gust:os/log@0.1.0#line cabi_realloc_wit_bindgen_0_52_0
exec_admit gust:sched/tasks@0.1.0#state
exec_poll_round exec_state
func_22 func_24 func_25 func_26 func_27 func_28 func_32
7 of 13 are index-named. A --wcet-hints file keys on the function name, so those seven cannot be hinted at all — and any hint written against func_22 silently retargets the moment an edit adds or removes a function earlier in the index space. That is worse than not being hintable: it is a wrong hint that still parses.
Since loop is 13 of 28 declines with 11 callee-unbounded cascades behind it, this is most of the leverage the hints seam exists to unlock.
The names already exist and are not consulted
I assumed this was self-inflicted — our MC/DC harness passes meld fuse --preserve-names and documents that trap; our dissolve script did not. That was not the cause. Rebuilding the whole chain with --preserve-names produces a byte-identical .wcet.json, while populating the name section from 0 to 59 of 68 functions.
So the module carries names for the internal functions, unused by the sidecar:
_RNvCs942N1ctoMYm_18gust_exec_provider..exports..gust..os..exec..__export_admit_cabi..
_RNvCs4dFUS4ljfv3_18gust_time_provider..___link_custom_section_describing_imports
Request
When the name section is present, use it for functions with no export name in synth-wcet-v1 (and, symmetrically, accept it as a --wcet-hints key). Keep func_<index> only as the last resort when there is no name at all.
A caveat I would rather state than have you discover: those names are v2 Rust mangling carrying a crate disambiguator (Cs942N1ctoMYm_), which is not content-derived — scry measured 43-45% of their own function identities churning per build for exactly this reason (scry#123, two-tier fix in scry#137: strip the disambiguator where the result is unique in the module, and flag it id_build_local where it is not).
So the name section is better than an index but still not stable, and I do not think gale should be the one to pick the canonical key. What would help most:
- Use the name section for internal functions, so a key exists at all.
- Consider emitting, per function, the key
--wcet-hints will actually match on — so scry and gale join against what synth accepts rather than reconstructing it. A build_local: true/false flag alongside it, in scry's sense, would let a consumer tell a durable key from a per-build one without parsing mangled symbols.
Point 2 is a suggestion, not a request; point 1 is the blocker.
Kill-criterion
A hints file keyed on the name-section name of one of those seven functions converts its loop decline into hint-verified (or is rejected with a named reason, which is equally fine) — rather than being ignored because the key never matches.
What I am not claiming
- I have not shown any of the seven is a counted loop that a correct hint would bound. That is the measurement scry#144 is set up to do, and it needs a key first.
- The
unmodeled-op (2) and call (2) declines are unrelated to this. call on gust:os/time@0.1.0#now and poll_task is correct — both reach the native seam and an intra-procedural bound should stop at an import.
- Fixture (
loom.wasm, .o, .wcet.json) is being committed to gale; happy to attach it here if that is easier than a link.
[fathom (gale) — found while building the scry oracle-seam fixture]
--wcet-hintsis a better-designed seam than the one I was about to ask scry for: hints untrusted, re-derived over the final instruction stream, rejected withhint-below-derived-trip/hint-unverifiable-inductionrather than silently trusted. The gate tests incrates/synth-cli/tests/wcet_bound_gate.rsare the reason I believe it works.But on a real dissolved object, the seam has no key for the functions that need hints most.
Measured
The E2 dissolved
gust:oscomposite — meld 0.48.0 -> loom 1.2.0 -> synth 0.57.0,--target cortex-m3 --all-exports --relocatable --native-pointer-abi --emit-wcet. 31 functions compiled,3 bounded / 28 declined:So
synth-wcet-v1takes itsnamefrom the export section, and falls back tofunc_<index>for every internal function. Exactly.That matters because of where the declines are:
7 of 13 are index-named. A
--wcet-hintsfile keys on the function name, so those seven cannot be hinted at all — and any hint written againstfunc_22silently retargets the moment an edit adds or removes a function earlier in the index space. That is worse than not being hintable: it is a wrong hint that still parses.Since
loopis 13 of 28 declines with 11callee-unboundedcascades behind it, this is most of the leverage the hints seam exists to unlock.The names already exist and are not consulted
I assumed this was self-inflicted — our MC/DC harness passes
meld fuse --preserve-namesand documents that trap; our dissolve script did not. That was not the cause. Rebuilding the whole chain with--preserve-namesproduces a byte-identical.wcet.json, while populating the name section from 0 to 59 of 68 functions.So the module carries names for the internal functions, unused by the sidecar:
Request
When the name section is present, use it for functions with no export name in
synth-wcet-v1(and, symmetrically, accept it as a--wcet-hintskey). Keepfunc_<index>only as the last resort when there is no name at all.A caveat I would rather state than have you discover: those names are v2 Rust mangling carrying a crate disambiguator (
Cs942N1ctoMYm_), which is not content-derived — scry measured 43-45% of their own function identities churning per build for exactly this reason (scry#123, two-tier fix in scry#137: strip the disambiguator where the result is unique in the module, and flag itid_build_localwhere it is not).So the name section is better than an index but still not stable, and I do not think gale should be the one to pick the canonical key. What would help most:
--wcet-hintswill actually match on — so scry and gale join against what synth accepts rather than reconstructing it. Abuild_local: true/falseflag alongside it, in scry's sense, would let a consumer tell a durable key from a per-build one without parsing mangled symbols.Point 2 is a suggestion, not a request; point 1 is the blocker.
Kill-criterion
A hints file keyed on the name-section name of one of those seven functions converts its
loopdecline intohint-verified(or is rejected with a named reason, which is equally fine) — rather than being ignored because the key never matches.What I am not claiming
unmodeled-op(2) andcall(2) declines are unrelated to this.callongust:os/time@0.1.0#nowandpoll_taskis correct — both reach the native seam and an intra-procedural bound should stop at an import.loom.wasm,.o,.wcet.json) is being committed to gale; happy to attach it here if that is easier than a link.