Files
cleveragents-core/benchmarks/resource_registry_migration_bench.py
brent.edwards 6f7ab08e12
CI / lint (pull_request) Successful in 13s
CI / typecheck (pull_request) Successful in 28s
CI / quality (pull_request) Successful in 16s
CI / security (pull_request) Successful in 29s
CI / integration_tests (pull_request) Successful in 5m22s
CI / build (pull_request) Successful in 16s
CI / unit_tests (pull_request) Successful in 15m25s
CI / coverage (pull_request) Successful in 8m26s
CI / docker (pull_request) Successful in 40s
Merge branch 'master' into feature/q0-min-coverage
# Conflicts:
#	benchmarks/cli_format_bench.py
#	benchmarks/plan_phase_migration_bench.py
#	benchmarks/project_migration_bench.py
#	benchmarks/resource_registry_migration_bench.py
#	benchmarks/uow_lifecycle_bench.py
2026-02-17 02:35:20 +00:00

206 lines
6.2 KiB
Python

"""ASV benchmarks for resource registry migration and ORM operations.
Measures:
- Schema creation time (Base.metadata.create_all)
- ResourceTypeModel insert throughput
- ResourceModel insert throughput
- ResourceEdgeModel insert throughput
- DAG query performance (children/parents lookup)
"""
from __future__ import annotations
import json
from datetime import UTC, datetime
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from cleveragents.infrastructure.database.models import (
Base,
ResourceEdgeModel,
ResourceModel,
ResourceTypeModel,
)
def _now_iso() -> str:
return datetime.now(tz=UTC).isoformat()
def _make_ulid(n: int) -> str:
return str(n).zfill(26)
class SchemaCreation:
"""Benchmark schema creation (all tables via metadata.create_all)."""
def time_create_all_tables(self) -> None:
engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(engine)
engine.dispose()
class ResourceTypeInsert:
"""Benchmark inserting resource type records."""
def setup(self) -> None:
self.engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(self.engine)
self.session_factory = sessionmaker(bind=self.engine)
self._iter = 0
def teardown(self) -> None:
self.engine.dispose()
def time_insert_single_resource_type(self) -> None:
self._iter += 1
session = self.session_factory()
rt = ResourceTypeModel()
rt.name = f"bench/type-single-{self._iter}"
rt.namespace = "bench"
rt.resource_kind = "physical"
rt.user_addable = True
rt.created_at = _now_iso()
rt.updated_at = _now_iso()
session.add(rt)
session.commit()
session.close()
def time_insert_100_resource_types(self) -> None:
self._iter += 1
batch = self._iter
session = self.session_factory()
for i in range(100):
rt = ResourceTypeModel()
rt.name = f"bench/type-{batch}-{i}"
rt.namespace = "bench"
rt.resource_kind = "physical" if i % 2 == 0 else "virtual"
rt.user_addable = i % 3 == 0
rt.args_schema_json = json.dumps([{"flag": f"--arg-{batch}-{i}"}])
rt.created_at = _now_iso()
rt.updated_at = _now_iso()
session.add(rt)
session.commit()
session.close()
class ResourceInsert:
"""Benchmark inserting resource records."""
def setup(self) -> None:
self.engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(self.engine)
self.session_factory = sessionmaker(bind=self.engine)
session = self.session_factory()
rt = ResourceTypeModel()
rt.name = "bench/git-checkout"
rt.namespace = "bench"
rt.resource_kind = "physical"
rt.user_addable = True
rt.created_at = _now_iso()
rt.updated_at = _now_iso()
session.add(rt)
session.commit()
session.close()
self._iter = 0
def teardown(self) -> None:
self.engine.dispose()
def time_insert_100_resources(self) -> None:
self._iter += 1
batch = self._iter
session = self.session_factory()
for i in range(100):
idx = batch * 1000 + i
r = ResourceModel()
r.resource_id = _make_ulid(idx)
r.namespaced_name = f"bench/resource-{batch}-{i}"
r.namespace = "bench"
r.type_name = "bench/git-checkout"
r.resource_kind = "physical"
r.location = f"/path/to/resource-{idx}"
r.properties_json = json.dumps({"index": idx})
r.created_at = _now_iso()
r.updated_at = _now_iso()
session.add(r)
session.commit()
session.close()
class ResourceEdgeQuery:
"""Benchmark DAG edge queries (children/parents lookup)."""
def setup(self) -> None:
self.engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(self.engine)
self.session_factory = sessionmaker(bind=self.engine)
session = self.session_factory()
# Create types
for tname in ("bench/parent-type", "bench/child-type"):
rt = ResourceTypeModel()
rt.name = tname
rt.namespace = "bench"
rt.resource_kind = "physical"
rt.user_addable = True
rt.created_at = _now_iso()
rt.updated_at = _now_iso()
session.add(rt)
# Create 1 parent + 50 children with edges
parent = ResourceModel()
parent.resource_id = _make_ulid(0)
parent.namespaced_name = "bench/parent"
parent.namespace = "bench"
parent.type_name = "bench/parent-type"
parent.resource_kind = "physical"
parent.created_at = _now_iso()
parent.updated_at = _now_iso()
session.add(parent)
self.parent_id = parent.resource_id
for i in range(1, 51):
child = ResourceModel()
child.resource_id = _make_ulid(i)
child.type_name = "bench/child-type"
child.resource_kind = "physical"
child.created_at = _now_iso()
child.updated_at = _now_iso()
session.add(child)
edge = ResourceEdgeModel()
edge.parent_id = parent.resource_id
edge.child_id = child.resource_id
edge.link_type = "contains"
edge.created_at = _now_iso()
session.add(edge)
session.commit()
session.close()
def teardown(self) -> None:
self.engine.dispose()
def time_query_50_children(self) -> None:
session = self.session_factory()
edges = (
session.query(ResourceEdgeModel)
.filter(ResourceEdgeModel.parent_id == self.parent_id)
.all()
)
assert len(edges) == 50
session.close()
def time_query_parent_of_child(self) -> None:
session = self.session_factory()
child_id = _make_ulid(25)
edges = (
session.query(ResourceEdgeModel)
.filter(ResourceEdgeModel.child_id == child_id)
.all()
)
assert len(edges) == 1
session.close()