Escalonamento no Linux
Crístian Deives
Priscila Sabóia
Sumário
- Introdução;
- Conceitos básicos de escalonamento
- Escalonamento no Linux
- Kernel 1.0;
- Kernel 2.4;
- Kernel 2.6;
- Kernel 2.6.23;
- Referências;
Introdução
- Sistemas Operacionais Multitarefa
- Ilusão: múltiplos processo (programas) executando simultaneamente
- Quando a troca de processos ocorrerá?
- Qual será o próximo processo da vez?
Básico do Escalonador
- O escalonador precisa garantir que o processo seja executado em certo período de tempo.
- Geralmente a mais alta prioridade no processo de um sistema
- Processos que passam a maior parte do seu tempo à espera de dados ou provenientes do disco
- Processos que consomem muito tempo de CPU
Básico do Escalonador
- Time slice
- Quantidade máxima de tempo que um processo pode usar a CPU
- Preempção
- Quando a execução de um processo apto é interrompida de forma a executar um outro processo de maior prioridade
Básico do Escalonador
- Prioridade
- Cada thread tem uma prioridade padrão
- Pode ser alterada por uma chamada ao sistema nice(valor) [ p = p - valor]
- A intenção é que a qualidade do serviço seja aproximadamente proporcional à prioridade
- Quantum
- Nº de tiques de relógio que a thread pode executar de modo contínuo
Processos/Threads no Linux
- As threads são processos simples que devem compartilhar certos recursos;
- Um processo é um grupo de threads que compartilham algo chamado ID de grupo de threads (TGID) e outros recursos necessários;
- O termo "tarefa" estará relacionado ao termo thread para se ajustar ao tratamento que o Linux dá aos termos threads e processos.
- O Linux considera que os processos só existem enquanto grupos de threads e não há diferença entre os dois.
- O Linux escalona apenas theads.
Processos/Threads no Linux
- Estrutura da tarefa: task_struct
- Existe uma para cada thread;
- A TGID que é um PID POSIX do processo é armazenada como [task_struct]->tgid;
- Linux determina PIDs únicos para cada thread
- O PID (POSIX) é na realidade o TGID das tarefas.
Mecanismo X Política
- O SO não conhece as necessidades das aplicações suficientemente para tomar as decisões mais apropriadas.
- O SO permite flexibilidade através de alguns mecanismos:
- Algoritmos de escalonamento parametrizáveis
- Os processos selecionam as políticas
- Ex.: valor nice
Metas do escalonador Linux
- Eficiência
- Interatividade
- Justiça e Prevenção de Starvation
- Escalonamento de Tempo-Real
Eficiência
- Comutação de contexto é caro
- Permitir a execução de tarefas por longos períodos de tempo aumenta a eficiência.
- Código do escalonador é executado muito freqüentemente
- A sua própria velocidade é um fator importante na eficiência.
- Quando há mais de um processador, distribuir as tarefas proporcionalmente entre eles.
- Eficiência pode ser prejudicada por causa de outros objetivos, como a interatividade.
- Ter mais interatividade significa ter mais freqüentes trocas de contexto.
- O escalonador deve cumprir todos os outros requisitos para ter uma eficiência global.
Interatividade
- Crescente esforço para otimizar o Linux para desktop.
- Compilar um programa X clique do mouse
Justiça e Prevenção de starvation
- Starvation acontece quando uma thread não está autorizada a funcionar durante um período de tempo longo, devido à priorização de outras threads sobre ele.
- Algumas threads são autorizadas a ter um nível consideravelmente maior prioridade do que outras baseadas em valores definidos pelo usuário - e / ou indicadores de heurísticas.
Justiça e Prevenção de starvation
- Threads que estão próximas a um limiar de starvation (definida na
implementação do escalonador) devem obter um aumento significativo da
prioridade ou uma preempção imediata antes do starvation.
- Justiça
- Nenhuma thread deve sempre ser privada de CPU ou estar apta a enganar
o escalonador de forma a lhe dar mais prioridade ou tempo de CPU que
ela deveria ter.
Escalonamento de Tempo-Real
- O escalonador do Linux suporta um escalonamento tempo real (RT) suave.
- Isso significa que ele pode efetivamente agendar tarefas que têm requisitos rigorosos de tempo.
- O kernel Linux 2.6.x é geralmente capaz de responder a muitos prazos rigorosos, mas não garante que os prazos serão cumpridos.
Escalonador do kernel 1.0.x
- Escalonamento baseado em threads
- Threads no Linux são threads de núcleo
- Toda tarefa pega um número fixo de tiques, por padrão 15.
- Considerando que o relógio executa a 100 Hz, cada tique equivale a 10ms (instante)
- Prioridade = quantum = número de tiques
- A cada interrupção de relógio o contador da tarefa corrente é decrescido, e quando o contador chega a zero, a flag 'need_resched' é configurada.
Atualização do quantum
if (current == task[0] || (--current->counter) <= 0) {
current->counter = 0;
need_resched = 1;
}
Escalonador do kernel 1.0.x
- O escalonador verifica todos os processos, seleciona o que tem o maior número de tiques, e deixa-o executar. Tempo O(n).
- Época
- Período no qual todas as tarefas executam durante suas respectivas fatias de tempo;
- As fatias de tempo são calculadas no início de cada época
- Se todos os processos prontos têm zero tiques restantes, o escalonador realiza o algoritmo do envelhecimento (aging algorithm) e tenta novamente.
Escalonador do kernel 1.0.x
if ((p = p->next_task) == &init_task)
goto confuse_gcc2;
if (p->state == TASK_RUNNING && p->counter > c)
c = p->counter, next = p;
}
...
if (!c) {
for_each_task(p)
p->counter = (p->counter >> 1) + p->priority;
}
Escalonador do kernel 1.0.x
- A função 'wake_up()' também configura a flag 'need_resched' se a tarefa despertada tem o contador de tiques maior que o da tarefa corrente em execução
- Forma de melhorar o tempo de resposta para as tarefas I/O
Escalonador do kernel 1.0.x
void wake_up(struct wait_queue **q)
…
if ((p = tmp->task) != NULL) {
if ((p->state == TASK_UNINTERRUPTIBLE) ||
(p->state == TASK_INTERRUPTIBLE)) {
p->state = TASK_RUNNING;
if (p->counter > current->counter)
need_resched = 1;
}
}
…
Escalonador do kernel 1.0.x
- Pra época era suficiente, o Linux também era somente console.
- 6 processos por segundo e se um deles era processo de interface gráfica, o usuário teria que esperar quase um segundo pra ver o mouse se mexer.
- Com a evolução do hardware e das aplicações, (i.e. com interface gráfica), o escalonador teve que ser melhorado.
Escalonamento - kernel 2.4
- Poucas diferenças em relação ao algoritmo anterior;
- Principais diferenças:
- Classes de escalonamento;
- Conceito de "bondade";
Escalonamento - kernel 2.4
- Três classes de threads:
- FIFO de tempo real
- Alternância circular de tempo real
- Tempo compartilhado
- A escolha do escalonador adequado é feita com base na classe de escalonamento
- Nenhuma dessas classes é realmente de tempo real
Classe de escalonamento
- Classe SCHED_FIFO:
- As tarefas associadas a esta classe são escalonadas usando uma política FCFS sem preempção e usando apenas suas prioridades estáticas (não há envelhecimento)
- Tarefa executa até bloquear por recursos ou liberar explicitamente o processador
- Classe SCHED_RR:
- Implementa uma política similar à anterior, com a inclusão da preempção por tempo. O valor do quantum é proporcional à prioridade atual de cada tarefa, variando de 10ms a 200ms.
Classe de escalonamento
- Classe SCHED_OTHER :
- Suporta tarefas interativas
- Tarefas desta classe somente são escalonadas se não houverem tarefas prontas nas classes SCHED_FIFO e SCHED_RR.
Escalonamento - kernel 2.4
- Bondade (goodness)
- Usada na decisão pela próxima tarefa a ser executada
- Depende da prioridade e do quantum
- Regra para calcular a bondade:
if (classe == tempo_real) bondade = 1000 + prioridade;if (classe == tempo_compartilhado && quantum > 0) bondade = quantum + prioridade;if (classe == tempo_compartilhado && quantum == 0) bondade = 0;Escalonamento - kernel 2.4
- O algoritmo de escalonamento
- Quando o escalonador é chamado, ele deve escolher a thread com maior bondade
- Enquanto a thread é executada a cada tique de relógio seu quantum é reduzido de 1
- A CPU é retirada da thread caso ocorra qualquer uma dessas condições:
- Seu quantum chegou a 0
- A thread foi bloqueada em E/S ou semáforo
- Uma thread criada previamente com uma bondade maior ficou pronta
Escalonamento - kernel 2.4
- O escalonador reinicializa o quantum de todas as threads prontas e bloqueadas quando as threads prontas têm quantum igual a zero
- Regra
- quantum = (quantum / 2) + prioridade
Escalonamento no kernel 2.6
- Complexidade O(1)
- O tempo de execução desse algoritmo não depende do número de tarefas existentes;
- Principal diferença em relação ao algoritmo de escalonamento anterior;
- Tenta identificar os processos interativos analisando o tempo médio de espera (sleep)
- Processos que dormem muito geralmente esperam por alguma entrada e, portanto, são considerados interativos;
- Código do algoritmo aproximadamente 3 vezes maior que o do kernel 2.4;
Algoritmo - kernel 2.6
- Estrutura de dados: array de prioridades;
- Contém todas as tarefas em execução separadas por prioridade;
- O escalonador escolhe sempre o array de maior prioridade
- Operação em tempo constante;
- As tarefas de mesma prioridade são alternadas em round-robin;
- Principal estrutura responsável pelo tempo O(1) do algoritmo;
Algoritmo - kernel 2.6
- Bitmap de prioridades
- unsigned long bitmap[MAX_PRIO + 1];
- Indica se existe pelo menos uma tarefa ativa por prioridade;
- Exemplo: se existirem apenas duas tarefas ativas na prioridade 3 e uma na prioridade 1, o bitmap deve ter a seguinte configuração: 010100000000...
- A busca pela maior prioridade que contém alguma tarefa ativa é feita através de uma função otimizada para achar o bit mais significativo do bitmap
- Operação em tempo constante;
Algoritmo - kernel 2.6
- Estrutura de dados: fila de execução;
- Mantém os processos que podem ser executador por um processador
- Uma fila de execução é criada e mantida pra cada processador existente no sistema;
- Cada fila de execução possui dois arrays de prioridades
- Lista ativa;
- Lista expirada;
- Serve para manter informações especiais das tarefas e os dois arrays de prioridade;
- É necessário obter um lock para poder alterar uma fila de execução;
Filas de execução e arrays de prioridades
Algoritmo - kernel 2.6
- Cada processo recebe uma fatia de tempo de acordo com sua prioridade estática
- Pode ser alterada através da chamada de sistema "nice()";
- p->static_prio;
- Quando um processo é criado, ele é movido para a lista ativa;
- Depois que um processo não-interativo termina de executar durante toda a sua fatia de tempo, ele é movido para a lista expirada;
- Os processos da lista expirada só serão executados quando todos os elementos da lista ativa tiverem sido executados;
Algoritmo - kernel 2.6
- Um processo interativo só é movido para a lista expirada em dois casos:
- Se o processo que estiver a mais tempo na lista expirada tiver esperado um tempo limite máximo;
- Se existir um processo na lista expirada cuja prioridade estática seja maior do que a do processo interativo;
- Dessa forma, o escalonador dá prioridade aos processos interativos e impede a ocorrência de starvation;
- Quando a lista ativa estiver vazia, a lista expirada passa a ser a nova lista ativa
- Operação em tempo constante;
- rq->active = rq->expired;
Escalonamento no kernel 2.6.23
- Reescrita completa do algoritmo de escalonamento;
- Algoritmo mais simples que o anterior;
- Não utiliza conceitos de:
- Tempo de sleep;
- Identificação de processo interativo;
- Fatia de tempo;
- Fila de execução;
- Array de prioridade;
- Utiliza árvore rubro-negra;
- Versão final foi liberada em 9 de outubro de 2007;
- Desenvolvido por Ingo Molnar;
Algoritmo - kernel 2.6.23
- Completely Fair Scheduler (CFS);
- De acordo com o autor:
- "80% do projeto do CFS pode ser resumido em uma única frase: CFS basicamente modela em hardware um processador ideal e precisamente multi-tarefa."
- Processador ideal:
- Executa vários processos em paralelo;
- Cada processo ocupa exatamente a mesma fração de energia do processador
- Se apenas um processo está sendo executado, ele ocupa 100% do processador;
- Se dois processos estão sendo executados, cada um ocupa 50% do processador;
- Se três processos estão sendo executados, cada um ocupa 33,3% do processador;
Algoritmo - kernel 2.6.23
- Mas na prática, apenas uma tarefa pode ser executada ao mesmo tempo
- Situação "injusta" para as outras tarefas que estão esperando pelo processador;
- O CFS torna o escalonamento "justo" através dos seguintes passos:
- Quando um processo espera pela CPU, é calculado o tempo que ele ocuparia em um processador ideal
- Tempo calculado = tempo de espera (em nanossegundos) / número de processos esperando pelo processador;
- Esse é o tempo de execução destinado ao processo
- Utilizado para classificar os processos no escalonamento;
Considerações - kernel 2.6.23
- Promete ser melhor que os algoritmos anteriores, para o caso geral;
- Ainda é muito recente
- Pode apresentar falhas;
- Não existe nenhum relatório detalhado de comparação com outros algoritmos de escalonamento;
Fim
Obrigado pela atenção! :-)