codexscheduling-fcfs-versus-round-robin.py
scheduling-fcfs-versus-round-robin.py
"""Draw a single-CPU scheduling example with no switching cost or I/O blocking.
Tested with Python 3.14.4, NumPy 2.3.5, Matplotlib 3.10.7.
Run from _media; write the opaque matching PNG to the current directory.
"""
from collections import deque
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
WORKLOAD = [("A", 0, 5), ("B", 1, 3), ("C", 2, 1)]
COLORS = {"A": "#155d8a", "B": "#187355", "C": "#a84b12"}
def schedule(quantum=None):
"""Queue arrivals through the slice endpoint before requeuing its task."""
pending = deque(WORKLOAD)
ready = deque()
remaining = {name: burst for name, _, burst in WORKLOAD}
time = 0
intervals = []
while pending or ready:
if not ready and pending:
time = max(time, pending[0][1])
while pending and pending[0][1] <= time:
ready.append(pending.popleft()[0])
name = ready.popleft()
duration = remaining[name] if quantum is None else min(quantum, remaining[name])
end = time + duration
intervals.append((name, time, end))
remaining[name] -= duration
while pending and pending[0][1] <= end:
ready.append(pending.popleft()[0])
if remaining[name]:
ready.append(name)
time = end
return intervals
def main():
plt.rcParams.update({"font.family": "DejaVu Sans", "font.size": 12})
fig, ax = plt.subplots(figsize=(9.8, 4.6), dpi=110, facecolor="white")
ax.set_facecolor("white")
for y, label, intervals in [(1, "FCFS", schedule()),
(0, "Round robin\nquantum = 2", schedule(2))]:
for name, start, end in intervals:
ax.broken_barh([(start, end - start)], (y - 0.23, 0.46),
facecolors=COLORS[name], edgecolors="white", linewidth=2)
ax.text((start + end) / 2, y, name, ha="center", va="center",
color="white", weight="bold", fontsize=15)
ax.text(-0.3, y, label, ha="right", va="center", color="#203040")
for name, arrival, burst in WORKLOAD:
ax.annotate(f"{name} arrives\nburst {burst}", xy=(arrival, 1.3),
xytext=(arrival, 1.63), ha="center", color=COLORS[name],
fontsize=11, arrowprops={"arrowstyle": "-|>", "color": COLORS[name]})
ax.set(xlim=(-0.5, 9.1), ylim=(-0.65, 2.05), xticks=np.arange(10),
yticks=[], xlabel="Time (abstract units)")
ax.grid(axis="x", color="#dfe5eb", linewidth=0.7)
ax.set_axisbelow(True)
for spine in ["top", "left", "right"]:
ax.spines[spine].set_visible(False)
fig.suptitle("Same work, different turns on one CPU", fontsize=17,
weight="bold", color="#203040", y=0.96)
fig.text(0.5, 0.11, "At a slice boundary: queue new arrivals before the expired task.",
ha="center", fontsize=11)
fig.text(0.5, 0.055, "Toy model: zero overhead; no I/O blocking; no measured OS timings.",
ha="center", fontsize=10.5)
fig.subplots_adjust(left=0.20, right=0.98, top=0.84, bottom=0.27)
fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"),
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()