A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Process Scheduling Renato de Castro Dutra COPPE/UFRJ Jul/2006

Apresentações semelhantes


Apresentação em tema: "Process Scheduling Renato de Castro Dutra COPPE/UFRJ Jul/2006"— Transcrição da apresentação:

1 Process Scheduling Renato de Castro Dutra COPPE/UFRJ Jul/2006
Baseado no capítulo 4 do livro Linux Kernel Development 2nd Edition de Robert Love

2 Agenda Chaveamento de Contexto Linux kernel Escalonador System Calls
Discussão Futuro do Escalonador Referências Linux kernel Escalonador Runqueue Vetores de Prioridade Sleeping e Wakeup Balanceamento de Carga

3 1.1. Linux Kernel Linux Kernel 2.6.17.4 (estável)
Kernel tornou-se preemptivo no Kernel 2.5 Robert Love foi o principal articulador Linux Kernel 2.4 (estável) Kernel não-preemptivo O que é kernel preemptivo ?

4 1.2. Kernel Preemptivo Os processos são preemptivos (podem ser interrompidos) se um processo A entra no estado TASK_RUNNING (processo runnable), o kernel checa se a prioridade dinâmica do processo A é maior que a prioridade do processo que está rodando Se é, a execução do processo corrente é interrompida e o escalonador é chamado para selecionar um outro processo para rodar (normalmente, o processo A) Um processo também pode entrar em preempção se o timeslice expira (este valor é pré-determinado, calculado dinamicamente) Se isto ocorre, o campo need_resched do processo corrente fica ativo, e o escalonador é chamado quando o tempo do interrupt handler termina ( ou seja, kernel libera o interrupt) Processo preemptivo não é suspenso, desde que ele fica no estado TASK_RUNNING, apenas não usa CPU.

5 1.3. Escalonador Função – componente do Kernel que seleciona o processo que vai rodar primeiro Pode ser visto como o elemento que divide os recursos finitos do tempo do processador entre os processos com estado TASK_RUNNING É a base da multi-tarefa, dando a impressão de que vários processos estão rodando simultaneamente Três formas de escalonamento: FIFO RoundRobin Prioridade (calculada dinamicamente)

6 1.4. Escalonamento Baseado em Prioridade Dinâmica
Inicia com uma prioridade default e permite ao escalonador aumentar ou diminuir, dinamicamente, a prioridade de acordo com seus objetivos. Duas faixas de Prioridade: Nice Range (default = 0) Real-Time Range Um processo Real-Time tem sempre maior prioridade do que um processo normal! -20 +19 Prioridade baixa Máximo Timeslice Mínimo Timeslice +99 Prioridade baixa

7 1.5. Timeslice* Valor numérico que representa quanto tempo uma tarefa pode rodar até ser interrompida na preempção. Este valor de Timeslice é difícil de estimar, nem deve ser curto demais, nem longo demais… Curto – muito do tempo será perdido na troca de processos Longo – processos interativos vão se tornar tediosos Mínimo 5 ms Default 100 ms Máximo 800 ms baixa prioridade alta prioridade menos interativo mais interativo Processos não precisam gastar todo seu Timeslice em uma rodada somente. Pode rodar em pedaços separados. Ao fim do Timeslice o processo é considerado expirado e só poderá rodar após todos os Timeslices dos outros processos terem terminado. Então o escalonador fará uma nova atribuição de Timeslices. *Em alguns sistemas operacionais também chamado de quantum ou processor slice

8 1.6. Equação de Timeslice 164 #define SCALE_PRIO(x, prio) \
165 max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO/2), MIN_TIMESLICE) Por pior que seja a prioridade do processo, o menor valor de Timeslice será MIN_TIMESLICE = 5ms O processo pode quebrar seu Timeslice utilizando a função TIMESLICE_GRANULARITY: 135 #define TIMESLICE_GRANULARITY(p) (GRANULARITY * \ 136 (1 << (((MAX_BONUS - CURRENT_BONUS(p)) ? : 1) - 1)))

9 1.7. Objetivos para o Kernel 2.5
O(1) scheduler preemptive kernel latency improvements redesigned block layer improved VM subsystem improved threading support new sound layer

