refactor: Convert scheduling algorithms to class-based BaseAlgorithm structure, update engine and tests, and add new algorithm and metrics documentation.

This commit is contained in:
Lucas Guerra committed 2026-03-23 16:04:14 -03:00
1 parent 9c552e53fa
commit 571d8e51d2
26 files changed
+1583 -1221

No files matched your search

+162
View File
@@ -0,0 +1,162 @@
# 📐 Algoritmos de Escalonamento
Este documento descreve em detalhes os algoritmos de escalonamento implementados no PSS. Para cada algoritmo são apresentados o princípio de funcionamento, parâmetros, regras de desempate e exemplos didáticos.
---
## Regras Gerais
- **Unidade de tempo:** o simulador opera em *ticks* discretos. Cada tick representa 1 unidade de tempo de CPU.
- **Bursts:** cada processo possui uma sequência de bursts alternados: `CPU → I/O → CPU → ...`, sempre começando com CPU.
- **Desempate:** quando dois processos estão empatados no critério de seleção do algoritmo, a prioridade vai para o que chegou primeiro (`arrivalTime`). Em segundo desempate, usa-se o `id` em ordem lexicográfica.
- **Context Switch:** se configurado (≥ 1 tick), um overhead é inserido toda vez que a CPU troca de processo.
---
## FCFS — First Come, First Served
**Tipo:** Não-preemptivo
### Como funciona
Talvez o algoritmo mais intuitivo: o processo que chegou primeiro é atendido primeiro. A fila Ready é ordenada por `arrivalTime`. Quando um processo ocupa a CPU, ele permanece lá até completar seu burst de CPU atual — sem interrupções.
### Exemplo
```
P1: chegada=0, CPU: 4 ticks
P2: chegada=1, CPU: 3 ticks
P3: chegada=2, CPU: 1 tick
Gantt: | P1 P1 P1 P1 | P2 P2 P2 | P3 |
Tick: 0 1 2 3 4 5 6 7
```
| Processo | Turnaround | Waiting |
|----------|:----------:|:-------:|
| P1 | 4 | 0 |
| P2 | 6 | 3 |
| P3 | 6 | 5 |
### Observação: Efeito de Comboio
Se um processo longo chega antes de vários processos curtos, estes ficam esperando por muito tempo — mesmo que a CPU esteja "disponível" para eles. Este fenômeno é chamado de **Convoy Effect** e é um dos principais problemas do FCFS. Experimente o preset `convoy_effect` para visualizá-lo.
---
## SJF — Shortest Job First (Não-Preemptivo)
**Tipo:** Não-preemptivo
### Como funciona
Ao selecionar o próximo processo, o SJF escolhe aquele com o **menor burst de CPU restante** na fila Ready. Uma vez na CPU, o processo não é interrompido até completar seu burst.
O SJF é ótimo para minimizar o tempo médio de espera, mas tem um problema prático: em sistemas reais, a duração dos bursts futuros é desconhecida. No simulador, você define os bursts explicitamente, então o SJF pode ser aplicado perfeitamente.
### Parâmetros
Nenhum parâmetro adicional.
---
## SRTF — Shortest Remaining Time First (SJF Preemptivo)
**Tipo:** Preemptivo
### Como funciona
Versão preemptiva do SJF. A cada tick, o escalonador verifica se algum processo na fila Ready possui tempo de burst restante **menor** que o processo atualmente em execução. Se sim, ocorre uma preempção: o processo atual é devolvido à fila Ready e o novo candidato assume a CPU.
### Exemplo
```
P1: chegada=0, CPU: 8 ticks
P2: chegada=1, CPU: 4 ticks
Tick 0: P1 começa (remaining=8)
Tick 1: P2 chega (remaining=4 < 7) → preempção!
Tick 5: P2 termina → P1 retoma (remaining=7)
Tick 12: P1 termina
```
---
## Round Robin (RR)
**Tipo:** Preemptivo
**Parâmetro:** `quantum` (fatia de tempo, padrão: 2)
### Como funciona
A fila Ready é tratada como uma fila circular. Cada processo recebe no máximo `quantum` ticks de CPU consecutivos. Se ao final do quantum o processo ainda tiver burst restante, ele retorna ao **fim** da fila Ready e aguarda sua vez.
I/O bursts **não** consomem quantum — o processo sai voluntariamente da CPU quando inicia I/O.
### Tradeoff
Quanto menor o quantum, mais justo o revezamento, mas maior o overhead de context switches. Quanto maior, o RR se aproxima do FCFS.
---
## Priority Scheduling (Não-Preemptivo e Preemptivo)
**Tipo:** Não-preemptivo ou Preemptivo (selecione no painel)
**Parâmetros:** Aging (opcional) + intervalo de aging
### Como funciona
Cada processo tem uma prioridade de `1` (maior) a `10` (menor). O escalonador sempre seleciona o processo de maior prioridade na fila Ready.
- **Não-preemptivo:** uma vez na CPU, o processo termina seu burst sem ser interrompido.
- **Preemptivo:** se um processo de prioridade maior chegar, o atual é preemptado imediatamente.
### Starvation e Aging
O problema clássico do Priority Scheduling é o **starvation**: processos de baixa prioridade podem *nunca* receber a CPU se processos de alta prioridade chegam continuamente.
A solução é o **aging**: a cada `agingInterval` ticks que um processo permanece na fila Ready, sua prioridade é incrementada em 1 (ou seja, o valor numérico diminui), até o mínimo de `1`. Com o tempo, mesmo processos de baixa prioridade chegam à cabeça da fila.
Experimente os presets `starvation` e `aging_fix` para ver esta diferença.
---
## HRRN — Highest Response Ratio Next
**Tipo:** Não-preemptivo
### Como funciona
O HRRN tenta ser mais justo que o SJF levando em conta o tempo de espera do processo. A cada seleção, calcula-se o **Response Ratio** de cada processo na fila:
```
ratio = (waitingTime + burstTime) / burstTime
```
O processo com o **maior ratio** é selecionado. Isso faz com que processos que esperam há muito tempo tenham sua prioridade aumentada naturalmente, evitando starvation.
| Situação | Efeito no ratio |
|----------|----------------|
| Processo com burst curto | ratio alto desde o início |
| Processo esperando há muito tempo | ratio cresce com o tempo |
| Processo com burst longo + pouco wait | ratio baixo |
---
## Multilevel Queue
**Tipo:** Preemptivo
**Parâmetros:** número de filas, quantum por fila
### Como funciona
Os processos são distribuídos em múltiplas filas com diferentes prioridades. Cada fila tem seu próprio quantum de Round Robin. Filas de maior prioridade sempre são servidas primeiro — uma fila de menor prioridade só recebe CPU se todas as filas acima dela estiverem vazias.
Isso permite tratar diferentes classes de processos de forma distinta: por exemplo, processos interativos em filas de alta prioridade (quantum pequeno) e processos batch em filas de baixa prioridade (quantum maior).
---
## Referências
- Silberschatz, A., Galvin, P. B., & Gagne, G. — *Operating System Concepts*, 10ª edição
- Tanenbaum, A. S. — *Modern Operating Systems*, 4ª edição
+114
View File
@@ -0,0 +1,114 @@
# 📏 Métricas
O PSS calcula automaticamente um conjunto de métricas ao final (ou durante) a simulação. Este documento explica cada métrica, sua fórmula, o que ela representa e como lê-la nos gráficos.
---
## Métricas por Processo
Estas métricas são calculadas individualmente para cada processo simulado.
| Métrica | Fórmula | O que significa |
|---------|---------|----------------|
| **Arrival Time** | `arrivalTime` | Tick em que o processo entrou na fila Ready pela primeira vez |
| **First CPU Tick** | `startTick` | Tick em que o processo usou a CPU pela primeira vez |
| **Finish Time** | `finishTick` | Tick em que o processo encerrou sua execução |
| **Response Time** | `startTick − arrivalTime` | Quanto tempo o processo esperou antes de receber a CPU pela primeira vez |
| **Turnaround Time** | `finishTick − arrivalTime` | Tempo total de vida do processo (chegada → término) |
| **Waiting Time** | `turnaround − cpuTime − ioTime` | Tempo total na fila Ready (sem fazer nada útil) |
| **CPU Time** | Σ ticks em estado Running | Total de CPU efetivamente consumido |
| **I/O Time** | Σ ticks em estado Waiting | Total de tempo aguardando dispositivos de I/O |
| **CPU Utilization** | `cpuTime / turnaround × 100` | Percentual do turnaround em que o processo estava de fato usando CPU |
| **Bound Type** | ver abaixo | Classificação do processo como CPU Bound, I/O Bound ou Balanced |
### Visualização na tabela
Na aba **Por Processo**, cada linha exibe mini barras de progresso horizontais inline ao lado dos valores numéricos. As barras são proporcionais ao **maior valor da mesma métrica entre todos os processos**, permitindo comparação visual imediata:
| Coluna | Cor da barra |
|--------|-------------|
| Response Time | Âmbar |
| Turnaround Time | Azul |
| Waiting Time | Laranja |
| CPU Time | Esmeralda |
| I/O Time | Ciano |
| CPU Utilization | Gradiente violeta → azul |
---
## Métricas Globais
Calculadas sobre o conjunto completo de processos da simulação.
| Métrica | Fórmula |
|---------|---------|
| **Avg Response Time** | Média dos response times de todos os processos |
| **Avg Turnaround Time** | Média dos turnaround times |
| **Avg Waiting Time** | Média dos waiting times |
| **CPU Throughput** | `processos concluídos / tempo total de simulação` |
| **CPU Utilization (global)** | `Σ ticks em Running / tempo total × 100` |
| **Total Simulation Time** | Tick do último evento de término |
Na aba **Global**, cada card de tempo (Response, Turnaround, Waiting) exibe uma barra proporcional ao **tempo total de simulação**, indicando "quanto desse tempo total o processo médio passa nesse estado". A barra de CPU Utilization usa um gradiente âmbar → verde para indicar saúde da utilização.
---
## Classificação CPU Bound vs. I/O Bound
Ao final da simulação, cada processo é classificado automaticamente com base na proporção de tempo gasto em CPU e I/O:
```
cpuRatio = cpuTime / (cpuTime + ioTime)
ioRatio = ioTime / (cpuTime + ioTime)
cpuRatio ≥ 0.65 → CPU Bound
ioRatio ≥ 0.65 → I/O Bound
caso contrário → Balanced
```
- **CPU Bound:** o processo passa a maior parte do tempo usando o processador.
- **I/O Bound:** o processo passa a maior parte do tempo esperando dispositivos de entrada/saída.
- **Balanced:** o processo usa CPU e I/O de forma equilibrada.
> **Na lista de processos:** estimativa calculada sobre os bursts declarados (antes da simulação).
> **Na tabela de métricas:** classificação calculada sobre os tempos reais registrados.
---
## Gráficos (aba "Gráfico")
### Perfil Comparativo — Radar Chart
Exibido quando há **2 ou mais processos**. Cada eixo representa uma dimensão de tempo, normalizada de 0–100% em relação ao maior valor dessa dimensão entre todos os processos:
| Eixo | Significado |
|------|------------|
| **Turnaround** | Tempo total de vida relativo |
| **Response** | Tempo até a primeira CPU relativo |
| **Waiting** | Tempo na fila Ready relativo |
| **CPU Time** | Uso de CPU relativo |
| **I/O Time** | Uso de I/O relativo |
Cada processo é desenhado como um polígono colorido (a cor configurada no processo). Polígonos mais "amplos" indicam processos com tempos maiores nas dimensões correspondentes. O radar é ideal para identificar **diferenças de perfil** entre processos — por exemplo, um processo CPU Bound terá o eixo CPU Time muito maior que o eixo I/O Time.
### Breakdown por Processo — Stacked Bar Chart
Sempre exibido. Cada barra representa um processo, com os segmentos empilhados:
- **Âmbar** — Waiting Time
- **Verde** — CPU Time
- **Ciano** — I/O Time
A altura total de cada barra equivale ao **Turnaround Time** do processo.
---
## Exemplo
Considere três processos com os seguintes bursts:
| Processo | Bursts | cpuTime | ioTime | cpuRatio | Classificação |
|----------|--------|:-------:|:------:|:--------:|:-------------:|
| P1 | CPU:8, IO:1, CPU:1 | 9 | 1 | 90% | CPU Bound |
| P2 | CPU:1, IO:8, CPU:1 | 2 | 8 | 20% | I/O Bound |
| P3 | CPU:4, IO:2, CPU:4 | 8 | 2 | 80% | CPU Bound |