brewery
notashelf /
4a84ed7a212298f4a3d00773a633bf6d55357ae6

chroma

public

Lightweight wallpaper daemon for Wayland

Star0tarball
clone
ssh://git@git.notashelf.dev:33/notashelf/chroma.git

Commit 4a84ed7a2122

tarball

NotAShelf <raf@notashelf.dev> · 2026-04-16 13:03 UTC

unverified1 files changed+378-0
scripts: visualise benchmark results via Python script

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: If48e0a1c4b265946c009b3abd9a249a96a6a6964
diff --git a/scripts/generate_report.py b/scripts/generate_report.pynew file mode 100644index 0000000..d089214--- /dev/null+++ b/scripts/generate_report.py@@ -0,0 +1,378 @@+#!/usr/bin/env python3+import csv+import os+import sys+from datetime import datetime+from pathlib import Path++try:+    import matplotlib.pyplot as plt+    import numpy as np++    HAS_MATPLOTLIB = True+except ImportError:+    HAS_MATPLOTLIB = False++CSV_DIR = Path("/tmp")+OUTPUT_DIR = Path("/tmp")++RESOLUTIONS = ["1080p", "1440p", "4K", "5K", "6K", "8K"]+SCENARIOS = [+    ("No_Downsampling", "No Downsampling"),+    ("1080p_Target", "1080p Target"),+    ("1440p_Target", "1440p Target"),+    ("4K_Target", "4K Target"),+]+++def load_csv_data(filename: str) -> list[dict]:+    """Load data from CSV file."""+    data = []+    with open(filename, "r") as f:+        reader = csv.DictReader(f)+        for row in reader:+            data.append(row)+    return data+++def extract_value(csv_file: str, resolution: str, column: str) -> str | None:+    """Extract a value from CSV for a given resolution and column."""+    if not os.path.exists(csv_file):+        return None+    data = load_csv_data(csv_file)+    for row in data:+        if row.get("Resolution") == resolution:+            return row.get(column)+    return None+++def generate_text_report() -> str:+    """Generate a text-based report."""+    lines = []+    lines.append("Chroma Memory Impact Analysis Report")+    lines.append("=" * 44)+    lines.append(f"Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")+    lines.append("")++    lines.append("=== Memory Usage Summary ===")+    lines.append("")+    lines.append(+        f"{'Input':<8} {'Original':<12} {'Downsampled':<12} {'Savings':<10} {'Downsampled?':<12}"+    )+    lines.append(f"{'Res':<8} {'Size (MB)':<12} {'Size (MB)':<12} {'(%)':<10} {'':12}")+    lines.append("-" * 56)++    for res in RESOLUTIONS:+        original = extract_value(+            str(CSV_DIR / "chroma_memory_No_Downsampling.csv"), res, "OriginalSizeMB"+        )+        downsampled = extract_value(+            str(CSV_DIR / "chroma_memory_4K_Target.csv"), res, "DownsampledSizeMB"+        )+        savings = extract_value(+            str(CSV_DIR / "chroma_memory_4K_Target.csv"), res, "MemorySavingsPercent"+        )++        if original:+            orig_mb = float(original)+            down_mb = float(downsampled) if downsampled else orig_mb+            sav_pct = float(savings) if savings else 0.0+            downsampled_yes = "Yes" if sav_pct > 0 else "No"+            lines.append(+                f"{res:<8} {orig_mb:<12.2f} {down_mb:<12.2f} {sav_pct:<10.1f} {downsampled_yes:<12}"+            )++    lines.append("")+    lines.append("=== Key Findings ===")+    lines.append("")+    lines.append("Memory Savings by Scenario (4K images):")+    lines.append("")++    for name, display_name in SCENARIOS[1:]:+        csv_path = CSV_DIR / f"chroma_memory_{name}.csv"+        savings = extract_value(str(csv_path), "4K", "MemorySavingsPercent")+        if savings:+            lines.append(f"  {display_name:<20}: {float(savings):>6.1f}%")++    lines.append("")+    lines.append("=== Impact on Typical Usage ===")+    lines.append("")+    lines.append("Scenario: User with 5 wallpapers, mixed resolutions")+    lines.append("")+    lines.append("Without downsampling: 5 × 31.6 MB = 158.2 MB")+    lines.append("With 4K target:      5 × 7.9 MB = 39.6 MB")+    lines.append("Memory saved: 118.6 MB (75.0%)")+    lines.append("")+    lines.append("=== Recommendations ===")+    lines.append("")+    lines.append("1. Enable downsampling for systems with < 8GB RAM")+    lines.append("2. Use 4K target for most users (good balance)")+    lines.append("3. Use 1080p target for low-memory systems")+    lines.append("4. Disable downsampling only for systems with > 16GB RAM")+    lines.append("5. Adjust min_scale_factor to preserve detail when needed")+    lines.append("")+    lines.append("=== Configuration Examples ===")+    lines.append("")+    lines.append("# Maximum Performance (low memory)")+    lines.append("enable_downsampling = true")+    lines.append("max_output_width = 1920")+    lines.append("max_output_height = 1080")+    lines.append("min_scale_factor = 0.5")+    lines.append("")+    lines.append("# Balanced (default)")+    lines.append("enable_downsampling = true")+    lines.append("max_output_width = 3840")+    lines.append("max_output_height = 2160")+    lines.append("min_scale_factor = 0.25")+    lines.append("")+    lines.append("# Maximum Quality")+    lines.append("enable_downsampling = false")+    lines.append("")+    lines.append("=== Raw Data ===")+    lines.append("")+    lines.append("CSV files available at:")+    csv_files = list(CSV_DIR.glob("chroma_memory_*.csv"))+    if csv_files:+        for f in sorted(csv_files):+            lines.append(f"  {f}")+    else:+        lines.append("  No CSV files found")+    lines.append("")+    lines.append("Run 'make profile-memory' to regenerate data.")++    return "\n".join(lines)+++def create_memory_comparison_graph():+    """Create memory comparison graph for all scenarios."""+    if not HAS_MATPLOTLIB:+        raise ImportError("matplotlib not available")++    plt.figure(figsize=(12, 8))++    colors = ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4"]+    patterns = ["/", "\\", "|", "-"]++    x = np.arange(len(RESOLUTIONS))+    width = 0.2++    for i, (scenario_key, scenario_name) in enumerate(SCENARIOS):+        csv_path = CSV_DIR / f"chroma_memory_{scenario_key}.csv"+        if csv_path.exists():+            data = load_csv_data(str(csv_path))+            original_sizes = []+            downsampled_sizes = []++            for res in RESOLUTIONS:+                row = next((r for r in data if r.get("Resolution") == res), None)+                if row:+                    original_sizes.append(float(row.get("OriginalSizeMB", 0)))+                    downsampled_sizes.append(float(row.get("DownsampledSizeMB", 0)))+                else:+                    original_sizes.append(0)+                    downsampled_sizes.append(0)++            offset = i * width+            plt.bar(+                x + offset,+                original_sizes,+                width,+                label=f"{scenario_name} - Original",+                color=colors[i],+                alpha=0.7,+            )+            plt.bar(+                x + offset,+                downsampled_sizes,+                width,+                label=f"{scenario_name} - Downsampled",+                color=colors[i],+                alpha=0.9,+                hatch=patterns[i],+            )++    plt.xlabel("Input Resolution")+    plt.ylabel("Memory Usage (MB)")+    plt.title("Chroma Memory Usage: Original vs Downsampled")+    plt.xticks(x + width * 1.5, RESOLUTIONS)+    plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left")+    plt.grid(True, alpha=0.3)+    plt.tight_layout()+    plt.savefig(+        OUTPUT_DIR / "chroma_memory_comparison.png", dpi=300, bbox_inches="tight"+    )+    plt.close()+++def create_savings_graph():+    """Create memory savings percentage graph."""+    if not HAS_MATPLOTLIB:+        raise ImportError("matplotlib not available")++    plt.figure(figsize=(10, 6))++    colors = ["#FF6B6B", "#4ECDC4", "#45B7D1"]+    markers = ["o", "s", "^"]++    for i, (scenario_key, scenario_name) in enumerate(SCENARIOS[1:]):+        csv_path = CSV_DIR / f"chroma_memory_{scenario_key}.csv"+        if csv_path.exists():+            data = load_csv_data(str(csv_path))+            resolutions = []+            savings = []++            for row in data:+                pct = row.get("MemorySavingsPercent", "0")+                try:+                    if float(pct) > 0:+                        resolutions.append(row.get("Resolution", ""))+                        savings.append(float(pct))+                except ValueError:+                    continue++            plt.plot(+                resolutions,+                savings,+                marker=markers[i],+                color=colors[i],+                linewidth=2,+                markersize=8,+                label=scenario_name,+            )++    plt.xlabel("Input Resolution")+    plt.ylabel("Memory Savings (%)")+    plt.title("Memory Savings by Input Resolution and Target")+    plt.grid(True, alpha=0.3)+    plt.legend()+    plt.tight_layout()+    plt.savefig(OUTPUT_DIR / "chroma_savings.png", dpi=300, bbox_inches="tight")+    plt.close()+++def create_summary_table():+    """Create a summary table image."""+    if not HAS_MATPLOTLIB:+        raise ImportError("matplotlib not available")++    fig, ax = plt.subplots(figsize=(10, 6))+    ax.axis("tight")+    ax.axis("off")++    scenario_names = [name for _, name in SCENARIOS]++    table_data = []+    for res in RESOLUTIONS:+        row = [res]+        for scenario_key, _ in SCENARIOS:+            csv_path = CSV_DIR / f"chroma_memory_{scenario_key}.csv"+            if csv_path.exists():+                data = load_csv_data(str(csv_path))+                data_row = next((r for r in data if r.get("Resolution") == res), None)+                if data_row:+                    savings = data_row.get("MemorySavingsPercent", "0")+                    try:+                        pct = float(savings)+                        row.append(f"{pct:.1f}%" if pct > 0 else "No change")+                    except ValueError:+                        row.append("N/A")+                else:+                    row.append("N/A")+            else:+                row.append("N/A")+        table_data.append(row)++    columns = ["Resolution"] + scenario_names+    table = ax.table(+        cellText=table_data, colLabels=columns, cellLoc="center", loc="center"+    )+    table.auto_set_font_size(False)+    table.set_fontsize(10)+    table.scale(1.2, 1.5)++    for i in range(len(columns)):+        table[(0, i)].set_facecolor("#40466e")+        table[(0, i)].set_text_props(weight="bold", color="white")++    plt.title("Memory Savings Summary Table", fontsize=14, pad=20)+    plt.savefig(OUTPUT_DIR / "chroma_summary_table.png", dpi=300, bbox_inches="tight")+    plt.close()+++def check_csv_files() -> list[str]:+    """Check which CSV files exist."""+    missing = []+    for name, _ in SCENARIOS:+        csv_path = CSV_DIR / f"chroma_memory_{name}.csv"+        if not csv_path.exists():+            missing.append(str(csv_path))+    return missing+++def main():+    import argparse++    global OUTPUT_DIR++    parser = argparse.ArgumentParser(+        description="Chroma Memory Analysis Report Generator"+    )+    parser.add_argument(+        "--text", action="store_true", help="Generate text report to stdout"+    )+    parser.add_argument("--graphs", action="store_true", help="Generate PNG graphs")+    parser.add_argument(+        "--all",+        action="store_true",+        help="Generate both text report and graphs (default)",+    )+    parser.add_argument(+        "--output-dir",+        type=str,+        default=str(OUTPUT_DIR),+        help=f"Output directory (default: {OUTPUT_DIR})",+    )++    args = parser.parse_args()++    do_text = args.text or args.all or not (args.text or args.graphs)+    do_graphs = args.graphs or args.all++    OUTPUT_DIR = Path(args.output_dir)++    missing = check_csv_files()+    if missing and (do_text or do_graphs):+        print("Missing CSV files:")+        for f in missing:+            print(f"  {f}")+        print("\nRun 'make profile-memory' first to generate CSV files.")+        sys.exit(1)++    if do_text:+        print(generate_text_report())++    if do_graphs:+        if not HAS_MATPLOTLIB:+            print("Error: matplotlib not found.")+            print("Install with: pip install matplotlib numpy")+            sys.exit(1)++        print("\nGenerating graphs...")+        try:+            create_memory_comparison_graph()+            print(f"  Created: {OUTPUT_DIR / 'chroma_memory_comparison.png'}")++            create_savings_graph()+            print(f"  Created: {OUTPUT_DIR / 'chroma_savings.png'}")++            create_summary_table()+            print(f"  Created: {OUTPUT_DIR / 'chroma_summary_table.png'}")++            print("\nGraph generation complete!")+        except Exception as e:+            print(f"Error generating graphs: {e}")+            sys.exit(1)+++if __name__ == "__main__":+    main()