Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
82092dd
Move core profiling module into a package
lkollar Jun 4, 2025
cd5c814
Add sampling profiler
lkollar Jul 3, 2025
b26d1fa
Add pstats.SampledStats to display sample results
lkollar Jun 22, 2025
2e8e0a9
Add collapsed sample profiler output format
lkollar Jun 22, 2025
bf9e3fa
Add tests for sampling profiler
lkollar Jun 19, 2025
aeca768
fixup! Add tests for sampling profiler
lkollar Jul 3, 2025
7a76f68
Improve CLI
pablogsal Jul 6, 2025
97ba97e
Add more tests
pablogsal Jul 6, 2025
543b13d
Format files
pablogsal Jul 6, 2025
a8f1bdd
Formatting improvementts
pablogsal Jul 6, 2025
0440856
Fix small issues
pablogsal Jul 6, 2025
65d60e9
Add news entry
pablogsal Jul 6, 2025
bf15570
Moar fixes
pablogsal Jul 6, 2025
219670e
Use the new gil sampling
pablogsal Jul 6, 2025
f3dc377
Correct NEWS entry
pablogsal Jul 6, 2025
3002ab8
Add docs
pablogsal Jul 6, 2025
59137e4
Add what's new
pablogsal Jul 6, 2025
fe12677
Add what's new 2
pablogsal Jul 6, 2025
c28b0e0
Add what's new 2
pablogsal Jul 6, 2025
0c7b1f1
fixup! Add docs
lkollar Jul 6, 2025
d7706e6
fixup! fixup! Add docs
lkollar Jul 6, 2025
5c8d939
fixup! fixup! fixup! Add docs
lkollar Jul 6, 2025
b75aee1
fixup! Add what's new 2
lkollar Jul 6, 2025
acace5b
Fix free threading
pablogsal Jul 7, 2025
f50cfd7
Add sample.profile module reference
lkollar Jul 7, 2025
8d5dc18
Merge branch 'main' into sampling-profiler
lkollar Jul 7, 2025
d534f1e
Fix whatsnew
lkollar Jul 9, 2025
0360a72
Change profile.stack_collectors to singular
lkollar Jul 9, 2025
4fa0832
Remove redundant len check
lkollar Jul 9, 2025
b42812e
Handle process exiting during sampling
lkollar Jul 9, 2025
8d9cbfe
fixup! Handle process exiting during sampling
lkollar Jul 9, 2025
260d934
Protect against permission errors
pablogsal Jul 9, 2025
f0de45a
Sync processes in test_sample_profiler
pablogsal Jul 9, 2025
dbe2c0a
More fixes
pablogsal Jul 9, 2025
bc43ec7
Skip unsupported platforms in profiler tests
lkollar Jul 10, 2025
85f12d0
Add profile directory to Makefile.pre.in
lkollar Jul 10, 2025
a33d166
Raise on unsupported platforms in GetPyRuntimeAddress
lkollar Jul 10, 2025
0235127
fixup! Skip unsupported platforms in profiler tests
lkollar Jul 10, 2025
90260a6
Require subprocess support
pablogsal Jul 10, 2025
5683b76
fixup! fixup! Skip unsupported platforms in profiler tests
lkollar Jul 10, 2025
5a83439
Skip test on Android
lkollar Jul 10, 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
More fixes
  • Loading branch information
pablogsal committed Jul 9, 2025
commit dbe2c0a4cc2b938158837b960fbbe9c0919fc68a
15 changes: 9 additions & 6 deletions Lib/test/test_sample_profiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -1634,15 +1634,18 @@ def test_invalid_output_format_with_mocked_profiler(self):
)

def test_is_process_running(self):
with (test_subprocess("import time; time.sleep(1000)") as proc,
mock.patch("_remote_debugging.RemoteUnwinder") as mock_unwinder_class):
mock_unwinder_class.return_value = mock.MagicMock()
profiler = SampleProfiler(pid=proc.pid, sample_interval_usec=1000, all_threads=False)
self.assertTrue(profiler._is_process_running())
proc.kill()
with test_subprocess("import time; time.sleep(1000)") as proc:
profiler = SampleProfiler(pid=proc.pid, sample_interval_usec=1000, all_threads=False)
self.assertTrue(profiler._is_process_running())
self.assertIsNotNone(profiler.unwinder.get_stack_trace())
proc.kill()
proc.wait()
# ValueError on MacOS (yeah I know), ProcessLookupError on Linux and Windows
self.assertRaises((ValueError, ProcessLookupError), profiler.unwinder.get_stack_trace)

# Exit the context manager to ensure the process is terminated
self.assertFalse(profiler._is_process_running())
self.assertRaises((ValueError, ProcessLookupError), profiler.unwinder.get_stack_trace)

@unittest.skipUnless(sys.platform == "linux", "Only valid on Linux")
def test_esrch_signal_handling(self):
Expand Down
15 changes: 15 additions & 0 deletions Python/remote_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,14 @@ search_linux_map_for_section(proc_handle_t *handle, const char* secname, const c

#ifdef MS_WINDOWS

static int is_process_alive(HANDLE hProcess) {
DWORD exitCode;
if (GetExitCodeProcess(hProcess, &exitCode)) {
return exitCode == STILL_ACTIVE;
}
return 0;
}

static void* analyze_pe(const wchar_t* mod_path, BYTE* remote_base, const char* secname) {
HANDLE hFile = CreateFileW(mod_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
Expand Down Expand Up @@ -950,6 +958,13 @@ _Py_RemoteDebug_ReadRemoteMemory(proc_handle_t *handle, uintptr_t remote_address
SIZE_T result = 0;
do {
if (!ReadProcessMemory(handle->hProcess, (LPCVOID)(remote_address + result), (char*)dst + result, len - result, &read_bytes)) {
// Check if the process is still alive: we need to be able to tell our caller
// that the process is dead and not just that the read failed.
if (!is_process_alive(handle->hProcess)) {
_set_errno(ESRCH);
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
PyErr_SetFromWindowsErr(0);
DWORD error = GetLastError();
_set_debug_exception_cause(PyExc_OSError,
Expand Down
Loading