> For the complete documentation index, see [llms.txt](https://smadi0x86-blog.gitbook.io/smadi0x86-playground/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://smadi0x86-blog.gitbook.io/smadi0x86-playground/architecture/operating-systems/cpu-scheduling.md).

# CPU Scheduling

CPU scheduling is a process which allows one process to use the CPU while the execution of another process is on hold (in waiting state) due to unavailability of any resource like I/O etc... thereby making full use of CPU.&#x20;

The aim of CPU scheduling is to make the system efficient, fast and fair.

#### We have 2 types of scheduling:

* **Long Term Scheduling:** For example the number of jobs executing at once in the primary memory.
* **Short Term Scheduling:** A small time scale, for example right now we have multiple processes wanting to run on CPU, which ones shall execute first.

## Short Term Scheduling

#### The kernel runs the scheduler at least when:

* A process switches from running to waiting.
* An interrupt occurs.
* A process is created or terminated.

**Non-preemptive system:** The scheduler must wait for one of these events.

**Preemptive system:** The scheduler can interrupt a running process.

## Criteria for comparing scheduling algorithms

* **CPU Utilization:** The percentage of time that the CPU is busy.
* **Throughput:** The number of processes completing in a unit of time.
* **Turnaround time:** The length of time it takes to run a process from initialization to termination, including all the waiting time.
* **Waiting time:** The total amount of time that a process is in the ready queue.
* **Response time:** The time between when a process is ready to run and its next I/O request.

## Scheduling Algorithms

1. **FCFS:** First Come, First Served.
2. **Round Robin:** Use a time slice and preemption to alternate jobs.&#x20;
3. **SJF:** Shortest Job First.
4. **Shortest Remaining Time First (SRTF):** A Preemptive SJF.
5. **Multilevel Feedback Queues:** Round robin on each priority queue.&#x20;

### FCFS

* The scheduler executes jobs to completion in arrival order.&#x20;
* In early FCFS schedulers, the job did not relinquish the CPU even when it was doing I/O.&#x20;
* We will assume a FCFS scheduler that runs when processes are blocked on I/O, but that is non-preemptive, i.e., the job keeps the CPU until it blocks (say on an I/O device).

<figure><img src="https://4247064012-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFLaJdzZGSq1DpczuSySw%2Fuploads%2FMCjoTHuOrOUoGOY0rDjS%2Fimage.png?alt=media&amp;token=53935069-cc3e-4688-8b88-d08de6980d07" alt=""><figcaption></figcaption></figure>

**Advantage:** FCFS is simple to implement.

**Disadvantages: A**verage wait time is highly variable as short jobs may wait behind long jobs.&#x20;

FCFS may lead to poor overlap of I/O and CPU since CPU-bound processes will force I/O bound processes to wait for the CPU, leaving the I/O devices idle.

### Round Robin

* Variants of round robin are used in most time sharing systems.
* Add a timer and use a preemptive policy.
* After each time slice, move the running thread to the back of the queue.
* Selecting a time slice:&#x20;
  * **Too large:** Waiting time suffers, degenerates to FCFS if processes are never preempted.&#x20;
  * **Too small:** Throughput suffers because too much time is spent context switching.&#x20;

{% hint style="info" %}
Balance these tradeoffs by selecting a time slice where context switching is roughly 1% of the time slice.&#x20;
{% endhint %}

**Today:**&#x20;

* **T**ypical time slice is 10-100 ms.
* Context switch time is 0.1-1 ms.
* **Advantage:** It's fair; each job gets an equal shot at the CPU.
* **Disadvantage:** Average waiting time can be bad.

### Shortest Job First

Schedule the job that has the least (expected) amount of work (CPU time) to do until its next I/O request or termination.

**Advantages:**

* Provably optimal with respect to minimizing the average waiting time.
* Works for preemptive and non-preemptive schedulers.
* Preemptive SJF is called SRTF (shortest remaining time first).

**Disadvantages:**

* Impossible to predict the amount of CPU time a job has left.
* Long running CPU bound jobs can starve.

### Multilevel Feedback Queues

Multilevel feedback queues use past behavior to predict the future and assign job priorities.

MLFQ overcomes the prediction problem in SJF.

* If a process is I/O bound in the past, it is also likely to be I/O bound in the future (programs turn out not to be random).&#x20;
* To exploit this behavior, the scheduler can favor jobs that have used the least amount of CPU time, thus approximating SJF.&#x20;
* This policy is adaptive because it relies on past behavior and changes in behavior result in changes to scheduling decisions.

#### Adjusting Priorities in MLFQ:

* Job starts in highest priority queue.&#x20;
* If job's time slices expires, drop its priority one level.&#x20;
* If job's time slices does not expire (the context switch comes from an I/O request instead), then increase its priority one level, up to the top priority level.

{% hint style="info" %}
CPU bound jobs quickly drop in priority and I/O bound jobs stay at a high priority.
{% endhint %}

### Summary

1. **FCFS:** Not fair, and average waiting time is poor.&#x20;
2. **Round Robin:** Fair, but average waiting time is poor.&#x20;
3. **SJF:** Not fair, but average waiting time is minimized assuming we can accurately predict the length of the next CPU burst. Starvation is possible.&#x20;
4. **Multilevel Queuing:** An implementation (approximation) of SJF.

{% hint style="info" %}
Our modeling assumed that context switches took no time, which is unrealistic.
{% endhint %}

Example #1 (FCFS & RR)

5 Jobs, 100 seconds each, time slice is 1 second and context switch time of 0

1. Using FCFS, each job will complete in 100 seconds and then do a context switch, we can calculate average completion time (100 + 200 + 300 + 400 + 500 / 5 = 300).

<figure><img src="https://4247064012-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFLaJdzZGSq1DpczuSySw%2Fuploads%2FtlbcjWmHs8YJfz50v4jT%2Fimage.png?alt=media&amp;token=90c49688-f8a1-4db3-bda1-9f16dbd29f0a" alt=""><figcaption></figcaption></figure>

2. Now for Round Robin, each job will get executed based on time slice (quantum time) for 1 second and move to the next job.

So if we calculate the completion time for round robin, each job will accomplish 1 second of work every 5 seconds, we can get FCFS completion time and minus it from the other 4 jobs to get the completion time for the first job, as its the first job which executed the time slice. The same applies for job 2 which will be `500 - 3 = 497` etc...

<figure><img src="https://4247064012-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFLaJdzZGSq1DpczuSySw%2Fuploads%2FtpFePMKDtoCEm9Xfl4u6%2Fimage.png?alt=media&amp;token=7984b955-6562-4881-9213-1e8477a3d4e3" alt=""><figcaption></figcaption></figure>

3. Now to calculate the wait time which is the time that the job waits until it gets executed, we can do it by computing `completion time - length (burst time)`

<figure><img src="https://4247064012-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFLaJdzZGSq1DpczuSySw%2Fuploads%2FzuNNQGoV724Ni2xd8iQi%2Fimage.png?alt=media&amp;token=8e9617bf-4bb5-4a51-b767-d54a4774b2d0" alt=""><figcaption></figcaption></figure>

#### Example #2 (FCFS & RR)

5 Jobs of length 50, 40, 30, 20 and 10, time slice 1 second and context switch time of 0 seconds

1. Using FCFS, we first get the first burst time (length) which is 50 then to get the second job burst time we add `50 + 40 = 90` etc...

<figure><img src="https://4247064012-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFLaJdzZGSq1DpczuSySw%2Fuploads%2FgtL5e4Ax7bO6Fs8xzonI%2Fimage.png?alt=media&amp;token=e09bba09-3ec9-4abb-a0a4-1e404b00d51f" alt=""><figcaption></figcaption></figure>

2. For round robin with a time slice (quantum time) of 1, the first job that will finish is job 5 because it needs to reach only 10 which would take `10 x 5 = 50` completion time, the formula used is `Length x Job number`.

<figure><img src="https://4247064012-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFLaJdzZGSq1DpczuSySw%2Fuploads%2FqNULIs3tP0GT10EeRjUI%2Fimage.png?alt=media&amp;token=1c659930-59cb-4b35-ae48-c467c9de4615" alt=""><figcaption></figcaption></figure>

3. Finally, for the waiting time we calculate using same formula which is `completion time - length`

<figure><img src="https://4247064012-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFLaJdzZGSq1DpczuSySw%2Fuploads%2FmlSdv4UfjFV7QJsovDHf%2Fimage.png?alt=media&amp;token=15978e78-317c-45ae-a01c-b725c8501b63" alt=""><figcaption></figcaption></figure>

Example #3 (FCFS & RR & SJF)

5 Jobs of length 50, 40, 30, 20 and 10 seconds each, time slice of 1 second and context switch time is 0

1. We calculate FCFS & RR same as Example 1 and 2

<figure><img src="https://4247064012-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFLaJdzZGSq1DpczuSySw%2Fuploads%2FCwAk0FuW83N4zk51DpSw%2Fimage.png?alt=media&amp;token=369f2757-15d3-4c1c-a89e-8300aa1bf881" alt=""><figcaption></figcaption></figure>

2. For SJF, we must pick the shortest Job First, which in this case is Job 5 which is = 10. after that we go to the second shortest job which is job 4 which is equals to `10 + 20 = 30` then to job 3 which is `30 + 30 = 60` etc...

<figure><img src="https://4247064012-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFLaJdzZGSq1DpczuSySw%2Fuploads%2FoKlvgU6eeW56i43aIcQG%2Fimage.png?alt=media&amp;token=6c6ecf76-8745-4ffc-8185-3ade9024baa4" alt=""><figcaption></figcaption></figure>

3. Finally, for the waiting time we calculate using same formula which is `completion time - length`
