2025-07-10 18:44:24 +01:00
|
|
|
from abc import ABC, abstractmethod
|
|
|
|
|
|
2025-09-19 19:17:28 +01:00
|
|
|
# Enums are slow
|
|
|
|
|
THREAD_STATE_RUNNING = 0
|
|
|
|
|
THREAD_STATE_IDLE = 1
|
|
|
|
|
THREAD_STATE_GIL_WAIT = 2
|
|
|
|
|
THREAD_STATE_UNKNOWN = 3
|
|
|
|
|
|
|
|
|
|
STATUS = {
|
|
|
|
|
THREAD_STATE_RUNNING: "running",
|
|
|
|
|
THREAD_STATE_IDLE: "idle",
|
|
|
|
|
THREAD_STATE_GIL_WAIT: "gil_wait",
|
|
|
|
|
THREAD_STATE_UNKNOWN: "unknown",
|
|
|
|
|
}
|
2025-07-10 18:44:24 +01:00
|
|
|
|
|
|
|
|
class Collector(ABC):
|
|
|
|
|
@abstractmethod
|
|
|
|
|
def collect(self, stack_frames):
|
|
|
|
|
"""Collect profiling data from stack frames."""
|
|
|
|
|
|
|
|
|
|
@abstractmethod
|
|
|
|
|
def export(self, filename):
|
|
|
|
|
"""Export collected data to a file."""
|
2025-09-09 00:41:08 +01:00
|
|
|
|
2025-09-19 19:17:28 +01:00
|
|
|
def _iter_all_frames(self, stack_frames, skip_idle=False):
|
2025-09-09 00:41:08 +01:00
|
|
|
"""Iterate over all frame stacks from all interpreters and threads."""
|
|
|
|
|
for interpreter_info in stack_frames:
|
|
|
|
|
for thread_info in interpreter_info.threads:
|
2025-09-19 19:17:28 +01:00
|
|
|
if skip_idle and thread_info.status != THREAD_STATE_RUNNING:
|
|
|
|
|
continue
|
2025-09-09 00:41:08 +01:00
|
|
|
frames = thread_info.frame_info
|
|
|
|
|
if frames:
|
|
|
|
|
yield frames
|