Skip to content

Commit 15f913a

Browse files
committed
Added README and CPU Scheduling Interface
1 parent a4f2a00 commit 15f913a

File tree

2 files changed

+111
-42
lines changed

2 files changed

+111
-42
lines changed

scheduling/cpu_scheduling_interface.py

Lines changed: 111 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
1+
import copy
2+
import threading
3+
import time
14
import tkinter as tk
2-
from tkinter import ttk, messagebox
5+
from tkinter import messagebox, ttk
6+
37
import matplotlib.pyplot as plt
48
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
5-
import threading, time, copy
9+
610

711
# ===================== Scheduler Engine ===================== #
812
class SchedulerEngine:
9-
def __init__(self, processes, algorithm, quantum=2):
13+
def __init__(self, processes, algorithm, quantum: int = 2):
1014
self.original = copy.deepcopy(processes)
1115
self.processes = [p.copy() for p in processes]
1216
self.algorithm = algorithm
1317
self.quantum = quantum
1418
for p in self.processes:
1519
p["remaining"] = p["burst"]
16-
self.timeline = [] # [(time, pid)]
17-
self.stats = []
20+
self.timeline: list[tuple[int, str]] = [] # [(time, pid)]
21+
self.stats: list[tuple] = []
1822

1923
def simulate(self):
2024
algo = self.algorithm.lower()
@@ -32,26 +36,30 @@ def simulate(self):
3236
yield from self._simulate_rr()
3337
self._calculate_stats()
3438

35-
#first come first serve
39+
# first come first serve
3640
def _simulate_fcfs(self):
3741
t = 0
3842
processes = sorted(self.processes, key=lambda p: p["arrival"])
3943
for p in processes:
40-
if t < p["arrival"]:
41-
t = p["arrival"]
44+
t = max(t, p["arrival"])
4245
for _ in range(p["burst"]):
4346
self.timeline.append((t, p["pid"]))
4447
yield (t, p["pid"], [])
4548
t += 1
4649
p["completion"] = t
47-
48-
#shortest job first non preemptive
50+
51+
# shortest job first non preemptive
4952
def _simulate_sjf_np(self):
5053
t = 0
5154
processes = sorted(self.processes, key=lambda p: p["arrival"])
5255
done = 0
5356
while done < len(processes):
54-
ready = [p for p in processes if p["arrival"] <= t and "completion" not in p]
57+
ready = [
58+
p
59+
for p in processes
60+
if p["arrival"] <= t and "completion" not in p
61+
]
62+
5563
if not ready:
5664
t += 1
5765
yield (t, None, [])
@@ -63,14 +71,18 @@ def _simulate_sjf_np(self):
6371
t += 1
6472
p["completion"] = t
6573
done += 1
66-
74+
6775
# shortest job first preemptive
6876
def _simulate_sjf_p(self):
6977
t = 0
7078
processes = sorted(self.processes, key=lambda p: p["arrival"])
7179
done = 0
7280
while done < len(processes):
73-
ready = [p for p in processes if p["arrival"] <= t and p["remaining"] > 0]
81+
ready = [
82+
p
83+
for p in processes
84+
if p["arrival"] <= t and p["remaining"] > 0
85+
]
7486
if not ready:
7587
t += 1
7688
yield (t, None, [])
@@ -83,13 +95,18 @@ def _simulate_sjf_p(self):
8395
p["completion"] = t + 1
8496
done += 1
8597
t += 1
86-
87-
# priority non preemptive
98+
99+
# priority non preemptive
88100
def _simulate_priority_np(self):
89101
t = 0
90102
done = 0
91103
while done < len(self.processes):
92-
ready = [p for p in self.processes if p["arrival"] <= t and "completion" not in p]
104+
ready = [
105+
p
106+
for p in self.processes
107+
if p["arrival"] <= t and "completion" not in p
108+
]
109+
93110
if not ready:
94111
t += 1
95112
yield (t, None, [])
@@ -102,12 +119,17 @@ def _simulate_priority_np(self):
102119
p["completion"] = t
103120
done += 1
104121

