Skip to content

xtajit64: batch Unicorn context transfers on Apple Silicon - #15

Open
jungwuk-ryu wants to merge 4 commits into
mainfrom
perf/apple-silicon-context-batching
Open

xtajit64: batch Unicorn context transfers on Apple Silicon#15
jungwuk-ryu wants to merge 4 commits into
mainfrom
perf/apple-silicon-context-batching

Conversation

@jungwuk-ryu

@jungwuk-ryu jungwuk-ryu commented Aug 27, 2026

Copy link
Copy Markdown
Owner

Summary

  • replace 36 scalar uc_reg_write() calls with one uc_reg_write_batch() call
  • replace 35 scalar uc_reg_read() calls with one uc_reg_read_batch() call
  • preserve the exact normalized x64 register ordering with dedicated read/write tables and compile-time layout assertions
  • extend the native-provider import check for the batch APIs
  • add a semantic-equivalence and nanosecond latency benchmark for native Apple Silicon
  • run the contract checks and pinned-Unicorn benchmark in a native arm64 GitHub Actions job

Motivation

write_context() and read_context() execute on the BeginSimulation boundary. The previous implementation crossed the Unicorn dylib/API dispatch boundary once for every register. This change keeps that dispatch and register-routing setup outside the per-register loop, reducing a complete write/read boundary from 71 Unicorn API calls to 2.

This is deliberately measurement-driven: optimize a proven hot boundary, preserve semantics, and reject instruction-level substitutions that do not improve measured Apple Silicon performance.

Native Apple Silicon measurements

Environment for every result below:

  • GitHub macos-26-arm64
  • reported CPU: Apple M1 (Virtual)
  • pinned Unicorn revision 8028ec436f2d9376525352dd38ed9ed6b9f6be10
  • Release Unicorn build and -O3 benchmark build
  • median of 9 rounds, 12,000 complete write/read boundaries per round, after warm-up
Run Scalar Batch Speedup Latency reduction
bootstrap validation 790.507 ns 473.958 ns 1.668x 40.0%
PR CI attempt 1 744.660 ns 576.396 ns 1.292x 22.6%
PR CI rerun 688.903 ns 509.896 ns 1.351x 26.0%

The virtualized M1 runner has visible run-to-run noise, so this PR does not treat one sample as a stable absolute latency. All independent native-arm64 measurements preserve the same result: batching wins, while the structural API-boundary reduction is deterministic at 71 calls → 2 calls.

The result is intentionally scoped. It measures the Unicorn register-transfer portion of a full context write/read boundary, not total translated-application runtime, and does not claim that the complete transition executes in 1 ns.

Validation

  • scalar-write/batch-read and batch-write/scalar-read state equivalence
  • exact GS-base preservation
  • integer, flags, MXCSR, and all 16 XMM register mappings checked
  • closed register tables plus compile-time context-layout assertions
  • source-contract checker proves write_context() and read_context() each use exactly one batch API boundary
  • python3 -m py_compile
  • bash -n for the benchmark and provider-concurrency scripts
  • git diff --check
  • pinned Unicorn release build and native arm64 benchmark
  • dedicated xtajit64 Apple Silicon hot paths PR workflow: passing on the original run and rerun

Commit structure

  1. xtajit64: batch Unicorn context transfers
  2. test: add Apple Silicon context-transfer benchmark
  3. ci: benchmark xtajit64 context batching on Apple Silicon

Rejected alternative

A separate experiment replaced EC-bitmap integer division with a shift derived from the power-of-two page size. On the same Apple Silicon runner it regressed the isolated classifier from 1.407 ns to 1.516 ns, so it is deliberately not included.

Unrelated repository check

The repository-wide Source integrity workflow currently fails in the pre-existing switchyard/tests/build_runtime_failure_propagation_test.sh check with nested failure returned 0 instead of 1. The exact failure also occurs on PR #14, which predates and does not contain this change. The dedicated native-arm64 contracts and benchmark for this PR pass.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 743f2c8312

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +39 to +40
python3 dlls/xtajit64/provider_tests/check_syscall_register_batching.py \
dlls/xtajit64/unixlib.c

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add the missing syscall batching scripts before invoking them

On every pull request touching dlls/xtajit64/**, this step invokes check_syscall_register_batching.py, but the reviewed tree contains neither that file nor the subsequently invoked run_syscall_register_hotpath.sh (a repository-wide git grep finds only these YAML references). Python therefore exits with a missing-file error before the benchmark starts, making the new workflow fail for every matching PR; add both scripts or remove their invocations.

Useful? React with 👍 / 👎.

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