diff --git a/metrics/handlers.py b/metrics/handlers.py index b135652..996257c 100644 --- a/metrics/handlers.py +++ b/metrics/handlers.py @@ -1,5 +1,6 @@ import re from datetime import datetime +from importlib.metadata import version from pathlib import Path from rich.console import Console @@ -14,6 +15,7 @@ from .benchmarks.entity import benchmarks as registered_benchmarks from .services.report_generator import ReportGenerator from .services.system_info_reader import get_system_info from .services.diagram_generator import DiagramGenerator +from .services.release_generator import ReleaseGenerator console = Console() router = Router(title="Metrics commands:", disable_redirect_stdout=True) @@ -106,7 +108,28 @@ def run_type_handler(response: Response) -> None: @router.command(Command("release-generate", description="Generate release report")) def release_generate_handler(_: Response) -> None: - console.print("[yellow]Release report generation not implemented yet[/yellow]") + lib_version = version("argenta") + + console.print(f"[cyan]Generating release report for version:[/cyan] [bold]{lib_version}[/bold]") + console.print("[dim]Running benchmarks (1000 iterations, GC disabled)...[/dim]\n") + + type_grouped_benchmarks: list[BenchmarkGroupResult] = registered_benchmarks.run_benchmarks_grouped_by_type( + iterations=1000, + is_gc_disabled=True + ) + + release_generator = ReleaseGenerator(lib_version) + output_dir = release_generator.generate_release(type_grouped_benchmarks) + + console.print(f"[green]✓[/green] Benchmarks completed. Generating release report...\n") + + for benchmark_group in type_grouped_benchmarks: + console.print(f"[cyan]Generated for:[/cyan] [bold]{benchmark_group.type_}[/bold]") + console.print(f" [green]✓[/green] {benchmark_group.type_}_comparison.png") + console.print(f" [green]✓[/green] {benchmark_group.type_}.json\n") + + console.print(f"[bold green]✓ Release report generated successfully[/bold green]") + console.print(f"[cyan]Output directory:[/cyan] [bold]{output_dir}[/bold]") @router.command( diff --git a/metrics/reports/releases/1.1.2/finds_appropriate_handler/finds_appropriate_handler.json b/metrics/reports/releases/1.1.2/finds_appropriate_handler/finds_appropriate_handler.json new file mode 100644 index 0000000..8a7ab02 --- /dev/null +++ b/metrics/reports/releases/1.1.2/finds_appropriate_handler/finds_appropriate_handler.json @@ -0,0 +1,42 @@ +{ + "type": "finds_appropriate_handler", + "iterations": 1000, + "gc_disabled": true, + "benchmarks": [ + { + "name": "benchmark_simple_command", + "description": "Simple command (no flags)", + "avg_time": 0.0354, + "median_time": 0.0345, + "std_dev": 0.0056 + }, + { + "name": "benchmark_command_with_flags", + "description": "Command with flags (3 flags)", + "avg_time": 0.0544, + "median_time": 0.0536, + "std_dev": 0.009 + }, + { + "name": "benchmark_many_commands", + "description": "Many commands (50 commands)", + "avg_time": 1.009, + "median_time": 1.0022, + "std_dev": 0.039 + }, + { + "name": "benchmark_command_with_many_flags", + "description": "Command with many flags (20 flags)", + "avg_time": 0.131, + "median_time": 0.1298, + "std_dev": 0.0054 + }, + { + "name": "benchmark_extreme_router", + "description": "Extreme (100 commands, 10 flags each)", + "avg_time": 3.1818, + "median_time": 3.1619, + "std_dev": 0.1673 + } + ] +} \ No newline at end of file diff --git a/metrics/reports/releases/1.1.2/finds_appropriate_handler/finds_appropriate_handler_comparison.png b/metrics/reports/releases/1.1.2/finds_appropriate_handler/finds_appropriate_handler_comparison.png new file mode 100644 index 0000000..404d202 Binary files /dev/null and b/metrics/reports/releases/1.1.2/finds_appropriate_handler/finds_appropriate_handler_comparison.png differ diff --git a/metrics/reports/releases/1.1.2/flag_validation/flag_validation.json b/metrics/reports/releases/1.1.2/flag_validation/flag_validation.json new file mode 100644 index 0000000..b7174ae --- /dev/null +++ b/metrics/reports/releases/1.1.2/flag_validation/flag_validation.json @@ -0,0 +1,70 @@ +{ + "type": "flag_validation", + "iterations": 1000, + "gc_disabled": true, + "benchmarks": [ + { + "name": "benchmark_validate_all_single_flag", + "description": "Single flag with PossibleValues.ALL", + "avg_time": 0.0009, + "median_time": 0.0009, + "std_dev": 0.0003 + }, + { + "name": "benchmark_validate_neither_single_flag", + "description": "Single flag with PossibleValues.NEITHER", + "avg_time": 0.0008, + "median_time": 0.0008, + "std_dev": 0.0002 + }, + { + "name": "benchmark_validate_list_small", + "description": "List validation (5 possible values)", + "avg_time": 0.001, + "median_time": 0.001, + "std_dev": 0.0003 + }, + { + "name": "benchmark_validate_list_large", + "description": "List validation (50 possible values)", + "avg_time": 0.0079, + "median_time": 0.0078, + "std_dev": 0.0007 + }, + { + "name": "benchmark_validate_regex_simple", + "description": "Regex validation (simple pattern)", + "avg_time": 0.0019, + "median_time": 0.0016, + "std_dev": 0.0073 + }, + { + "name": "benchmark_validate_regex_complex", + "description": "Regex validation (complex pattern)", + "avg_time": 0.0018, + "median_time": 0.0017, + "std_dev": 0.0051 + }, + { + "name": "benchmark_validate_multiple_flags_10", + "description": "Multiple flags validation (10 flags)", + "avg_time": 0.0147, + "median_time": 0.0146, + "std_dev": 0.0013 + }, + { + "name": "benchmark_validate_multiple_flags_50", + "description": "Multiple flags validation (50 flags)", + "avg_time": 0.0669, + "median_time": 0.0661, + "std_dev": 0.0025 + }, + { + "name": "benchmark_validate_extreme_100_flags", + "description": "Extreme (100 flags with regex validation)", + "avg_time": 0.1626, + "median_time": 0.1609, + "std_dev": 0.007 + } + ] +} \ No newline at end of file diff --git a/metrics/reports/releases/1.1.2/flag_validation/flag_validation_comparison.png b/metrics/reports/releases/1.1.2/flag_validation/flag_validation_comparison.png new file mode 100644 index 0000000..6008aee Binary files /dev/null and b/metrics/reports/releases/1.1.2/flag_validation/flag_validation_comparison.png differ diff --git a/metrics/reports/releases/1.1.2/input_command_parse/input_command_parse.json b/metrics/reports/releases/1.1.2/input_command_parse/input_command_parse.json new file mode 100644 index 0000000..6c03ccc --- /dev/null +++ b/metrics/reports/releases/1.1.2/input_command_parse/input_command_parse.json @@ -0,0 +1,56 @@ +{ + "type": "input_command_parse", + "iterations": 1000, + "gc_disabled": true, + "benchmarks": [ + { + "name": "benchmark_parse_simple_command", + "description": "Simple command (no flags)", + "avg_time": 0.0099, + "median_time": 0.0098, + "std_dev": 0.0014 + }, + { + "name": "benchmark_command_with_few_flags", + "description": "Command with few flags (3 flags)", + "avg_time": 0.0214, + "median_time": 0.0211, + "std_dev": 0.003 + }, + { + "name": "benchmark_command_with_flags_and_values", + "description": "Command with flags and values (5 flags)", + "avg_time": 0.0598, + "median_time": 0.0591, + "std_dev": 0.0041 + }, + { + "name": "benchmark_command_with_mixed_prefixes", + "description": "Command with mixed prefixes (-, --, ---)", + "avg_time": 0.0545, + "median_time": 0.0541, + "std_dev": 0.0024 + }, + { + "name": "benchmark_command_with_long_values", + "description": "Command with long values (10 flags)", + "avg_time": 0.2114, + "median_time": 0.2103, + "std_dev": 0.0068 + }, + { + "name": "benchmark_command_with_quoted_values", + "description": "Command with quoted values (5 flags)", + "avg_time": 0.0489, + "median_time": 0.0488, + "std_dev": 0.0019 + }, + { + "name": "benchmark_extreme_many_flags", + "description": "Extreme (50 flags with values)", + "avg_time": 0.8057, + "median_time": 0.7997, + "std_dev": 0.024 + } + ] +} \ No newline at end of file diff --git a/metrics/reports/releases/1.1.2/input_command_parse/input_command_parse_comparison.png b/metrics/reports/releases/1.1.2/input_command_parse/input_command_parse_comparison.png new file mode 100644 index 0000000..e55a824 Binary files /dev/null and b/metrics/reports/releases/1.1.2/input_command_parse/input_command_parse_comparison.png differ diff --git a/metrics/reports/releases/1.1.2/most_similar_command/most_similar_command.json b/metrics/reports/releases/1.1.2/most_similar_command/most_similar_command.json new file mode 100644 index 0000000..24b0ffc --- /dev/null +++ b/metrics/reports/releases/1.1.2/most_similar_command/most_similar_command.json @@ -0,0 +1,42 @@ +{ + "type": "most_similar_command", + "iterations": 1000, + "gc_disabled": true, + "benchmarks": [ + { + "name": "benchmark_few_commands", + "description": "Few commands (10 commands, no match)", + "avg_time": 0.207, + "median_time": 0.2051, + "std_dev": 0.01 + }, + { + "name": "benchmark_many_commands_most_similar", + "description": "Many commands (50 commands, no match)", + "avg_time": 1.0116, + "median_time": 1.0074, + "std_dev": 0.0306 + }, + { + "name": "benchmark_many_aliases", + "description": "Many aliases (20 commands, 10 aliases each)", + "avg_time": 0.6857, + "median_time": 0.6672, + "std_dev": 0.0811 + }, + { + "name": "benchmark_partial_match", + "description": "Partial match (50 commands, prefix match)", + "avg_time": 1.0218, + "median_time": 1.0192, + "std_dev": 0.0232 + }, + { + "name": "benchmark_extreme_commands", + "description": "Extreme (100 commands, 20 aliases each)", + "avg_time": 6.4118, + "median_time": 6.4225, + "std_dev": 0.2008 + } + ] +} \ No newline at end of file diff --git a/metrics/reports/releases/1.1.2/most_similar_command/most_similar_command_comparison.png b/metrics/reports/releases/1.1.2/most_similar_command/most_similar_command_comparison.png new file mode 100644 index 0000000..65e80bf Binary files /dev/null and b/metrics/reports/releases/1.1.2/most_similar_command/most_similar_command_comparison.png differ diff --git a/metrics/reports/releases/1.1.2/pre_cycle_setup/pre_cycle_setup.json b/metrics/reports/releases/1.1.2/pre_cycle_setup/pre_cycle_setup.json new file mode 100644 index 0000000..7d50f26 --- /dev/null +++ b/metrics/reports/releases/1.1.2/pre_cycle_setup/pre_cycle_setup.json @@ -0,0 +1,42 @@ +{ + "type": "pre_cycle_setup", + "iterations": 1000, + "gc_disabled": true, + "benchmarks": [ + { + "name": "benchmark_no_aliases", + "description": "With no aliases", + "avg_time": 8.9994, + "median_time": 8.9559, + "std_dev": 0.242 + }, + { + "name": "benchmark_few_aliases", + "description": "With few aliases (6 total)", + "avg_time": 8.957, + "median_time": 8.936, + "std_dev": 0.2296 + }, + { + "name": "benchmark_with_many_aliases", + "description": "With many aliases (15 total)", + "avg_time": 8.9953, + "median_time": 8.9721, + "std_dev": 0.2243 + }, + { + "name": "benchmark_very_many_aliases", + "description": "With very many aliases (60 total)", + "avg_time": 9.0155, + "median_time": 8.9992, + "std_dev": 0.2433 + }, + { + "name": "benchmark_extreme_aliases", + "description": "With extreme aliases (300 total)", + "avg_time": 9.2977, + "median_time": 9.255, + "std_dev": 0.3884 + } + ] +} \ No newline at end of file diff --git a/metrics/reports/releases/1.1.2/pre_cycle_setup/pre_cycle_setup_comparison.png b/metrics/reports/releases/1.1.2/pre_cycle_setup/pre_cycle_setup_comparison.png new file mode 100644 index 0000000..29386c2 Binary files /dev/null and b/metrics/reports/releases/1.1.2/pre_cycle_setup/pre_cycle_setup_comparison.png differ diff --git a/metrics/reports/releases/1.1.2/validate_routers_for_collisions/validate_routers_for_collisions.json b/metrics/reports/releases/1.1.2/validate_routers_for_collisions/validate_routers_for_collisions.json new file mode 100644 index 0000000..5ff7ecc --- /dev/null +++ b/metrics/reports/releases/1.1.2/validate_routers_for_collisions/validate_routers_for_collisions.json @@ -0,0 +1,42 @@ +{ + "type": "validate_routers_for_collisions", + "iterations": 1000, + "gc_disabled": true, + "benchmarks": [ + { + "name": "benchmark_few_routers", + "description": "With few routers (3 routers, 1 command each)", + "avg_time": 0.0912, + "median_time": 0.0901, + "std_dev": 0.0051 + }, + { + "name": "benchmark_many_routers", + "description": "With many routers (10 routers, 1 command each)", + "avg_time": 0.2433, + "median_time": 0.2382, + "std_dev": 0.0292 + }, + { + "name": "benchmark_many_commands_per_router", + "description": "With many commands per router (3 routers, 10 commands each)", + "avg_time": 0.6157, + "median_time": 0.6132, + "std_dev": 0.0199 + }, + { + "name": "benchmark_many_aliases_per_command", + "description": "With many aliases (3 routers, 5 commands, 10 aliases each)", + "avg_time": 0.516, + "median_time": 0.5082, + "std_dev": 0.0403 + }, + { + "name": "benchmark_extreme_routers", + "description": "Extreme (20 routers, 10 commands, 20 aliases each)", + "avg_time": 10.8103, + "median_time": 10.7871, + "std_dev": 0.2788 + } + ] +} \ No newline at end of file diff --git a/metrics/reports/releases/1.1.2/validate_routers_for_collisions/validate_routers_for_collisions_comparison.png b/metrics/reports/releases/1.1.2/validate_routers_for_collisions/validate_routers_for_collisions_comparison.png new file mode 100644 index 0000000..9f93ee0 Binary files /dev/null and b/metrics/reports/releases/1.1.2/validate_routers_for_collisions/validate_routers_for_collisions_comparison.png differ diff --git a/metrics/services/__init__.py b/metrics/services/__init__.py index 9095bae..fd0f6e0 100644 --- a/metrics/services/__init__.py +++ b/metrics/services/__init__.py @@ -1,5 +1,6 @@ from .diagram_generator import DiagramGenerator from .report_generator import ReportGenerator from .system_info_reader import get_system_info +from .release_generator import ReleaseGenerator -__all__ = ["DiagramGenerator", "ReportGenerator", "get_system_info"] +__all__ = ["DiagramGenerator", "ReportGenerator", "get_system_info", "ReleaseGenerator"] diff --git a/metrics/services/release_generator.py b/metrics/services/release_generator.py new file mode 100644 index 0000000..e4c0079 --- /dev/null +++ b/metrics/services/release_generator.py @@ -0,0 +1,49 @@ +__all__ = ["ReleaseGenerator"] + +import json +import shutil +from pathlib import Path + +from ..benchmarks.core.models import BenchmarkGroupResult +from .diagram_generator import DiagramGenerator + + +class ReleaseGenerator: + def __init__(self, lib_version: str) -> None: + self.lib_version = lib_version + self.output_dir = Path("metrics/reports/releases") / lib_version + + def generate_release(self, benchmark_groups: list[BenchmarkGroupResult]) -> Path: + if self.output_dir.exists(): + shutil.rmtree(self.output_dir) + + self.output_dir.mkdir(parents=True, exist_ok=True) + + for benchmark_group in benchmark_groups: + type_dir = self.output_dir / benchmark_group.type_ + type_dir.mkdir(exist_ok=True) + + diagram_generator = DiagramGenerator(type_dir) + diagram_generator.generate_comparison_diagram(benchmark_group) + + json_data = { + "type": benchmark_group.type_, + "iterations": benchmark_group.iterations, + "gc_disabled": benchmark_group.is_gc_disabled, + "benchmarks": [ + { + "name": br.name, + "description": br.description, + "avg_time": br.avg_time, + "median_time": br.median_time, + "std_dev": br.std_dev + } + for br in benchmark_group.benchmark_results + ] + } + + json_path = type_dir / f"{benchmark_group.type_}.json" + with open(json_path, 'w', encoding='utf-8') as f: + json.dump(json_data, f, indent=2, ensure_ascii=False) + + return self.output_dir