Repository navigation
perf(ffi): look up the running loop only while something on it waits - #581
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated
marked this pull request as ready for review
November 4, 2026 10:34
|
This run was cancelled before it finished. |
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 24 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
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.

Problem
#564 resumes a same-thread wake without the socket pair by calling
asyncio._get_running_loop()at the start of every call made on a thread whose loop has polled. Most of those calls wake nothing, yet each pays the lookup: a handle call inside a loop costs about 15 ns more than one outside it. moq's Python calls run inside a loop.Approach
Queuecounts what may wake on it: its futures while parked, and itsWakers while alive.PARKED. A close now marks the node woken, so a wake Rust makes after the close queues nothing.Skipping the lookup is always safe: with no running loop noted, a wake takes the socket path, as a wake from another thread does. The lookup itself is unchanged, so it never trusts a stale loop, the hazard #564's PR body describes.
#564's tests still pass: no lost or double wake, same-thread vs cross-thread, a wake during cancel, a wake before the first await, and 64 concurrent receives woken from both threads.
tests/api.pynow also checks that aWaker's wake on the loop's thread writes no byte when nothing else waits. Before this, the check after the settle could not fail, since the dispatch drains the socket. Without theWakercount, the new check fails.moq/bench/export.pynow times a handle call inside the loop the woken reads ran on, once nothing waits on it. This is the state a moq app's sync calls run in.Measurements
The Python leg of
just ffi bench(moq/bench/export.py), on main and on this branch, interleaved with BoltFFI 0.31.1's Python harness from moq@0f986d9 in the same run, rotating order. Shared host with load average 4 to 5 on 32 threads, CPython 3.14.8. Medians of 9 rounds, min to max in parentheses:sequence142 ns (140 to 147)yield_once27,477 ns (26,876 to 28,770)An in-loop call now costs within 2 ns of one outside a loop. The woken read keeps #564's direct path. An earlier 9-round run at load 7 to 11 measured before the in-loop timing was moved after a loop had polled. In that position main skipped the lookup too, so it showed no difference there. Its other rows matched these.
Impact
Alternatives
_get_running_loop's C function directly. That would shave the vectorcall dispatch, but every in-loop call would still pay part of the cost, and it relies on CPython internals.Follow-ups
None.
Review
quest review, Codex gpt-6.1-sol at medium effort, round 1 at head 26dbec8. No findings.Checks run locally on 26dbec8:
just ci(ffi lint and the 21 fixture tests driving C, C++, Kotlin, Python, Swift, Go, and Dart), andjust ffi moqon every language (run on 416487f; later commits touch only the bench script and the quest tree). Not run:just ffi android, which needs a device.🤖 Generated with Claude Code