Skip to content

Latest commit

 

History

History
104 lines (82 loc) · 4.6 KB

debugging.md

File metadata and controls

104 lines (82 loc) · 4.6 KB

Debugging

First locate the broken boundary: ingest IR, typed/lowered IR, emitted source, or the running program. Build the relevant tool once or invoke it with cargo run --bin <name> --.

Inspect a Ruby expression

roundhouse-ast exposes Prism, template compilation, ingest, and Ruby expression emission:

cargo run --bin roundhouse-ast -- --help
cargo run --bin roundhouse-ast -- -e '[:a, :b]'
cargo run --bin roundhouse-ast -- --stage prism -e '@x.y do end'
cargo run --bin roundhouse-ast -- --stage compile-erb view.html.erb
cargo run --bin roundhouse-ast -- --stage emit-ruby -e '"a#{x}b"'
cargo run --bin roundhouse-ast -- --stages --erb -e '<%= x %>'
cargo run --bin roundhouse-ast -- --round-trip -e '[:a, :b]'

A positional .rb/.erb file replaces -e; .erb selects template mode. IR stages print JSON. --round-trip accepts plain Ruby only and compares ingest → emit-ruby → ingest IR; it does not prove whole-app source equality or runtime correctness. On divergence it prints both IRs and a diff.

Inspect lowered IR

dump_ir analyzes and lowers a fixture before dumping the shape consumed by application emitters. Narrow it to the failing class/method rather than reading the entire app:

cargo run --bin dump_ir -- --help
cargo run --bin dump_ir -- fixtures/real-blog --select 'ArticlesController#create'
cargo run --bin dump_ir -- fixtures/real-blog --format json --select Article

--raw-views instead shows pre-lowering view bodies. Use the same selector as the failing regression to distinguish a wrong lowering from a wrong emitter.

Inspect emitted files

emit_preview is a narrow bench/browser debugging tool. It analyzes source IR directly and emits bare files, not the complete packaged application or the shared post-analyze lowering path:

cargo run --bin emit_preview -- --target rust --out /tmp/rh-preview fixtures/real-blog

It has no --help; its source lists supported targets and TypeScript profiles. It replaces the output directory, so use a disposable path. For normal application assembly, including Ruby/Spinel, use bin/rh transpile <target>.

Compare running output or measure phases

bin/rh compare <target> drives Rails and the emitted server together. The raw comparator is a standalone crate, not a root Cargo binary. Using it on your own app: the compare guide. Do not mask a genuine translation bug as a variable value.

To see compiler phase wall times and process peak RSS:

ROUNDHOUSE_TIMINGS=1 cargo test --test emit_and_run the_unedited_blog_runs -- --nocapture

Timing is opt-in; a process high-water RSS is not per-phase allocated memory. On Linux each line also reports the current anonymous RSS (rss anon), which leaves out file-backed pages.

To see what holds the heap, build with the memory-census feature. Each timing line then adds the exact live heap, its high-water mark over the run so far (live peak), and the high-water mark within that phase or lap alone (phase peak), so a late phase's own cost shows even when an earlier phase peaked higher. ROUNDHOUSE_MEMORY_CENSUS=1 prints the size of every App field, the body/header split of the unit collections, IR node counts and the analyzer's fields after ingest, analysis, the post-analyze lowerings and emit:

cargo build --bin roundhouse --features memory-census
scripts/synth-app /tmp/synth --packs 50
ROUNDHOUSE_TIMINGS=1 ROUNDHOUSE_MEMORY_CENSUS=1 \
  target/debug/roundhouse --target ruby --survey --allow-unsupported -o /tmp/synth-out /tmp/synth

scripts/memory-budget checks two such runs, on two sizes of scripts/synth-app, and fails when the peak, or its growth per pack, exceeds ci/memory-budget.json. A change that lowers memory updates the budget with scripts/memory-budget --record; raising it needs a reason in the PR.

ROUNDHOUSE_STORE=spill keeps library method bodies in a file (the unit store, src/store.rs) while the analysis fixpoint runs: the library pass writes each class's bodies there once it has typed them, and a body that anything reads again is decoded on that read. Output is the same either way; only memory and time change. The file goes in ROUNDHOUSE_STORE_DIR (the system temp directory otherwise), which must not be tmpfs. ROUNDHOUSE_STORE=check also round-trips every record as it is written. Other debugging controls are discoverable at their readers: rg -n 'ROUNDHOUSE_' src/ scripts/. Matches include comments and generated code; inspect the actual read before assuming a variable is live.