| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 2e94f14 commit 3efd2f4
11 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -153,6 +153,10 @@ Attach to a running process by PID:: | |||
| 153 | 153 | ||
| 154 | 154 | python -m profiling.sampling attach 12345 | |
| 155 | 155 | ||
| 156 | + Print a single snapshot of a running process's stack:: | ||
| 157 | + | ||
| 158 | + python -m profiling.sampling dump 12345 | ||
| 159 | + | ||
| 156 | 160 | Use live mode for real-time monitoring (press ``q`` to quit):: | |
| 157 | 161 | ||
| 158 | 162 | python -m profiling.sampling run --live script.py | |
@@ -173,8 +177,9 @@ Enable opcode-level profiling to see which bytecode instructions are executing:: | |||
| 173 | 177 | Commands | |
| 174 | 178 | ======== | |
| 175 | 179 | ||
| 176 | - Tachyon operates through two subcommands that determine how to obtain the | ||
| 177 | - target process. | ||
| 180 | + Tachyon operates through several subcommands. ``run`` and ``attach`` collect | ||
| 181 | + samples over time; ``dump`` captures a single snapshot; ``replay`` converts | ||
| 182 | + binary profiles to other formats. | ||
| 178 | 183 | ||
| 179 | 184 | ||
| 180 | 185 | The ``run`` command | |
@@ -217,6 +222,78 @@ On most systems, attaching to another process requires appropriate permissions. | |||
| 217 | 222 | See :ref:`profiling-permissions` for platform-specific requirements. | |
| 218 | 223 | ||
| 219 | 224 | ||
| 225 | + .. _dump-command: | ||
| 226 | + | ||
| 227 | + The ``dump`` command | ||
| 228 | + -------------------- | ||
| 229 | + | ||
| 230 | + The ``dump`` command prints a single snapshot of a running process's Python | ||
| 231 | + stack and exits, similar to a traceback:: | ||
| 232 | + | ||
| 233 | + python -m profiling.sampling dump 12345 | ||
| 234 | + | ||
| 235 | + Unlike ``attach``, ``dump`` does not run a sampling loop: it reads the | ||
| 236 | + stack once. This is useful for investigating hung or unresponsive | ||
| 237 | + processes, or for answering "what is this process doing right now?". | ||
| 238 | + | ||
| 239 | + The output mirrors a traceback (most recent call last) and annotates each | ||
| 240 | + thread with its current state (main thread, has GIL, on CPU, waiting for | ||
| 241 | + GIL, has exception, or idle): | ||
| 242 | + | ||
| 243 | + .. code-block:: text | ||
| 244 | + | ||
| 245 | + Stack dump for PID 12345, thread 140735 (main thread, has GIL, on CPU; most recent call last): | ||
| 246 | + File "server.py", line 28, in serve | ||
| 247 | + await handle_request(req) | ||
| 248 | + File "handler.py", line 91, in handle_request | ||
| 249 | + result = expensive_call(req) | ||
| 250 | + | ||
| 251 | + When the target's source files are readable, ``dump`` prints the source | ||
| 252 | + line for each frame and highlights the executing expression. | ||
| 253 | + | ||
| 254 | + Like ``attach``, ``dump`` requires permission to read the target process's | ||
| 255 | + memory. See :ref:`profiling-permissions`. | ||
| 256 | + | ||
| 257 | + The ``dump`` command supports the following options: | ||
| 258 | + | ||
| 259 | + ``-a``, ``--all-threads`` | ||
| 260 | + Dump every thread in the target process. Without this flag only the main | ||
| 261 | + thread is shown. | ||
| 262 | + | ||
| 263 | + ``--native`` | ||
| 264 | + Include synthetic ``<native>`` frames marking transitions into C | ||
| 265 | + extensions or other non-Python code. | ||
| 266 | + | ||
| 267 | + ``--no-gc`` | ||
| 268 | + Hide the synthetic ``<GC>`` frames that mark active garbage collection. | ||
| 269 | + | ||
| 270 | + ``--opcodes`` | ||
| 271 | + Annotate each frame with the bytecode opcode the thread is currently | ||
| 272 | + executing (for example, ``opcode=CALL_KW``). Useful for | ||
| 273 | + instruction-level investigation, including identifying specializations | ||
| 274 | + chosen by the adaptive interpreter. | ||
| 275 | + | ||
| 276 | + ``--async-aware`` | ||
| 277 | + Reconstruct stacks across ``await`` boundaries. ``dump`` walks the task | ||
| 278 | + graph and emits one section per task, with ``<task>`` markers separating | ||
| 279 | + coroutines awaiting each other. | ||
| 280 | + | ||
| 281 | + ``--async-mode {running,all}`` | ||
| 282 | + Controls which tasks are included when ``--async-aware`` is enabled. | ||
| 283 | + ``running`` shows only the task currently executing on each thread; | ||
| 284 | + ``all`` (the default for ``dump``) also includes tasks suspended on a | ||
| 285 | + wait. ``attach``'s default for this flag is ``running``; ``dump`` | ||
| 286 | + defaults to ``all`` because a single snapshot is most useful when it | ||
| 287 | + shows the full task graph. | ||
| 288 | + | ||
| 289 | + ``--blocking`` | ||
| 290 | + Pause every thread in the target while reading its stack and resume | ||
| 291 | + them after. Guarantees a fully consistent snapshot at the cost of | ||
| 292 | + briefly stopping the target. Without it, ``dump`` reads memory while | ||
| 293 | + the target keeps running, which is faster but can occasionally produce | ||
| 294 | + a torn stack. | ||
| 295 | + | ||
| 296 | + | ||
| 220 | 297 | .. _replay-command: | |
| 221 | 298 | ||
| 222 | 299 | The ``replay`` command | |
@@ -1441,11 +1518,52 @@ Global options | |||
| 1441 | 1518 | ||
| 1442 | 1519 | Attach to and profile a running process by PID. | |
| 1443 | 1520 | ||
| 1521 | + .. option:: dump | ||
| 1522 | + | ||
| 1523 | + Print a single one-shot snapshot of a running process's Python stack. | ||
| 1524 | + | ||
| 1444 | 1525 | .. option:: replay | |
| 1445 | 1526 | ||
| 1446 | 1527 | Convert a binary profile file to another output format. | |
| 1447 | 1528 | ||
| 1448 | 1529 | ||
| 1530 | + Dump options | ||
| 1531 | + ------------ | ||
| 1532 | + | ||
| 1533 | + The following options apply to the ``dump`` subcommand: | ||
| 1534 | + | ||
| 1535 | + .. option:: -a, --all-threads | ||
| 1536 | + | ||
| 1537 | + Dump all threads in the target process instead of just the main thread. | ||
| 1538 | + | ||
| 1539 | + .. option:: --native | ||
| 1540 | + | ||
| 1541 | + Include ``<native>`` frames for non-Python code. | ||
| 1542 | + | ||
| 1543 | + .. option:: --no-gc | ||
| 1544 | + | ||
| 1545 | + Exclude ``<GC>`` frames for active garbage collection. | ||
| 1546 | + | ||
| 1547 | + .. option:: --opcodes | ||
| 1548 | + | ||
| 1549 | + Show bytecode opcode names when available. | ||
| 1550 | + | ||
| 1551 | + .. option:: --async-aware | ||
| 1552 | + | ||
| 1553 | + Reconstruct the stack across ``await`` boundaries for asyncio | ||
| 1554 | + applications. | ||
| 1555 | + | ||
| 1556 | + .. option:: --async-mode <mode> | ||
| 1557 | + | ||
| 1558 | + Async stack mode: ``running`` (only the running task) or ``all`` | ||
| 1559 | + (all tasks including waiting). Defaults to ``all`` for ``dump``. | ||
| 1560 | + Requires :option:`--async-aware`. | ||
| 1561 | + | ||
| 1562 | + .. option:: --blocking | ||
| 1563 | + | ||
| 1564 | + Pause all threads in the target process while reading the stack. | ||
| 1565 | + | ||
| 1566 | + | ||
| 1449 | 1567 | Sampling options | |
| 1450 | 1568 | ---------------- | |
| 1451 | 1569 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -322,6 +322,9 @@ Key features include: | |||
| 322 | 322 | * Profile running processes by PID (``attach``) - attach to already-running applications | |
| 323 | 323 | * Run and profile scripts directly (``run``) - profile from the very start of execution | |
| 324 | 324 | * Execute and profile modules (``run -m``) - profile packages run as ``python -m module`` | |
| 325 | + * Capture a one-shot snapshot of a running process (``dump``) - print a | ||
| 326 | + traceback-style stack of every thread (or all asyncio tasks with | ||
| 327 | + ``--async-aware``). Useful for investigating hung processes. | ||
| 325 | 328 | ||
| 326 | 329 | * **Multiple profiling modes**: Choose what to measure based on your performance investigation: | |
| 327 | 330 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -359,6 +359,23 @@ class LiveProfiler(ThemeSection): | |||
| 359 | 359 | ) | |
| 360 | 360 | ||
| 361 | 361 | ||
| 362 | + @dataclass(frozen=True, kw_only=True) | ||
| 363 | + class ProfilerDump(ThemeSection): | ||
| 364 | + header: str = ANSIColors.BOLD_BLUE | ||
| 365 | + interpreter: str = ANSIColors.GREY | ||
| 366 | + thread: str = ANSIColors.BOLD_CYAN | ||
| 367 | + status: str = ANSIColors.YELLOW | ||
| 368 | + frame_index: str = ANSIColors.GREY | ||
| 369 | + frame: str = ANSIColors.BOLD_GREEN | ||
| 370 | + filename: str = ANSIColors.CYAN | ||
| 371 | + line_no: str = ANSIColors.YELLOW | ||
| 372 | + source: str = ANSIColors.WHITE | ||
| 373 | + source_highlight: str = ANSIColors.BOLD_YELLOW | ||
| 374 | + opcode: str = ANSIColors.GREY | ||
| 375 | + warning: str = ANSIColors.YELLOW | ||
| 376 | + reset: str = ANSIColors.RESET | ||
| 377 | + | ||
| 378 | + | ||
| 362 | 379 | @dataclass(frozen=True, kw_only=True) | |
| 363 | 380 | class Pickletools(ThemeSection): | |
| 364 | 381 | annotation: str = ANSIColors.GREY | |
@@ -447,6 +464,7 @@ class Theme: | |||
| 447 | 464 | http_server: HttpServer = field(default_factory=HttpServer) | |
| 448 | 465 | live_profiler: LiveProfiler = field(default_factory=LiveProfiler) | |
| 449 | 466 | pickletools: Pickletools = field(default_factory=Pickletools) | |
| 467 | + profiler_dump: ProfilerDump = field(default_factory=ProfilerDump) | ||
| 450 | 468 | syntax: Syntax = field(default_factory=Syntax) | |
| 451 | 469 | timeit: Timeit = field(default_factory=Timeit) | |
| 452 | 470 | tokenize: Tokenize = field(default_factory=Tokenize) | |
@@ -463,6 +481,7 @@ def copy_with( | |||
| 463 | 481 | http_server: HttpServer | None = None, | |
| 464 | 482 | live_profiler: LiveProfiler | None = None, | |
| 465 | 483 | pickletools: Pickletools | None = None, | |
| 484 | + profiler_dump: ProfilerDump | None = None, | ||
| 466 | 485 | syntax: Syntax | None = None, | |
| 467 | 486 | timeit: Timeit | None = None, | |
| 468 | 487 | tokenize: Tokenize | None = None, | |
@@ -482,6 +501,7 @@ def copy_with( | |||
| 482 | 501 | http_server=http_server or self.http_server, | |
| 483 | 502 | live_profiler=live_profiler or self.live_profiler, | |
| 484 | 503 | pickletools=pickletools or self.pickletools, | |
| 504 | + profiler_dump=profiler_dump or self.profiler_dump, | ||
| 485 | 505 | syntax=syntax or self.syntax, | |
| 486 | 506 | timeit=timeit or self.timeit, | |
| 487 | 507 | tokenize=tokenize or self.tokenize, | |
@@ -505,6 +525,7 @@ def no_colors(cls) -> Self: | |||
| 505 | 525 | http_server=HttpServer.no_colors(), | |
| 506 | 526 | live_profiler=LiveProfiler.no_colors(), | |
| 507 | 527 | pickletools=Pickletools.no_colors(), | |
| 528 | + profiler_dump=ProfilerDump.no_colors(), | ||
| 508 | 529 | syntax=Syntax.no_colors(), | |
| 509 | 530 | timeit=Timeit.no_colors(), | |
| 510 | 531 | tokenize=Tokenize.no_colors(), | |
| Back | FazBrowse Home | New Git URL |
0 commit comments