GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Keep monitoring dispatch and event metadata interpreter-local by youknowdot · Pull Request #9439 · RustPython/RustPython

Conversation

@youknowdot

@youknowdot youknowdot commented Oct 28, 2026 •
edited by youknowone
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Summary

Keep monitoring dispatch and layer state interpreter-local without rewriting shared bytecode into monitoring wrappers.

The metadata substrate no longer depends on #9450: use byte-width atomic instruction reads and a bounded base-family walk that skips inline caches, rather than a permanent construction-provenance copy. Remove the new external-bytecode rejection/trust framework and frozen/import fallibility. Preserve existing constructor, code.replace, and marshal admission behavior, ordinary owning-code normalization, and literal GET_ITER construction order.

This follows CPython's base-operation/deoptimization conventions, not a claim to port its critical-section or thread-local bytecode machinery. Existing generic internal Clone/cache safety is outside this correction. The current-PC legacy trace path avoids an unnecessary prefix scan; arbitrary-offset metadata lookups remain bounded linear scans.

Rebase and cleanup

Rebased the final feature delta onto main f1f38c1594. Before cleanup, the rebased tree exactly matched Git's clean merge result. This avoids replaying the discarded intermediate prerequisites.

Remove four redundant production tail drops in monitoring state cleanup. Named retired owners still outlive the inner lock scopes. Keep operand releases before fused dispatch, callback destruction before tool-name removal, and the early retired-owner release before metadata construction. Tests are unchanged from the previous feature.

Validation on bbfa0c6e7

  • All 23 compiler-core unit tests passed, including the scalar instruction reader, base-family walker and cache-width tests.
  • Scoped VM strict Clippy passed with compiler, threading, host environment, standard I/O, docs and importlib enabled.
  • Full workspace all-targets strict Clippy passed, excluding the separately configured C-API, WASM and Windows venv launcher crates. Separate C-API all-targets strict Clippy also passed, both with -D warnings.
  • Independent cleanup review and a standalone Rust drop-order comparison passed. Formatting and normal commit hooks passed.

Exact-head hosted CI has passed all three OS Rust test jobs and strict Clippy checks, including separate C-API tests and doctests on Linux and macOS. The optimized Linux CPython suite finished successfully: 47,587 tests run, 4,076 existing skips, and 485 modules OK. Its logs explicitly show test_monitoring and test.test_free_threading.test_monitoring passed. The optimized macOS suite also succeeded (47,154 tests run, 4,205 existing skips, 482 modules OK), as did Windows (46,587 filtered tests run, 5,346 existing skips, 467 modules OK). Both monitoring modules passed on every OS. All 24 CI jobs completed successfully; existing platform exclusions and the Windows launcher-version filter remain unchanged. This remains a draft.

Earlier runtime evidence

Before this rebase, on base b85582d, guarded fixture and CLI builds passed. Eleven selected canonical methods passed on RustPython and pinned CPython 3.15 d220409a, with no skips, failures or expected failures: code replacement, marshal code/filename behavior, coroutine/generator methods, LINE/INSTRUCTION installation order, simple/loop line events and basic legacy tracing.

Two valid-input first-read normalization orders also passed in each engine: warm distinct code objects without first reading subject co_code, enable both monitoring events, read normalized bytes, round-trip through replace and marshal, and execute ordinary copies. These are historical results, not runtime validation of the current head.

Additional concurrency/GC/stress probes and performance validation remain outstanding. The reviewer's performance-before-merge request remains open; the cleanup does not resolve overall dispatch overhead. No merge-readiness claim.

AI assistance: OpenAI Codex assisted source audit, rebase, cleanup, independent review and validation. The exact model version was not exposed.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@coderabbitai

coderabbitai Bot commented Oct 28, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

Share

  • X
  • Mastodon
  • Reddit
  • LinkedIn
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@github-actions

github-actions Bot commented Oct 28, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

📦 Library Dependencies

The following Lib/ modules were modified. Here are their dependencies:

[x] lib: cpython/Lib/profile.py
[x] test: cpython/Lib/test/test_profile.py
[x] test: cpython/Lib/test/test_profiling/test_tracing_profiler.py

dependencies:

  • profile

dependent tests: (1 tests)

  • profile: test_profile

[ ] test: cpython/Lib/test/test_free_threading (TODO: 1)

dependencies:

dependent tests: (no tests depend on free_threading)

Legend:

  • [+] path exists in CPython
  • [x] up-to-date, [ ] outdated
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@codspeed

codspeed Bot commented Oct 28, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Merging this PR will degrade performance by 19.03%

