# The Art of Context Switching : Maximizing OS Efficiency

> Explore how you can maximize your operating system's performance with our deep dive into Context Switching. Learn how this core OS concept can be optimized.

Source: https://krishparekhdev.com/blog/the-art-of-context-switching-maximizing-os-efficiency
Published: 2023-06-06
Tags: computer-science, operating-system, optimization, education, learning

---

## Introduction

In this blog, we are going to delve into the topic of **context switching** in operating systems. We will explore the basics, seeking answers to the questions *'What?' 'Why?' and 'How?'* to understand how things work. By breaking down this complex topic into more manageable subtopics, we aim to enhance our understanding of the fundamentals.

## What is Context Switch?

1. Context Switching is the technique using which the operating system can switch the processes.

2. When the context switch happens it stores the state of the current process inside the **process control block (PCB)**.

I know this could be confusing. So, let's break it down and delve into what happens internally. We'll also familiarize ourselves with some key terminology such as 'process' and 'process control block'.

## What is a process?

1. A process is a program under execution.

2. Let's say you write a C++ code, pass it to the compiler and the compiler provides us with an **executable file**, for the CPU to run that executable file, it will create a process. So our C++ program is under execution inside the CPU.

Now, let's dissect what constitutes a process. To understand the meaning and implications of starting a process, we must first understand its composition.

## The architecture of the process?

![](/images/blog/the-art-of-context-switching-maximizing-os-efficiency/01.webp)

### Text Section (Code Segment)
1. This area stores the actual **binary code** of the program. It includes the compiled program code, processed by a compiler.

2. For instance, when you compile your C++ program, it results in an executable file in binary format. This is the file that we are referring to here, denoted as `(.exe)`, not the source code file, which is denoted as `(.cpp)`.

### Data Section (Global Segment)
1. This area contains **static** or **global** variables that have been initialized by the programmer. They retain their value throughout the lifetime of the program.

2. For example, in a C++ program, we often define **global** variables like the value of `PI` or a specific constant that remains unaltered or maintains a **single instance** throughout the program's execution.

    ```cpp
    #include &lt;iostream>
    using namespace std;

    // Global variable declaration:
    const double PI = 3.141592653589793;

    int main() \{
       // PI can be used anywhere in the program from here onwards.
       cout &lt;&lt; "The value of PI is: " &lt;&lt; PI &lt;&lt; endl;
       return 0;
    \}
    ```

### BSS (Block Started by Symbol) Segment
1. This segment contains the **global** and **static** variables that are uninitialized. They are automatically initialized to **zero**. Let's understand this with an example

    ```cpp
    #include &lt;iostream>

    using namespace std;

    // Uninitialized global variable
    int globalVar;

    int main() \{
        // Uninitialized local static variable
        static int staticVar;

        cout &lt;&lt; "The value of uninitialized global variable is: " &lt;&lt; globalVar &lt;&lt; endl;
        cout &lt;&lt; "The value of uninitialized static variable is: " &lt;&lt; staticVar &lt;&lt; endl;

        return 0;
    \}
    ```

### Heap Section
1. This is the section of memory that is dynamically allocated. When your program runs and you use `new` (in C++) or `malloc` (in C) or similar constructs in other languages, the memory is allocated from the heap.

2. It is used for **dynamic memory allocation**. This becomes essential when there is a need to allocate additional memory space during **runtime**. That's where the heap comes in, facilitating dynamic memory allocation in real time.

3. However, it's important to remember to **deallocate** this memory once the need for it has been satisfied, otherwise, you could run into *memory-related issues*.

    ```cpp
    #include &lt;iostream>
    using namespace std;

    int main() \{
        int* p = new int(29); // Dynamically allocate memory and initialize to 29
        cout &lt;&lt; "Value of p: " &lt;&lt; *p &lt;&lt; endl;
        delete p; // Deallocate memory when done
        return 0;
    \}
    ```

### Stack Section
1. This contains data that helps keep track of function calls, parameters, local variables, and return addresses.

2. The stack is used in a last-in-first-out (LIFO) manner, where items are pushed (added) and popped (removed) from the top of the stack. Each thread gets its stack. For instance In this code, when `function(x)` is called in `main`, a new stack frame is created for the `function`. This frame contains the parameter `x`, the local variable `y`, and the return address (the point in the `main` to return to after `function` finishes). Once `function` completes its execution, its stack frame is removed, and execution continues in `main` at the point right after the call to function

    ```cpp
    #include &lt;iostream>
    using namespace std;

    void function(int x) \{
        int y = x + 5; // local variable
        cout &lt;&lt; "The value of y is: " &lt;&lt; y &lt;&lt; endl;
    \}

    int main() \{
        int x = 10; // local variable
        function(x); // function call
        return 0;
    \}
    ```

## What is a PCB?

![](/images/blog/the-art-of-context-switching-maximizing-os-efficiency/02.webp)

A Process Control Block (PCB), is a *data structure* maintained by the operating system for **every process in the system**. In a nutshell, the PCB stores everything the operating system needs to know to manage a process.

So now let's understand what this data structure stores about the process and how it helps the operating system.

### Process ID (PID)

1. A unique identifier that distinguishes one process from another, facilitating process tracking and management.

2. To check the processes running on Windows computer you can use the below command.

```bash
tasklist
```

### Process State

![](/images/blog/the-art-of-context-switching-maximizing-os-efficiency/03.webp)

1. The **current status** of the process.