105-
# priority preemptive
122+
# priority preemptive
106123
def _simulate_priority_p(self):
107124
t = 0
108125
done = 0
109126
while done < len(self.processes):
110-
ready = [p for p in self.processes if p["arrival"] <= t and p["remaining"] > 0]
127+
ready = [
128+
p
129+
for p in self.processes
130+
if p["arrival"] <= t and p["remaining"] > 0
131+
]
132+
111133
if not ready:
112134
t += 1
113135
yield (t, None, [])
@@ -124,7 +146,7 @@ def _simulate_priority_p(self):
124146
# round robin
125147
def _simulate_rr(self):
126148
t = 0
127-
q = []
149+
q: list[dict] = []
128150
processes = sorted(self.processes, key=lambda p: p["arrival"])
129151
i = 0
130152
done = 0
@@ -152,34 +174,41 @@ def _simulate_rr(self):
152174
p["completion"] = t
153175
done += 1
154176

155-
156177
def _calculate_stats(self):
157178
for p in self.processes:
158179
pid = p["pid"]
159180
arrival = p["arrival"]
160181
burst = p["burst"]
161182
completion = p["completion"]
162-
first_exec = next((t for t, pid2 in self.timeline if pid2 == pid), arrival)
183+
first_exec = next(
184+
(t for t, pid2 in self.timeline if pid2 == pid), arrival
185+
)
163186
tat = completion - arrival
164187
wt = tat - burst
165188
rt = first_exec - arrival
166189
self.stats.append((pid, arrival, burst, completion, tat, wt, rt))
167190

168-
# Interface
191+
192+
# Interface
169193
class CPUSchedulerGUI:
170194
def __init__(self, root):
171195
self.root = root
172196
self.root.title("CPU Scheduling Visualizer")
173197
self.root.geometry("1000x700")
174198

175-
self.processes = []
199+
self.processes: list[dict] = []
176200
self.setup_ui()
177201

178202
def setup_ui(self):
179203
top_frame = ttk.Frame(self.root)
180204
top_frame.pack(pady=10)
181205

182-
self.tree = ttk.Treeview(top_frame, columns=("pid", "arrival", "burst", "priority"), show="headings")
206+
self.tree = ttk.Treeview(
207+
top_frame,
208+
columns=("pid", "arrival", "burst", "priority"),
209+
show="headings",
210+
)
211+
183212
for col in self.tree["columns"]:
184213
self.tree.heading(col, text=col.capitalize())
185214
self.tree.pack(side="left")
@@ -198,23 +227,37 @@ def setup_ui(self):
198227
self.arrival_e.grid(row=1, column=1)
199228
self.burst_e.grid(row=2, column=1)
200229
self.priority_e.grid(row=3, column=1)
201-
ttk.Button(form, text="Add", command=self.add_process).grid(row=4, column=0, pady=5)
202-
ttk.Button(form, text="Delete", command=self.delete_process).grid(row=4, column=1)
230+
ttk.Button(form, text="Add", command=self.add_process).grid(
231+
row=4, column=0, pady=5
232+
)
233+
234+
ttk.Button(form, text="Delete", command=self.delete_process).grid(
235+
row=4, column=1
236+
)
203237

204238
algo_frame = ttk.Frame(self.root)
205239
algo_frame.pack(pady=10)
206240
ttk.Label(algo_frame, text="Algorithm:").pack(side="left")
207-
self.algo_cb = ttk.Combobox(algo_frame, values=[
208-
"FCFS", "SJF (Non-Preemptive)", "SJF (Preemptive)",
209-
"Priority (Non-Preemptive)", "Priority (Preemptive)", "Round Robin"
210-
])
241+
self.algo_cb = ttk.Combobox(
242+
algo_frame,
243+
values=[
244+
"FCFS",
245+
"SJF (Non-Preemptive)",
246+
"SJF (Preemptive)",
247+
"Priority (Non-Preemptive)",
248+
"Priority (Preemptive)",
249+
"Round Robin",
250+
],
251+
)
211252
self.algo_cb.current(0)
212253
self.algo_cb.pack(side="left", padx=5)
213254
ttk.Label(algo_frame, text="Quantum:").pack(side="left")
214255
self.quantum_e = ttk.Entry(algo_frame, width=5)
215256
self.quantum_e.insert(0, "2")
216257
self.quantum_e.pack(side="left")
217-
ttk.Button(algo_frame, text="Run", command=self.run_scheduling).pack(side="left", padx=10)
258+
ttk.Button(algo_frame, text="Run", command=self.run_scheduling).pack(
259+
side="left", padx=10
260+
)
218261