❌ 23 regressed benchmarks
✅ 39 untouched benchmarks
⏩ 4 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
❌ generators.py[rustpython] 4.3 s 6.8 s -35.76%
❌ nbody.py[rustpython] 1.3 s 1.7 s -24.67%
❌ rustpython[comprehension_list.py] 872 µs 1,127.1 µs -22.63%
❌ rustpython[20000] 2.1 s 2.6 s -20.9%
❌ rustpython[30000] 3.1 s 3.9 s -20.88%
❌ rustpython[10000] 1 s 1.3 s -20.53%
❌ richards.py[rustpython] 2.4 s 3 s -20.39%
❌ rustpython[cmp.py] 66.9 ms 83.4 ms -19.82%
❌ fannkuch.py[rustpython] 16.4 s 20.4 s -19.44%
❌ float.py[rustpython] 320.8 ms 394.4 ms -18.64%
❌ nqueens.py[rustpython] 4.3 s 5.3 s -18.64%
❌ rustpython[strings.py] 43.6 ms 53.6 ms -18.6%
❌ rustpython[comprehension_set.py] 1.4 ms 1.7 ms -18.27%
❌ rustpython[loop_string.py] 903.6 µs 1,105.1 µs -18.23%
❌ unpickle.py[rustpython] 189 ms 227.5 ms -16.95%
❌ decimal_factorial.py[rustpython] 1.1 s 1.3 s -16.35%
❌ pickle.py[rustpython] 661.2 ms 784.9 ms -15.76%
❌ rustpython[loop_append.py] 2.4 ms 2.8 ms -15.64%
❌ deltablue.py[rustpython] 243.2 ms 288 ms -15.56%
❌ deepcopy.py[rustpython] 139.1 ms 164.5 ms -15.44%
... ... ... ... ...

ℹ️ Only the first 20 benchmarks are displayed. Go to the app to view all benchmarks.

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing youknowdot:youknowdot/free-threading-remaining-batch-315-20261028 (2845454) with main (05daf00)

Open in CodSpeed

Footnotes

  1. 4 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

youknowone
youknowone approved these changes Oct 29, 2026
View reviewed changes
@youknowone

youknowone commented Oct 29, 2026

Copy link
Copy Markdown
Member

hmm, let's check performance before merge

@codspeedbot explain performance drop

