123 lines
4.1 KiB
Markdown
123 lines
4.1 KiB
Markdown
|
|
---
|
||
|
|
model: claude-fable-5
|
||
|
|
service: claude
|
||
|
|
timestamp: 2026-07-02T15:56:26Z
|
||
|
|
git_ref: 65bf9df5
|
||
|
|
diff_cmd: git diff main..wkt/boot_latency_470
|
||
|
|
---
|
||
|
|
|
||
|
|
# Raw AI output — gh #470 `import tractor` latency trim
|
||
|
|
|
||
|
|
All generated code is committed on the
|
||
|
|
`wkt/boot_latency_470` branch; per diff-ref mode each
|
||
|
|
file's content is referenced via its diff instead of
|
||
|
|
copied verbatim.
|
||
|
|
|
||
|
|
## Profiling findings (verbatim analysis output)
|
||
|
|
|
||
|
|
Baseline: `import tractor` ~0.39-0.42s wall.
|
||
|
|
|
||
|
|
`python -X importtime` + `cProfile` traced the cost NOT
|
||
|
|
primarily to third-party deps (the issue's hypothesis)
|
||
|
|
but to `tractor/log.py:get_logger()` calling
|
||
|
|
`get_caller_mod()` -> `inspect.stack()` at module level
|
||
|
|
in ~39 tractor modules:
|
||
|
|
|
||
|
|
- `inspect.stack()` builds `FrameInfo` (incl. src-file
|
||
|
|
and line-context resolution) for EVERY frame on the
|
||
|
|
stack; during nested imports the stack is dozens of
|
||
|
|
importlib frames deep.
|
||
|
|
- each `FrameInfo` resolution calls
|
||
|
|
`inspect.getmodule()` which scans all of
|
||
|
|
`sys.modules` per frame (1.4M `ismodule()` calls in
|
||
|
|
one profiled import).
|
||
|
|
- aggregate: ~244ms of tractor-own module "self" time
|
||
|
|
vs ~20ms for ALL the issue-listed third-party deps
|
||
|
|
(`pdbp` ~10ms, `bidict` ~4.5ms, `multiaddr` ~3.5ms,
|
||
|
|
`wrapt`/`colorlog` ~1ms each); `trio` itself is
|
||
|
|
~70-100ms and unavoidable.
|
||
|
|
|
||
|
|
## Generated changes
|
||
|
|
|
||
|
|
> `git diff main..wkt/boot_latency_470 -- tractor/log.py`
|
||
|
|
|
||
|
|
`get_caller_mod()` rewritten from `inspect.stack()` +
|
||
|
|
`inspect.getmodule()` to `sys._getframe(frames_up)` +
|
||
|
|
`frame.f_globals['__name__']` -> `sys.modules` lookup
|
||
|
|
(O(1) vs O(stack x sys.modules)). Unused `inspect`
|
||
|
|
imports dropped; `FrameType` imported from `types`.
|
||
|
|
Also `colorlog` lazy-imported inside
|
||
|
|
`get_console_log()`.
|
||
|
|
|
||
|
|
> `git diff main..wkt/boot_latency_470 -- tractor/discovery/_addr.py`
|
||
|
|
|
||
|
|
`bidict` import moved under `TYPE_CHECKING`
|
||
|
|
(annotation-only use; `_address_types` is a plain dict
|
||
|
|
literal).
|
||
|
|
|
||
|
|
> `git diff main..wkt/boot_latency_470 -- tractor/discovery/_multiaddr.py`
|
||
|
|
|
||
|
|
`from __future__ import annotations` added; `multiaddr`
|
||
|
|
import moved under `TYPE_CHECKING` + function-local
|
||
|
|
imports in `mk_maddr()`/`parse_maddr()`.
|
||
|
|
|
||
|
|
> `git diff main..wkt/boot_latency_470 -- tractor/ipc/_tcp.py tractor/ipc/_uds.py`
|
||
|
|
|
||
|
|
`Multiaddr` imports moved under `TYPE_CHECKING`
|
||
|
|
(annotation-only in both transports).
|
||
|
|
|
||
|
|
> `git diff main..wkt/boot_latency_470 -- tractor/runtime/_state.py`
|
||
|
|
|
||
|
|
`platformdirs` lazy-imported inside `get_rt_dir()`
|
||
|
|
(NOTE: still imported eagerly via
|
||
|
|
`UDSAddress.def_bindspace` class-var eval; see
|
||
|
|
follow-ups).
|
||
|
|
|
||
|
|
> `git diff main..wkt/boot_latency_470 -- tractor/devx/_frame_stack.py`
|
||
|
|
|
||
|
|
`pdbp` + `wrapt` lazy-imported inside
|
||
|
|
`hide_runtime_frames()` / `api_frame()` respectively.
|
||
|
|
|
||
|
|
> `git diff main..wkt/boot_latency_470 -- tractor/devx/debug/_trace.py tractor/devx/debug/_tty_lock.py`
|
||
|
|
|
||
|
|
`asyncio` moved to `TYPE_CHECKING` + call-site local
|
||
|
|
imports (`asyncio.current_task()` sites);
|
||
|
|
`tractor.to_asyncio.run_trio_task_in_future` imports
|
||
|
|
moved into the infected-aio runtime branches.
|
||
|
|
|
||
|
|
> `git diff main..wkt/boot_latency_470 -- tractor/spawn/_entry.py`
|
||
|
|
|
||
|
|
`run_as_asyncio_guest` import moved into the
|
||
|
|
`infect_asyncio=True` branches of `_mp_main()` /
|
||
|
|
`_trio_main()`.
|
||
|
|
|
||
|
|
> `git diff main..wkt/boot_latency_470 -- tractor/__init__.py`
|
||
|
|
|
||
|
|
PEP 562 module `__getattr__` added so
|
||
|
|
`tractor.to_asyncio` attr-access still works (required
|
||
|
|
by `tests/test_child_manages_service_nursery.py` and
|
||
|
|
any downstream user) while keeping `asyncio` off the
|
||
|
|
eager import path.
|
||
|
|
|
||
|
|
## Measured results (verbatim)
|
||
|
|
|
||
|
|
- `import tractor`: 0.39-0.42s -> ~0.145s (~65% cut)
|
||
|
|
- `start_actor` spawn+boot+reg+cancel: ~0.40-0.44s ->
|
||
|
|
~0.179s/actor (n=5 sequential, warm parent)
|
||
|
|
- post-change eager-module check: only `pdbp` +
|
||
|
|
`platformdirs` of the issue's list remain eager.
|
||
|
|
|
||
|
|
## Known follow-ups (not implemented, deadline-bound)
|
||
|
|
|
||
|
|
- `pdbp` (~10ms): still eager via
|
||
|
|
`devx/debug/_repl.py` class bases
|
||
|
|
(`class PdbREPL(pdbp.Pdb)`) + `_tty_lock.py`
|
||
|
|
module-level `@pdbp.hideframe`; needs `_repl`
|
||
|
|
restructure + PEP 562 in `devx.debug.__init__`.
|
||
|
|
- `platformdirs` (~1.5ms): eager via
|
||
|
|
`UDSAddress.def_bindspace: ClassVar = get_rt_dir()`
|
||
|
|
class-body call; needs `Address`-protocol rework of
|
||
|
|
`def_bindspace` to a lazy accessor.
|
||
|
|
- `stackscope` + `setproctitle`: already lazy/absent —
|
||
|
|
no change needed.
|