🌐 AI搜索 & 代理 主页
Skip to content

Conversation

@pablogsal
Copy link
Member

@pablogsal pablogsal commented Dec 7, 2025

When profiling Python code, knowing which source line is hot often isn't enough—a single line can contain multiple operations with very different performance characteristics. For example, result = obj.attr + expensive_call() has an attribute load, a function call, and an addition, but traditional line-level profiling treats them identically. This becomes especially important with the adaptive specialization, where understanding whether the interpreter has specialized an instruction (e.g., LOAD_ATTRLOAD_ATTR_INSTANCE_VALUE) provides crucial optimization insights that were previously only visible through manual dis inspection.

This PR threads bytecode information through the existing sampling profiler infrastructure by extending RemoteUnwinder to optionally extract the executing opcode and its precise source span (including column offsets) from the remote process's frame state. The column-level location data flows through to the visualization layers, where the heatmap can highlight the exact expression within a line, the gecko format emits interval markers for Firefox Profiler's timeline, and the live TUI displays real-time instruction breakdowns. The feature is opt-in via --opcodes to avoid the overhead when not needed, and the opcode utilities handle the mapping between specialized instruction variants and their base forms so users can see both what's actually executing and what it was specialized from.

screenrecording-2025-12-02_21-12-36.mp4
screenrecording-2025-12-01_01-18-26.mp4

Introduces LocationInfo struct sequence with end_lineno, col_offset, and
end_col_offset fields. Adds opcodes parameter to RemoteUnwinder that
extracts the currently executing opcode alongside its source span.

Refactors linetable parsing to correctly accumulate line numbers
separately from output values, fixing edge cases in computed_line.
New opcode_utils.py maps opcode numbers to names and detects specialized
variants using opcode module metadata. Adds normalize_location() and
extract_lineno() helpers to collector base for uniform location handling.

CLI gains --opcodes flag, validated against compatible formats (gecko,
flamegraph, heatmap, live).
Stores per-node opcode counts in the tree structure. Exports opcode
mapping (names and deopt relationships) in JSON so the JS renderer can
show instruction names and distinguish specialized variants.
Tracks opcode state transitions per thread and emits interval markers
when the executing opcode changes. Markers include opcode name, line,
column, and duration. Adds Opcodes category to marker schema.
Expandable panel per hot line shows instruction-level sample breakdown
with opcode names and specialization percentage. Converts call graph
data structures from lists to sets for O(1) deduplication.
New widget displays instruction-level stats for selected function when
--opcodes is enabled. Navigation via j/k keys with scroll support.
Adds per-thread opcode tracking. Updates pstats collector for new frame
format.
Frame location is now a 4-tuple (lineno, end_lineno, col_offset,
end_col_offset). MockFrameInfo wraps locations in LocationInfo struct.
Updates assertions throughout and adds opcode_utils coverage.
# Conflicts:
#	Lib/test/test_profiling/test_sampling_profiler/test_integration.py
@pablogsal pablogsal requested review from ivonastojanovic and savannahostrowski and removed request for ivonastojanovic December 7, 2025 23:42

This comment was marked as outdated.

@pablogsal pablogsal marked this pull request as ready for review December 8, 2025 19:22
Copy link
Member

@savannahostrowski savannahostrowski left a comment

Choose a reason for hiding this comment

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

First pass on most of the files (mainly the JS/CSS)! I ended up playing around with this quite a bit (flamegraph, heatmap, live mode, etc) and it looks awesome. You're on a roll 💫 !

A couple of comments here and then I also opened pablogsal#110 to move a bunch of the CSS into proper classes instead of inlining all the styles, which fixes some dark mode theming bugs (figured that'd be simpler than commenting in a bunch of places)!

This comment was marked as off-topic.

Signed-off-by: Pablo Galindo <pablogsal@gmail.com>
Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com>
pablogsal and others added 2 commits December 9, 2025 19:13
Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com>
Copy link
Member

@savannahostrowski savannahostrowski left a comment

Choose a reason for hiding this comment

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

Two small comments (and another CSS fix PR) but this looks good to me otherwise!

python -m profiling.sampling run --opcodes --flamegraph script.py

This feature provides visibility into Python's bytecode execution, including
adaptive specialization optimizations. When a generic instruction like
Copy link
Member

Choose a reason for hiding this comment

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

Wondering if it's worth linking back to https://docs.python.org/3/whatsnew/3.11.html#whatsnew311-pep659, in case people want to learn more about the specializing adaptive interpreter?

@pablogsal pablogsal added the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Dec 10, 2025
@bedevere-bot
Copy link

🤖 New build scheduled with the buildbot fleet by @pablogsal for commit ede0f79 🤖

Results will be shown at:

https://buildbot.python.org/all/#/grid?branch=refs%2Fpull%2F142394%2Fmerge

If you want to schedule another build, you need to add the 🔨 test-with-buildbots label again.

@bedevere-bot bedevere-bot removed the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Dec 10, 2025
Copy link
Member

@StanFromIreland StanFromIreland left a comment

Choose a reason for hiding this comment

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

Comment on lines 621 to 623
(taskgroups.__file__, 121, "TaskGroup._aexit", None),
(taskgroups.__file__, 72, "TaskGroup.__aexit__", None),
(script_name, 26, "main", None),
Copy link
Member

Choose a reason for hiding this comment

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

The line numbers are subject to change, why did you set them instead of using ANY like before?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, let me change the ones that are not profiling specific. Good catch

Comment on lines 666 to 668
(taskgroups.__file__, 121, "TaskGroup._aexit", None),
(taskgroups.__file__, 72, "TaskGroup.__aexit__", None),
(script_name, 26, "main", None),
Copy link
Member

Choose a reason for hiding this comment

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

Ditto.

Comment on lines 684 to 686
(taskgroups.__file__, 121, "TaskGroup._aexit", None),
(taskgroups.__file__, 72, "TaskGroup.__aexit__", None),
(script_name, 26, "main", None),
Copy link
Member

Choose a reason for hiding this comment

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

And here.

@pablogsal
Copy link
Member Author

Some final notes.

Also https://github.com/pablogsal/cpython/compare/tachyon-opcodes...StanFromIreland:cpython:tachyon-opcodes-jump?expand=1, but that can be done after.

Merged! Thanks a lot for that!

Copy link
Member

@StanFromIreland StanFromIreland left a comment

Choose a reason for hiding this comment

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

LGTM

I have a docs suggestion but feel free to disregard it.

pablogsal and others added 2 commits December 11, 2025 02:05
Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com>
@pablogsal pablogsal merged commit 5b19c75 into python:main Dec 11, 2025
46 checks passed
@pablogsal pablogsal deleted the tachyon-opcodes branch December 11, 2025 03:41
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.

4 participants