notashelf /
4a84ed7a212298f4a3d00773a633bf6d55357ae6
chroma
publicLightweight wallpaper daemon for Wayland
clone
ssh://git@git.notashelf.dev:33/notashelf/chroma.gitCommit 4a84ed7a2122
tarballunverified1 files changed+378-0
@@ -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()