(binary: str, sample_interval_s: float)
| 355 | # Server spawn profiling |
| 356 | # --------------------------------------------------------------------------- # |
| 357 | def profile_server_spawn(binary: str, sample_interval_s: float) -> dict | None: |
| 358 | root = tempfile.mkdtemp(prefix="jcode-spawn-server-") |
| 359 | env = isolated_env(root) |
| 360 | sock = env["JCODE_SOCKET"] |
| 361 | proc = None |
| 362 | try: |
| 363 | t0 = time.perf_counter() |
| 364 | proc = subprocess.Popen( |
| 365 | [binary, "--no-update", "serve"], |
| 366 | stdout=subprocess.DEVNULL, |
| 367 | stderr=subprocess.DEVNULL, |
| 368 | env=env, |
| 369 | ) |
| 370 | mon = ProcessMonitor(proc.pid) |
| 371 | ready_ms = None |
| 372 | deadline = t0 + 8.0 |
| 373 | while time.perf_counter() < deadline: |
| 374 | if not mon.poll(): |
| 375 | break |
| 376 | if ready_ms is None and socket_connectable(sock): |
| 377 | ready_ms = (time.perf_counter() - t0) * 1000.0 |
| 378 | # keep sampling briefly to capture steady-state footprint |
| 379 | settle_until = time.perf_counter() + 0.4 |
| 380 | while time.perf_counter() < settle_until: |
| 381 | mon.poll() |
| 382 | time.sleep(sample_interval_s) |
| 383 | break |
| 384 | time.sleep(sample_interval_s) |
| 385 | res = mon.finalize() |
| 386 | out = asdict(res) |
| 387 | out["ready_ms"] = ready_ms |
| 388 | return out |
| 389 | finally: |
| 390 | if proc is not None: |
| 391 | proc.terminate() |
| 392 | try: |
| 393 | proc.wait(timeout=2) |
| 394 | except subprocess.TimeoutExpired: |
| 395 | proc.kill() |
| 396 | proc.wait(timeout=2) |
| 397 | shutil.rmtree(root, ignore_errors=True) |
| 398 | |
| 399 | |
| 400 | # --------------------------------------------------------------------------- # |
no test coverage detected