Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
dd27e5e
Extend RemoteUnwinder to capture precise bytecode locations
pablogsal Dec 3, 2025
70f2ae0
Add opcode utilities and --opcodes CLI flag
pablogsal Dec 3, 2025
aedc000
Track opcode sample counts in flamegraph collector
pablogsal Dec 3, 2025
19ff11b
Emit opcode interval markers in Gecko collector
pablogsal Dec 3, 2025
af27d23
Add bytecode panel to heatmap visualization
pablogsal Dec 3, 2025
7ffe4cb
Add opcode panel to live profiler TUI
pablogsal Dec 3, 2025
8b423df
Update tests for location tuple and opcode field
pablogsal Dec 3, 2025
8129e3d
Merge remote-tracking branch 'upstream/main' into tachyon-opcodes
pablogsal Dec 7, 2025
965f521
Better test
pablogsal Dec 7, 2025
dac78a5
Merge remote-tracking branch 'upstream/main' into tachyon-opcodes
pablogsal Dec 7, 2025
12c02f6
Add news entry
pablogsal Dec 7, 2025
c10628a
CI fixes
pablogsal Dec 7, 2025
04563f0
CI fixes
pablogsal Dec 8, 2025
f368890
Fix C-API calls
pablogsal Dec 8, 2025
93f7abd
CSS fixes for classes and dark mode
savannahostrowski Dec 9, 2025
dc127bb
Merge pull request #110 from savannahostrowski/tachyon-opcodes-savannah
pablogsal Dec 9, 2025
43a298b
address review
pablogsal Dec 9, 2025
a4685fd
Merge branch 'main' into tachyon-opcodes
pablogsal Dec 9, 2025
b13b6f0
Docs
pablogsal Dec 9, 2025
50f63d0
Make bytecode spacer
pablogsal Dec 9, 2025
6eed927
Update Lib/profiling/sampling/_heatmap_assets/heatmap.js
pablogsal Dec 9, 2025
1c630ce
Update heatmap.css
pablogsal Dec 9, 2025
56e68c1
Tachyon Heatmap responsive styles
savannahostrowski Dec 10, 2025
e010870
Merge pull request #113 from savannahostrowski/heatmap-responsive
pablogsal Dec 10, 2025
ede0f79
Update Doc/library/profiling.sampling.rst
pablogsal Dec 10, 2025
f838c5d
Fix shift when selecting
StanFromIreland Dec 10, 2025
13ecd61
Merge pull request #114 from StanFromIreland/tachyon-opcodes-jump
pablogsal Dec 10, 2025
66610ff
Use any for stdlib line numbers
pablogsal Dec 10, 2025
aab1f3c
Update profiling.sampling.rst
pablogsal Dec 11, 2025
947f555
Docs
pablogsal Dec 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Better test
  • Loading branch information
pablogsal committed Dec 7, 2025
commit 965f5210f4d2f902f0793ae96ffb3fde5e553a86
94 changes: 24 additions & 70 deletions Lib/test/test_external_inspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -1878,66 +1878,33 @@ def test_opcodes_collection(self):
"""Test that opcodes are collected when the opcodes flag is set."""
script = textwrap.dedent(
"""\
import time
import sys
import socket

def compute():
# Do some work that involves bytecode execution
total = 0
for i in range(1000):
total += i
return total

def bar():
compute()

def foo():
bar()
import time, sys, socket

# Signal that we're ready
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('localhost', {port}))
sock.sendall(b"ready")
sock.close()

# Keep computing in a loop
while True:
foo()
def foo():
sock.sendall(b"ready")
time.sleep(10_000)

foo()
"""
)

def get_trace_with_opcodes(pid):
unwinder = RemoteUnwinder(pid, opcodes=True)
return unwinder.get_stack_trace()
return RemoteUnwinder(pid, opcodes=True).get_stack_trace()

stack_trace, _ = self._run_script_and_get_trace(
script,
get_trace_with_opcodes,
wait_for_signals=b"ready",
script, get_trace_with_opcodes, wait_for_signals=b"ready"
)

# Find the thread with our compute/bar/foo stack
found_opcodes = False
for interpreter_info in stack_trace:
for thread_info in interpreter_info.threads:
for frame in thread_info.frame_info:
# Check that frames have opcodes (not None)
# when opcodes=True is set
if frame.funcname in ("compute", "bar", "foo"):
# Opcode should be an integer, not None
self.assertIsInstance(
frame.opcode,
int,
f"Expected opcode to be int for {frame.funcname}, got {type(frame.opcode)}"
)
self.assertGreaterEqual(frame.opcode, 0)
found_opcodes = True

self.assertTrue(
found_opcodes,
"Did not find any frames with opcodes from compute/bar/foo"
# Find our foo frame and verify it has an opcode
foo_frame = self._find_frame_in_trace(
stack_trace, lambda f: f.funcname == "foo"
)
self.assertIsNotNone(foo_frame, "Could not find foo frame")
self.assertIsInstance(foo_frame.opcode, int)
self.assertGreaterEqual(foo_frame.opcode, 0)

@skip_if_not_supported
@unittest.skipIf(
Expand All @@ -1950,10 +1917,10 @@ def test_location_tuple_format(self):
"""\
import time, sys, socket

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('localhost', {port}))

def foo():
x = 1 + 2
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('localhost', {port}))
sock.sendall(b"ready")
time.sleep(10_000)

Expand All @@ -1962,13 +1929,10 @@ def foo():
)

def get_trace_with_opcodes(pid):
unwinder = RemoteUnwinder(pid, opcodes=True)
return unwinder.get_stack_trace()
return RemoteUnwinder(pid, opcodes=True).get_stack_trace()

stack_trace, script_name = self._run_script_and_get_trace(
script,
get_trace_with_opcodes,
wait_for_signals=b"ready",
stack_trace, _ = self._run_script_and_get_trace(
script, get_trace_with_opcodes, wait_for_signals=b"ready"
)

# Find our foo frame
Expand All @@ -1977,25 +1941,15 @@ def get_trace_with_opcodes(pid):
)
self.assertIsNotNone(foo_frame, "Could not find foo frame")

# Check location is a tuple with 4 elements
# Check location is a 4-tuple with valid values
location = foo_frame.location
self.assertIsInstance(location, tuple, "Location should be a tuple")
self.assertEqual(
len(location), 4,
f"Location should have 4 elements (lineno, end_lineno, col_offset, end_col_offset), got {len(location)}"
)

self.assertIsInstance(location, tuple)
self.assertEqual(len(location), 4)
lineno, end_lineno, col_offset, end_col_offset = location

# Lineno should be positive
self.assertIsInstance(lineno, int)
self.assertGreater(lineno, 0, "lineno should be positive")

# end_lineno should be >= lineno
self.assertGreater(lineno, 0)
self.assertIsInstance(end_lineno, int)
self.assertGreaterEqual(end_lineno, lineno)

# col_offset and end_col_offset should be non-negative
self.assertIsInstance(col_offset, int)
self.assertGreaterEqual(col_offset, 0)
self.assertIsInstance(end_col_offset, int)
Expand Down