Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 93 additions & 75 deletions scheduling/shortest_job_first.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,34 @@
"""
Shortest job remaining first
Please note arrival time and burst
Please use spaces to separate times entered.
Shortest Job Remaining First (Preemptive SJF)
---------------------------------------------
Please note arrival time and burst time.
Use spaces to separate times entered.
"""

from __future__ import annotations

import pandas as pd
import matplotlib.pyplot as plt

Check failure on line 10 in scheduling/shortest_job_first.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (I001)

scheduling/shortest_job_first.py:8:1: I001 Import block is un-sorted or un-formatted


def calculate_waitingtime(
arrival_time: list[int], burst_time: list[int], no_of_processes: int
) -> list[int]:
) -> tuple[list[int], list[tuple[int, int, int]]]:
"""
Calculate the waiting time of each processes
Return: List of waiting times.
>>> calculate_waitingtime([1,2,3,4],[3,3,5,1],4)
[0, 3, 5, 0]
>>> calculate_waitingtime([1,2,3],[2,5,1],3)
[0, 2, 0]
>>> calculate_waitingtime([2,3],[5,1],2)
[1, 0]
Calculate the waiting time for each process and record execution timeline for Gantt Chart.

Check failure on line 17 in scheduling/shortest_job_first.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E501)

scheduling/shortest_job_first.py:17:89: E501 Line too long (94 > 88)
Returns: (waiting_time, timeline)
timeline -> list of tuples: (start_time, end_time, process_id)
"""
remaining_time = [0] * no_of_processes
remaining_time = burst_time.copy()
waiting_time = [0] * no_of_processes
# Copy the burst time into remaining_time[]
for i in range(no_of_processes):
remaining_time[i] = burst_time[i]

complete = 0
increment_time = 0
minm = 999999999
minm = float("inf")
short = 0
check = False

# Process until all processes are completed
timeline = [] # To store execution sequence for Gantt chart
last_process = -1

