mirror of
https://github.com/python/cpython.git
synced 2025-07-19 01:05:26 +00:00
gh-135953: Implement sampling tool under profile.sample (#135998)
Some checks are pending
Tests / (push) Blocked by required conditions
Tests / Windows MSI (push) Blocked by required conditions
Tests / Change detection (push) Waiting to run
Tests / Docs (push) Blocked by required conditions
Tests / Check if Autoconf files are up to date (push) Blocked by required conditions
Tests / Check if generated files are up to date (push) Blocked by required conditions
Tests / Ubuntu SSL tests with OpenSSL (push) Blocked by required conditions
Tests / WASI (push) Blocked by required conditions
Tests / Hypothesis tests on Ubuntu (push) Blocked by required conditions
Tests / Address sanitizer (push) Blocked by required conditions
Tests / Undefined behavior sanitizer (push) Blocked by required conditions
Tests / Cross build Linux (push) Blocked by required conditions
Tests / CIFuzz (push) Blocked by required conditions
Tests / All required checks pass (push) Blocked by required conditions
Lint / lint (push) Waiting to run
mypy / Run mypy on Lib/_pyrepl (push) Waiting to run
mypy / Run mypy on Lib/test/libregrtest (push) Waiting to run
mypy / Run mypy on Lib/tomllib (push) Waiting to run
mypy / Run mypy on Tools/build (push) Waiting to run
mypy / Run mypy on Tools/cases_generator (push) Waiting to run
mypy / Run mypy on Tools/clinic (push) Waiting to run
mypy / Run mypy on Tools/jit (push) Waiting to run
mypy / Run mypy on Tools/peg_generator (push) Waiting to run
Some checks are pending
Tests / (push) Blocked by required conditions
Tests / Windows MSI (push) Blocked by required conditions
Tests / Change detection (push) Waiting to run
Tests / Docs (push) Blocked by required conditions
Tests / Check if Autoconf files are up to date (push) Blocked by required conditions
Tests / Check if generated files are up to date (push) Blocked by required conditions
Tests / Ubuntu SSL tests with OpenSSL (push) Blocked by required conditions
Tests / WASI (push) Blocked by required conditions
Tests / Hypothesis tests on Ubuntu (push) Blocked by required conditions
Tests / Address sanitizer (push) Blocked by required conditions
Tests / Undefined behavior sanitizer (push) Blocked by required conditions
Tests / Cross build Linux (push) Blocked by required conditions
Tests / CIFuzz (push) Blocked by required conditions
Tests / All required checks pass (push) Blocked by required conditions
Lint / lint (push) Waiting to run
mypy / Run mypy on Lib/_pyrepl (push) Waiting to run
mypy / Run mypy on Lib/test/libregrtest (push) Waiting to run
mypy / Run mypy on Lib/tomllib (push) Waiting to run
mypy / Run mypy on Tools/build (push) Waiting to run
mypy / Run mypy on Tools/cases_generator (push) Waiting to run
mypy / Run mypy on Tools/clinic (push) Waiting to run
mypy / Run mypy on Tools/jit (push) Waiting to run
mypy / Run mypy on Tools/peg_generator (push) Waiting to run
Implement a statistical sampling profiler that can profile external Python processes by PID. Uses the _remote_debugging module and converts the results to pstats-compatible format for analysis. Co-authored-by: Pablo Galindo <pablogsal@gmail.com>
This commit is contained in:
parent
35e2c35970
commit
59acdba820
15 changed files with 3319 additions and 74 deletions
|
@ -751,6 +751,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) {
|
||||
|
@ -911,7 +919,9 @@ _Py_RemoteDebug_GetPyRuntimeAddress(proc_handle_t* handle)
|
|||
_PyErr_ChainExceptions1(exc);
|
||||
}
|
||||
#else
|
||||
Py_UNREACHABLE();
|
||||
_set_debug_exception_cause(PyExc_RuntimeError,
|
||||
"Reading the PyRuntime section is not supported on this platform");
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return address;
|
||||
|
@ -981,6 +991,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,
|
||||
|
@ -1013,6 +1030,9 @@ _Py_RemoteDebug_ReadRemoteMemory(proc_handle_t *handle, uintptr_t remote_address
|
|||
return read_remote_memory_fallback(handle, remote_address, len, dst);
|
||||
}
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
if (errno == ESRCH) {
|
||||
return -1;
|
||||
}
|
||||
_set_debug_exception_cause(PyExc_OSError,
|
||||
"process_vm_readv failed for PID %d at address 0x%lx "
|
||||
"(size %zu, partial read %zd bytes): %s",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue