Last active
May 8, 2025 18:13
-
-
Save sithumonline/4d53b055b269ae2f74798790f5f23846 to your computer and use it in GitHub Desktop.
Go vs Java v1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import json | |
| import matplotlib.pyplot as plt | |
| import numpy as np | |
| import pandas as pd | |
| import seaborn as sns | |
| from matplotlib.ticker import FuncFormatter | |
| # Set the style | |
| plt.style.use('ggplot') | |
| sns.set_palette("Set2") | |
| plt.rcParams['font.family'] = 'DejaVu Sans' | |
| plt.rcParams['font.size'] = 12 | |
| plt.rcParams['axes.labelsize'] = 14 | |
| plt.rcParams['axes.titlesize'] = 16 | |
| plt.rcParams['figure.titlesize'] = 20 | |
| # Load the benchmark data | |
| with open('hyperfines-01.json', 'r') as file: | |
| benchmark_data = json.load(file) | |
| # Extract relevant data | |
| go_data = benchmark_data['results'][0] | |
| java_data = benchmark_data['results'][1] | |
| # Calculate percentage difference | |
| def calc_percentage_diff(go_val, java_val): | |
| return ((go_val - java_val) / go_val) * 100 | |
| # Prepare data for key metrics | |
| metrics = ['Mean', 'Median', 'Min', 'Max', 'StdDev'] | |
| go_values = [go_data['mean'], go_data['median'], go_data['min'], go_data['max'], go_data['stddev']] | |
| java_values = [java_data['mean'], java_data['median'], java_data['min'], java_data['max'], java_data['stddev']] | |
| differences = [calc_percentage_diff(go_val, java_val) for go_val, java_val in zip(go_values, java_values)] | |
| # Prepare data for CPU metrics | |
| cpu_metrics = ['User CPU', 'System CPU'] | |
| go_cpu = [go_data['user'], go_data['system']] | |
| java_cpu = [java_data['user'], java_data['system']] | |
| cpu_differences = [calc_percentage_diff(go_val, java_val) for go_val, java_val in zip(go_cpu, java_cpu)] | |
| # 1. Create main metrics comparison chart | |
| fig, ax = plt.subplots(figsize=(12, 8)) | |
| # Set up bar positions | |
| x = np.arange(len(metrics)) | |
| width = 0.35 | |
| # Create bars | |
| go_bars = ax.bar(x - width/2, go_values, width, label='Go', color='#2563eb', alpha=0.9, edgecolor='black', linewidth=1) | |
| java_bars = ax.bar(x + width/2, java_values, width, label='Java', color='#dc2626', alpha=0.9, edgecolor='black', linewidth=1) | |
| # Customize chart | |
| ax.set_ylabel('Time (seconds)', fontweight='bold') | |
| ax.set_title('Go vs Java: Performance Metrics Comparison', fontweight='bold', pad=20) | |
| ax.set_xticks(x) | |
| ax.set_xticklabels(metrics, fontweight='bold') | |
| ax.legend(fontsize=12) | |
| # Format y-axis to show seconds | |
| def seconds_formatter(x, pos): | |
| return f'{x:.1f}s' | |
| ax.yaxis.set_major_formatter(FuncFormatter(seconds_formatter)) | |
| # Add value labels on the bars | |
| def add_labels(bars): | |
| for bar in bars: | |
| height = bar.get_height() | |
| ax.annotate(f'{height:.1f}s', | |
| xy=(bar.get_x() + bar.get_width() / 2, height), | |
| xytext=(0, 3), # 3 points vertical offset | |
| textcoords="offset points", | |
| ha='center', va='bottom', | |
| fontsize=10, fontweight='bold') | |
| add_labels(go_bars) | |
| add_labels(java_bars) | |
| # Add percentage difference as text | |
| for i, diff in enumerate(differences): | |
| ax.annotate(f'{diff:.1f}% faster', | |
| xy=(x[i], min(go_values[i], java_values[i]) / 2), | |
| xytext=(0, 0), | |
| textcoords="offset points", | |
| ha='center', va='center', | |
| fontsize=12, fontweight='bold', | |
| color='green' if diff > 0 else 'red', | |
| bbox=dict(boxstyle="round,pad=0.3", fc='white', alpha=0.8)) | |
| plt.grid(axis='y', linestyle='--', alpha=0.7) | |
| plt.tight_layout() | |
| plt.savefig('go_vs_java_metrics.png', dpi=300, bbox_inches='tight') | |
| # 2. Create CPU usage comparison chart | |
| fig, ax = plt.subplots(figsize=(10, 6)) | |
| # Set up bar positions | |
| x = np.arange(len(cpu_metrics)) | |
| width = 0.35 | |
| # Create bars | |
| go_cpu_bars = ax.bar(x - width/2, go_cpu, width, label='Go', color='#2563eb', alpha=0.9, edgecolor='black', linewidth=1) | |
| java_cpu_bars = ax.bar(x + width/2, java_cpu, width, label='Java', color='#dc2626', alpha=0.9, edgecolor='black', linewidth=1) | |
| # Customize chart | |
| ax.set_ylabel('CPU Time (seconds)', fontweight='bold') | |
| ax.set_title('Go vs Java: CPU Usage Comparison', fontweight='bold', pad=20) | |
| ax.set_xticks(x) | |
| ax.set_xticklabels(cpu_metrics, fontweight='bold') | |
| ax.legend(fontsize=12) | |
| ax.yaxis.set_major_formatter(FuncFormatter(seconds_formatter)) | |
| # Add value labels on the bars | |
| add_labels(go_cpu_bars) | |
| add_labels(java_cpu_bars) | |
| # Add percentage difference as text | |
| for i, diff in enumerate(cpu_differences): | |
| ax.annotate(f'{diff:.1f}% less', | |
| xy=(x[i], min(go_cpu[i], java_cpu[i]) / 2), | |
| xytext=(0, 0), | |
| textcoords="offset points", | |
| ha='center', va='center', | |
| fontsize=12, fontweight='bold', | |
| color='green' if diff > 0 else 'red', | |
| bbox=dict(boxstyle="round,pad=0.3", fc='white', alpha=0.8)) | |
| plt.grid(axis='y', linestyle='--', alpha=0.7) | |
| plt.tight_layout() | |
| plt.savefig('go_vs_java_cpu.png', dpi=300, bbox_inches='tight') | |
| # 3. Create run-by-run comparison chart | |
| fig, ax = plt.subplots(figsize=(14, 8)) | |
| # Prepare data for individual runs | |
| runs = list(range(1, len(go_data['times']) + 1)) | |
| go_times = go_data['times'] | |
| java_times = java_data['times'] | |
| # Plot the lines | |
| ax.plot(runs, go_times, 'o-', linewidth=3, markersize=10, label='Go', color='#2563eb') | |
| ax.plot(runs, java_times, 'o-', linewidth=3, markersize=10, label='Java', color='#dc2626') | |
| # Fill the area between lines | |
| ax.fill_between(runs, go_times, java_times, where=(np.array(go_times) > np.array(java_times)), | |
| color='#dc2626', alpha=0.2, interpolate=True) | |
| ax.fill_between(runs, go_times, java_times, where=(np.array(go_times) <= np.array(java_times)), | |
| color='#2563eb', alpha=0.2, interpolate=True) | |
| # Add horizontal lines for means | |
| ax.axhline(y=go_data['mean'], color='#2563eb', linestyle='--', alpha=0.7, linewidth=2) | |
| ax.axhline(y=java_data['mean'], color='#dc2626', linestyle='--', alpha=0.7, linewidth=2) | |
| # Annotate the means | |
| ax.annotate(f"Go Mean: {go_data['mean']:.1f}s", | |
| xy=(runs[-1], go_data['mean']), | |
| xytext=(10, 0), | |
| textcoords="offset points", | |
| ha='left', va='center', | |
| fontsize=12, fontweight='bold', | |
| color='#2563eb', | |
| bbox=dict(boxstyle="round,pad=0.3", fc='white', alpha=0.8)) | |
| ax.annotate(f"Java Mean: {java_data['mean']:.1f}s", | |
| xy=(runs[-1], java_data['mean']), | |
| xytext=(10, 0), | |
| textcoords="offset points", | |
| ha='left', va='center', | |
| fontsize=12, fontweight='bold', | |
| color='#dc2626', | |
| bbox=dict(boxstyle="round,pad=0.3", fc='white', alpha=0.8)) | |
| # Customize chart | |
| ax.set_xlabel('Run Number', fontweight='bold') | |
| ax.set_ylabel('Execution Time (seconds)', fontweight='bold') | |
| ax.set_title('Go vs Java: Run-by-Run Performance Comparison', fontweight='bold', pad=20) | |
| ax.legend(fontsize=14, loc='upper right') | |
| ax.set_xticks(runs) | |
| ax.yaxis.set_major_formatter(FuncFormatter(seconds_formatter)) | |
| # Add additional annotations | |
| plt.annotate(f'Java is {calc_percentage_diff(go_data["mean"], java_data["mean"]):.1f}% faster on average', | |
| xy=(0.5, 0.05), xycoords='figure fraction', | |
| ha='center', va='center', | |
| fontsize=14, fontweight='bold', | |
| bbox=dict(boxstyle="round,pad=0.5", fc='#dcfce7', ec='green', alpha=0.8)) | |
| plt.grid(True, linestyle='--', alpha=0.7) | |
| plt.tight_layout() | |
| plt.savefig('go_vs_java_runs.png', dpi=300, bbox_inches='tight') | |
| # 4. Create summary card with key metrics | |
| fig, ax = plt.subplots(figsize=(10, 6)) | |
| ax.axis('off') | |
| # Create a table with the summary data | |
| summary_data = { | |
| 'Metric': ['Mean Time', 'Median Time', 'Min Time', 'Max Time', 'Std Dev', 'User CPU', 'System CPU'], | |
| 'Go': [f'{go_data["mean"]:.2f}s', f'{go_data["median"]:.2f}s', f'{go_data["min"]:.2f}s', | |
| f'{go_data["max"]:.2f}s', f'{go_data["stddev"]:.2f}s', f'{go_data["user"]:.2f}s', f'{go_data["system"]:.2f}s'], | |
| 'Java': [f'{java_data["mean"]:.2f}s', f'{java_data["median"]:.2f}s', f'{java_data["min"]:.2f}s', | |
| f'{java_data["max"]:.2f}s', f'{java_data["stddev"]:.2f}s', f'{java_data["user"]:.2f}s', f'{java_data["system"]:.2f}s'], | |
| 'Java Advantage': [f'{calc_percentage_diff(go_data["mean"], java_data["mean"]):.2f}%', | |
| f'{calc_percentage_diff(go_data["median"], java_data["median"]):.2f}%', | |
| f'{calc_percentage_diff(go_data["min"], java_data["min"]):.2f}%', | |
| f'{calc_percentage_diff(go_data["max"], java_data["max"]):.2f}%', | |
| f'{calc_percentage_diff(go_data["stddev"], java_data["stddev"]):.2f}%', | |
| f'{calc_percentage_diff(go_data["user"], java_data["user"]):.2f}%', | |
| f'{calc_percentage_diff(go_data["system"], java_data["system"]):.2f}%'] | |
| } | |
| # Convert to pandas DataFrame and create a styled table | |
| df = pd.DataFrame(summary_data) | |
| table = ax.table(cellText=df.values, colLabels=df.columns, cellLoc='center', loc='center', colWidths=[0.3, 0.2, 0.2, 0.3]) | |
| table.auto_set_font_size(False) | |
| table.set_fontsize(12) | |
| table.scale(1, 2) | |
| # Style the table headers | |
| for (i, j), cell in table.get_celld().items(): | |
| if i == 0: # Header row | |
| cell.set_text_props(fontweight='bold', color='white') | |
| cell.set_facecolor('#4b5563') | |
| elif j == 0: # Metric column | |
| cell.set_text_props(fontweight='bold') | |
| elif j == 3: # Java Advantage column | |
| value = float(cell.get_text().get_text().strip('%')) | |
| if value > 0: | |
| cell.set_facecolor('#dcfce7') # Light green for positive advantage | |
| else: | |
| cell.set_facecolor('#fee2e2') # Light red for negative advantage | |
| # Add a title | |
| plt.figtext(0.5, 0.95, 'Go vs Java: Performance Summary', | |
| ha='center', fontsize=18, fontweight='bold') | |
| plt.figtext(0.5, 0.02, 'Note: Positive percentages indicate Java is faster/more efficient', | |
| ha='center', fontsize=10, style='italic') | |
| plt.tight_layout() | |
| plt.savefig('go_vs_java_summary.png', dpi=300, bbox_inches='tight') | |
| # 5. Create a radar/spider chart comparing multiple metrics | |
| fig = plt.figure(figsize=(10, 8)) | |
| ax = fig.add_subplot(111, polar=True) | |
| # Prepare data - normalize all metrics to 0-1 scale where 1 is better | |
| # For time metrics, lower is better, so we invert them | |
| metrics_names = ['Mean Time', 'Median Time', 'Min Time', 'Max Time', 'Std Dev', 'User CPU', 'System CPU'] | |
| go_norm = [] | |
| java_norm = [] | |
| for i, metric in enumerate(metrics_names): | |
| if i < 5: # Time metrics | |
| # Higher is better for the radar chart, so invert (use reciprocal) | |
| max_val = max(1/go_values[i], 1/java_values[i]) | |
| go_norm.append((1/go_values[i]) / max_val) | |
| java_norm.append((1/java_values[i]) / max_val) | |
| else: # CPU metrics | |
| # Higher is better for the radar chart, so invert (use reciprocal) | |
| idx = i - 5 | |
| max_val = max(1/go_cpu[idx], 1/java_cpu[idx]) | |
| go_norm.append((1/go_cpu[idx]) / max_val) | |
| java_norm.append((1/java_cpu[idx]) / max_val) | |
| # Complete the loop for the radar chart | |
| go_norm.append(go_norm[0]) | |
| java_norm.append(java_norm[0]) | |
| metrics_names.append(metrics_names[0]) | |
| # Set up angle for each metric | |
| angles = np.linspace(0, 2*np.pi, len(metrics_names)-1, endpoint=False).tolist() | |
| angles += [angles[0]] # Close the loop | |
| # Plot data | |
| ax.plot(angles, go_norm, 'o-', linewidth=2, markersize=8, label='Go', color='#2563eb') | |
| ax.plot(angles, java_norm, 'o-', linewidth=2, markersize=8, label='Java', color='#dc2626') | |
| ax.fill(angles, go_norm, alpha=0.1, color='#2563eb') | |
| ax.fill(angles, java_norm, alpha=0.1, color='#dc2626') | |
| # Set labels and customize | |
| ax.set_thetagrids(np.degrees(angles[:-1]), metrics_names[:-1]) | |
| ax.set_rlabel_position(0) | |
| ax.set_rticks([0.25, 0.5, 0.75, 1]) | |
| ax.set_rmax(1) | |
| ax.set_axisbelow(True) | |
| ax.grid(True, linestyle='--', alpha=0.7) | |
| # Add title and legend | |
| plt.title('Go vs Java: Performance Metrics Comparison', size=18, y=1.1, fontweight='bold') | |
| plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1)) | |
| # Add note explaining the chart | |
| plt.figtext(0.5, 0.01, 'Note: All metrics normalized. Further from center = better performance', | |
| ha='center', fontsize=10, style='italic') | |
| plt.tight_layout() | |
| plt.savefig('go_vs_java_radar.png', dpi=300, bbox_inches='tight') | |
| print("All visualizations have been generated successfully!") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "results": [ | |
| { | |
| "command": "./workerpool", | |
| "mean": 647.7689493191599, | |
| "stddev": 147.3561668256607, | |
| "median": 594.71315645256, | |
| "user": 3954.229811139999, | |
| "system": 33.14184544, | |
| "min": 484.93092318106005, | |
| "max": 865.30768430606, | |
| "times": [ | |
| 595.8115210150601, | |
| 706.99645072306, | |
| 865.30768430606, | |
| 821.85377455706, | |
| 834.34622589006, | |
| 512.45318218206, | |
| 500.89188443206, | |
| 561.48305501506, | |
| 484.93092318106005, | |
| 593.61479189006 | |
| ], | |
| "exit_codes": [ | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0 | |
| ] | |
| }, | |
| { | |
| "command": "java WorkerPool", | |
| "mean": 485.65776722736007, | |
| "stddev": 46.38658353813867, | |
| "median": 491.95819580656007, | |
| "user": 3447.20835794, | |
| "system": 17.186345940000002, | |
| "min": 416.95270722406, | |
| "max": 544.8545639730601, | |
| "times": [ | |
| 467.48910147306003, | |
| 544.8545639730601, | |
| 501.64080172306, | |
| 451.20588126506004, | |
| 419.78766022306, | |
| 489.91337226506005, | |
| 494.00301934806004, | |
| 535.39166005606, | |
| 416.95270722406, | |
| 535.3389047230601 | |
| ], | |
| "exit_codes": [ | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| 0 | |
| ] | |
| } | |
| ] | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "log" | |
| "sync" | |
| "time" | |
| ) | |
| // simulateWork performs a time-consuming calculation (e.g., Fibonacci). | |
| func simulateWork(n int) int { | |
| if n <= 1 { | |
| return n | |
| } | |
| return simulateWork(n-1) + simulateWork(n-2) | |
| } | |
| // worker processes jobs from its dedicated jobs channel, does some work, | |
| // then sends the result on the results channel. | |
| func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) { | |
| defer wg.Done() | |
| log.Printf("Worker %d: starting\n", id) | |
| for j := range jobs { | |
| log.Printf("Worker %d: started job %d\n", id, j) | |
| result := simulateWork(45) // Example: Calculate the 45th Fibonacci number | |
| log.Printf("Worker %d: finished job %d with result %d\n", id, j, result) | |
| results <- result | |
| } | |
| } | |
| func main() { | |
| start := time.Now() // Start timer | |
| const numJobs = 5 * 100 | |
| const numWorkers = 3 * 100 | |
| // Create a dedicated jobs channel for each worker | |
| workerJobs := make([]chan int, numWorkers) | |
| for i := range workerJobs { | |
| workerJobs[i] = make(chan int, numJobs) | |
| } | |
| results := make(chan int, numJobs) | |
| var wg sync.WaitGroup | |
| // Start the worker goroutines | |
| for w := 1; w <= numWorkers; w++ { | |
| wg.Add(1) | |
| go worker(w, workerJobs[w-1], results, &wg) | |
| } | |
| log.Println("Main: All workers started") | |
| // Send jobs to specific workers | |
| for j := 1; j <= numJobs; j++ { | |
| workerID := (j - 1) % numWorkers // Assign jobs in a round-robin manner | |
| workerJobs[workerID] <- j | |
| log.Printf("Main: sent job %d to worker %d\n", j, workerID+1) | |
| } | |
| // Close all worker job channels | |
| for _, ch := range workerJobs { | |
| close(ch) | |
| } | |
| // Wait for all workers to finish, then close results | |
| wg.Wait() | |
| close(results) | |
| // Collect and print results | |
| for res := range results { | |
| log.Printf("Result received: %d\n", res) | |
| } | |
| elapsed := time.Since(start) // End timer | |
| log.Printf("Execution time: %s\n", elapsed) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.util.concurrent.*; | |
| import java.util.logging.Logger; | |
| import java.util.logging.Level; | |
| import java.util.ArrayList; | |
| import java.util.List; | |
| public class WorkerPool { | |
| private static final Logger logger = Logger.getLogger(WorkerPool.class.getName()); | |
| // simulateWork performs a time-consuming calculation (e.g., Fibonacci). | |
| private static int simulateWork(int n) { | |
| if (n <= 1) { | |
| return n; | |
| } | |
| return simulateWork(n - 1) + simulateWork(n - 2); | |
| } | |
| // Worker class processes jobs from a blocking queue, does some work, | |
| // then puts the result on the results queue. | |
| static class Worker implements Runnable { | |
| private final int id; | |
| private final BlockingQueue<Integer> jobs; | |
| private final BlockingQueue<Integer> results; | |
| private final CountDownLatch latch; | |
| public Worker(int id, BlockingQueue<Integer> jobs, BlockingQueue<Integer> results, CountDownLatch latch) { | |
| this.id = id; | |
| this.jobs = jobs; | |
| this.results = results; | |
| this.latch = latch; | |
| } | |
| @Override | |
| public void run() { | |
| try { | |
| logger.info("Worker " + id + ": starting"); | |
| while (true) { | |
| Integer job = jobs.take(); // Wait for a job | |
| if (job == -1) { // Poison pill to signal no more jobs | |
| break; | |
| } | |
| logger.info("Worker " + id + ": started job " + job); | |
| int result = simulateWork(45); // Example: Calculate the 45th Fibonacci number | |
| logger.info("Worker " + id + ": finished job " + job + " with result " + result); | |
| results.put(result); | |
| } | |
| } catch (InterruptedException e) { | |
| Thread.currentThread().interrupt(); | |
| logger.log(Level.SEVERE, "Worker interrupted", e); | |
| } finally { | |
| latch.countDown(); | |
| logger.info("Worker " + id + ": finished all jobs"); | |
| } | |
| } | |
| } | |
| public static void main(String[] args) { | |
| long startTime = System.nanoTime(); // Start timer | |
| final int numJobs = 5 * 100; | |
| final int numWorkers = 3 * 100; | |
| // Create a dedicated jobs queue for each worker | |
| List<BlockingQueue<Integer>> workerJobs = new ArrayList<>(); | |
| for (int i = 0; i < numWorkers; i++) { | |
| workerJobs.add(new LinkedBlockingQueue<>()); | |
| } | |
| // Create results queue | |
| BlockingQueue<Integer> results = new LinkedBlockingQueue<>(); | |
| // Create a latch to wait for all workers to complete | |
| CountDownLatch latch = new CountDownLatch(numWorkers); | |
| // Start the worker threads | |
| for (int w = 1; w <= numWorkers; w++) { | |
| Thread workerThread = new Thread(new Worker(w, workerJobs.get(w - 1), results, latch)); | |
| workerThread.start(); | |
| } | |
| logger.info("Main: All workers started"); | |
| // Send jobs to specific workers | |
| for (int j = 1; j <= numJobs; j++) { | |
| int workerID = (j - 1) % numWorkers; // Assign jobs in a round-robin manner | |
| workerJobs.get(workerID).add(j); | |
| logger.info("Main: sent job " + j + " to worker " + (workerID + 1)); | |
| } | |
| // Send poison pills to signal workers to stop | |
| for (int i = 0; i < numWorkers; i++) { | |
| workerJobs.get(i).add(-1); // -1 is the poison pill | |
| } | |
| // Wait for all workers to finish | |
| try { | |
| latch.await(); | |
| // Collect and print results | |
| int receivedResults = 0; | |
| while (receivedResults < numJobs) { | |
| Integer result = results.poll(1, TimeUnit.SECONDS); // Wait for results | |
| if (result != null) { | |
| logger.info("Result received: " + result); | |
| receivedResults++; | |
| } | |
| } | |
| } catch (InterruptedException e) { | |
| Thread.currentThread().interrupt(); | |
| logger.log(Level.SEVERE, "Main thread interrupted", e); | |
| } finally { | |
| logger.info("Main: All workers have completed their tasks"); | |
| } | |
| long endTime = System.nanoTime(); // End timer | |
| long elapsedTime = endTime - startTime; | |
| logger.info("Execution time: " + (elapsedTime / 1_000_000) + " ms"); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment