Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 8 additions & 1 deletion stdlib/@tests/stubtest_allowlists/darwin-py315.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,17 @@ ctypes.c_longdouble_complex._type_
os.NODEV
os.__all__
posix.NODEV
readline.get_pre_input_hook


# =============================================================
# Allowlist entries that cannot or should not be fixed; >= 3.15
# =============================================================

# Internal implementation details of the sampling profiler.
profiling.sampling.live_collector
profiling.sampling.live_collector.collector
profiling.sampling.live_collector.constants
profiling.sampling.live_collector.display
profiling.sampling.live_collector.trend_tracker
profiling.sampling.live_collector.widgets
readline.get_pre_input_hook
9 changes: 8 additions & 1 deletion stdlib/@tests/stubtest_allowlists/linux-py315.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,17 @@ posix.STATX_SIZE
posix.STATX_TYPE
posix.STATX_UID
posix.statx
readline.get_pre_input_hook


# =============================================================
# Allowlist entries that cannot or should not be fixed; >= 3.15
# =============================================================

# Internal implementation details of the sampling profiler.
profiling.sampling.live_collector
profiling.sampling.live_collector.collector
profiling.sampling.live_collector.constants
profiling.sampling.live_collector.display
profiling.sampling.live_collector.trend_tracker
profiling.sampling.live_collector.widgets
readline.get_pre_input_hook
55 changes: 36 additions & 19 deletions stdlib/@tests/stubtest_allowlists/py315.txt
Original file line number Diff line number Diff line change
Expand Up @@ -178,25 +178,6 @@ posixpath.splitroot
pprint.PrettyPrinter.__init__
pprint.pformat
pprint.pprint
profiling
profiling.sampling
profiling.sampling.binary_collector
profiling.sampling.binary_reader
profiling.sampling.cli
profiling.sampling.collector
profiling.sampling.constants
profiling.sampling.dump
profiling.sampling.errors
profiling.sampling.gecko_collector
profiling.sampling.heatmap_collector
profiling.sampling.jsonl_collector
profiling.sampling.module_utils
profiling.sampling.opcode_utils
profiling.sampling.pstats_collector
profiling.sampling.sample
profiling.sampling.stack_collector
profiling.sampling.string_table
profiling.tracing
pydoc.Doc.STDLIB_DIR
pydoc.Doc.getdocloc
site.addsitedir
Expand Down Expand Up @@ -277,3 +258,39 @@ xml.etree.ElementTree.__all__
xml.is_valid_name
xml.utils
zipimport.zipimporter.load_module


# =============================================================
# Allowlist entries that cannot or should not be fixed; >= 3.15
# =============================================================

# Internal implementation details of the sampling profiler.
profiling.sampling.binary_collector
profiling.sampling.binary_reader
profiling.sampling.cli
profiling.sampling.constants
profiling.sampling.dump
profiling.sampling.errors
profiling.sampling.gecko_collector.CATEGORY_CODE_TYPE
profiling.sampling.gecko_collector.CATEGORY_CPU
profiling.sampling.gecko_collector.CATEGORY_EXCEPTION
profiling.sampling.gecko_collector.CATEGORY_GC
profiling.sampling.gecko_collector.CATEGORY_GIL
profiling.sampling.gecko_collector.CATEGORY_NATIVE
profiling.sampling.gecko_collector.CATEGORY_OPCODES
profiling.sampling.gecko_collector.CATEGORY_OTHER
profiling.sampling.gecko_collector.CATEGORY_PYTHON
profiling.sampling.gecko_collector.DEFAULT_SUBCATEGORY
profiling.sampling.gecko_collector.FRAME_ADDRESS_NONE
profiling.sampling.gecko_collector.FRAME_INLINE_DEPTH_ROOT
profiling.sampling.gecko_collector.GECKO_CATEGORIES
profiling.sampling.gecko_collector.GECKO_FORMAT_VERSION
profiling.sampling.gecko_collector.GECKO_PREPROCESSED_VERSION
profiling.sampling.gecko_collector.PROCESS_TYPE_MAIN
profiling.sampling.gecko_collector.RESOURCE_TYPE_LIBRARY
profiling.sampling.gecko_collector.STACKWALK_DISABLED
profiling.sampling.heatmap_collector.FileStats
profiling.sampling.heatmap_collector.TreeNode
profiling.sampling.module_utils
profiling.sampling.opcode_utils
profiling.sampling.sample
4 changes: 4 additions & 0 deletions stdlib/VERSIONS
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ _py_abc: 3.7-
_pydecimal: 3.5-
_queue: 3.7-
_random: 3.0-
_remote_debugging: 3.15-
_sitebuiltins: 3.4-
_socket: 3.0- # present in 3.0 at runtime, but not in typeshed
_sqlite3: 3.0-
Expand Down Expand Up @@ -242,6 +243,9 @@ posix: 3.0-
posixpath: 3.0-
pprint: 3.0-
profile: 3.0-
profiling: 3.15-
profiling.sampling: 3.15-
profiling.tracing: 3.15-
pstats: 3.0-
pty: 3.0-
pwd: 3.0-
Expand Down
183 changes: 183 additions & 0 deletions stdlib/_remote_debugging.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
from _typeshed import StrOrBytesPath, structseq
from collections.abc import Callable
from typing import Final, TypeAlias, final
from typing_extensions import Self

