Guard the cold import latency budget
Run seven fresh interpreters and gate the median `import tractor` time below a conservative 0.35s ceiling. Provide an explicit environment override for platforms with a different baseline. Also assert the optional modules deferred by this patch remain unloaded so a timing pass cannot hide an eager-import regression. Review: PR #478 (goodboy) https://github.com/goodboy/tractor/pull/478#pullrequestreview-4922213201 (this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))wkt/boot_latency_470
parent
66ac7863b5
commit
3705bbe594
|
|
@ -3,6 +3,8 @@ Regression tests for the cold package import surface.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
|
from statistics import median
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from typing import (
|
from typing import (
|
||||||
|
|
@ -68,6 +70,72 @@ def test_lazy_to_asyncio_package_api():
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_cold_import_budget():
|
||||||
|
'''
|
||||||
|
Keep cold package import below the pre-optimization regression.
|
||||||
|
|
||||||
|
The original `inspect.stack()` caller lookup made a fresh
|
||||||
|
`import tractor` take about 0.42s and dominate actor startup.
|
||||||
|
Run seven independent interpreters and gate their median at a
|
||||||
|
deliberately broad 0.35s: over twice the measured ~0.145s
|
||||||
|
baseline, but low enough to catch restoration of that hot path.
|
||||||
|
|
||||||
|
Taking the median absorbs process-start and shared-runner noise.
|
||||||
|
The child measures only its import, rather than parent-side
|
||||||
|
process creation. `TRACTOR_IMPORT_BUDGET_S` provides an explicit,
|
||||||
|
reviewable override for platforms that establish a different
|
||||||
|
baseline instead of silently weakening the project default.
|
||||||
|
|
||||||
|
Each child also reports the modules whose eager loading this PR
|
||||||
|
intentionally removes, proving a timing pass cannot hide a
|
||||||
|
dependency-import regression.
|
||||||
|
|
||||||
|
'''
|
||||||
|
budget_s = float(
|
||||||
|
os.environ.get(
|
||||||
|
'TRACTOR_IMPORT_BUDGET_S',
|
||||||
|
'0.35',
|
||||||
|
)
|
||||||
|
)
|
||||||
|
optional_mods = (
|
||||||
|
'asyncio',
|
||||||
|
'bidict',
|
||||||
|
'colorlog',
|
||||||
|
'multiaddr',
|
||||||
|
'wrapt',
|
||||||
|
)
|
||||||
|
code = (
|
||||||
|
'import json, sys, time; '
|
||||||
|
'started = time.perf_counter(); '
|
||||||
|
'import tractor; '
|
||||||
|
'elapsed = time.perf_counter() - started; '
|
||||||
|
f'optional = {optional_mods!r}; '
|
||||||
|
'print(json.dumps({'
|
||||||
|
'"elapsed": elapsed, '
|
||||||
|
'"loaded": [name for name in optional '
|
||||||
|
'if name in sys.modules]}))'
|
||||||
|
)
|
||||||
|
samples = [
|
||||||
|
run_cold_import(code)
|
||||||
|
for _ in range(7)
|
||||||
|
]
|
||||||
|
elapsed = [
|
||||||
|
float(sample['elapsed'])
|
||||||
|
for sample in samples
|
||||||
|
]
|
||||||
|
loaded = {
|
||||||
|
name
|
||||||
|
for sample in samples
|
||||||
|
for name in sample['loaded']
|
||||||
|
}
|
||||||
|
|
||||||
|
assert not loaded
|
||||||
|
assert median(elapsed) < budget_s, (
|
||||||
|
f'cold import median exceeded {budget_s:.3f}s budget: '
|
||||||
|
f'{elapsed!r}'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_lazy_annotation_names_resolve():
|
def test_lazy_annotation_names_resolve():
|
||||||
'''
|
'''
|
||||||
Resolve annotations without importing optional dependencies.
|
Resolve annotations without importing optional dependencies.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue