92c83ecc7e
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 16s
CI / build (pull_request) Successful in 17s
CI / quality (pull_request) Successful in 19s
CI / typecheck (pull_request) Successful in 33s
CI / security (pull_request) Successful in 35s
CI / integration_tests (pull_request) Successful in 2m41s
CI / unit_tests (pull_request) Successful in 6m18s
CI / docker (pull_request) Successful in 1m2s
CI / benchmark-regression (pull_request) Successful in 15m41s
CI / coverage (pull_request) Failing after 20m52s
274 lines
8.0 KiB
Python
274 lines
8.0 KiB
Python
"""ASV benchmarks for resource DAG link and auto_discover."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import contextlib
|
|
import typing
|
|
from datetime import UTC, datetime
|
|
from typing import Any
|
|
|
|
|
|
def _setup_db() -> Any:
|
|
"""Create in-memory database and return session factory."""
|
|
from sqlalchemy import create_engine, event
|
|
from sqlalchemy.orm import sessionmaker
|
|
|
|
from cleveragents.infrastructure.database.models import Base
|
|
|
|
engine = create_engine("sqlite:///:memory:")
|
|
|
|
@event.listens_for(engine, "connect")
|
|
def _fk(conn: Any, _rec: Any) -> None:
|
|
conn.cursor().execute("PRAGMA foreign_keys=ON")
|
|
|
|
Base.metadata.create_all(engine)
|
|
return sessionmaker(bind=engine)
|
|
|
|
|
|
_CB32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
|
|
_BENCH_CTR = 0
|
|
|
|
|
|
def _bench_ulid() -> str:
|
|
global _BENCH_CTR
|
|
_BENCH_CTR += 1
|
|
n = _BENCH_CTR
|
|
suffix = ""
|
|
for _ in range(7):
|
|
suffix = _CB32[n % 32] + suffix
|
|
n //= 32
|
|
return f"01HDAGBNCH0AQDYTR4B{suffix}"[:26]
|
|
|
|
|
|
def _seed_types(
|
|
rt_repo: Any,
|
|
session_factory: Any,
|
|
parent_name: str = "bench/dag-parent",
|
|
child_name: str = "bench/dag-child",
|
|
) -> None:
|
|
"""Seed parent and child resource types."""
|
|
from cleveragents.domain.models.core.resource_type import (
|
|
ResourceKind,
|
|
ResourceTypeSpec,
|
|
SandboxStrategy,
|
|
)
|
|
|
|
parent_spec = ResourceTypeSpec(
|
|
name=parent_name,
|
|
description="Bench parent type",
|
|
resource_kind=ResourceKind.PHYSICAL,
|
|
sandbox_strategy=SandboxStrategy.NONE,
|
|
user_addable=True,
|
|
cli_args=[],
|
|
parent_types=[],
|
|
child_types=[child_name],
|
|
auto_discovery={
|
|
"enabled": True,
|
|
"rules": [{"type": child_name, "pattern": "*"}],
|
|
},
|
|
equivalence=None,
|
|
handler=None,
|
|
capabilities={
|
|
"read": True,
|
|
"write": True,
|
|
"sandbox": True,
|
|
"checkpoint": False,
|
|
},
|
|
built_in=False,
|
|
)
|
|
child_spec = ResourceTypeSpec(
|
|
name=child_name,
|
|
description="Bench child type",
|
|
resource_kind=ResourceKind.PHYSICAL,
|
|
sandbox_strategy=SandboxStrategy.NONE,
|
|
user_addable=True,
|
|
cli_args=[],
|
|
parent_types=[],
|
|
child_types=[],
|
|
auto_discovery=None,
|
|
equivalence=None,
|
|
handler=None,
|
|
capabilities={
|
|
"read": True,
|
|
"write": True,
|
|
"sandbox": True,
|
|
"checkpoint": False,
|
|
},
|
|
built_in=False,
|
|
)
|
|
rt_repo.create(parent_spec)
|
|
if child_name != parent_name:
|
|
rt_repo.create(child_spec)
|
|
# Commit so types survive across session boundaries (StaticPool).
|
|
session_factory().commit()
|
|
|
|
|
|
def _seed_single_type(
|
|
rt_repo: Any,
|
|
type_name: str = "bench/chain-type",
|
|
) -> None:
|
|
"""Seed a single self-linking resource type for DAG chain benchmarks."""
|
|
from cleveragents.domain.models.core.resource_type import (
|
|
ResourceKind,
|
|
ResourceTypeSpec,
|
|
SandboxStrategy,
|
|
)
|
|
|
|
spec = ResourceTypeSpec(
|
|
name=type_name,
|
|
description="Bench chain type",
|
|
resource_kind=ResourceKind.PHYSICAL,
|
|
sandbox_strategy=SandboxStrategy.NONE,
|
|
user_addable=True,
|
|
cli_args=[],
|
|
parent_types=[],
|
|
child_types=[type_name],
|
|
auto_discovery=None,
|
|
equivalence=None,
|
|
handler=None,
|
|
capabilities={
|
|
"read": True,
|
|
"write": True,
|
|
"sandbox": True,
|
|
"checkpoint": False,
|
|
},
|
|
built_in=False,
|
|
)
|
|
rt_repo.create(spec)
|
|
|
|
|
|
def _make_resource(
|
|
res_repo: Any,
|
|
type_name: str,
|
|
session_factory: Any,
|
|
) -> str:
|
|
"""Create a resource and return its ID."""
|
|
from cleveragents.domain.models.core.resource import (
|
|
PhysVirt,
|
|
Resource,
|
|
ResourceCapabilities,
|
|
)
|
|
|
|
rid = _bench_ulid()
|
|
res = Resource(
|
|
resource_id=rid,
|
|
name=None,
|
|
resource_type_name=type_name,
|
|
classification=PhysVirt.PHYSICAL,
|
|
description="Bench resource",
|
|
properties={},
|
|
location=None,
|
|
content_hash=None,
|
|
sandbox_strategy=None,
|
|
capabilities=ResourceCapabilities(),
|
|
created_at=datetime.now(tz=UTC),
|
|
updated_at=datetime.now(tz=UTC),
|
|
)
|
|
res_repo.create(res)
|
|
# Commit so the resource survives across session boundaries.
|
|
session_factory().commit()
|
|
return rid
|
|
|
|
|
|
class TimeLinkChild:
|
|
"""Benchmark ResourceRepository.link_child()."""
|
|
|
|
def setup(self) -> None:
|
|
from cleveragents.infrastructure.database.repositories import (
|
|
ResourceRepository,
|
|
ResourceTypeRepository,
|
|
)
|
|
|
|
self.factory = _setup_db()
|
|
self.rt_repo = ResourceTypeRepository(self.factory)
|
|
self.res_repo = ResourceRepository(self.factory)
|
|
_seed_types(self.rt_repo, self.factory)
|
|
self.parent_id = _make_resource(self.res_repo, "bench/dag-parent", self.factory)
|
|
self._child_ctr = 0
|
|
|
|
def time_link_child(self) -> None:
|
|
child_id = _make_resource(self.res_repo, "bench/dag-child", self.factory)
|
|
self.res_repo.link_child(self.parent_id, child_id)
|
|
|
|
|
|
class TimeUnlinkChild:
|
|
"""Benchmark ResourceRepository.unlink_child()."""
|
|
|
|
def setup(self) -> None:
|
|
from cleveragents.infrastructure.database.repositories import (
|
|
ResourceRepository,
|
|
ResourceTypeRepository,
|
|
)
|
|
|
|
self.factory = _setup_db()
|
|
self.rt_repo = ResourceTypeRepository(self.factory)
|
|
self.res_repo = ResourceRepository(self.factory)
|
|
_seed_types(self.rt_repo, self.factory)
|
|
self.parent_id = _make_resource(self.res_repo, "bench/dag-parent", self.factory)
|
|
self.child_id = _make_resource(self.res_repo, "bench/dag-child", self.factory)
|
|
self.res_repo.link_child(self.parent_id, self.child_id)
|
|
self.factory().commit()
|
|
|
|
def time_unlink_child(self) -> None:
|
|
self.res_repo.unlink_child(self.parent_id, self.child_id)
|
|
# Re-link so the benchmark can run multiple times
|
|
self.res_repo.link_child(self.parent_id, self.child_id)
|
|
|
|
|
|
class TimeAutoDiscoverChildren:
|
|
"""Benchmark ResourceRepository.auto_discover_children()."""
|
|
|
|
def setup(self) -> None:
|
|
from cleveragents.infrastructure.database.repositories import (
|
|
ResourceRepository,
|
|
ResourceTypeRepository,
|
|
)
|
|
|
|
self.factory = _setup_db()
|
|
self.rt_repo = ResourceTypeRepository(self.factory)
|
|
self.res_repo = ResourceRepository(self.factory)
|
|
_seed_types(self.rt_repo, self.factory)
|
|
self.parent_id = _make_resource(self.res_repo, "bench/dag-parent", self.factory)
|
|
|
|
def time_auto_discover_children(self) -> None:
|
|
self.res_repo.auto_discover_children(self.parent_id)
|
|
|
|
|
|
class TimeCycleDetection:
|
|
"""Benchmark cycle detection with deep DAG chains."""
|
|
|
|
params: typing.ClassVar[list[int]] = [5, 10, 50]
|
|
param_names: typing.ClassVar[list[str]] = ["chain_depth"]
|
|
|
|
def setup(self, chain_depth: int) -> None:
|
|
from cleveragents.infrastructure.database.repositories import (
|
|
ResourceRepository,
|
|
ResourceTypeRepository,
|
|
)
|
|
|
|
self.factory = _setup_db()
|
|
self.rt_repo = ResourceTypeRepository(self.factory)
|
|
self.res_repo = ResourceRepository(self.factory)
|
|
_seed_single_type(self.rt_repo, "bench/chain-type")
|
|
|
|
# Build a chain: r0 -> r1 -> ... -> rN
|
|
self.chain_ids: list[str] = []
|
|
for _ in range(chain_depth + 1):
|
|
rid = _make_resource(self.res_repo, "bench/chain-type", self.factory)
|
|
self.chain_ids.append(rid)
|
|
|
|
for i in range(chain_depth):
|
|
self.res_repo.link_child(
|
|
self.chain_ids[i],
|
|
self.chain_ids[i + 1],
|
|
)
|
|
self.factory().commit()
|
|
|
|
def time_cycle_detection(self, chain_depth: int) -> None:
|
|
"""Attempt to close the cycle (should raise)."""
|
|
with contextlib.suppress(Exception):
|
|
self.res_repo.link_child(
|
|
self.chain_ids[-1],
|
|
self.chain_ids[0],
|
|
)
|