feat: add MLFQ scheduling algorithm and thread scheduler
- Implemented MLFQ (Multilevel Feedback Queue) algorithm with dynamic priority levels and quantum management. - Created unit tests for MLFQ algorithm covering initialization, demotion, selection, priority boost, preemption, and quantum expiration. - Developed a ThreadScheduler class supporting FCFS, RR, and PRIORITY scheduling policies for intra-process thread management. - Added unit tests for ThreadScheduler to validate thread selection and quantum expiration logic.
This commit is contained in:
1 parent
532c14e382
commit
5761dfe70a
34 files changed
+3789
-334
No files matched your search
+101
-1
@@ -147,7 +147,7 @@ The process with the **highest ratio** is selected. This naturally increases the
|
||||
|
||||
## Multilevel Queue
|
||||
|
||||
**Type:** Preemptive
|
||||
**Type:** Preemptive
|
||||
**Parameters:** number of queues, quantum per queue
|
||||
|
||||
### How it works
|
||||
@@ -158,6 +158,106 @@ This allows different classes of processes to be treated distinctly: for example
|
||||
|
||||
---
|
||||
|
||||
## MLFQ (Multilevel Feedback Queue)
|
||||
|
||||
**Type:** Preemptive
|
||||
**Parameters:** number of queues, quantum per queue (default: [2, 4, 8]), boost interval
|
||||
|
||||
### How it works
|
||||
|
||||
MLFQ is an extension of the Multilevel Queue that allows **processes to move between queues** based on their observed runtime behavior — eliminating the need to know burst durations in advance.
|
||||
|
||||
#### Movement rules
|
||||
|
||||
| Event | Action |
|
||||
|-------|--------|
|
||||
| Newly arrived process | Enters **queue 0** (highest priority) |
|
||||
| Process exhausts the quantum of its current queue | **Demoted** to the next queue (lower priority) |
|
||||
| Process returns from I/O | Stays in the **same queue** (cooperative behavior is rewarded) |
|
||||
| Boost tick (configurable interval) | **All** processes are moved to queue 0 |
|
||||
|
||||
#### Why is MLFQ efficient?
|
||||
|
||||
- Interactive processes (I/O Bound) naturally stay in high-priority queues because they leave the CPU before exhausting the quantum.
|
||||
- Batch processes (CPU Bound) progressively migrate to lower-priority queues where they receive larger quantums.
|
||||
- The periodic boost prevents starvation: even processes that fell to lower queues eventually return to the top.
|
||||
|
||||
#### Example with 3 queues (quantums: 2, 4, 8)
|
||||
|
||||
```
|
||||
Process A (CPU Bound, burst=12):
|
||||
Queue 0 → uses 2 ticks, demoted → Queue 1
|
||||
Queue 1 → uses 4 ticks, demoted → Queue 2
|
||||
Queue 2 → uses remaining 6 ticks (quantum=8, not exhausted)
|
||||
|
||||
Process B (I/O Bound, burst=1 CPU + I/O + burst=1 CPU):
|
||||
Queue 0 → uses 1 tick → goes to I/O → returns to Queue 0
|
||||
→ always stays in the highest-priority queue
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| Number of queues | 3 | Number of priority queues |
|
||||
| Quantum per queue | [2, 4, 8] | Time slice for each queue |
|
||||
| Boost interval | 20 ticks | Every N ticks, all processes move up to queue 0 |
|
||||
|
||||
---
|
||||
|
||||
## Thread Models
|
||||
|
||||
PSS supports **thread** simulation within processes, implementing the three classical models described in Operating Systems textbooks.
|
||||
|
||||
### General Concepts
|
||||
|
||||
- A process can have **N user threads**, each with its own burst sequence (CPU and I/O).
|
||||
- The scheduling policy among threads within the same process is configurable: **FCFS**, **Round Robin**, or **Priority**.
|
||||
- The thread model determines how user threads map to kernel threads.
|
||||
|
||||
### MANY_TO_ONE (N:1)
|
||||
|
||||
**N user threads → 1 kernel thread**
|
||||
|
||||
- Only one thread can use the CPU at a time within the process.
|
||||
- If any thread initiates I/O, **the entire process blocks** (the kernel thread is stuck).
|
||||
- No real parallelism; very simple to implement.
|
||||
- Simulated by the `many_to_one` presets.
|
||||
|
||||
### ONE_TO_ONE (1:1)
|
||||
|
||||
**Each user thread → 1 dedicated kernel thread**
|
||||
|
||||
- Threads block **independently**: if Thread A does I/O, Threads B and C remain in the Ready queue.
|
||||
- The process only terminates when **all** threads have terminated.
|
||||
- The process blocks only when all threads are simultaneously in I/O.
|
||||
- Simulated by the `one_to_one` presets.
|
||||
|
||||
### MANY_TO_MANY (N:M)
|
||||
|
||||
**N user threads → M kernel threads (M ≤ N)**
|
||||
|
||||
- The number of kernel threads (`kernelThreadCount`) is configurable.
|
||||
- If all M kernel slots are occupied, additional user threads wait in the **kernel wait queue** (`KernelWait`).
|
||||
- Combines flexibility with resource control: more active threads than N:1 but less overhead than 1:1.
|
||||
- Simulated by the `many_to_many` presets.
|
||||
|
||||
### Intra-Process Policy
|
||||
|
||||
Defines how the scheduler selects the next thread when multiple threads are Ready within the same process:
|
||||
|
||||
| Policy | Behavior |
|
||||
|--------|----------|
|
||||
| **FCFS** | The oldest thread in the Ready queue is selected |
|
||||
| **Round Robin (RR)** | Each thread receives `threadQuantum` ticks; when exhausted, it goes to the end of the queue |
|
||||
| **Priority** | The highest-priority thread is selected; immediate preemption if a higher-priority thread becomes ready |
|
||||
|
||||
### Gantt Chart with Threads
|
||||
|
||||
When a process has threads, the Gantt chart displays **sub-rows** below the process row, one per thread, with colors derived from the process color (40° hue shift per thread). The state of each thread (New, Ready, Running, Waiting, Terminated) is colored using the same CSS variables as process states.
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- Silberschatz, A., Galvin, P. B., & Gagne, G., *Operating System Concepts*, 10th edition.
|
||||
|
||||
+101
-1
@@ -147,7 +147,7 @@ O processo com o **maior ratio** é selecionado. Isso faz com que processos que
|
||||
|
||||
## Multilevel Queue
|
||||
|
||||
**Tipo:** Preemptivo
|
||||
**Tipo:** Preemptivo
|
||||
**Parâmetros:** número de filas, quantum por fila
|
||||
|
||||
### Como funciona
|
||||
@@ -158,6 +158,106 @@ Isso permite tratar diferentes classes de processos de forma distinta: por exemp
|
||||
|
||||
---
|
||||
|
||||
## MLFQ (Multilevel Feedback Queue)
|
||||
|
||||
**Tipo:** Preemptivo
|
||||
**Parâmetros:** número de filas, quantum por fila (padrão: [2, 4, 8]), intervalo de boost
|
||||
|
||||
### Como funciona
|
||||
|
||||
O MLFQ é uma extensão do Multilevel Queue que permite **mover processos entre filas** com base em seu comportamento observado em tempo de execução — eliminando a necessidade de conhecer os bursts antecipadamente.
|
||||
|
||||
#### Regras de movimentação
|
||||
|
||||
| Evento | Ação |
|
||||
|--------|------|
|
||||
| Processo recém-chegado | Entra na **fila 0** (maior prioridade) |
|
||||
| Processo esgota o quantum da fila atual | **Rebaixado** para a fila seguinte (menor prioridade) |
|
||||
| Processo retorna do I/O | Permanece na **mesma fila** (comportamento cooperativo é recompensado) |
|
||||
| Tick de boost (intervalo configurável) | **Todos** os processos são movidos para a fila 0 |
|
||||
|
||||
#### Por que o MLFQ é eficiente?
|
||||
|
||||
- Processos interativos (I/O Bound) naturalmente ficam nas filas de alta prioridade porque abandonam a CPU antes de esgotar o quantum.
|
||||
- Processos batch (CPU Bound) migram progressivamente para filas de baixa prioridade onde recebem quantuns maiores.
|
||||
- O boost periódico evita starvation: mesmo processos que caíram para as filas inferiores eventualmente retornam ao topo.
|
||||
|
||||
#### Exemplo com 3 filas (quantuns: 2, 4, 8)
|
||||
|
||||
```
|
||||
Processo A (CPU Bound, burst=12):
|
||||
Fila 0 → usa 2 ticks, rebaixado → Fila 1
|
||||
Fila 1 → usa 4 ticks, rebaixado → Fila 2
|
||||
Fila 2 → usa 6 ticks restantes (quantum=8, não esgota)
|
||||
|
||||
Processo B (I/O Bound, burst=1 CPU + I/O + burst=1 CPU):
|
||||
Fila 0 → usa 1 tick → vai para I/O → retorna à Fila 0
|
||||
→ sempre permanece na fila de maior prioridade
|
||||
```
|
||||
|
||||
### Parâmetros
|
||||
|
||||
| Parâmetro | Padrão | Descrição |
|
||||
|-----------|--------|-----------|
|
||||
| Número de filas | 3 | Quantidade de filas de prioridade |
|
||||
| Quantuns por fila | [2, 4, 8] | Fatia de tempo de cada fila |
|
||||
| Intervalo de boost | 20 ticks | A cada N ticks, todos os processos sobem para a fila 0 |
|
||||
|
||||
---
|
||||
|
||||
## Modelos de Threads
|
||||
|
||||
O PSS suporta simulação de **threads** dentro de processos, implementando os três modelos clássicos descritos em Sistemas Operacionais.
|
||||
|
||||
### Conceitos Gerais
|
||||
|
||||
- Um processo pode ter **N threads de usuário**, cada uma com sua própria sequência de bursts (CPU e I/O).
|
||||
- A política de escalonamento entre threads de um mesmo processo é configurável: **FCFS**, **Round Robin** ou **Prioridade**.
|
||||
- O modelo de thread determina como threads de usuário se mapeiam para threads de kernel.
|
||||
|
||||
### MANY_TO_ONE (N:1)
|
||||
|
||||
**N threads de usuário → 1 thread de kernel**
|
||||
|
||||
- Apenas uma thread pode usar a CPU por vez dentro do processo.
|
||||
- Se qualquer thread iniciar I/O, **todo o processo bloqueia** (a thread de kernel fica presa).
|
||||
- Sem paralelismo real; muito simples de implementar.
|
||||
- Simulado pelos presets `many_to_one`.
|
||||
|
||||
### ONE_TO_ONE (1:1)
|
||||
|
||||
**Cada thread de usuário → 1 thread de kernel dedicada**
|
||||
|
||||
- Threads bloqueiam **independentemente**: se a Thread A faz I/O, as Threads B e C continuam na fila Ready.
|
||||
- Processo só termina quando **todas** as threads terminam.
|
||||
- Processo bloqueia somente quando todas as threads estão simultâneamente em I/O.
|
||||
- Simulado pelos presets `one_to_one`.
|
||||
|
||||
### MANY_TO_MANY (N:M)
|
||||
|
||||
**N threads de usuário → M threads de kernel (M ≤ N)**
|
||||
|
||||
- O número de threads de kernel (`kernelThreadCount`) é configurável.
|
||||
- Se todas as M slots de kernel estiverem ocupadas, threads de usuário adicionais ficam em **fila de espera de kernel** (`KernelWait`).
|
||||
- Combina flexibilidade com controle de recursos: mais threads ativas que N:1 mas menos overhead que 1:1.
|
||||
- Simulado pelos presets `many_to_many`.
|
||||
|
||||
### Política Intra-Processo
|
||||
|
||||
Define como o escalonador seleciona a próxima thread quando há múltiplas threads Ready no mesmo processo:
|
||||
|
||||
| Política | Comportamento |
|
||||
|----------|--------------|
|
||||
| **FCFS** | Thread mais antiga na fila Ready é selecionada |
|
||||
| **Round Robin (RR)** | Cada thread recebe `threadQuantum` ticks; ao esgotar, vai para o fim da fila |
|
||||
| **Priority** | Thread de maior prioridade é selecionada; preempção imediata se nova thread de maior prioridade chegar |
|
||||
|
||||
### Diagrama de Gantt com Threads
|
||||
|
||||
Quando um processo possui threads, o Gantt exibe **sub-linhas** abaixo da linha do processo, uma por thread, com cores derivadas da cor do processo (deslocamento de matiz de 40° por thread). O estado de cada thread (New, Ready, Running, Waiting, Terminated) é colorido com as mesmas variáveis CSS dos processos.
|
||||
|
||||
---
|
||||
|
||||
## Referências
|
||||
|
||||
- Silberschatz, A., Galvin, P. B., & Gagne, G., *Operating System Concepts*, 10ª edição.
|
||||
|
||||
@@ -105,6 +105,41 @@ The total height of each bar equals the **Turnaround Time** of the process.
|
||||
|
||||
---
|
||||
|
||||
## Thread Metrics
|
||||
|
||||
When a process has threads, PSS computes individual metrics for each thread. These metrics are displayed in the **Threads** tab of the metrics panel (visible only when there are processes with threads).
|
||||
|
||||
### Per-Thread Metrics
|
||||
|
||||
| Metric | Formula | What it means |
|
||||
|--------|---------|----------------|
|
||||
| **Arrival Time** | `arrivalTick` | Tick at which the thread first entered the Ready queue |
|
||||
| **Start** | `startTick` | Tick at which the thread first used the CPU |
|
||||
| **Finish** | `finishTick` | Tick at which the thread completed all of its bursts |
|
||||
| **Response Time** | `startTick − arrivalTick` | How long the thread waited before receiving the CPU for the first time |
|
||||
| **Turnaround Time** | `finishTick − arrivalTick` | Total lifetime of the thread (arrival → completion) |
|
||||
| **Waiting Time** | `turnaround − cpuTime − ioTime` | Time in the Ready queue without doing anything useful |
|
||||
| **CPU Time** | Σ ticks in Running state | Total CPU consumed by the thread |
|
||||
| **I/O Time** | Σ ticks in Waiting state | Total time waiting for I/O |
|
||||
|
||||
### Thread Models and their impact on metrics
|
||||
|
||||
The thread model directly affects the recorded times:
|
||||
|
||||
| Model | Impact on Waiting Time |
|
||||
|-------|------------------------|
|
||||
| **MANY_TO_ONE** | Waiting Time tends to be high: any thread's I/O blocks the entire process, forcing other threads to wait |
|
||||
| **ONE_TO_ONE** | Lower Waiting Time: threads block independently; while one does I/O, the others remain in the Ready queue |
|
||||
| **MANY_TO_MANY** | Intermediate Waiting Time: threads that exceed the kernel slots enter `KernelWait` (shown with reduced opacity in the Gantt chart) |
|
||||
|
||||
### Visualization
|
||||
|
||||
The thread table displays inline horizontal mini progress bars in the Response, Turnaround, Waiting, CPU, and I/O columns, normalized by the largest value in each column across all threads — just like the process metrics table.
|
||||
|
||||
Each thread has a color derived from the parent process color (40° HSL hue shift per thread), shown as a colored dot in the table and as a sub-row in the Gantt chart.
|
||||
|
||||
---
|
||||
|
||||
## Example
|
||||
|
||||
Consider three processes with the following bursts:
|
||||
|
||||
@@ -105,6 +105,41 @@ A altura total de cada barra equivale ao **Turnaround Time** do processo.
|
||||
|
||||
---
|
||||
|
||||
## Métricas de Threads
|
||||
|
||||
Quando um processo possui threads, o PSS calcula métricas individuais para cada thread. Essas métricas são exibidas na aba **Threads** do painel de métricas (visível apenas quando há processos com threads).
|
||||
|
||||
### Métricas por Thread
|
||||
|
||||
| Métrica | Fórmula | O que significa |
|
||||
|---------|---------|----------------|
|
||||
| **Arrival Time** | `arrivalTick` | Tick em que a thread entrou pela primeira vez na fila Ready |
|
||||
| **Start** | `startTick` | Tick em que a thread usou a CPU pela primeira vez |
|
||||
| **Finish** | `finishTick` | Tick em que a thread encerrou todos os seus bursts |
|
||||
| **Response Time** | `startTick − arrivalTick` | Quanto a thread esperou antes de receber a CPU pela primeira vez |
|
||||
| **Turnaround Time** | `finishTick − arrivalTick` | Tempo total de vida da thread (chegada → término) |
|
||||
| **Waiting Time** | `turnaround − cpuTime − ioTime` | Tempo na fila Ready sem executar nada útil |
|
||||
| **CPU Time** | Σ ticks em estado Running | Total de CPU consumido pela thread |
|
||||
| **I/O Time** | Σ ticks em estado Waiting | Total de tempo aguardando I/O |
|
||||
|
||||
### Modelos de Thread e seu impacto nas métricas
|
||||
|
||||
O modelo de thread afeta diretamente os tempos registrados:
|
||||
|
||||
| Modelo | Impacto no Waiting Time |
|
||||
|--------|------------------------|
|
||||
| **MANY_TO_ONE** | Waiting Time tende a ser alto: qualquer I/O de uma thread bloqueia todo o processo, forçando as demais threads a esperarem |
|
||||
| **ONE_TO_ONE** | Waiting Time menor: threads bloqueiam independentemente; enquanto uma faz I/O, as outras continuam na fila Ready |
|
||||
| **MANY_TO_MANY** | Waiting Time intermediário: threads que excedem os slots de kernel ficam em `KernelWait` (indicadas com `opacity` reduzida no Gantt) |
|
||||
|
||||
### Visualização
|
||||
|
||||
A tabela de threads exibe mini barras de progresso horizontais nas colunas de Response, Turnaround, Waiting, CPU e I/O, normalizadas pelo maior valor de cada coluna entre todas as threads — assim como na tabela de processos.
|
||||
|
||||
Cada thread possui uma cor derivada da cor do processo pai (deslocamento de matiz HSL de 40° por thread), exibida como ponto colorido na tabela e como sub-linha no Gantt.
|
||||
|
||||
---
|
||||
|
||||
## Exemplo
|
||||
|
||||
Considere três processos com os seguintes bursts:
|
||||
|
||||
Reference in new issue
Block a user