codspeed[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@codspeed

codspeed Bot commented Oct 29, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

hmm, let's check performance before merge

@codspeedbot explain performance drop

Why performance dropped

This is a real regression, not noise. All of it comes from f8a7823 ("Keep monitoring dispatch in interpreter-local state"):

  • The run for c672599 (dict/CSV/mmap/syslog changes) matches main.
  • Comparing c672599 → f8a7823 shows the same 24 regressions (−10% to −25%) as the PR report.
  • The regressions cover every interpreter-heavy benchmark (nbody, generators, pystone, richards, fannkuch, the microbenchmarks). That pattern points to a cost paid on every bytecode instruction.

What the flamegraph shows (nbody.py, Simulation)

c672599 f8a7823
Interpreter loop self time (run_until → run_until_inner) 366.6 ms 534.0 ms
monitoring::dispatch_operation self time — 175.8 ms
mem::replace<Option<u32>> (inlined) — 39.3 ms
Total 1.3 s 1.7 s

The float, list and call code costs the same in both runs (e.g. default_dealloc<PyFloat> 67.9 → 67.2 ms, PyFloat::into_ref 31.7 → 31.8 ms). The added time is all overhead in the dispatch loop, even though no monitoring tool is active.

Where it comes from in the code

  1. A function call before every instruction (crates/vm/src/frame.rs:3909):

    let mut virtual_dispatch = if PREPARE_GENERATOR { None }
        else { monitoring::dispatch_operation(vm, self.code, idx) };

    dispatch_operation (sys/monitoring.rs:718) is not inlined. Even its fast path (vm.state.monitoring_events.load() == 0) costs a call, a pointer chase through vm.state and an atomic load per instruction. It also returns an Option<(MonitoringInstruction, Instruction)> that the loop then branches on. On main, the loop goes straight to read_unit_from. This adds extra live values in the hottest loop, which also explains why the loop's own self time grew by ~45%.

  2. Extra writes per instruction in execute_instruction (frame.rs:4665-4666):

    let index = self.lasti().saturating_sub(1);
    self.monitoring_previous = self.monitoring_current.replace(Some(index));

    This re-loads lasti, even though the loop already holds idx, and writes two Option<u32> frame fields on every instruction, monitored or not.

  3. Smaller additions: the virtual_line/legacy_line_processed checks and the DispatchMode/caches tuple on the decode path. Each one is cheap, but they all sit in the loop.

Ways to recover it

  • Make the disabled case close to free. Split dispatch_operation into an #[inline(always)] check on monitoring_events == 0 and a #[cold] #[inline(never)] slow path. Better still, follow CPython: check instrumentation only at RESUME, backward jumps or the eval breaker, and keep a frame-local "monitored" flag. The plain path would then match main.
  • Track monitoring_previous/monitoring_current only in monitored mode, and take the index from idx instead of re-loading lasti. If the generator-close LINE fix (f1c31d7) needs the previous position in the normal path too, it could be saved only when a frame suspends instead of on every instruction.
  • Re-run the benchmarks after either change. A plain path that matches main should bring these benchmarks back to their baseline.

I haven't changed any code on the branch. Comment @codspeedbot try making the monitoring fast path zero-cost when no tool is active and I'll prototype the fix and benchmark it.

Summary
  • Warming up the performance wizard...
  • Isolate the commit causing the regression — c672599 (dict/CSV) is flat vs main; all 24 regressions appear at f8a7823 (monitoring dispatch).
  • Compare flamegraphs to find hot spots — New per-instruction work in the dispatch loop: out-of-line monitoring::dispatch_operation call plus monitoring_previous/current bookkeeping.
  • Report findings — Report findings
  • Handling comment — Comment handling finished successfully

Was this response helpful? React with 👍 or 👎 to help us improve CodSpeedBot.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

This was referenced Oct 29, 2026
Update remaining free-threading library tests for Python 3.15 #9446
Merged
Serialize host syslog mask changes #9447
Merged
Synchronize mmap cursor updates and sequence bytes #9448
Merged
Keep CSV reader state coherent across callbacks #9449
Merged
Snapshot live code through its owner in the compiler adapter #9450
Merged
Revalidate dictionary insertion slots after callbacks #9451
Merged
youknowdot pushed a commit to youknowdot/RustPython that referenced this pull request Oct 29, 2026
@codex
Merge current main before narrowing monitoring prerequisites
ba82f66
Preserve original RustPython#9439 ancestry and the reviewed float-power integration while preparing its functionality split.

Assisted-by: OpenAI Codex: model version unavailable
@youknowdot youknowdot changed the title Update remaining free-threading Lib tests with native prerequisites Keep monitoring dispatch and event metadata interpreter-local Oct 29, 2026
youknowone pushed a commit that referenced this pull request Oct 29, 2026
@youknowdot @codex
Update remaining free-threading library tests for Python 3.15 (#9446)
39a7388
Extract the six canonical library-only modules from #9439. Regenerated with scripts/update_lib from CPython d220409a13b77de7a6c30abe16ea90db01528edc.

Assisted-by: OpenAI Codex: model version unavailable

Co-authored-by: Codex <[email protected]>
youknowone pushed a commit that referenced this pull request Oct 29, 2026
@youknowdot @codex
Serialize host syslog mask changes (#9447)
6137860
Extract the syslog lock and whole canonical free-threading test from #9439. Regenerate the test with scripts/update_lib from CPython d220409a13b77de7a6c30abe16ea90db01528edc.

Assisted-by: OpenAI Codex: model version unavailable

Co-authored-by: Codex <[email protected]>
youknowone pushed a commit that referenced this pull request Oct 29, 2026
@youknowdot @codex
Synchronize mmap cursor updates and sequence bytes (#9448)
a300ff2
Extract mmap cursor and sequence behavior plus its whole canonical free-threading test from #9439. Regenerate the test with scripts/update_lib from CPython d220409a13b77de7a6c30abe16ea90db01528edc.

Assisted-by: OpenAI Codex: model version unavailable

Co-authored-by: Codex <[email protected]>
youknowone pushed a commit that referenced this pull request Oct 29, 2026
@youknowdot @codex
Keep CSV reader payload access callback-safe (#9449)
499c7b0
Extract CSV reader synchronization with its PyOperation facade and float-error helper from #9439. Include the whole canonical free-threading CSV test regenerated by scripts/update_lib from CPython d220409a13b77de7a6c30abe16ea90db01528edc.

Assisted-by: OpenAI Codex: model version unavailable

Co-authored-by: Codex <[email protected]>
youknowone pushed a commit that referenced this pull request Oct 29, 2026
@youknowdot @codex
Revalidate dictionary insertion slots after preparation (#9451)
b85582d
Extract dictionary insertion and setdefault re-probing from #9439 with its five structural fixtures and whole canonical free-threading test. Regenerate the Lib file with scripts/update_lib from CPython d220409a13b77de7a6c30abe16ea90db01528edc.

Assisted-by: OpenAI Codex: model version unavailable

Co-authored-by: Codex <[email protected]>
@youknowdot youknowdot mentioned this pull request Oct 29, 2026
Keep deque contents and bounds in coherent shared state #9457
Merged
youknowone pushed a commit that referenced this pull request Oct 31, 2026
@youknowdot @codex
Preserve code construction provenance across execution storage (#9450)
ddd8fbf
Extract the independent code-source, clone, co_code and fallible decoding foundation from #9439. Interpreter-local monitoring dispatch remains in the dependent original PR.

Assisted-by: OpenAI Codex: model version unavailable

Co-authored-by: Codex <[email protected]>
youknowdot added a commit to youknowdot/RustPython that referenced this pull request Nov 3, 2026
@youknowdot
Merge current main before narrowing monitoring prerequisites
23abe73
Preserve original RustPython#9439 ancestry and the reviewed float-power integration while preparing its functionality split.

Assisted-by: OpenAI Codex: model version unavailable
@youknowdot
youknowdot force-pushed the youknowdot/free-threading-remaining-batch-315-20261028 branch from a2c7122 to fac8d18 Compare November 3, 2026 07:14
@youknowdot youknowdot mentioned this pull request Nov 4, 2026
Share code construction and comparison controls #9713
Merged
@youknowone

youknowone commented Nov 6, 2026

Copy link
Copy Markdown
Member

TODO: need review

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@youknowdot
youknowdot force-pushed the youknowdot/free-threading-remaining-batch-315-20261028 branch from 95a4916 to bbfa0c6 Compare November 6, 2026 21:50
youknowdot added 2 commits November 8, 2026 15:28
@youknowdot
Rebase monitoring and use scope-exit cleanup
fb57204
Preserve the final monitoring feature delta from 95a4916 on current main. Before cleanup, the rebased tree exactly matches Git merge-tree, avoiding obsolete intermediate prerequisites.

Remove four redundant production tail drops while retaining named retired owners outside lock scopes. Preserve all operand, callback and early-release order. No test content changed relative to the prior feature.

Assisted-by: OpenAI Codex:model-version-unavailable
@youknowdot
Avoid inactive monitoring dispatch calls and direct-yield prefix scans
2845454
Inline the no-events guard without pulling metadata preparation into the ordinary opcode loop. Reject direct yields using the suspended frame instruction provenance before the bounded yield-from shape walk. Preserve all monitored dispatch and unproven-position fallbacks.

Assisted-by: OpenAI Codex:model-version-unavailable
@youknowdot
youknowdot force-pushed the youknowdot/free-threading-remaining-batch-315-20261028 branch from bbfa0c6 to 2845454 Compare November 8, 2026 06:39
@codex
Reuse validated yield-from instruction boundaries on generator resume
fdb6f6d
Cache only the last bounded-walk-validated suspension offset. Keep dynamic SEND specialization, stack, receiver, and monitoring guards, and preserve the cache when the same code frame is materialized.

Assisted-by: OpenAI Codex:model-version-unavailable
codex and others added 4 commits November 8, 2026 23:07
@codex
Cache monitoring instruction boundaries and coalesce dispatch checks
29a41eb
Keep ordinary dispatch separate from observed execution, preserve prefix state across mode changes, and reuse per-thread safepoint requests for monitoring activation. Retain displaced slot owners outside registry locks.

Assisted-by: OpenAI Codex:model-version-unavailable
@codex
Clarify registry snapshot ownership across exception loads
1cd15ee
The intermediate snapshot is required to release the registry lock before a failed atomic snapshot can finalize an exception. Keep displaced slots alive with lexical ownership instead of an explicit drop.

Assisted-by: OpenAI Codex:model-version-unavailable
@codex
Make conditional test modules explicit for Clippy
c3ac704
Assisted-by: OpenAI Codex:model-version-unavailable
@youknowdot
Preserve native profile events in observed dispatch
50ccd86
Restrict legacy c events to native functions and method descriptors, binding each descriptor event independently. Route native-call specializations through a local observed CALL with adaptive writes suppressed, without changing the unobserved dispatch body or shared bytecode. Preserve full static type names in descriptor repr and remove the profile output expected failure.

Assisted-by: Codex:unknown
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@youknowone youknowone youknowone approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

3 participants

@youknowdot @youknowone @codex
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.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.