Skip to content

Report total emulated cycles at exit under --clock-mhz - #104

Merged
sidick merged 1 commit into
mainfrom
clock-mhz-report-cycles
Sep 29, 2026
Merged

sidick merged 1 commit into
mainfrom
clock-mhz-report-cycles

Conversation

@sidick

@sidick sidick commented Sep 29, 2026

Copy link
Copy Markdown
Owner

Follow-up to #103.

--clock-mhz gave volamos a cycle counter, but only an indirect way to
read it: the guest program itself had to call ReadEClock and report its
own elapsed time. That works for an instrumented benchmark like
BenchWork, but it leaves an
uninstrumented binary unmeasurable.

vamos has not had that limitation — vamos -v prints a total cycles:
line for any run, straight out of its main loop
(amitools/vamos/main.py, summing Musashi's per-call cycle returns).
This closes the gap.

What it does

$ volamos --clock-mhz 25 ./bench
...program output...
volamos: 340020 emulated cycles, 0.013601 s at 25 MHz

Nothing is printed without --clock-mhz, because on the default
run_batch path there is no cycle count to print — BatchResult carries
only an instruction count. That's also why Runtime::emulated_cycles()
returns Option rather than u64: reporting 0 on the uncounted path
would read as "this run took no time" instead of "this run was never
counted".

Two deliberate choices:

  • stderr, not stdout — a harness parsing the guest program's own
    output must never have this line spliced into it.
  • printed even when the run ends in an error — a benchmark that died
    part-way still burned the cycles it burned, and "how far did it get" is
    usually the first question.

Cross-check against vamos

Same binary, same two runtimes:

CPU volamos vamos delta
68000 340,020 339,044 +0.3%
--cpu 68020 157,436 155,855 +1.0%

These come from entirely independent cycle models — the m68k crate's
per-CPU timing tables (timing.rs, timing_020/040/060.rs) versus
Musashi's — so the agreement is mutual corroboration rather than a shared
assumption. Both are deterministic across repeated runs.

This doesn't make either accurate in absolute terms; the caveats from
#103 all still apply, the wait-state one especially. It does mean the two
oracles can now be compared on a directly equivalent number, which the
existing vamos comparison harness can use.

Changes

  • dispatch.rs: Runtime::emulated_cycles() — the top-level run's count
    and the rate it was counted at. A nested System()/Execute() child
    keeps its own counter from 0, the same boundary ReadEClock already
    reports across, so its cycles aren't folded in here.
  • main.rs: report_emulated_cycles at exit, with the formatting split
    into a pure format_emulated_cycles so the wording and arithmetic are
    testable without capturing stderr.
  • userdocs/CLI-Reference.md: documents the line, and the vamos
    comparison above.

Testing

cargo test --workspace: 1038 passed, 0 failed. Build, clippy
(--all-targets) and fmt --check clean.

New tests cover the accessor's None/Some split, the seconds
conversion and quoted MHz (including a fractional rate), a zero-cycle
run still reporting, and a non-positive or NaN rate formatting to nothing
rather than to inf.

One incidental fix: restored a #[test] attribute on the existing
no_jit_flag_after_jit_wins, which this branch's first draft had
accidentally orphaned — it was silently not running. It passes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EHvk3UiKvgnG2xb71UJ67R

As merged in #103, volamos's cycle counter was only reachable
indirectly: the guest itself had to call ReadEClock and report its own
elapsed time. That works for an instrumented benchmark like BenchWork,
but leaves an uninstrumented binary unmeasurable -- while `vamos -v` has
printed an equivalent "total cycles:" line for its own runs all along
(amitools/vamos/main.py, summing Musashi's per-call cycle returns).

Adds Runtime::emulated_cycles(), reporting the top-level run's count and
the rate it was counted at, and prints one line from it at exit when
--clock-mhz is active. Nothing is printed otherwise, because on the
default run_batch path no cycle count exists to print.

The line goes to stderr, so a harness parsing the guest's own stdout
never sees it, and is printed even when the run ends in an error -- a
benchmark that died part-way still burned the cycles it burned.

Cross-checked against vamos on the same binary: 340,020 cycles vs
vamos's 339,044 at 68000 (+0.3%), and 157,436 vs 155,855 at 68020
(+1.0%) -- two independent cycle models (the m68k crate's timing tables
vs Musashi's) agreeing closely.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EHvk3UiKvgnG2xb71UJ67R
@sidick
sidick merged commit b9506b9 into main Sep 29, 2026
9 checks passed
@sidick
sidick deleted the clock-mhz-report-cycles branch September 29, 2026 13:13
@sidick sidick mentioned this pull request Oct 10, 2026
2 of 3 tasks
sidick added a commit that referenced this pull request Oct 10, 2026
* Bump version to 0.9.0

Closes out the 0.9 changelog section: the ten commits merged since
v0.8 (#100) were landing under a stale "## 0.8" header without a
version bump, so this also backfills changelog entries that were
missing entirely -- the --clock-mhz base feature and its two follow-on
reports (#102/#103, #104, #107), both math-library condition-code
fixes (#112, #113), HUNK_RELRELOC32 loader support (#116), and the
dispatch task-struct-corruption diagnostic -- alongside the two that
already had entries (clap migration #108, native-handler counts #110).

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* docs: fix two stale cross-page anchor links

mkdocs slugifies a heading like "## \`--sanitize\`" to #-sanitize, not
#--sanitize -- the backtick-wrapped flag name collapses the doubled
dash to one. Found via mkdocs build --strict's anchor-mismatch INFO
output while checking 0.9's docs were current.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 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