9b30421b34
CI / lint (pull_request) Successful in 16s
CI / typecheck (pull_request) Successful in 27s
CI / security (pull_request) Successful in 21s
CI / quality (pull_request) Successful in 16s
CI / integration_tests (pull_request) Successful in 4m10s
CI / build (pull_request) Successful in 15s
CI / unit_tests (pull_request) Successful in 8m0s
CI / docker (pull_request) Successful in 40s
CI / coverage (pull_request) Successful in 6m22s
CI / lint (push) Successful in 13s
CI / typecheck (push) Successful in 27s
CI / security (push) Successful in 22s
CI / quality (push) Successful in 15s
CI / integration_tests (push) Successful in 4m16s
CI / build (push) Successful in 15s
CI / unit_tests (push) Successful in 8m2s
CI / docker (push) Successful in 39s
CI / coverage (push) Successful in 6m23s
170 lines
5.8 KiB
Python
170 lines
5.8 KiB
Python
"""ASV benchmarks for action_arguments table ORM round-trip performance.
|
|
|
|
Measures the performance of:
|
|
- ActionArgument construction and serialization for ORM child rows
|
|
- Bulk argument serialization for actions with many arguments
|
|
- ActionArgumentModel construction patterns
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
try:
|
|
from cleveragents.domain.models.core.action import (
|
|
Action,
|
|
ActionArgument,
|
|
ArgumentRequirement,
|
|
ArgumentType,
|
|
)
|
|
from cleveragents.domain.models.core.plan import NamespacedName
|
|
from cleveragents.infrastructure.database.models import (
|
|
ActionArgumentModel,
|
|
LifecycleActionModel,
|
|
)
|
|
except ModuleNotFoundError:
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
|
from cleveragents.domain.models.core.action import (
|
|
Action,
|
|
ActionArgument,
|
|
ArgumentRequirement,
|
|
ArgumentType,
|
|
)
|
|
from cleveragents.domain.models.core.plan import NamespacedName
|
|
from cleveragents.infrastructure.database.models import (
|
|
ActionArgumentModel,
|
|
LifecycleActionModel,
|
|
)
|
|
|
|
|
|
def _make_argument(name: str, idx: int) -> ActionArgument:
|
|
"""Create a typed argument cycling through types by index."""
|
|
types = list(ArgumentType)
|
|
arg_type = types[idx % len(types)]
|
|
return ActionArgument(
|
|
name=name,
|
|
arg_type=arg_type,
|
|
requirement=ArgumentRequirement.REQUIRED
|
|
if idx % 2 == 0
|
|
else ArgumentRequirement.OPTIONAL,
|
|
description=f"Argument {name} for benchmarking",
|
|
default_value="default" if idx % 2 == 1 else None,
|
|
min_value=0 if arg_type == ArgumentType.INTEGER else None,
|
|
max_value=100 if arg_type == ArgumentType.INTEGER else None,
|
|
validation_pattern=r"^[a-z]+$" if arg_type == ArgumentType.STRING else None,
|
|
)
|
|
|
|
|
|
def _make_action_with_n_args(n: int) -> Action:
|
|
"""Create an action with N arguments."""
|
|
return Action(
|
|
namespaced_name=NamespacedName(
|
|
server=None, namespace="local", name=f"multi-arg-{n}"
|
|
),
|
|
description=f"Action with {n} arguments",
|
|
definition_of_done="All args validated",
|
|
strategy_actor="openai/gpt-4",
|
|
execution_actor="openai/gpt-4",
|
|
arguments=[_make_argument(f"arg_{i}", i) for i in range(n)],
|
|
)
|
|
|
|
|
|
class ArgumentModelConstructionSuite:
|
|
"""Benchmark ActionArgumentModel construction patterns."""
|
|
|
|
def setup(self) -> None:
|
|
self.args = [_make_argument(f"arg_{i}", i) for i in range(20)]
|
|
|
|
def time_construct_single_model(self) -> None:
|
|
"""Construct a single ActionArgumentModel from values."""
|
|
arg = self.args[0]
|
|
ActionArgumentModel(
|
|
action_name="local/bench-action",
|
|
name=arg.name,
|
|
arg_type=arg.arg_type.value,
|
|
requirement=arg.requirement.value,
|
|
description=arg.description,
|
|
default_value_json=json.dumps(arg.default_value)
|
|
if arg.default_value is not None
|
|
else None,
|
|
min_value=arg.min_value,
|
|
max_value=arg.max_value,
|
|
validation_pattern=arg.validation_pattern,
|
|
position=0,
|
|
)
|
|
|
|
def time_construct_20_models(self) -> None:
|
|
"""Construct 20 ActionArgumentModel instances."""
|
|
for i, arg in enumerate(self.args):
|
|
ActionArgumentModel(
|
|
action_name="local/bench-action",
|
|
name=arg.name,
|
|
arg_type=arg.arg_type.value,
|
|
requirement=arg.requirement.value,
|
|
description=arg.description,
|
|
default_value_json=json.dumps(arg.default_value)
|
|
if arg.default_value is not None
|
|
else None,
|
|
min_value=arg.min_value,
|
|
max_value=arg.max_value,
|
|
validation_pattern=arg.validation_pattern,
|
|
position=i,
|
|
)
|
|
|
|
|
|
class ArgumentRoundTripSuite:
|
|
"""Benchmark action ORM round-trip with varying argument counts."""
|
|
|
|
def setup(self) -> None:
|
|
self.action_2_args = _make_action_with_n_args(2)
|
|
self.action_10_args = _make_action_with_n_args(10)
|
|
self.action_20_args = _make_action_with_n_args(20)
|
|
|
|
def time_round_trip_2_args(self) -> None:
|
|
"""Round-trip an action with 2 arguments through ORM."""
|
|
model = LifecycleActionModel.from_domain(self.action_2_args)
|
|
model.to_domain()
|
|
|
|
def time_round_trip_10_args(self) -> None:
|
|
"""Round-trip an action with 10 arguments through ORM."""
|
|
model = LifecycleActionModel.from_domain(self.action_10_args)
|
|
model.to_domain()
|
|
|
|
def time_round_trip_20_args(self) -> None:
|
|
"""Round-trip an action with 20 arguments through ORM."""
|
|
model = LifecycleActionModel.from_domain(self.action_20_args)
|
|
model.to_domain()
|
|
|
|
|
|
class ArgumentSerializationSuite:
|
|
"""Benchmark JSON serialization of argument default values."""
|
|
|
|
def setup(self) -> None:
|
|
self.string_val = "default-string-value"
|
|
self.int_val = 42
|
|
self.float_val = 3.14159
|
|
self.bool_val = True
|
|
self.list_val = ["alpha", "beta", "gamma", "delta"]
|
|
|
|
def time_serialize_string(self) -> None:
|
|
"""Serialize a string default value to JSON."""
|
|
json.dumps(self.string_val)
|
|
|
|
def time_serialize_integer(self) -> None:
|
|
"""Serialize an integer default value to JSON."""
|
|
json.dumps(self.int_val)
|
|
|
|
def time_serialize_list(self) -> None:
|
|
"""Serialize a list default value to JSON."""
|
|
json.dumps(self.list_val)
|
|
|
|
def time_deserialize_string(self) -> None:
|
|
"""Deserialize a JSON string default value."""
|
|
json.loads('"default-string-value"')
|
|
|
|
def time_deserialize_list(self) -> None:
|
|
"""Deserialize a JSON list default value."""
|
|
json.loads('["alpha", "beta", "gamma", "delta"]')
|