This project is a simulation of the Completely Fair Scheduler (CFS), a process scheduling algorithm used in the Linux kernel. The simulation demonstrates how CFS manages CPU-bound and I/O-bound tasks by maintaining fairness and prioritizing tasks based on their vruntime and weight.
The Completely Fair Scheduler (CFS) is designed to provide fair CPU time to all tasks by using a virtual runtime (vruntime) metric. Tasks with lower vruntime are prioritized, ensuring that higher-priority tasks (those with higher weight) get more CPU time. This simulation implements a simplified version of CFS, focusing on:
- CPU-bound tasks: Tasks that primarily use the CPU.
- I/O-bound tasks: Tasks that frequently wait for I/O operations.
- Weight: A priority value assigned to each task. Higher weight means higher priority.
- Formula:
weight = NICE_0_LOAD / (priority + 1) NICE_0_LOADis a constant (1024 in this simulation).
- Formula:
- vruntime: Virtual runtime of a task, calculated as:
vruntime += (executed_time * NICE_0_LOAD) / weight- Higher-priority tasks have slower
vruntimegrowth.
- Runqueue: A priority queue (min-heap) sorted by
vruntime. The task with the smallestvruntimeis scheduled next.
- CPU-bound tasks:
- Execute for a fixed time slice (1ms in this simulation).
- Update
vruntimebased on executed time and weight.
- I/O-bound tasks:
- Simulate I/O wait by sleeping for a fixed duration (10ms in this simulation).
- Penalize
vruntimefor the I/O wait time. - Execute for a short time slice (1ms) after I/O completion.
- Tasks that primarily use the CPU.
- Each task has:
cpu_burst_time: Total CPU time required.priority: Determines the task's weight.
- Execution:
- Run for a fixed time slice (1ms).
- Update
vruntimeand reducecpu_burst_time. - Requeue if
cpu_burst_time > 0.
- Tasks that frequently wait for I/O.
- Each task has:
cpu_burst_time: Total CPU time required.priority: Determines the task's weight.iowait: Simulated I/O wait time (10ms).
- Execution:
- Sleep for
iowaitto simulate I/O wait. - Penalize
vruntimefor the I/O wait time. - Run for a short time slice (1ms) after I/O completion.
- Requeue if
cpu_burst_time > 0.
- Sleep for
-
Initialization:
- All tasks are added to the runqueue with initial
vruntimevalues. - Tasks are categorized as CPU-bound or I/O-bound.
- All tasks are added to the runqueue with initial
-
Scheduling Loop:
- The scheduler picks the task with the smallest
vruntimefrom the runqueue. - If the task is CPU-bound:
- Execute for 1ms.
- Update
vruntimeand reducecpu_burst_time. - Requeue if
cpu_burst_time > 0.
- If the task is I/O-bound:
- Simulate I/O wait by sleeping for 10ms.
- Penalize
vruntimefor the I/O wait time. - Execute for 1ms after I/O completion.
- Requeue if
cpu_burst_time > 0.
- The scheduler picks the task with the smallest
-
Termination:
- The simulation ends when all tasks have completed their
cpu_burst_time.
- The simulation ends when all tasks have completed their
- C++ compiler (e.g.,
g++). - Basic understanding of process scheduling.
- Clone the repository:
git clone <repo-url> cd cfs-scheduler-cpp python -m venv /myvenv # create virtual env if not created, use python3 if python not working source myvenv/bin/activate cd build # make build dir in root folder if it is not there cmake .. make ./cfs-schedular cd .. python3 plot.py
First simulation is of processes with different vruntime, priority etc but all processes are of IO_BOUND nature whereas second one contains all CPU_BOUND processes.
We can clearly see that IO tasks are waiting for their iowait time and getting penalised. More priority IO task is getting more penalised and scheduling will get delayed whereas in CPU bound tasks, Process 1 got finalised quickly because it has the highest priroirty and got penalised the least because it started with least vruntime and highest priority. So, resulted in more frequent scheduling.
dissecting linux schedulers & implementing our toy cfs_scheduler simulation:- Link