_Location: TypeAlias = tuple[int, int, int, int] | LocationInfo | None
_Frame: TypeAlias = tuple[str, _Location, str, int | None] | FrameInfo
_Stats: TypeAlias = dict[str, int | float]

PROCESS_VM_READV_SUPPORTED: Final[int]
THREAD_STATUS_GIL_REQUESTED: Final[int]
THREAD_STATUS_HAS_EXCEPTION: Final[int]
THREAD_STATUS_HAS_GIL: Final[int]
THREAD_STATUS_MAIN_THREAD: Final[int]
THREAD_STATUS_ON_CPU: Final[int]
THREAD_STATUS_UNKNOWN: Final[int]

@final
class LocationInfo(structseq[int], tuple[int, int, int, int]):
__match_args__: Final = ("lineno", "end_lineno", "col_offset", "end_col_offset")
@property
def lineno(self) -> int: ...
@property
def end_lineno(self) -> int: ...
@property
def col_offset(self) -> int: ...
@property
def end_col_offset(self) -> int: ...

@final
class FrameInfo(structseq[object], tuple[str, _Location, str, int | None]):
__match_args__: Final = ("filename", "location", "funcname", "opcode")
@property
def filename(self) -> str: ...
@property
def location(self) -> _Location: ...
@property
def funcname(self) -> str: ...
@property
def opcode(self) -> int | None: ...

@final
class CoroInfo(structseq[object], tuple[list[_Frame], int | str]):
__match_args__: Final = ("call_stack", "task_name")
@property
def call_stack(self) -> list[_Frame]: ...
@property
def task_name(self) -> int | str: ...

@final
class TaskInfo(structseq[object], tuple[int, str, list[CoroInfo], list[CoroInfo]]):
__match_args__: Final = ("task_id", "task_name", "coroutine_stack", "awaited_by")
@property
def task_id(self) -> int: ...
@property
def task_name(self) -> str: ...
@property
def coroutine_stack(self) -> list[CoroInfo]: ...
@property
def awaited_by(self) -> list[CoroInfo]: ...

@final
class ThreadInfo(structseq[object], tuple[int, int, list[_Frame]]):
__match_args__: Final = ("thread_id", "status", "frame_info")
@property
def thread_id(self) -> int: ...
@property
def status(self) -> int: ...
@property
def frame_info(self) -> list[_Frame]: ...

@final
class InterpreterInfo(structseq[object], tuple[int, list[ThreadInfo]]):
__match_args__: Final = ("interpreter_id", "threads")
@property
def interpreter_id(self) -> int: ...
@property
def threads(self) -> list[ThreadInfo]: ...

@final
class AwaitedInfo(structseq[object], tuple[int, list[TaskInfo]]):
__match_args__: Final = ("thread_id", "awaited_by")
@property
def thread_id(self) -> int: ...
@property
def awaited_by(self) -> list[TaskInfo]: ...

@final
class GCStatsInfo(structseq[object], tuple[int, int, int, int, int, int, int, int, int, float]):
__match_args__: Final = (
"gen",
"iid",
"ts_start",
"ts_stop",
"collections",
"collected",
"uncollectable",
"candidates",
"heap_size",
"duration",
)
@property
def gen(self) -> int: ...
@property
def iid(self) -> int: ...
@property
def ts_start(self) -> int: ...
@property
def ts_stop(self) -> int: ...
@property
def collections(self) -> int: ...
@property
def collected(self) -> int: ...
@property
def uncollectable(self) -> int: ...
@property
def candidates(self) -> int: ...
@property
def heap_size(self) -> int: ...
@property
def duration(self) -> float: ...

@final
class RemoteUnwinder:
def __init__(
self,
pid: int,
*,
all_threads: bool = False,
only_active_thread: bool = False,
mode: int = 0,
debug: bool = False,
skip_non_matching_threads: bool = True,
native: bool = False,
gc: bool = False,
opcodes: bool = False,
cache_frames: bool = False,
stats: bool = False,
) -> None: ...
def get_stack_trace(self) -> list[InterpreterInfo]: ...
def get_all_awaited_by(self) -> list[AwaitedInfo]: ...
def get_async_stack_trace(self) -> list[AwaitedInfo]: ...
def get_stats(self) -> _Stats: ...
def pause_threads(self) -> bool: ...
def resume_threads(self) -> bool: ...

@final
class GCMonitor:
def __init__(self, pid: int, *, debug: bool = False) -> None: ...
def get_gc_stats(self, all_interpreters: bool = False) -> list[GCStatsInfo]: ...

