perf(runtime): call the guest execute helpers directly instead of compiling snippets - #418
Merged
Merged
Conversation
sd2k
force-pushed
the
perf/guest-direct-execute
branch
from
September 10, 2026 22:47
7895c8e to
3b4313c
Compare
… snippets
execute() built a `_eryx_exec("""<escaped code>""", False)` string and ran it
through PyRun_SimpleString, then compiled three more fixed snippets and
re-resolved __main__ four times to read the results back, so CPython parsed
an escaped copy of the user's source in the wrapper and compiled it again
inside _eryx_exec on every request.
Resolve __main__.__dict__ and the _eryx_exec / _eryx_get_output /
_eryx_capture_result / _eryx_discard_result function objects once at the
end of initialize_python() (owned references that survive the pre-init
snapshot) and call them with PyObject_Call, passing the source as a str.
PyErr_Print() still runs before the streams are restored, so a traceback
lands in the captured stderr exactly as before. Falls back to the
PyRun_SimpleString path if the helpers are missing.
session_execution/pass: 187 µs -> 86 µs on stock wasmtime 48.0.1.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
sd2k
force-pushed
the
perf/guest-direct-execute
branch
from
September 11, 2026 08:48
3b4313c to
616d7c1
Compare
Collaborator
Author
|
Rebased onto |
Contributor
|
🌐 Demo preview: https://perf-guest-direct-execute.eryx-bvy.pages.dev |
This was referenced Sep 11, 2026
Merged
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The guest's
executepath built a_eryx_exec("""<escaped user code>""", False)string and ran it throughPyRun_SimpleString, then compiled three more fixed snippets (_eryx_output, _eryx_errors = _eryx_get_output(),_eryx_capture_result(),_eryx_discard_result()) and re-resolved__main__four times to read the results back. So CPython tokenised an escaped copy of the user's source inside the wrapper and compiled it again inside_eryx_exec, on every request.This resolves
__main__.__dict__and the four_eryx_*helper function objects once, at the end ofinitialize_python()(owned references in aOnceLock; they live in linear memory and survive the pre-init snapshot like everything else), andexecute_pythonnow:_eryx_exec(code, trace_enabled)withPyObject_Call, passing the source as astrobject — no wrapper string, no escaping, no second parse;(stdout, stderr)from the tuple_eryx_get_output()returns;_eryx_capture_result()/_eryx_discard_result()directly and reads_eryx_result/_eryx_result_errorwith two dict lookups.Error semantics are unchanged: on an exception
PyErr_Print()runs before the streams are restored, so the traceback lands in the captured stderr exactly asPyRun_SimpleStringproduced it (the contract from #239). The pending/async path is untouched. If the helpers are missing from__main__for any reason the oldPyRun_SimpleStringpath is used, so a broken infrastructure snippet degrades rather than fails.Stacked on #416 (
perf/guest-callback-setup-cache) because that is where the session path stopped being dominated by callback re-setup; thepython.rschanges are disjoint from it.prebuilt/liberyx_runtime.so.zstis rebuilt from this branch, so the usual conflict-on-merge applies to that file.Benchmarks
Criterion (
cargo bench --package eryx --features embedded --bench execution), stock wasmtime 48.0.1, Ryzen 9 7950X, this branch vs its base #416:session_execution/passstateless_execution/pass(3 callbacks)session_creation/newSpike harness (
profile_stateless, 2000 executions, median of 3; measured on top of the wasmtime pagemap/funcref fixes from the cold-start spike so instantiation cost does not hide the guest cost):json+string.Template), trace offIn the warm-path profile the parser/compiler symbols (
_PyPegen_*,_PyCfg_*,_PyAssemble_*,tok_get_*) drop from 6% to 1.8%; what remains iscompile()of the user's own source.Testing
cargo nextest run --workspace --features embedded --cargo-profile release: 629 passed, 0 failed.cargo clippy --workspace --all-targets --all-features -- -D warnings: clean.Not included
list-callbackshost call on the execute path (still made every execute; cheap next to the above).🤖 Generated with Claude Code