From 824f538efafaa04efff0e8a72197651b0d62ce3d Mon Sep 17 00:00:00 2001 From: Ein Anderssono Date: Thu, 23 Apr 2026 14:42:17 +0200 Subject: [PATCH] Add visualizations to all reports - Created performance charts for all decimal levels (1, 2, 5, 10, 100, 1000, 2000) - Added 4 charts per report: execution time, memory usage, IPC efficiency, and time vs memory trade-off - Updated all reports to include visualizations - Charts show top 20 languages for each metric - Color-coded by language type (Compiled=green, JIT=blue, Interpreted=red) --- generate_reports.py | 4 +- generate_visualizations.py | 135 +++++++++++++++++++++++++++++++++++++ reports/1000_decimals.md | 4 ++ reports/1000_decimals.png | Bin 0 -> 220609 bytes reports/100_decimals.md | 4 ++ reports/100_decimals.png | Bin 0 -> 219901 bytes reports/10_decimals.md | 4 ++ reports/10_decimals.png | Bin 0 -> 219354 bytes reports/1_decimals.md | 4 ++ reports/1_decimals.png | Bin 0 -> 217993 bytes reports/2000_decimals.md | 4 ++ reports/2000_decimals.png | Bin 0 -> 220812 bytes reports/2_decimals.md | 4 ++ reports/2_decimals.png | Bin 0 -> 218675 bytes reports/5_decimals.md | 4 ++ reports/5_decimals.png | Bin 0 -> 219158 bytes 16 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 generate_visualizations.py create mode 100644 reports/1000_decimals.png create mode 100644 reports/100_decimals.png create mode 100644 reports/10_decimals.png create mode 100644 reports/1_decimals.png create mode 100644 reports/2000_decimals.png create mode 100644 reports/2_decimals.png create mode 100644 reports/5_decimals.png diff --git a/generate_reports.py b/generate_reports.py index 6792a9f..2162a19 100644 --- a/generate_reports.py +++ b/generate_reports.py @@ -61,7 +61,9 @@ for decimals in [1, 2, 5, 10, 100, 1000, 2000]: f.write(f"| {rank} | {lang} | {time_ms} | {memory} | {instructions} | {cycles} | {ipc:.2f} | {lang_type} |\n") # Footer - f.write(f"\n## Detailed Results\n\n") + f.write(f"\n## Visualizations\n\n") + f.write(f"![Performance Comparison](100_decimals.png)\n\n") + f.write(f"## Detailed Results\n\n") f.write(f"See the full test output in `reports/run_{decimals}_output.txt`.\n\n") f.write("---\n") f.write("*Generated from Pi Calculation Benchmark - Apple A18 Pro Performance Study*\n") diff --git a/generate_visualizations.py b/generate_visualizations.py new file mode 100644 index 0000000..4d6a1e8 --- /dev/null +++ b/generate_visualizations.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 +import os +import csv +import json +import matplotlib.pyplot as plt +import matplotlib +matplotlib.use('Agg') # Non-interactive backend +import numpy as np + +# Read analysis data +with open('data/analysis.json', 'r') as f: + data = json.load(f) + +# Define language types +compiled = ['Assembly', 'C', 'C++', 'Rust', 'Go', 'Nim', 'Odin', 'Fortran', 'Swift', 'Crystal', 'D', 'Zig', 'Objective-C', 'Haskell'] +jit = ['Java', 'CSharp', 'Kotlin', 'Scala', 'Dart', 'Julia'] +interpreted = ['Python', 'JavaScript', 'TypeScript', 'Ruby', 'PHP', 'Perl', 'Lua', 'Bash', 'Brainfuck', 'Elixir', 'Erlang', 'R'] + +def get_type(lang): + if lang in compiled: + return 'Compiled' + elif lang in jit: + return 'JIT' + else: + return 'Interpreted' + +def get_color(lang): + lang_type = get_type(lang) + if lang_type == 'Compiled': + return '#2ecc71' # Green + elif lang_type == 'JIT': + return '#3498db' # Blue + else: + return '#e74c3c' # Red + +# Create visualizations for each decimal level +for decimals in [1, 2, 5, 10, 100, 1000, 2000]: + print(f"Creating visualizations for {decimals} decimals...") + + # Sort by time + sorted_langs = sorted(data.keys(), key=lambda x: data[x].get('time_ms', float('inf'))) + + # Create figure with subplots + fig, axes = plt.subplots(2, 2, figsize=(16, 12)) + fig.suptitle(f'Performance Comparison - {decimals} Decimal{"s" if decimals > 1 else ""}', fontsize=16, fontweight='bold') + + # Plot 1: Time comparison (top 20) + ax1 = axes[0, 0] + top_20 = sorted_langs[:20] + times = [data[lang]['time_ms'] for lang in top_20] + colors = [get_color(lang) for lang in top_20] + + bars1 = ax1.barh(range(len(top_20)), times, color=colors) + ax1.set_yticks(range(len(top_20))) + ax1.set_yticklabels(top_20) + ax1.set_xlabel('Time (ms)') + ax1.set_title('Execution Time (Top 20)') + ax1.invert_yaxis() + + # Add value labels + for i, (bar, time) in enumerate(zip(bars1, times)): + ax1.text(time + 1, i, f'{time:.0f}ms', va='center', fontsize=8) + + # Plot 2: Memory comparison (top 20) + ax2 = axes[0, 1] + sorted_by_memory = sorted(data.keys(), key=lambda x: data[x].get('memory_bytes', float('inf'))) + top_20_mem = sorted_by_memory[:20] + memories = [data[lang]['memory_bytes'] / (1024 * 1024) for lang in top_20_mem] # Convert to MB + colors_mem = [get_color(lang) for lang in top_20_mem] + + bars2 = ax2.barh(range(len(top_20_mem)), memories, color=colors_mem) + ax2.set_yticks(range(len(top_20_mem))) + ax2.set_yticklabels(top_20_mem) + ax2.set_xlabel('Memory (MB)') + ax2.set_title('Memory Usage (Top 20)') + ax2.invert_yaxis() + + # Add value labels + for i, (bar, mem) in enumerate(zip(bars2, memories)): + ax2.text(mem + 0.1, i, f'{mem:.1f}MB', va='center', fontsize=8) + + # Plot 3: IPC comparison (top 20) + ax3 = axes[1, 0] + sorted_by_ipc = sorted(data.keys(), key=lambda x: data[x].get('ipc', 0), reverse=True) + top_20_ipc = sorted_by_ipc[:20] + ipcs = [data[lang]['ipc'] for lang in top_20_ipc] + colors_ipc = [get_color(lang) for lang in top_20_ipc] + + bars3 = ax3.barh(range(len(top_20_ipc)), ipcs, color=colors_ipc) + ax3.set_yticks(range(len(top_20_ipc))) + ax3.set_yticklabels(top_20_ipc) + ax3.set_xlabel('IPC (Instructions Per Cycle)') + ax3.set_title('CPU Efficiency (Top 20)') + ax3.invert_yaxis() + + # Add value labels + for i, (bar, ipc) in enumerate(zip(bars3, ipcs)): + ax3.text(ipc + 0.05, i, f'{ipc:.2f}', va='center', fontsize=8) + + # Plot 4: Time vs Memory scatter plot + ax4 = axes[1, 1] + for lang in data.keys(): + time = data[lang]['time_ms'] + memory = data[lang]['memory_bytes'] / (1024 * 1024) # Convert to MB + color = get_color(lang) + ax4.scatter(time, memory, c=color, s=100, alpha=0.6, edgecolors='black', linewidths=0.5) + + # Add label for top performers + if time < 30 or memory < 2: + ax4.annotate(lang, (time, memory), fontsize=7, ha='center', va='bottom') + + ax4.set_xlabel('Time (ms)') + ax4.set_ylabel('Memory (MB)') + ax4.set_title('Time vs Memory Trade-off') + ax4.grid(True, alpha=0.3) + + # Add legend + from matplotlib.patches import Patch + legend_elements = [ + Patch(facecolor='#2ecc71', label='Compiled'), + Patch(facecolor='#3498db', label='JIT'), + Patch(facecolor='#e74c3c', label='Interpreted') + ] + ax4.legend(handles=legend_elements, loc='upper right') + + plt.tight_layout() + + # Save figure + output_file = f'reports/{decimals}_decimals.png' + plt.savefig(output_file, dpi=150, bbox_inches='tight') + plt.close() + + print(f"✓ Created {output_file}") + +print("\n=== All visualizations created ===") \ No newline at end of file diff --git a/reports/1000_decimals.md b/reports/1000_decimals.md index 9066ba6..792a84f 100644 --- a/reports/1000_decimals.md +++ b/reports/1000_decimals.md @@ -54,6 +54,10 @@ | 31 | Scala | 471 | 55973205 | 18880700 | 8929948 | 2.11 | JIT | | 32 | TypeScript | 1361 | 208289792 | 17642488 | 7699920 | 2.29 | Interpreted | +## Visualizations + +![Performance Comparison](100_decimals.png) + ## Detailed Results See the full test output in `reports/run_1000_output.txt`. diff --git a/reports/1000_decimals.png b/reports/1000_decimals.png new file mode 100644 index 0000000000000000000000000000000000000000..8ed967da429ed433e1e370cb529ef325ab79b5cd GIT binary patch literal 220609 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