Skip to content

Commit 427d712

Browse files
committed
Use remote debugging structseqs in profiling
1 parent e31d00c commit 427d712

4 files changed

Lines changed: 164 additions & 65 deletions

File tree

stdlib/VERSIONS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ _py_abc: 3.7-
6060
_pydecimal: 3.5-
6161
_queue: 3.7-
6262
_random: 3.0-
63+
_remote_debugging: 3.15-
6364
_sitebuiltins: 3.4-
6465
_socket: 3.0- # present in 3.0 at runtime, but not in typeshed
6566
_sqlite3: 3.0-

stdlib/_remote_debugging.pyi

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
from _typeshed import StrOrBytesPath, structseq
2+
from collections.abc import Callable, Sequence
3+
from typing import Final, Self, TypeAlias, final
4+
5+
_Location: TypeAlias = int | LocationInfo | None
6+
_Frame: TypeAlias = tuple[str, _Location, str, int | None] | FrameInfo
7+
_StackFrames: TypeAlias = Sequence[InterpreterInfo]
8+
_Stats: TypeAlias = dict[str, int | float]
9+
10+
PROCESS_VM_READV_SUPPORTED: Final[int]
11+
THREAD_STATUS_GIL_REQUESTED: Final[int]
12+
THREAD_STATUS_HAS_EXCEPTION: Final[int]
13+
THREAD_STATUS_HAS_GIL: Final[int]
14+
THREAD_STATUS_MAIN_THREAD: Final[int]
15+
THREAD_STATUS_ON_CPU: Final[int]
16+
THREAD_STATUS_UNKNOWN: Final[int]
17+
18+
@final
19+
class LocationInfo(structseq[int], tuple[int, int, int, int]):
20+
@property
21+
def lineno(self) -> int: ...
22+
@property
23+
def end_lineno(self) -> int: ...
24+
@property
25+
def col_offset(self) -> int: ...
26+
@property
27+
def end_col_offset(self) -> int: ...
28+
29+
@final
30+
class FrameInfo(structseq[object], tuple[str, _Location, str, int | None]):
31+
@property
32+
def filename(self) -> str: ...
33+
@property
34+
def location(self) -> _Location: ...
35+
@property
36+
def funcname(self) -> str: ...
37+
@property
38+
def opcode(self) -> int | None: ...
39+
40+
@final
41+
class CoroInfo(structseq[object], tuple[list[_Frame], int | str]):
42+
@property
43+
def call_stack(self) -> list[_Frame]: ...
44+
@property
45+
def task_name(self) -> int | str: ...
46+
47+
@final
48+
class TaskInfo(structseq[object], tuple[int, str, list[CoroInfo], list[CoroInfo]]):
49+
@property
50+
def task_id(self) -> int: ...
51+
@property
52+
def task_name(self) -> str: ...
53+
@property
54+
def coroutine_stack(self) -> list[CoroInfo]: ...
55+
@property
56+
def awaited_by(self) -> list[CoroInfo]: ...
57+
58+
@final
59+
class ThreadInfo(structseq[object], tuple[int, int, list[_Frame]]):
60+
@property
61+
def thread_id(self) -> int: ...
62+
@property
63+
def status(self) -> int: ...
64+
@property
65+
def frame_info(self) -> list[_Frame]: ...
66+
67+
@final
68+
class InterpreterInfo(structseq[object], tuple[int, list[ThreadInfo]]):
69+
@property
70+
def interpreter_id(self) -> int: ...
71+
@property
72+
def threads(self) -> list[ThreadInfo]: ...
73+
74+
@final
75+
class AwaitedInfo(structseq[object], tuple[int, list[TaskInfo]]):
76+
@property
77+
def thread_id(self) -> int: ...
78+
@property
79+
def awaited_by(self) -> list[TaskInfo]: ...
80+
81+
@final
82+
class GCStatsInfo(structseq[object], tuple[int, int, int, int, int, int, int, int, int, float]):
83+
@property
84+
def gen(self) -> int: ...
85+
@property
86+
def iid(self) -> int: ...
87+
@property
88+
def ts_start(self) -> int: ...
89+
@property
90+
def ts_stop(self) -> int: ...
91+
@property
92+
def collections(self) -> int: ...
93+
@property
94+
def collected(self) -> int: ...
95+
@property
96+
def uncollectable(self) -> int: ...
97+
@property
98+
def candidates(self) -> int: ...
99+
@property
100+
def heap_size(self) -> int: ...
101+
@property
102+
def duration(self) -> float: ...
103+
104+
class RemoteUnwinder:
105+
def __init__(
106+
self,
107+
pid: int,
108+
*,
109+
all_threads: bool = False,
110+
only_active_thread: bool = False,
111+
mode: int = 0,
112+
debug: bool = False,
113+
skip_non_matching_threads: bool = True,
114+
native: bool = False,
115+
gc: bool = False,
116+
) -> None: ...
117+
def get_stack_trace(self) -> list[InterpreterInfo]: ...
118+
def get_all_awaited_by(self) -> list[AwaitedInfo]: ...
119+
def get_async_stack_trace(self) -> list[AwaitedInfo]: ...
120+
def get_stats(self) -> _Stats: ...
121+
def pause_threads(self) -> bool: ...
122+
def resume_threads(self) -> bool: ...
123+
124+
class GCMonitor:
125+
def __init__(self, pid: int, *, debug: bool = False) -> None: ...
126+
def get_gc_stats(self, all_interpreters: bool = False) -> list[GCStatsInfo]: ...
127+
128+
class BinaryWriter:
129+
total_samples: int
130+
def __init__(
131+
self, filename: StrOrBytesPath, sample_interval_us: int, start_time_us: int, *, compression: int = 0
132+
) -> None: ...
133+
def write_sample(self, stack_frames: _StackFrames, timestamp_us: int) -> None: ...
134+
def finalize(self) -> None: ...
135+
def close(self) -> None: ...
136+
def __enter__(self) -> Self: ...
137+
def __exit__(self, exc_type: object = None, exc_val: object = None, exc_tb: object = None) -> bool: ...
138+
def get_stats(self) -> _Stats: ...
139+
140+
class BinaryReader:
141+
sample_count: int
142+
sample_interval_us: int
143+
def __init__(self, filename: StrOrBytesPath) -> None: ...
144+
def replay(self, collector: object, progress_callback: Callable[[int, int], object] | None = None) -> int: ...
145+
def get_info(self) -> dict[str, object]: ...
146+
def get_stats(self) -> _Stats: ...
147+
def close(self) -> None: ...
148+
def __enter__(self) -> Self: ...
149+
def __exit__(self, exc_type: object = None, exc_val: object = None, exc_tb: object = None) -> bool: ...
150+
151+
def zstd_available() -> bool: ...
152+
def get_child_pids(pid: int, *, recursive: bool = True) -> list[int]: ...
153+
def is_python_process(pid: int) -> bool: ...
154+
def get_gc_stats(pid: int, *, all_interpreters: bool = False) -> list[GCStatsInfo]: ...

