Files
2026-02-25 10:02:38 +00:00

199 lines
6.2 KiB
Python

"""ASV benchmarks for diff review artifact building and serialization.
Measures the performance of:
- DiffBuilder.build() with various changeset sizes
- DiffSerializer.to_plain() / to_json() / to_rich()
- Rename detection with content hash matching
- ReviewArtifact and DiffEntry construction
"""
from __future__ import annotations
import sys
from pathlib import Path
try:
from cleveragents.domain.models.core.change import (
ChangeEntry,
ChangeOperation,
SpecChangeSet,
)
from cleveragents.domain.models.core.diff_review import (
DiffBuilder,
DiffEntry,
DiffSerializer,
ResourceDiffGroup,
ReviewArtifact,
)
except ModuleNotFoundError:
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from cleveragents.domain.models.core.change import (
ChangeEntry,
ChangeOperation,
SpecChangeSet,
)
from cleveragents.domain.models.core.diff_review import (
DiffBuilder,
DiffEntry,
DiffSerializer,
ResourceDiffGroup,
ReviewArtifact,
)
def _make_changeset(
n_entries: int = 10,
) -> tuple[SpecChangeSet, dict[str, str], dict[str, str]]:
"""Create a changeset with n_entries MODIFY entries and content maps."""
cs = SpecChangeSet(plan_id="BENCH-PLAN")
before_map: dict[str, str] = {}
after_map: dict[str, str] = {}
for i in range(n_entries):
path = f"src/module_{i:04d}.py"
cs.add_change(
ChangeEntry(
plan_id="BENCH-PLAN",
resource_id=f"RES{i % 5:03d}",
tool_name="builtin/bench-tool",
operation=ChangeOperation.MODIFY,
path=path,
before_hash=f"before-{i}",
after_hash=f"after-{i}",
)
)
before_map[path] = f"# module {i}\nx = {i}\n"
after_map[path] = f"# module {i}\nx = {i + 1}\ny = {i}\n"
return cs, before_map, after_map
class DiffBuildSuite:
"""Benchmark DiffBuilder.build() with various changeset sizes."""
def setup(self) -> None:
"""Prepare changesets of different sizes."""
self.builder = DiffBuilder()
self.cs_small, self.bm_small, self.am_small = _make_changeset(5)
self.cs_medium, self.bm_medium, self.am_medium = _make_changeset(50)
self.cs_large, self.bm_large, self.am_large = _make_changeset(200)
def time_build_small(self) -> None:
"""Benchmark building artifact from 5-entry changeset."""
self.builder.build(
self.cs_small,
before_contents=self.bm_small,
after_contents=self.am_small,
)
def time_build_medium(self) -> None:
"""Benchmark building artifact from 50-entry changeset."""
self.builder.build(
self.cs_medium,
before_contents=self.bm_medium,
after_contents=self.am_medium,
)
def time_build_large(self) -> None:
"""Benchmark building artifact from 200-entry changeset."""
self.builder.build(
self.cs_large,
before_contents=self.bm_large,
after_contents=self.am_large,
)
class DiffSerializationSuite:
"""Benchmark DiffSerializer output formats."""
def setup(self) -> None:
"""Build an artifact to serialize."""
cs, bm, am = _make_changeset(20)
builder = DiffBuilder()
self.artifact = builder.build(cs, before_contents=bm, after_contents=am)
def time_to_plain(self) -> None:
"""Benchmark plain text serialization."""
DiffSerializer.to_plain(self.artifact)
def time_to_json(self) -> None:
"""Benchmark JSON serialization."""
DiffSerializer.to_json(self.artifact)
def time_to_rich(self) -> None:
"""Benchmark rich text serialization."""
DiffSerializer.to_rich(self.artifact)
class DiffRenameSuite:
"""Benchmark rename detection with content hash matching."""
def setup(self) -> None:
"""Prepare a changeset with rename pairs."""
self.builder = DiffBuilder()
self.cs = SpecChangeSet(plan_id="BENCH-PLAN")
for i in range(20):
self.cs.add_change(
ChangeEntry(
plan_id="BENCH-PLAN",
resource_id="RES001",
tool_name="builtin/bench-tool",
operation=ChangeOperation.DELETE,
path=f"old/module_{i:04d}.py",
before_hash=f"hash-{i}",
)
)
self.cs.add_change(
ChangeEntry(
plan_id="BENCH-PLAN",
resource_id="RES001",
tool_name="builtin/bench-tool",
operation=ChangeOperation.CREATE,
path=f"new/module_{i:04d}.py",
after_hash=f"hash-{i}",
)
)
def time_rename_detection(self) -> None:
"""Benchmark rename detection for 20 pairs."""
self.builder.build(self.cs)
class DiffModelSuite:
"""Benchmark DiffEntry and ReviewArtifact construction."""
def time_diff_entry_construction(self) -> None:
"""Benchmark creating a DiffEntry."""
DiffEntry(
resource_id="RES001",
resource_name="test-resource",
path="src/main.py",
change_type="modify",
diff_text="--- a/src/main.py\n+++ b/src/main.py\n",
)
def time_resource_diff_group_construction(self) -> None:
"""Benchmark creating a ResourceDiffGroup."""
ResourceDiffGroup(
resource_id="RES001",
resource_name="test-resource",
entries=[
DiffEntry(
resource_id="RES001",
path="a.py",
change_type="create",
),
DiffEntry(
resource_id="RES001",
path="b.py",
change_type="modify",
),
],
)
def time_review_artifact_construction(self) -> None:
"""Benchmark creating a ReviewArtifact."""
ReviewArtifact(
plan_id="PLAN001",
changeset_id="CS001",
total_changes=5,
)