"""ASV benchmarks for async resource cleanup overhead (#321). Measures registration, close_all, and leak-warning latency to establish baselines for the AsyncResourceTracker. """ from __future__ import annotations import asyncio from cleveragents.core.async_cleanup import AsyncResourceTracker class _FakeResource: """Minimal async resource for benchmarking.""" def __init__(self) -> None: self.closed = False async def close(self) -> None: self.closed = True def _make_tracker(count: int) -> AsyncResourceTracker: """Create a tracker pre-loaded with *count* fake resources.""" tracker = AsyncResourceTracker() for i in range(count): tracker.register(f"res-{i}", _FakeResource()) return tracker class TimeRegisterSingle: """Benchmark registering a single resource.""" timeout = 10 def setup(self) -> None: self.tracker = AsyncResourceTracker() self.counter = 0 def teardown(self) -> None: pass def time_register_one(self) -> None: name = f"bench-{self.counter}" self.counter += 1 self.tracker.register(name, _FakeResource()) class TimeRegisterBatch: """Benchmark registering 100 resources in sequence.""" timeout = 10 number = 1 # Tracker cannot re-register names; recreate each iteration. def setup(self) -> None: self.tracker = AsyncResourceTracker() def teardown(self) -> None: pass def time_register_100(self) -> None: tracker = AsyncResourceTracker() for i in range(100): tracker.register(f"batch-{i}", _FakeResource()) class TimeCloseAll: """Benchmark close_all on pre-loaded trackers.""" timeout = 30 number = 1 # Re-create tracker for each iteration. def setup(self) -> None: self.tracker = _make_tracker(50) def teardown(self) -> None: pass def time_close_50_resources(self) -> None: asyncio.run(self.tracker.close_all()) class TimeCloseAllLarge: """Benchmark close_all with 500 resources.""" timeout = 60 number = 1 def setup(self) -> None: self.tracker = _make_tracker(500) def teardown(self) -> None: pass def time_close_500_resources(self) -> None: asyncio.run(self.tracker.close_all()) class TimeLeakWarning: """Benchmark the _warn_unclosed finalizer path.""" timeout = 10 def setup(self) -> None: self.tracker = _make_tracker(20) def teardown(self) -> None: pass def time_warn_20_unclosed(self) -> None: self.tracker._warn_unclosed() class TimeOpenCount: """Benchmark the open_count property.""" timeout = 10 def setup(self) -> None: self.tracker = _make_tracker(100) def teardown(self) -> None: pass def time_open_count(self) -> None: _ = self.tracker.open_count