@final
class BinaryWriter:
def __init__(
self, filename: StrOrBytesPath, sample_interval_us: int, start_time_us: int, *, compression: int = 0
) -> None: ...
@property
def total_samples(self) -> int: ...
def write_sample(self, stack_frames: list[InterpreterInfo], timestamp_us: int) -> None: ...
def finalize(self) -> None: ...
def close(self) -> None: ...
def __enter__(self) -> Self: ...
def __exit__(self, exc_type: object = None, exc_val: object = None, exc_tb: object = None) -> bool: ...
def get_stats(self) -> _Stats: ...

@final
class BinaryReader:
def __init__(self, filename: StrOrBytesPath) -> None: ...
@property
def sample_count(self) -> int: ...
@property
def sample_interval_us(self) -> int: ...
def replay(self, collector: object, progress_callback: Callable[[int, int], object] | None = None) -> int: ...
def get_info(self) -> dict[str, object]: ...
def get_stats(self) -> _Stats: ...
def close(self) -> None: ...
def __enter__(self) -> Self: ...
def __exit__(self, exc_type: object = None, exc_val: object = None, exc_tb: object = None) -> bool: ...

def zstd_available() -> bool: ...
def get_child_pids(pid: int, *, recursive: bool = True) -> list[int]: ...
def is_python_process(pid: int) -> bool: ...
def get_gc_stats(pid: int, *, all_interpreters: bool = False) -> list[GCStatsInfo]: ...
3 changes: 3 additions & 0 deletions stdlib/profiling/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from . import sampling as sampling, tracing as tracing

__all__ = ("tracing", "sampling")
17 changes: 17 additions & 0 deletions stdlib/profiling/sampling/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from .collector import Collector as Collector
from .gecko_collector import GeckoCollector as GeckoCollector
from .heatmap_collector import HeatmapCollector as HeatmapCollector
from .jsonl_collector import JsonlCollector as JsonlCollector
from .pstats_collector import PstatsCollector as PstatsCollector
from .stack_collector import CollapsedStackCollector as CollapsedStackCollector
from .string_table import StringTable as StringTable

__all__ = (
"Collector",
"PstatsCollector",
"CollapsedStackCollector",
"HeatmapCollector",
"GeckoCollector",
"JsonlCollector",
"StringTable",
)
24 changes: 24 additions & 0 deletions stdlib/profiling/sampling/collector.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from _typeshed import StrOrBytesPath
from abc import ABC, abstractmethod
from collections.abc import Sequence
from typing import TypeAlias

from _remote_debugging import AwaitedInfo, FrameInfo, InterpreterInfo, LocationInfo

_Location: TypeAlias = int | tuple[int, int, int, int] | LocationInfo | None
_Frame: TypeAlias = FrameInfo | tuple[str, _Location, str, int | None]
_Timestamps: TypeAlias = Sequence[int] | None

def normalize_location(location: _Location) -> tuple[int, int, int, int]: ...
def extract_lineno(location: _Location) -> int: ...
def filter_internal_frames(frames: Sequence[_Frame]) -> list[_Frame]: ...
def iter_async_frames(awaited_info_list: Sequence[AwaitedInfo]) -> object: ...

class Collector(ABC):
@abstractmethod
def collect(
self, stack_frames: Sequence[InterpreterInfo] | Sequence[AwaitedInfo], timestamps_us: _Timestamps = None
) -> None: ...
def collect_failed_sample(self) -> None: ...
@abstractmethod
def export(self, filename: StrOrBytesPath) -> None: ...
13 changes: 13 additions & 0 deletions stdlib/profiling/sampling/gecko_collector.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from _typeshed import StrOrBytesPath
from collections.abc import Sequence

from _remote_debugging import AwaitedInfo, InterpreterInfo

from .collector import Collector, _Timestamps

class GeckoCollector(Collector):
def __init__(self, sample_interval_usec: int, *, skip_idle: bool = False, opcodes: bool = False) -> None: ...
def collect(
self, stack_frames: Sequence[InterpreterInfo] | Sequence[AwaitedInfo], timestamps_us: _Timestamps = None
) -> None: ...
def export(self, filename: StrOrBytesPath) -> None: ...
24 changes: 24 additions & 0 deletions stdlib/profiling/sampling/heatmap_collector.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from _typeshed import StrOrBytesPath
from collections.abc import Sequence

from _remote_debugging import AwaitedInfo, InterpreterInfo

from .collector import Collector, _Frame, _Timestamps

class HeatmapCollector(Collector):
FILE_INDEX_FORMAT: str
def __init__(self, sample_interval_usec: int, *, skip_idle: bool = False) -> None: ...
def collect(
self, stack_frames: Sequence[InterpreterInfo] | Sequence[AwaitedInfo], timestamps_us: _Timestamps = None
) -> None: ...
def export(self, output_path: StrOrBytesPath) -> None: ...
def process_frames(self, frames: Sequence[_Frame], thread_id: int, weight: int = 1) -> None: ...
def set_stats(
self,
sample_interval_usec: int,
duration_sec: float,
sample_rate: float,
error_rate: float | None = None,
missed_samples: float | None = None,
**kwargs: object,
) -> None: ...
Loading
Loading