stdlib/asyncio/tools.pyi

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,9 @@
11
import sys
22
from collections.abc import Iterable
33
from enum import Enum
4-
from typing import NamedTuple, SupportsIndex, type_check_only
4+
from typing import SupportsIndex
55

6-
@type_check_only
7-
class _AwaitedInfo(NamedTuple): # AwaitedInfo_Type from _remote_debugging
8-
thread_id: int
9-
awaited_by: list[_TaskInfo]
10-
11-
@type_check_only
12-
class _TaskInfo(NamedTuple): # TaskInfo_Type from _remote_debugging
13-
task_id: int
14-
task_name: str
15-
coroutine_stack: list[_CoroInfo]
16-
awaited_by: list[_CoroInfo]
17-
18-
@type_check_only
19-
class _CoroInfo(NamedTuple): # CoroInfo_Type from _remote_debugging
20-
call_stack: list[_FrameInfo]
21-
task_name: int | str
22-
23-
@type_check_only
24-
class _FrameInfo(NamedTuple): # FrameInfo_Type from _remote_debugging
25-
filename: str
26-
lineno: int
27-
funcname: str
6+
from _remote_debugging import AwaitedInfo as _AwaitedInfo
287

298
class NodeType(Enum):
309
COROUTINE = 1

stdlib/profiling/sampling/collector.pyi

Lines changed: 7 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,19 @@
11
from _typeshed import StrOrBytesPath
22
from abc import ABC, abstractmethod
33
from collections.abc import Sequence
4-
from typing import Protocol, TypeAlias
4+
from typing import TypeAlias
55

6-
_Location: TypeAlias = int | tuple[int, int, int, int] | _LocationInfo | None
7-
_Frame: TypeAlias = _FrameInfo | tuple[str, _Location, str, int | None]
8-
_Timestamps: TypeAlias = Sequence[int] | None
9-
_StackFrames: TypeAlias = Sequence[_InterpreterInfo] | Sequence[_AwaitedInfo]
10-
11-
class _LocationInfo(Protocol):
12-
lineno: int
13-
end_lineno: int
14-
col_offset: int
15-
end_col_offset: int
16-
def __getitem__(self, index: int, /) -> int: ...
17-
18-
class _FrameInfo(Protocol):
19-
filename: str
20-
location: _Location
21-
funcname: str
22-
opcode: int | None
23-
def __getitem__(self, index: int, /) -> object: ...
24-
25-
class _ThreadInfo(Protocol):
26-
thread_id: int
27-
status: int
28-
frame_info: Sequence[_Frame]
6+
from _remote_debugging import AwaitedInfo, FrameInfo, InterpreterInfo, LocationInfo
297

30-
class _InterpreterInfo(Protocol):
31-
interpreter_id: int
32-
threads: Sequence[_ThreadInfo]
33-
34-
class _CoroInfo(Protocol):
35-
call_stack: Sequence[_Frame]
36-
task_name: int | str
37-
38-
class _TaskInfo(Protocol):
39-
task_id: int
40-
task_name: str
41-
coroutine_stack: Sequence[_CoroInfo]
42-
awaited_by: Sequence[_CoroInfo]
43-
44-
class _AwaitedInfo(Protocol):
45-
thread_id: int
46-
awaited_by: Sequence[_TaskInfo]
8+
_Location: TypeAlias = int | tuple[int, int, int, int] | LocationInfo | None
9+
_Frame: TypeAlias = FrameInfo | tuple[str, _Location, str, int | None]
10+
_Timestamps: TypeAlias = Sequence[int] | None
11+
_StackFrames: TypeAlias = Sequence[InterpreterInfo] | Sequence[AwaitedInfo]
4712

4813
def normalize_location(location: _Location) -> tuple[int, int, int, int]: ...
4914
def extract_lineno(location: _Location) -> int: ...
5015
def filter_internal_frames(frames: Sequence[_Frame]) -> list[_Frame]: ...
51-
def iter_async_frames(awaited_info_list: Sequence[_AwaitedInfo]) -> object: ...
16+
def iter_async_frames(awaited_info_list: Sequence[AwaitedInfo]) -> object: ...
5217

5318
class Collector(ABC):
5419
@abstractmethod

0 commit comments

Comments
 (0)