while complete != no_of_processes:
for j in range(no_of_processes):
if (
Expand All @@ -49,43 +43,41 @@
if not check:
increment_time += 1
continue
remaining_time[short] -= 1

# Record when process switches (for Gantt chart)
if short != last_process:
if timeline and timeline[-1][2] == last_process:
timeline[-1] = (timeline[-1][0], increment_time, last_process)
if short != -1:
timeline.append((increment_time, None, short))
last_process = short

remaining_time[short] -= 1
minm = remaining_time[short]
if minm == 0:
minm = 999999999
minm = float("inf")

if remaining_time[short] == 0:
complete += 1
check = False

# Find finish time of current process
finish_time = increment_time + 1

# Calculate waiting time
finar = finish_time - arrival_time[short]
waiting_time[short] = finar - burst_time[short]

waiting_time[short] = max(waiting_time[short], 0)

# Increment time
increment_time += 1
return waiting_time

# Close last ongoing process in timeline
if timeline and timeline[-1][1] is None:
timeline[-1] = (timeline[-1][0], increment_time, last_process)

return waiting_time, timeline


def calculate_turnaroundtime(
burst_time: list[int], no_of_processes: int, waiting_time: list[int]
) -> list[int]:
"""
Calculate the turn around time of each Processes
Return: list of turn around times.
>>> calculate_turnaroundtime([3,3,5,1], 4, [0,3,5,0])
[3, 6, 10, 1]
>>> calculate_turnaroundtime([3,3], 2, [0,3])
[3, 6]
>>> calculate_turnaroundtime([8,10,1], 3, [1,0,3])
[9, 10, 4]
"""
"""Calculate the turn around time for each process."""
turn_around_time = [0] * no_of_processes
for i in range(no_of_processes):
turn_around_time[i] = burst_time[i] + waiting_time[i]
Expand All @@ -94,60 +86,86 @@

def calculate_average_times(
waiting_time: list[int], turn_around_time: list[int], no_of_processes: int
) -> tuple[float, float]:
"""Calculate and return average waiting and turnaround times."""
avg_wait = sum(waiting_time) / no_of_processes
avg_turn = sum(turn_around_time) / no_of_processes
print(f"Average waiting time = {avg_wait:.5f}")
print(f"Average turn around time = {avg_turn:.5f}")
return avg_wait, avg_turn


def plot_gantt_chart(
timeline: list[tuple[int, int, int]], processes: list[int]
) -> None:
"""
This function calculates the average of the waiting & turnaround times
Prints: Average Waiting time & Average Turn Around Time
>>> calculate_average_times([0,3,5,0],[3,6,10,1],4)
Average waiting time = 2.00000
Average turn around time = 5.0
>>> calculate_average_times([2,3],[3,6],2)
Average waiting time = 2.50000
Average turn around time = 4.5
>>> calculate_average_times([10,4,3],[2,7,6],3)
Average waiting time = 5.66667
Average turn around time = 5.0
"""
total_waiting_time = 0
total_turn_around_time = 0
for i in range(no_of_processes):
total_waiting_time = total_waiting_time + waiting_time[i]
total_turn_around_time = total_turn_around_time + turn_around_time[i]
print(f"Average waiting time = {total_waiting_time / no_of_processes:.5f}")
print("Average turn around time =", total_turn_around_time / no_of_processes)
"""Plot a Gantt chart for process execution."""
fig, ax = plt.subplots(figsize=(10, 2))

Check failure on line 102 in scheduling/shortest_job_first.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (RUF059)

scheduling/shortest_job_first.py:102:5: RUF059 Unpacked variable `fig` is never used
colors = plt.cm.tab10.colors # Nice color set
for start, end, pid in timeline:
ax.barh(
0,
end - start,
left=start,
color=colors[pid % len(colors)],
edgecolor="black",
label=f"P{processes[pid]}",
)
ax.text(
(start + end) / 2,
0,
f"P{processes[pid]}",
ha="center",
va="center",
color="white",
fontsize=9,
)

ax.set_xlabel("Time")
ax.set_yticks([])
ax.set_title("Gantt Chart - Shortest Job Remaining First (SJF Preemptive)")
handles, labels = plt.gca().get_legend_handles_labels()
by_label = dict(zip(labels, handles))
ax.legend(
by_label.values(), by_label.keys(), bbox_to_anchor=(1.05, 1), loc="upper left"
)
plt.tight_layout()
plt.show()


if __name__ == "__main__":
print("Enter how many process you want to analyze")
no_of_processes = int(input())
print("Enter how many processes you want to analyze:")
no_of_processes = int(input().strip())

burst_time = [0] * no_of_processes
arrival_time = [0] * no_of_processes
processes = list(range(1, no_of_processes + 1))

for i in range(no_of_processes):
print("Enter the arrival time and burst time for process:--" + str(i + 1))
print(f"Enter the arrival time and burst time for process {i + 1}:")
arrival_time[i], burst_time[i] = map(int, input().split())

waiting_time = calculate_waitingtime(arrival_time, burst_time, no_of_processes)

bt = burst_time
n = no_of_processes
wt = waiting_time
turn_around_time = calculate_turnaroundtime(bt, n, wt)

waiting_time, timeline = calculate_waitingtime(
arrival_time, burst_time, no_of_processes
)
turn_around_time = calculate_turnaroundtime(
burst_time, no_of_processes, waiting_time
)
calculate_average_times(waiting_time, turn_around_time, no_of_processes)

fcfs = pd.DataFrame(
list(zip(processes, burst_time, arrival_time, waiting_time, turn_around_time)),
# Display results table
df = pd.DataFrame(
list(zip(processes, arrival_time, burst_time, waiting_time, turn_around_time)),
columns=[
"Process",
"BurstTime",
"ArrivalTime",
"BurstTime",
"WaitingTime",
"TurnAroundTime",
],
)
pd.set_option("display.max_rows", df.shape[0] + 1)
print("\n--- Process Table ---")
print(df)

# Printing the dataFrame
pd.set_option("display.max_rows", fcfs.shape[0] + 1)
print(fcfs)
# Plot Gantt chart
plot_gantt_chart(timeline, processes)
103 changes: 103 additions & 0 deletions scheduling/shortest_remaining_time_first.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
"""
Shortest Remaining Time First (SRTF) Scheduling Algorithm.
SRTF is the preemptive version of Shortest Job First (SJF).
At every moment, the process with the smallest remaining burst time is executed.
https://en.wikipedia.org/wiki/Shortest_remaining_time
"""

from __future__ import annotations
from statistics import mean

Check failure on line 9 in scheduling/shortest_remaining_time_first.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (I001)

scheduling/shortest_remaining_time_first.py:8:1: I001 Import block is un-sorted or un-formatted


def calculate_waiting_times(
burst_times: list[int], arrival_times: list[int]
) -> list[int]:
"""
Calculate the waiting times of processes using SRTF scheduling.

Args:
burst_times: List of burst times for each process.
arrival_times: List of arrival times for each process.

Returns:
A list containing waiting time for each process.

Examples:
>>> calculate_waiting_times([6, 8, 7, 3], [0, 1, 2, 3])
[9, 15, 10, 0]
>>> calculate_waiting_times([5, 4, 2, 1], [0, 1, 2, 3])
[6, 3, 1, 0]
"""
n = len(burst_times)
remaining_times = burst_times.copy()
waiting_times = [0] * n
complete = 0
t = 0
min_remaining = float("inf")
shortest = 0
check = False
finish_time = 0

while complete != n:
# Find process with minimum remaining time at current time
for j in range(n):
if (
arrival_times[j] <= t
and remaining_times[j] < min_remaining
and remaining_times[j] > 0
):
min_remaining = remaining_times[j]
shortest = j
check = True

if not check:
t += 1
continue

# Reduce remaining time of current process
remaining_times[shortest] -= 1
min_remaining = remaining_times[shortest]
if min_remaining == 0:
min_remaining = float("inf")

# If a process finishes
if remaining_times[shortest] == 0:
complete += 1
check = False
finish_time = t + 1
waiting_times[shortest] = (
finish_time - burst_times[shortest] - arrival_times[shortest]
)
if waiting_times[shortest] < 0:
waiting_times[shortest] = 0

Check failure on line 72 in scheduling/shortest_remaining_time_first.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (PLR1730)

scheduling/shortest_remaining_time_first.py:71:13: PLR1730 Replace `if` statement with `max` call

t += 1

return waiting_times


def calculate_turn_around_times(
burst_times: list[int], waiting_times: list[int]
) -> list[int]:
"""
Calculate turn-around times for each process.

>>> calculate_turn_around_times([6, 8, 7, 3], [9, 15, 10, 0])
[15, 23, 17, 3]
"""
return [burst + waiting for burst, waiting in zip(burst_times, waiting_times)]


if __name__ == "__main__":
burst_times = [6, 8, 7, 3]
arrival_times = [0, 1, 2, 3]
waiting_times = calculate_waiting_times(burst_times, arrival_times)
turn_around_times = calculate_turn_around_times(burst_times, waiting_times)

print("Process ID \tArrival Time \tBurst Time \tWaiting Time \tTurnaround Time")
for i, burst_time in enumerate(burst_times):
print(
f" {i + 1}\t\t {arrival_times[i]}\t\t {burst_time}\t\t {waiting_times[i]}\t\t {turn_around_times[i]}"

Check failure on line 100 in scheduling/shortest_remaining_time_first.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E501)

scheduling/shortest_remaining_time_first.py:100:89: E501 Line too long (118 > 88)
)
print(f"\nAverage waiting time = {mean(waiting_times):.5f}")
print(f"Average turn around time = {mean(turn_around_times):.5f}")
Loading