10 1.8. Objetivos para o Escalonador O(1)
Prover complexidade O(1) ! Escalabilidade SMP perfeita – Quando aumenta o número de processadores o escalonamento é escalável. Afinidade SMP melhorada – a troca de processos entre processadores apenas para fim de balanceamento da runqueue, evitando efeito “ping-pong”.

11 Escala linearmente com o número de processos !
2. Escalonador O(1) Escalonador O(1) – Decidir qual processo vai rodar em tempo constante, independente do número de processos. Antigamente O(N): Lista única de processos N: Para cada processo N runnable{ Acha a dignidade deste processo; Se (este é o processo mais digno ainda) { Lembra isto; } Roda o processo mais digno; Mesma prioridade -> Round Robin Escala linearmente com o número de processos !

12 2.1. Escalonador O(1) (cont.)
O(1) – utiliza Listas de Prioridade Pegue a Lista de Prioridade Mais Alta que tenha processos Pegue o primeiro processo desta Lista de Prioridade Mais Alta Rode este processo Como fazer isto ? Agradecimentos ao Ingo Molnar! 12 * New ultra-scalable O(1) scheduler by Ingo Molnar: 13 * hybrid priority-list and round-robin design with 14 * an array-switch method of distributing timeslices 15 * and per-CPU runqueues. Cleanups and useful suggestions 16 * by Davide Libenzi, preemptible kernel bits by Robert Love. Fonte: Linux-kernel-sched_c.htm

13 2.2. Gráfico O(N) x O(1) v.2.4 v.2.6 Fonte: Timo Hönig – Linux Magazin
1 CPU: Pentium III 1 GHz, 512 MByte RAM 2 CPU: Pentium III 850 MHz, 1 GByte RAM 4 CPU: Pentium III 700 MHz, 4 GByte RAM 8 CPU: Pentium III 700 MHz, 8 GByte RAM v.2.4 v.2.6

14 3. Runqueue Estrutura básica do Escalonador é a runqueue
É uma lista de processos runnable em um dado processador Adicionalmente contém informação de escalonamento por processador

15 3.1. Struct Runqueue 234 task_t *migration_thread;
235 struct list_head migration_queue; 236 #endif 237 238 #ifdef CONFIG_SCHEDSTATS 239 /* latency stats */ 240 struct sched_info rq_sched_info; 241 242 /* sys_sched_yield() stats */ 243 unsigned long yld_exp_empty; 244 unsigned long yld_act_empty; 245 unsigned long yld_both_empty; 246 unsigned long yld_cnt; 247 248 /* schedule() stats */ 249 unsigned long sched_noswitch; 250 unsigned long sched_switch; 251 unsigned long sched_cnt; 252 unsigned long sched_goidle; 253 254 /* pull_task() stats */ 255 unsigned long pt_gained[MAX_IDLE_TYPES]; 256 unsigned long pt_lost[MAX_IDLE_TYPES]; 257 258 /* active_load_balance() stats */ 259 unsigned long alb_cnt; 260 unsigned long alb_lost; 261 unsigned long alb_gained; 262 unsigned long alb_failed; 263 264 /* try_to_wake_up() stats */ 265 unsigned long ttwu_cnt; 266 unsigned long ttwu_attempts; 267 unsigned long ttwu_moved; 268 269 /* wake_up_new_task() stats */ 270 unsigned long wunt_cnt; 271 unsigned long wunt_moved; 272 273 /* sched_migrate_task() stats */ 274 unsigned long smt_cnt; 275 276 /* sched_balance_exec() stats */ 277 unsigned long sbe_cnt; 278 #endif 279 }; 198 struct runqueue { 199 spinlock_t lock; 200 201 /* 202 * nr_running and cpu_load should be in the same cacheline because 203 * remote CPUs use both these fields when doing load calculation. 204 */ 205 unsigned long nr_running; 206 #ifdef CONFIG_SMP 207 unsigned long cpu_load; 208 #endif 209 unsigned long long nr_switches; 210 211 /* 212 * This is part of a global counter where only the total sum 213 * over all CPUs matters. A task can increase this counter on 214 * one CPU and if it got migrated afterwards it may decrease 215 * it on another CPU. Always updated under the runqueue lock: 216 */ 217 unsigned long nr_uninterruptible; 218 219 unsigned long expired_timestamp; 220 unsigned long long timestamp_last_tick; 221 task_t *curr, *idle; 222 struct mm_struct *prev_mm; 223 prio_array_t *active, *expired, arrays[2]; 224 int best_expired_prio; 225 atomic_t nr_iowait; 226 227 #ifdef CONFIG_SMP 228 struct sched_domain *sd; 229 230 /* For active balancing */ 231 int active_balance; 232 int push_cpu; 233

16 3.2. Struct Runqueue Clean struct runqueue{
spinlock_t lock; /* spin lock that protects this runqueue */ unsigned long nr_running; /* number of runnable tasks */ unsigned long nr_switches; /* context switch count */ unsigned long expired_timestamp; /* time of last array swap */ unsigned long nr_uninterruptible;; /* uninterruptible tasks */ unsigned long long timestamp_last_tick; /* last scheduler tick */ struct task_struct *curr; /* currently running task */ struct tasl_struct *idel; /* this processor´s idle task */ struct mm_struct *prev_mm; /* mm_struct of last ran task */ struct prio_array *active; /* active priority array */ struct prio_array *expired; /* the expired priority array */ struct prio_array arrays[2]; /* the actual priority arrays */ struct tasl_strucut *migration_thread; /* migration thread */ struct list_head migration_queue; /* migration queue */ atomic_t nr_iowait; /* number of tasks waiting in I/O */ }; Antes de um runqueue ser manipulado deve ser protegido por um lock

17 3.3. Parênteses Escalabilidade SMP
Em máquinas uniprocessadas o escalonador O(1) de Ingor Molnat é muito bom, porém como resolver os problemas inerentes a escalonamento em SMP/NUMA ? Escalonamento Multiqueue SpinLock Balanceamento de Carga

18 3.4. Parênteses SMP, MPP, NUMA
Symmetric Multi-Processor Non-Uniform Memory Access Massively Parallel Processor

19 3.5. Parênteses Problemas Deadlock Formas de evitar: Starvation
Condições necessárias e suficientes para ocorrer: Exclusão Mútua – somente um processo pode usar um recurso por vez Hold-and-wait – processo pode bloquear um recurso enquanto aguarda Não preemptivo – recurso não pode ser removido de um processo rodando Ciclo no grafo – A -> B -> C -> A Formas de evitar: Prevention - Prevenir Avoidance - Evitar Detection - Detetar Starvation

20 3.6. Solução Multiqueue Scheduler

21 3.7. Afinidade entre SMP Versão 2.4 tinha um problema indesejável:
Um processo podia ficar pingando de um processador para outro (efeito “Ping-Pong”) Este problema foi solucionado também pelas runqueues por processador e garante a afinidade entre multi-processadores CPU time 1 time 2 time 3 time 4 time 5 Process A CPU 0 CPU 1 Process B

22 3.8. Lock Para garantir que somente um processador possa manipular concorrentemente a runqueue, esta é protegida por um lock. Assim, somente um processador pode executar o escalonador concorrentemente. É raro um processador diferente da origem da runqueue manipulá-lo, porém é possível. Funções de lock e unlock: task_rq_lock() task_rq_unlock() Para evitar deadlock o código deve sempre obter o lock na mesma ordem: pelo endereço de runqueues ascendente (cap. 8) v.2.4 v.2.6

23 4. Vetores de Prioridade Cada runqueue possui dois vetores de prioridade: Vetor de Prioridade Ativo Vetor de Prioridade Expirado São estes vetores que permitem que a complexidade do algoritmo seja O(1).

24 4.1. Vetores de Prioridade Cada vetor de prioridade contém uma fila de processos runnable por nível de prioridade. As filas contém listas de processos runnable em cada nível de prioridade O vetor de prioridade também contém um bitmap de prioridade usado para eficientemente descobrir a tarefa de mais alta prioridade no sistema. 185 struct prio_array { 186 unsigned int nr_active; 187 unsigned long bitmap[BITMAP_SIZE]; 188 struct list_head queue[MAX_PRIO]; 189 };

25 4.2. Vetores de Prioridade Cada vetor de prioridade contém um campo bitmap que tem ao menos um bit para toda prioridade no sistema. Inicialmente todos os bits são 0. Quando uma tarefa torna-se runnable, o bit correspondente à prioridade da tarefa no bitmap torna-se 1. O problema, então é achar, na tabela, o processo mais prioritário dos que tiverem bit 1. Como a tabela é estática porque o número de prioridades é fixo (140), esta busca tem complexidade constante e não depende do número de processos N. Cada vetor de prioridade também contém um vetor queue da struct list_head, uma fila para cada prioridade e contém todos os processos que têm o mesmo valor de prioridade (representado pela variável nr_active).

26 4.3. Recálculo de Timeslice
Sistemas antigos faziam esta tarefa em O(N). Devido aos vetores Ativo e Expirado, este recálculo não precisa ser feito em O(N). Vetor de Prioridade Ativo – contém todas as tarefas na runqueue associada em que o Timeslice não expirou. Vetor de Prioridade Expirado – contém todas as tarefas na runqueue associada em que o Timeslice expirou Quando o Timeslice da tarefa expira, este é movido para o vetor Expirado, porém, antes, seu Timeslice é recalculado.

27 4.4. Troca de Vetores Ativo / Expirado
2765 array = rq->active; 2766 if (unlikely(!array->nr_active)) { 2767 /* 2768 * Switch the active and expired arrays. 2769 */ 2770 schedstat_inc(rq, sched_switch); 2771 rq->active = rq->expired; 2772 rq->expired = array; 2773 array = rq->active; 2774 rq->expired_timestamp = 0; 2775 rq->best_expired_prio = MAX_PRIO;

28 4.5. Cálculo de Prioridade e Timeslice
Prioridade Dinâmica – leva em conta uma heurística porque não sabe se o processo é interativo ou não. Se o processo tem muito tempo inativo, é interativo. Se não, não é. Implementação -> guarda em sleep_avg (uma tabela) a razão entre o tempo dormindo e o tempo acordado para cada processo. Sleep_avg é incrementado quando o processo se torna runnable (até MAX_SLEEP_AVG) e decrementado a cada tick de tempo que o processo roda (até 0) Default = 10 ms MAX_SLEEP_AVG Bonus/penalty -5 +5

29 4.6. Cálculo de Prioridade e Timeslice
105 * Here are a few examples of different nice levels: 106 * 107 * TASK_INTERACTIVE(-20): [1, 1, 1, 1, 1, 1,1,1,1,0,0] 108 * TASK_INTERACTIVE(-10): [1,1,1,1,1,1,1,0,0,0,0] 109 * TASK_INTERACTIVE( 0): [1,1,1,1,0,0,0,0,0,0,0] 110 * TASK_INTERACTIVE( 10): [1,1,0,0,0,0,0,0,0,0,0] 111 * TASK_INTERACTIVE( 19): [0,0,0,0,0,0,0,0,0,0,0] 112 * 113 * (the X axis represents the possible dynamic 114 * priority range a task can explore, a value of '1' means the 115 * task is rated interactive.)

30 4.7. Cálculo de Prioridade e Timeslice
Timeslice é recalculado baseado na prioridade estática. Quando um novo filho é criado o pai e o filho dividem o Timeslice remanescente (como?) Quando o Timeslice expira, o escalonador inclui a tarefa no vetor Expirado, recalculando antes o Timeslice.

31 5. Sleeping e Wakeup

32 6. Balanceamento de Carga
load_balance() no Escalonador. Dois métodos de chamada: Quando a runqueue está vazia Pelo timer A cada 1ms quando o sistema está parado A cada 200ms quando não Em sistema uniprocessados não é compilado.

33 7. Chaveamento de Contexto
Manipulado pelo context_switch. Ocorre sempre que um novo processo é chamado para run. Executa dois trabalhos: Chama switch_mm() – troca o mapeamento de memória virtual do processo antigo para o novo Chama switch_to() – troca o estado do processador do processo novo para o antigo, envolvendo atualização de pilhas e registradores Utiliza uma flag need_resched para que o kernel chame o escalonador pis existe um processo novo para substituir o antigo Duas formas para ativar a flag Quando o timeslice de um processo expira o scheduler_tick() ativa a flag Quando um processo de maior prioridade acorda o try_to_wake_up() ativa a flag

34 8. SystemCalls Relacionadas com Escalonamento
Splice () e Tee() system calls (fonte: Abril/2006 – Linus Torvalds) Splice() é um read/write para um buffer do kernel diretamente. Tee() é um memcpy() de um buffer do Kernel para outro, sem copiar realmente, apenas incrementando ponteiros de referência. Existe um buffer do kernel aleatório no espaço do usuário e que o usuário tem controle (como é buffer do kernel, é mais eficiente). Pode fazer movimento de dado zero-copy. Exemplo: Direcionar dado de um socket para outro sem copiar isto no espaço do usuário. Assim, é possível direcionar dado que venha de um Encoder MPEG-4 e fazer um Tee() para duplicar o stream e escrever um dos streams para disco e outro para socket para um broadcast em tempo real, sem copiar fisicamente na memória. Aumentam a performance, porque agiliza os processos que precisam de leitura/escrita.

35 9. Discussão A versao é mais rápida em SMP (Symmetric Multi-Processor), porém em máquinas uniprocessadas rápidas (2GHz) esta diferença não é perceptível.

36 1GB Crucial Registered/ECC PC2700
9.1. Discussão Comparação entre Linux e Test System and Benchmarks Dual Xeon Test Box CPU 2x 3.2GHz Xeons w/ 1MB L3 Cache Motherboard MSI Master LS2 Chipset Intel E7505 Memory 1GB Crucial Registered/ECC PC2700 Storage Western Digital 400JB OS Gentoo Linux 1.4 What benchmarks will we run? picColor Image software compiling (MySQL source code compiled with make -j 4) mp3 encoding (BladeEnc) Apache Static HTML Apache PHP/MySQL MySQL Super Smack(SELECT and UPDATE) dbench v. 2.0 (file server performance)

37 9.2. Discussão

38 9.3. Discussão File Server

39 10. Futuro do Escalonador Scheduler Modes – classificar workloads em categorias e permitir que usuários root ajustem o comportamento do escalonador dinamicamente. Swappable Scheduler ( - usuário especifica qual escalonador deve ser usado dependendo da aplicação.

40 11. Referências Love, R., Linux Kernel Development – 2nd edition, Novell Press, June 2005. Bovet, D. P., Cesati, M. Understanding The Linux Kernel – 1st edition, O´Reilly, October 2000. Aas, J., Understanding the Linux kernel CPU Scheduler – Silicon Graphics Inc., February 2005. Cross Reference Linux – Linux/kernel/sched.c - Love, R., Introducing the 2.6 kernel – Linux Journal, may 2003 Heursch, A.C., Grambow, D., Roedel, D., Rzehak, H., Time-critical tasks in Linux 2.6 Concepts to increase the preemptability of the Linux kernel – Linux Automation Konferenz 2004 Ge, l. – Kernel Comparison: Web Serving on 2.4 and 2.6 – Linux Technology Center IBM – February 2004

41 12. Questão _______ Suponha que 5 processos, de P1 a P5, sejam sucessivamente submetidos para execução em intervalos de 1ut (unidade de tempo). O tempo estimado de serviço para os processos é respectivamente de: 5, 3, 4, 5 e 2ut, uma política de time slice de 2ut é igualmente usada para todos os processos, o critério de escalonamento adotado é o Round Robin e a estratégia para deadlock é a da detecção. a) Defina e compare as estratégias para: prevenir (prevention) evitar (avoidance) e detectar (detecion) deadlocks. b) Monte o gráfico e determine o turnaround dos processos. c) Determine o fator de eficiência do método (Ts/Tq).


Carregar ppt "Process Scheduling Renato de Castro Dutra COPPE/UFRJ Jul/2006"

Apresentações semelhantes


Anúncios Google