mirror of
https://github.com/koloideal/Argenta.git
synced 2026-06-10 10:05:28 +03:00
diagrams
This commit is contained in:
+53
-4
@@ -1,3 +1,7 @@
|
||||
import re
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
from rich.console import Console
|
||||
|
||||
from argenta.command import Flag, PossibleValues, Flags
|
||||
@@ -9,9 +13,12 @@ from .benchmarks.core.models import BenchmarkGroupResult
|
||||
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
|
||||
|
||||
console = Console()
|
||||
router = Router(title="Metrics commands:")
|
||||
router = Router(title="Metrics commands:", disable_redirect_stdout=True)
|
||||
|
||||
POSITIVE_INTEGER_PATTERN = re.compile(r"^[1-9]\d*$")
|
||||
|
||||
|
||||
@router.command(
|
||||
@@ -102,6 +109,48 @@ def release_generate_handler(_: Response) -> None:
|
||||
console.print("[yellow]Release report generation not implemented yet[/yellow]")
|
||||
|
||||
|
||||
@router.command(Command("diagrams-generate", description="Generate diagrams"))
|
||||
def diagrams_generate_handler(_: Response) -> None:
|
||||
console.print("[yellow]Diagrams generation not implemented yet[/yellow]")
|
||||
@router.command(
|
||||
Command(
|
||||
"diagrams-generate",
|
||||
description="Generate diagrams for all benchmarks",
|
||||
flags=Flags([
|
||||
Flag('without-gc', possible_values=PossibleValues.NEITHER),
|
||||
Flag('iterations', possible_values=POSITIVE_INTEGER_PATTERN)
|
||||
])
|
||||
)
|
||||
)
|
||||
def diagrams_generate_handler(response: Response) -> None:
|
||||
iterations = 100
|
||||
iterations_flag = response.input_flags.get_flag_by_name("iterations", with_status=ValidationStatus.VALID)
|
||||
if iterations_flag:
|
||||
iterations = int(iterations_flag.input_value)
|
||||
|
||||
is_gc_disabled = bool(response.input_flags.get_flag_by_name("without-gc", with_status=ValidationStatus.VALID))
|
||||
|
||||
console.print("[cyan]Running all benchmarks...[/cyan]")
|
||||
console.print(f"[dim]Iterations: {iterations}, GC Disabled: {is_gc_disabled}[/dim]\n")
|
||||
|
||||
type_grouped_benchmarks: list[BenchmarkGroupResult] = registered_benchmarks.run_benchmarks_grouped_by_type(
|
||||
iterations=iterations,
|
||||
is_gc_disabled=is_gc_disabled
|
||||
)
|
||||
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
||||
output_dir = Path("metrics/reports/diagrams") / timestamp
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
diagram_generator = DiagramGenerator(output_dir)
|
||||
|
||||
console.print(f"[green]✓[/green] Benchmarks completed. Generating diagrams...\n")
|
||||
|
||||
generated_count = 0
|
||||
|
||||
for benchmark_group in type_grouped_benchmarks:
|
||||
console.print(f"[cyan]Generating diagram for:[/cyan] [bold]{benchmark_group.type_}[/bold]")
|
||||
|
||||
comparison_path = diagram_generator.generate_comparison_diagram(benchmark_group)
|
||||
generated_count += 1
|
||||
console.print(f" [green]✓[/green] {comparison_path.name}\n")
|
||||
|
||||
console.print(f"[bold green]✓ Successfully generated {generated_count} diagrams[/bold green]")
|
||||
console.print(f"[cyan]Output directory:[/cyan] [bold]{output_dir}[/bold]")
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
from .diagram_generator import DiagramGenerator
|
||||
from .report_generator import ReportGenerator
|
||||
from .system_info_reader import get_system_info
|
||||
|
||||
__all__ = ["DiagramGenerator", "ReportGenerator", "get_system_info"]
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
__all__ = ["DiagramGenerator"]
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import matplotlib
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
from ..benchmarks.core.models import BenchmarkGroupResult
|
||||
|
||||
|
||||
class DiagramGenerator:
|
||||
def __init__(self, output_dir: Path | str) -> None:
|
||||
self.output_dir = output_dir
|
||||
matplotlib.use('Agg')
|
||||
plt.style.use('seaborn-v0_8-whitegrid')
|
||||
|
||||
def generate_comparison_diagram(self, benchmark_group: BenchmarkGroupResult) -> Path:
|
||||
results = benchmark_group.benchmark_results
|
||||
sorted_results = sorted(results, key=lambda br: br.avg_time)
|
||||
|
||||
descriptions = [br.description for br in sorted_results]
|
||||
avg_times = [br.avg_time for br in sorted_results]
|
||||
median_times = [br.median_time for br in sorted_results]
|
||||
std_devs = [br.std_dev for br in sorted_results]
|
||||
|
||||
max_value = max(max(avg_times), max(median_times), max(std_devs))
|
||||
y_limit = max_value / 0.85
|
||||
|
||||
x = np.arange(len(descriptions))
|
||||
width = 0.25
|
||||
|
||||
fig, ax = plt.subplots(figsize=(16, 8))
|
||||
fig.patch.set_facecolor('white')
|
||||
|
||||
bars1 = ax.bar(x - width, std_devs, width, label='Std Deviation',
|
||||
color='#2ecc71', alpha=0.9, edgecolor='#27ae60', linewidth=1.5)
|
||||
bars2 = ax.bar(x, avg_times, width, label='Average Time',
|
||||
color='#3498db', alpha=0.9, edgecolor='#2980b9', linewidth=1.5)
|
||||
bars3 = ax.bar(x + width, median_times, width, label='Median Time',
|
||||
color='#e74c3c', alpha=0.9, edgecolor='#c0392b', linewidth=1.5)
|
||||
|
||||
for bars in [bars1, bars2, bars3]:
|
||||
for bar in bars:
|
||||
height = bar.get_height()
|
||||
ax.text(bar.get_x() + bar.get_width() / 2., height,
|
||||
f'{height:.3f}',
|
||||
ha='center', va='bottom', fontsize=9, fontweight='bold')
|
||||
|
||||
ax.set_ylabel('Time (ms)', fontsize=14, fontweight='bold', labelpad=10)
|
||||
|
||||
title_text = f'{benchmark_group.type_.replace("_", " ").title()}'
|
||||
metadata_text = f'Iterations: {benchmark_group.iterations} | GC: {"Disabled" if benchmark_group.is_gc_disabled else "Enabled"}'
|
||||
|
||||
ax.text(0.5, 1.08, title_text, transform=ax.transAxes,
|
||||
fontsize=18, fontweight='bold', ha='center', color='#2c3e50')
|
||||
ax.text(0.5, 1.03, metadata_text, transform=ax.transAxes,
|
||||
fontsize=12, ha='center', color='#7f8c8d', style='italic')
|
||||
|
||||
ax.set_xticks(x)
|
||||
ax.set_xticklabels([])
|
||||
|
||||
for i, (pos, desc) in enumerate(zip(x, descriptions)):
|
||||
bar_x = pos - width - width / 2
|
||||
ax.text(bar_x, y_limit * 0.02, desc,
|
||||
rotation=90, va='bottom', ha='right', fontsize=10,
|
||||
color='#2c3e50')
|
||||
|
||||
ax.set_ylim(0, y_limit)
|
||||
|
||||
legend = ax.legend(loc='upper left', fontsize=12, framealpha=0.95,
|
||||
edgecolor='#34495e', fancybox=True, shadow=True)
|
||||
legend.get_frame().set_facecolor('#ecf0f1')
|
||||
|
||||
ax.grid(axis='y', alpha=0.4, linestyle='--', linewidth=0.8)
|
||||
ax.set_axisbelow(True)
|
||||
|
||||
ax.spines['top'].set_visible(False)
|
||||
ax.spines['right'].set_visible(False)
|
||||
ax.spines['left'].set_color('#7f8c8d')
|
||||
ax.spines['bottom'].set_color('#7f8c8d')
|
||||
|
||||
plt.tight_layout()
|
||||
|
||||
filename = f"{benchmark_group.type_}_comparison.png"
|
||||
output_path = self.output_dir / filename
|
||||
plt.savefig(output_path, dpi=200, bbox_inches='tight', facecolor='white')
|
||||
plt.close(fig)
|
||||
|
||||
return output_path
|
||||
Reference in New Issue
Block a user