Files
cleveragents-core/benchmarks/resource_handler_bench.py
T

215 lines
7.3 KiB
Python

"""ASV benchmarks for resource handler resolution overhead.
Measures the performance of:
- Handler resolver (import + cache lookup)
- GitCheckoutHandler.resolve() with mock sandbox
- FsDirectoryHandler.resolve() with mock sandbox
- ResourceHandlerService.resolve_binding() end-to-end
"""
from __future__ import annotations
import sys
from datetime import datetime
from pathlib import Path
from unittest.mock import MagicMock, PropertyMock
try:
from cleveragents.domain.models.core.resource import (
PhysVirt,
Resource,
ResourceCapabilities,
)
from cleveragents.domain.models.core.resource_slot import BindingResult
from cleveragents.domain.models.core.resource_type import (
ResourceKind,
ResourceTypeSpec,
)
from cleveragents.domain.models.core.resource_type import (
SandboxStrategy as TypeSandboxStrategy,
)
from cleveragents.infrastructure.sandbox.factory import SandboxFactory
from cleveragents.infrastructure.sandbox.manager import SandboxManager
from cleveragents.infrastructure.sandbox.protocol import (
SandboxContext,
SandboxStatus,
)
from cleveragents.resource.handlers.fs_directory import FsDirectoryHandler
from cleveragents.resource.handlers.git_checkout import GitCheckoutHandler
from cleveragents.resource.handlers.resolver import (
clear_handler_cache,
resolve_handler,
)
except ModuleNotFoundError:
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from cleveragents.domain.models.core.resource import (
PhysVirt,
Resource,
ResourceCapabilities,
)
from cleveragents.domain.models.core.resource_slot import BindingResult
from cleveragents.domain.models.core.resource_type import (
ResourceKind,
ResourceTypeSpec,
)
from cleveragents.domain.models.core.resource_type import (
SandboxStrategy as TypeSandboxStrategy,
)
from cleveragents.infrastructure.sandbox.factory import SandboxFactory
from cleveragents.infrastructure.sandbox.manager import SandboxManager
from cleveragents.infrastructure.sandbox.protocol import (
SandboxContext,
SandboxStatus,
)
from cleveragents.resource.handlers.fs_directory import FsDirectoryHandler
from cleveragents.resource.handlers.git_checkout import GitCheckoutHandler
from cleveragents.resource.handlers.resolver import (
clear_handler_cache,
resolve_handler,
)
def _make_resource(rtype: str, location: str) -> Resource:
return Resource(
resource_id="01KJ5C5TPMP8GGX3QC83E2MAQS",
resource_type_name=rtype,
classification=PhysVirt.PHYSICAL,
location=location,
capabilities=ResourceCapabilities(
readable=True, writable=True, sandboxable=True
),
)
def _make_mock_manager() -> SandboxManager:
mock_factory = MagicMock(spec=SandboxFactory)
mock_sandbox = MagicMock()
mock_sandbox.sandbox_id = "sb-bench-001"
type(mock_sandbox).status = PropertyMock(return_value=SandboxStatus.CREATED)
mock_sandbox.context = SandboxContext(
sandbox_id="sb-bench-001",
sandbox_path="/tmp/sandbox/sb-bench-001",
original_path="/tmp/original",
resource_id="res-bench",
plan_id="plan-bench",
created_at=datetime.now(),
)
mock_sandbox.create.return_value = mock_sandbox.context
mock_factory.create_sandbox.return_value = mock_sandbox
return SandboxManager(factory=mock_factory, cleanup_on_exit=False)
class HandlerResolverSuite:
"""Benchmark handler resolver import and cache performance."""
def time_resolve_git_handler_cold(self) -> None:
"""Benchmark cold resolve (no cache)."""
clear_handler_cache()
resolve_handler(
"cleveragents.resource.handlers.git_checkout:GitCheckoutHandler"
)
def time_resolve_git_handler_cached(self) -> None:
"""Benchmark cached resolve."""
resolve_handler(
"cleveragents.resource.handlers.git_checkout:GitCheckoutHandler"
)
def time_resolve_fs_handler_cold(self) -> None:
"""Benchmark cold resolve for fs-directory."""
clear_handler_cache()
resolve_handler(
"cleveragents.resource.handlers.fs_directory:FsDirectoryHandler"
)
class GitCheckoutHandlerSuite:
"""Benchmark GitCheckoutHandler.resolve() overhead."""
def setup(self) -> None:
self.resource = _make_resource("git-checkout", "/tmp/bench-repo")
self.manager = _make_mock_manager()
self.handler = GitCheckoutHandler()
def time_resolve_git_checkout(self) -> None:
"""Benchmark single git-checkout resolution."""
self.handler.resolve(
resource=self.resource,
plan_id="PLAN_BENCH",
slot_name="repo",
sandbox_manager=self.manager,
)
class FsDirectoryHandlerSuite:
"""Benchmark FsDirectoryHandler.resolve() overhead."""
def setup(self) -> None:
self.resource = _make_resource("fs-directory", "/tmp/bench-dir")
self.manager = _make_mock_manager()
self.handler = FsDirectoryHandler()
def time_resolve_fs_directory(self) -> None:
"""Benchmark single fs-directory resolution."""
self.handler.resolve(
resource=self.resource,
plan_id="PLAN_BENCH",
slot_name="workdir",
sandbox_manager=self.manager,
)
class ResourceHandlerServiceSuite:
"""Benchmark ResourceHandlerService end-to-end resolution."""
def setup(self) -> None:
from cleveragents.application.services.resource_handler_service import (
ResourceHandlerService,
)
self.resource = _make_resource("git-checkout", "/tmp/bench-repo")
self.type_spec = ResourceTypeSpec(
name="git-checkout",
description="Test git-checkout type",
resource_kind=ResourceKind.PHYSICAL,
sandbox_strategy=TypeSandboxStrategy.GIT_WORKTREE,
user_addable=True,
built_in=True,
handler="cleveragents.resource.handlers.git_checkout:GitCheckoutHandler",
)
self.manager = _make_mock_manager()
self.service = ResourceHandlerService(
sandbox_manager=self.manager,
resource_lookup=lambda _: self.resource,
type_lookup=lambda _: self.type_spec,
)
self.binding = BindingResult(
slot_name="repo",
resource_id="01KJ5C5TPMP8GGX3QC83E2MAQS",
resource_name="test-repo",
binding_mode="contextual",
)
def time_resolve_binding(self) -> None:
"""Benchmark single binding resolution."""
self.service.resolve_binding(
binding=self.binding,
plan_id="PLAN_BENCH",
)
def time_resolve_bindings_batch(self) -> None:
"""Benchmark batch binding resolution (5 bindings)."""
bindings = [
BindingResult(
slot_name=f"slot-{i}",
resource_id="01KJ5C5TPMP8GGX3QC83E2MAQS",
resource_name=f"res-{i}",
binding_mode="contextual",
)
for i in range(5)
]
self.service.resolve_bindings(
bindings=bindings,
plan_id="PLAN_BENCH",
)