| | import time |
| | import random |
| | import numpy as np |
| | import matplotlib.pyplot as plt |
| | import gradio as gr |
| |
|
| | |
| | plt.style.use('seaborn-v0_8-darkgrid') |
| |
|
| | |
| | random.seed(42) |
| | np.random.seed(42) |
| |
|
| | def simulate_batches(num_workers=4, |
| | batch_time=500, |
| | network_latency=200, |
| | mode='synchronous', |
| | num_batches=10): |
| | """ |
| | Simulates mini-batch scheduling under synchronous vs asynchronous update strategies. |
| | Returns worker timelines and performance metrics. |
| | """ |
| | timelines = [] |
| | current_time = [0] * num_workers |
| |
|
| | for batch in range(num_batches): |
| | for w in range(num_workers): |
| | |
| | proc_time = random.uniform(batch_time * 0.8, batch_time * 1.2) |
| | start = current_time[w] |
| | end = start + proc_time |
| | timelines.append((w, start, end, 'active')) |
| | current_time[w] = end |
| |
|
| | if mode == 'synchronous': |
| | |
| | max_time = max(current_time) |
| | for w in range(num_workers): |
| | if current_time[w] < max_time: |
| | timelines.append((w, current_time[w], max_time, 'idle')) |
| | current_time[w] = max_time |
| | |
| | current_time = [t + network_latency for t in current_time] |
| | else: |
| | |
| | current_time = [t + random.uniform(0, network_latency * 0.3) for t in current_time] |
| |
|
| | total_time = max(current_time) |
| | idle_time = sum( |
| | end - start for (w, start, end, flag) in timelines if flag == 'idle' |
| | ) |
| | total_blocks = sum(end - start for (_, start, end, _) in timelines) |
| | idle_percent = (idle_time / total_blocks) * 100 |
| | throughput = (num_workers * num_batches * 1000) / total_time |
| |
|
| | metrics = { |
| | "epoch_time_ms": total_time, |
| | "idle_percent": round(idle_percent, 2), |
| | "throughput": round(throughput, 2) |
| | } |
| |
|
| | return timelines, metrics |
| |
|
| |
|
| | def plot_timeline(timelines, metrics, num_workers): |
| | colors = {'active': '#4CAF50', 'idle': '#E74C3C'} |
| | fig, ax = plt.subplots(figsize=(10, 5)) |
| |
|
| | for (w, start, end, flag) in timelines: |
| | ax.barh(y=w, width=end-start, left=start, color=colors[flag], edgecolor='black') |
| |
|
| | ax.set_xlabel("Time (ms)") |
| | ax.set_ylabel("Worker ID") |
| | ax.set_title("Batch Scheduler Simulation") |
| | ax.set_yticks(range(num_workers)) |
| | ax.set_yticklabels([f"W{i}" for i in range(num_workers)]) |
| | ax.invert_yaxis() |
| |
|
| | text_summary = ( |
| | f"Epoch Duration: {metrics['epoch_time_ms']:.2f} ms\n" |
| | f"Idle Time: {metrics['idle_percent']}%\n" |
| | f"Throughput: {metrics['throughput']} batches/sec" |
| | ) |
| |
|
| | plt.figtext(0.72, 0.35, text_summary, fontsize=10, |
| | bbox=dict(facecolor='white', alpha=0.7, edgecolor='gray')) |
| | plt.tight_layout() |
| | return fig |
| |
|
| |
|
| | def run_simulation(num_workers, batch_time, network_latency, mode, num_batches): |
| | timelines, metrics = simulate_batches( |
| | num_workers=int(num_workers), |
| | batch_time=float(batch_time), |
| | network_latency=float(network_latency), |
| | mode=mode, |
| | num_batches=int(num_batches) |
| | ) |
| | fig = plot_timeline(timelines, metrics, num_workers) |
| | summary = ( |
| | f"Mode: {mode.capitalize()}\n" |
| | f"Epoch Time: {metrics['epoch_time_ms']:.2f} ms\n" |
| | f"Idle Time: {metrics['idle_percent']} %\n" |
| | f"Throughput: {metrics['throughput']} batches/sec" |
| | ) |
| | return fig, summary |
| |
|
| |
|
| | interface = gr.Interface( |
| | fn=run_simulation, |
| | inputs=[ |
| | gr.Slider(1, 8, value=4, step=1, label="Number of Workers"), |
| | gr.Slider(100, 1000, value=500, step=50, label="Batch Processing Time (ms)"), |
| | gr.Slider(50, 500, value=200, step=25, label="Network Latency (ms)"), |
| | gr.Radio(["synchronous", "asynchronous"], value="synchronous", label="Mode"), |
| | gr.Slider(5, 30, value=10, step=1, label="Number of Batches per Epoch"), |
| | ], |
| | outputs=[ |
| | gr.Plot(label="Timeline Visualization"), |
| | gr.Textbox(label="Simulation Summary", lines=8, max_lines=12, show_copy_button=True) |
| | ], |
| | title="🧠 Batch Scheduler Simulator", |
| | description="Visualize how synchronous vs asynchronous batch scheduling affects throughput, idle time, and epoch duration.", |
| | examples=[ |
| | [4, 500, 200, "synchronous", 10], |
| | [8, 400, 150, "asynchronous", 15] |
| | ] |
| | ) |
| |
|
| | if __name__ == "__main__": |
| | interface.launch() |
| |
|