2. The OS uses this data to decide what actions should be taken for the associated process let's understand what each state means.

    1. **New**: The process is being created.

    2. **Ready**: The process is waiting to be assigned to a processor.

    3. **Running**: Instructions are being executed.

    4. **Waiting**: The process is waiting for some event to occur (such as an I/O operation).

    5. **Terminated**: The process has finished execution.

### Program Counter

1. The address of the **next instruction** in the process that needs to be executed.

2. When a process is running, the CPU fetches the instruction at the address stored in the Program Counter, executes it, and then updates the Program Counter to point to the next instruction.

3. For instance, we have 3 instructions inside a program `Instruction A`,

    `Instruction B`, and `Instruction C`. When the program starts running, the Program Counter, points to `Instruction A`. After `Instruction A` is executed, and the Program Counter is updated to point to `Instruction B`, and so on. In context to C++, this instruction could be initializing a variable, calling a function or controlling flow statements.

### CPU Registers

1. The data in all the processor registers are saved at the time of the last context switch. These are saved to allow the process to be continued later from the same point.

2. For instance, we have a process running that will perform the addition of two numbers the number to be added might be stored in `2 data registers` (small storage area inside the CPU that holds the data that is being processed), `Register A` and `Register B`. Furthermore, we have a 3rd register `Register C` which stores the result of the addition.

3. Now suppose an **interrupt** occurs (like a timer interrupt), triggering a context switch. The operating system decides to pause the current process and switch to another process. Before the switch, the operating system saves the current state of all registers for the current process in its Process Control Block (PCB). This includes the values in `Register A` and `Register B` (the numbers to be added) and any existing value in `Register C`.

4. The OS then loads the state of the registers for the new process (which were saved in its PCB during its last context switch).

### CPU Scheduling Information
1. Includes priorities, scheduling queue pointers, and other scheduling parameters. This helps us in determining how the CPU's time should be allocated to different processes.

2. For instance, we have 2 Processes `Process A` and `Process B`, `Process A` has a priority of **5** and `Process B` has a priority of **10**. The operating system using a priority-based scheduling algorithm will choose to run `Process B` first then `Process A` as `Process B` has a higher priority.

3. Without this information, the operating system would lack a systematic way to allocate CPU time, which could result in inefficient CPU utilization and poor performance.

### Memory Management Information
1. Memory allocation details, such as page tables and memory limits, play a pivotal role in process management.

2. They ensure each process can access its memory without interference, ensuring accurate data access. For example, without proper memory management, a memory-intensive game like `PUBG` could potentially overwrite memory allocated to lighter applications like `Discord`, or monopolize system memory, leading to crashes in other applications.

3. Therefore, memory management information in the process control block is crucial for system stability and balanced resource utilization.

### **I/O Status Information**:

1. Includes the list of I/O devices allocated to the process, a list of open files, etc.

2. It's necessary to manage input/output operations for a process and keep track of the devices and files associated with it.

## Reasons for Context Switching
### Multitasking

![](/images/blog/the-art-of-context-switching-maximizing-os-efficiency/04.webp)

1. Multitasking allows multiple processes or threads to share CPU time.

2. For example, while studying, you might use **Microsoft Word** `(Process 1)` for writing and simultaneously listening to music on **Spotify** `(Process 2)`. The operating system switches between these processes, allowing each to execute their instructions.

### Higher Priority Task

1. Preemption occurs when a **higher-priority** task becomes ready.

2. For instance, when you are listening to `music` on your smartphone and receive a `phone call`, the operating system switches the context to prioritize the `phone call`. The music playback is paused, and the focus shifts to the call.

### Interrupts and system calls

![](/images/blog/the-art-of-context-switching-maximizing-os-efficiency/05.webp)

1. Interrupts and system calls require context switches to handle events and services.

2. When a `digital camera` is connected to a computer via USB, it generates an interrupt signal, prompting the operating system to execute an `interrupt handler routine`.

3. This routine initializes the necessary drivers and services to establish a connection between the camera and the computer.

### Resource wait

1. Resource wait occurs when a process requests a resource that is not immediately available.

2. For instance, while **downloading a file in a browser**, if you receive a **call**, the context switches to focus on the call, and the **download pauses** due to the lack of available resources. Once the call ends, the context switches back to resume the download.

### Time Quantum

![](/images/blog/the-art-of-context-switching-maximizing-os-efficiency/06.webp)

1. In preemptive scheduling algorithms, each process is allocated a fixed amount of CPU time called a `quantum`.

2. When a process's quantum expires, a context switch may occur to allow another process to run. This prevents a single heavy process from monopolizing the CPU and ensures fair execution for all processes.

## The Context Switching phases?
The process of context switching involves a series of steps managed by the operating system's scheduler. Here is a simplified step-by-step breakdown of what typically happens during a context switch:

### System Request
A context switch begins when the running process is preempted (usually because its time slice has expired or a higher priority process has become ready to run), or when the running process makes a system call or is interrupted.

### Store Current Process State
1. The operating system's scheduler stores the state of the currently running process in its Process Control Block (PCB).

2. This includes data such as the process's priority, its state (e.g., running, waiting), and its CPU registers (e.g., the program counter, stack pointer, and other registers).

### Select New Process
1. The scheduler determines which process should run next.

2. This decision is based on factors such as process priority and scheduling algorithm (e.g., round-robin, priority scheduling, etc.).

### Load New Process State
1. The state of the new process, which has been stored in its PCB, is loaded into the CPU's registers.

2. This prepares the new process to start executing where it last left off.

### Execute New Process
The new process begins to execute.

## Conclusion

In summary, context switching plays a crucial role in the management of processes and threads within an operating system. It allows a single CPU to handle multiple tasks almost simultaneously, achieving what we perceive as multi-tasking in computer systems.