219262
self.ready_label = ttk.Label(self.root, text="Ready Queue:")
220263
self.ready_list = tk.Listbox(self.root, height=3)
@@ -225,9 +268,13 @@ def setup_ui(self):
225268
self.canvas = FigureCanvasTkAgg(self.figure, master=self.root)
226269
self.canvas.get_tk_widget().pack()
227270

228-
self.result_box = ttk.Treeview(self.root,
229-
columns=("pid", "arrival", "burst", "completion", "tat", "wt", "rt"),
230-
show="headings", height=6)
271+
self.result_box = ttk.Treeview(
272+
self.root,
273+
columns=("pid", "arrival", "burst", "completion", "tat", "wt", "rt"),
274+
show="headings",
275+
height=6,
276+
)
277+
231278
for col in self.result_box["columns"]:
232279
self.result_box.heading(col, text=col.upper())
233280
self.result_box.pack(pady=10)
@@ -241,7 +288,14 @@ def add_process(self):
241288
arrival = int(self.arrival_e.get())
242289
burst = int(self.burst_e.get())
243290
priority = int(self.priority_e.get() or 0)
244-
self.processes.append({"pid": pid, "arrival": arrival, "burst": burst, "priority": priority})
291+
self.processes.append(
292+
{
293+
"pid": pid,
294+
"arrival": arrival,
295+
"burst": burst,
296+
"priority": priority,
297+
}
298+
)
245299
self.tree.insert("", "end", values=(pid, arrival, burst, priority))
246300
except ValueError:
247301
messagebox.showerror("Error", "Invalid input")
@@ -264,22 +318,31 @@ def run_scheduling(self):
264318
self.ready_list.pack_forget()
265319

266320
self.engine = SchedulerEngine(self.processes, algo, quantum)
267-
threading.Thread(target=self.animate).start()
321+
threading.Thread(target=self.animate, daemon=True).start()
268322

269323
def animate(self):
270324
self.ax.clear()
271325
x, colors, current_pid = 0, {}, None
272326
for step in self.engine.simulate():
273-
t, pid, rq = step
327+
_, pid, rq = step
274328
if pid:
275329
if pid != current_pid:
276330
self.ax.axvline(x, color="black", linewidth=0.8)
277331
current_pid = pid
278332
colors.setdefault(pid, plt.cm.tab20(len(colors) % 20))
279333
self.ax.barh(0, 1, left=x, color=colors[pid])
280-
self.ax.text(x + 0.5, 0, pid, ha="center", va="center", color="white", fontsize=9)
334+
self.ax.text(
335+
x + 0.5,
336+
0,
337+
pid,
338+
ha="center",
339+
va="center",
340+
color="white",
341+
fontsize=9,
342+
)
343+
281344
x += 1
282-
self.ax.set_xticks(range(0, x + 1))
345+
self.ax.set_xticks(range(x + 1))
283346
self.ax.set_yticks([])
284347
self.ax.set_xlabel("Time")
285348
self.canvas.draw()
@@ -299,12 +362,18 @@ def show_results(self):
299362
total_wt += row[5]
300363
total_tat += row[4]
301364
total_rt += row[6]
302-
n = len(self.engine.stats)
303-
self.avg_label.config(text=f"AVG WT = {total_wt/n:.2f} | AVG TAT = {total_tat/n:.2f} | AVG RT = {total_rt/n:.2f}")
365+
n = len(self.engine.stats) or 1
366+
self.avg_label.config(
367+
text=(
368+
f"AVG WT = {total_wt/n:.2f} | "
369+
f"AVG TAT = {total_tat/n:.2f} | "
370+
f"AVG RT = {total_rt/n:.2f}"
371+
)
372+
)
373+
304374

305375
# main call
306376
if __name__ == "__main__":
307377
root = tk.Tk()
308378
CPUSchedulerGUI(root)
309379
root.mainloop()
310-
File renamed without changes.

0 commit comments

Comments
 (0)