Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ae33ca8
Add support for tracking garbage collection and calls to native calls…
brandtbucher Oct 27, 2025
6427b6e
No need to use atomics here
brandtbucher Oct 30, 2025
3801924
Clean up the diff
brandtbucher Nov 2, 2025
cb433c1
Add docs
brandtbucher Nov 5, 2025
c26de8f
Whitespace
brandtbucher Nov 6, 2025
9ea2512
Whitespace
brandtbucher Nov 6, 2025
c06158b
fixup
brandtbucher Nov 6, 2025
e831b33
blurb add
brandtbucher Nov 6, 2025
269fe68
Separate tests
pablogsal Nov 8, 2025
25e770b
Do not show artificial lines in GC frames or native
pablogsal Nov 8, 2025
103835e
Fix flamegraph
pablogsal Nov 8, 2025
1118285
Rework to share code, also catch calls into native code in top frames
brandtbucher Nov 11, 2025
f3ade0d
Default "native" to False
brandtbucher Nov 12, 2025
a280f97
Fix crashes
brandtbucher Nov 12, 2025
06a7bda
Add native frame tests
brandtbucher Nov 12, 2025
920c9e3
Cleanup
brandtbucher Nov 12, 2025
f2b6607
Fix docs
brandtbucher Nov 12, 2025
bc45007
Loosen requirement for native frames in the middle of the stack
brandtbucher Nov 12, 2025
fd7a209
Fewer loops
brandtbucher Nov 12, 2025
4539b6e
fixup
brandtbucher Nov 12, 2025
6c2e2fb
More time for ASan
brandtbucher Nov 12, 2025
c31c6dc
Less native time
brandtbucher Nov 12, 2025
abf1337
Simplify the test
brandtbucher Nov 12, 2025
0b54df2
Don't detect native frames at the top of the stack
brandtbucher Nov 13, 2025
d23ca10
Merge upstream/main into native-gc-sampling
pablogsal Nov 17, 2025
329f549
Clarify comment
pablogsal Nov 17, 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
Merge upstream/main into native-gc-sampling
  • Loading branch information
pablogsal committed Nov 17, 2025
commit d23ca1041deb5a5f90987bb106cd73b85f71278d
11 changes: 7 additions & 4 deletions Lib/profiling/sampling/sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,18 +137,20 @@ def _run_with_sync(original_cmd):


class SampleProfiler:
def __init__(self, pid, sample_interval_usec, all_threads, *, mode=PROFILING_MODE_WALL, native=False, gc=True):
def __init__(self, pid, sample_interval_usec, all_threads, *, mode=PROFILING_MODE_WALL, native=False, gc=True, skip_non_matching_threads=True):
self.pid = pid
self.sample_interval_usec = sample_interval_usec
self.all_threads = all_threads
if _FREE_THREADED_BUILD:
self.unwinder = _remote_debugging.RemoteUnwinder(
self.pid, all_threads=self.all_threads, mode=mode, native=native, gc=gc
self.pid, all_threads=self.all_threads, mode=mode, native=native, gc=gc,
skip_non_matching_threads=skip_non_matching_threads
)
else:
only_active_threads = bool(self.all_threads)
self.unwinder = _remote_debugging.RemoteUnwinder(
self.pid, only_active_thread=only_active_threads, mode=mode, native=native, gc=gc
self.pid, only_active_thread=only_active_threads, mode=mode, native=native, gc=gc,
skip_non_matching_threads=skip_non_matching_threads
)
# Track sample intervals and total sample count
self.sample_intervals = deque(maxlen=100)
Expand Down Expand Up @@ -627,7 +629,8 @@ def sample(
skip_idle = mode != PROFILING_MODE_WALL

profiler = SampleProfiler(
pid, sample_interval_usec, all_threads=all_threads, mode=mode, native=native, gc=gc
pid, sample_interval_usec, all_threads=all_threads, mode=mode, native=native, gc=gc,
skip_non_matching_threads=skip_non_matching_threads
)
profiler.realtime_stats = realtime_stats

Expand Down
41 changes: 41 additions & 0 deletions Lib/test/test_profiling/test_sampling_profiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -3312,5 +3312,46 @@ def test_native_frames_disabled(self):
# Native frames should NOT be present:
self.assertNotIn("<native>", output)


class TestProcessPoolExecutorSupport(unittest.TestCase):
"""
Test that ProcessPoolExecutor works correctly with profiling.sampling.
"""

def test_process_pool_executor_pickle(self):
# gh-140729: test use ProcessPoolExecutor.map() can sampling
test_script = '''
import concurrent.futures

def worker(x):
return x * 2

if __name__ == "__main__":
with concurrent.futures.ProcessPoolExecutor() as executor:
results = list(executor.map(worker, [1, 2, 3]))
print(f"Results: {results}")
'''
with os_helper.temp_dir() as temp_dir:
script = script_helper.make_script(
temp_dir, 'test_process_pool_executor_pickle', test_script
)
with SuppressCrashReport():
with script_helper.spawn_python(
"-m", "profiling.sampling.sample",
"-d", "5",
"-i", "100000",
script,
stderr=subprocess.PIPE,
text=True
) as proc:
proc.wait(timeout=SHORT_TIMEOUT)
stdout = proc.stdout.read()
stderr = proc.stderr.read()

if "PermissionError" in stderr:
self.skipTest("Insufficient permissions for remote profiling")

self.assertIn("Results: [2, 4, 6]", stdout)
self.assertNotIn("Can't pickle", stderr)
if __name__ == "__main__":
unittest.main()
Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.