Índice
A parte conceitual apenas explica
CFS
o agendador
Destaques do Agendador CFS
conceito básico
Linux 2.6
Na minha opinião é uma versão relativamente perfeita, e 2.4
o 2.6
maior diferencial está na CFS
introdução do agendador
CFS
Devido à introdução da prioridade, cpu
a alocação de recursos (ou seja, o tempo de execução real runtime
) é alocada com base no peso. O mapeamento entre peso weight
e prioridade nice
é o seguinte: Prioridade e peso são inversamente proporcionais.
static const int prio_to_weight[40] = {
/* -20 */ 88761, 71755, 56483, 46273, 36291,
/* -15 */ 29154, 23254, 18705, 14949, 11916,
/* -10 */ 9548, 7620, 6100, 4904, 3906,
/* -5 */ 3121, 2501, 1991, 1586, 1277,
/* 0 */ 1024, 820, 655, 526, 423,
/* 5 */ 335, 272, 215, 172, 137,
/* 10 */ 110, 87, 70, 56, 45,
/* 15 */ 36, 29, 23, 18, 15,
};
O tempo real de execução runtime
é calculado como
tempo de execução = período do cronograma × pesoi / ∑ i = 1 npesoi ( i = 1 , 2... n ) tempo de execução = período do cronograma \times peso_i / \sum_{i=1}^{n} peso_i(i=1,2... n)corra o tempo _ _ _=período do cronograma _ _ _ _ _ _ _ _ _×nós pensamos _ _ _ _eu/eu = 1∑nãonós pensamos _ _ _ _eu( eu=1 ,2... n )
Um tempo de execução virtual é definido aquivruntime
vruntime = tempo de execução × (1024 / pesoi) vruntime = tempo de execução\times(1024/peso_i)v r u n time _ _=corra o tempo _ _ _×( 1024 / peso _ _ _ _eu)
A simplificação mostra que o peso de cada entidade escalonadora vruntime
não muda devido a mudanças no seu próprio peso. Portanto, do ponto de vista macro, o peso de cada entidade escalonadora vruntime
deve ser o mesmo em cada ciclo de escalonamento. Este é um estado ideal.
vruntime = período de programação × ( 1024 / ∑ i = 1 nweighti ( i = 1 , 2... n ) ) vruntime = período de programação \times (1024/\sum_{i=1}^{n} peso_i(i=1,2 ...n))v r u n time _ _=período do cronograma _ _ _ _ _ _ _ _ _×( 1024/eu = 1∑nãonós pensamos _ _ _ _eu( eu=1 ,2... n ))
Quando uma determinada entidade de agendamento entra no estado de bloqueio ou suspensão por algum motivo, ela desistirá ativamente do intervalo de tempo, fazendo com que ele permaneça vruntime
inalterado temporariamente, enquanto outras entidades de agendamento obtêm o intervalo de tempo e começam a executar, fazendo com que ele aumente vruntime
. cria uma assimetria, o que é injusto, então o vruntime
menor processo precisa ser agendado na próxima troca de processo.
Por que é completamente justo diferenciar a distribuição de alta e baixa prioridade
runtime
?
Como a justiça é baseada vruntime
na lógica de, e não runtime
na lógica de, cfs
ela garante que cada entidade de agendamento seja vruntime
igual. Se houver uma menor, vruntime
ela será agendada primeiro.
A prioridade mais alta é runtime
maior, a prioridade mais baixa runtime
é menor, mas é vruntime
a mesma coisa, então neste caso a prioridade mais baixa é na verdade o relógio tem uma taxa de decaimento mais alta
alguns problemas
vruntime
O valor inicial do novo processo é 0
?
- Quando o processo filho é criado,
vruntime
o valor inicial é primeiro definido comomin_vruntime
- Se os bits
sched_features
forem definidosSTART_DEBIT
,vruntime
elemin_vruntime
será aumentado com base em - Depois de definir o processo filho
vruntime
, verifiquesched_child_runs_first
os parâmetros. Se for 1, compare o processo pai e o processo filhovruntime
. Se o processo paivruntime
for menor, troque os processos pai e filhovruntime
. Isso garante que o processo filho estará antes do processo pai .correr
O valor do processo de hibernação vruntime
permanece inalterado?
Redefina vruntime
o valor quando o processo de hibernação for despertado e min_vruntime
dê uma certa compensação com base no valor, mas não muito.
O intervalo de tempo ocupado por um processo pode ser infinitamente pequeno?
CFS
Define o valor mínimo de tempo para o processo ocupar a CPU. sched_min_granularity_ns
Se o processo em execução na CPU for menor que esse tempo, ele não poderá ser transferido CPU
.
liuzixuan@10-60-73-159:~$ cat /proc/sys/kernel/sched_min_granularity_ns
1500000
Isso muda quando um processo é movido de um CPU
para outro ?CPU
vruntime
Quando um processo sai da fila de execução de uma CPU, ele vruntime
subtrai min_vruntime
o valor da fila; e quando um processo entra CPU
na fila de execução de outro, ele vruntime
adiciona min_vruntime
o valor dessa fila. Desta forma, os processos permanecem relativamente justos após CPU
a migração de um para outroCPU
vruntime
vruntime
O que devo fazer se ocorrer acumulação infinita e ocorrer transbordamento?
A árvore rubro-negra não é a menor da árvore rubro-negra key
. vruntime
Subtraia a menor para cercar todos os processos com o menor . Em outras palavras, apenas os tamanhos relativos são comparados.vruntime-min_vruntime
min_vruntime
key
vruntime
key
vruntime
static inline int less(u32 left, u32 right)
{
return (less_eq(left, right) && (mod(right) != mod(left)));
}
Código fonte e suplementos
Agendamento de aulas e estratégias de agendamento
Linux
Classe de agendamento: Aloque o poder de computação conforme necessário para fornecer o máximo de justiça a cada processo no sistema
fair_sched_class
:CFS
Agendador completamente justoidle_sched_class
: Cada processador possui um thread ocioso, ou seja,0
número de threadrt_sched_class
: Mantenha uma fila para cada prioridade de agendamento
struct sched_class {
const struct sched_class *next;
void (*enqueue_task) (struct rq *rq, struct task_struct *p, int wakeup);
void (*dequeue_task) (struct rq *rq, struct task_struct *p, int sleep);
void (*yield_task) (struct rq *rq);
void (*check_preempt_curr) (struct rq *rq, struct task_struct *p, int sync);
struct task_struct * (*pick_next_task) (struct rq *rq);
void (*put_prev_task) (struct rq *rq, struct task_struct *p);
#ifdef CONFIG_SMP
int (*select_task_rq)(struct task_struct *p, int sync);
unsigned long (*load_balance) (struct rq *this_rq, int this_cpu,
struct rq *busiest, unsigned long max_load_move,
struct sched_domain *sd, enum cpu_idle_type idle,
int *all_pinned, int *this_best_prio);
int (*move_one_task) (struct rq *this_rq, int this_cpu,
struct rq *busiest, struct sched_domain *sd,
enum cpu_idle_type idle);
void (*pre_schedule) (struct rq *this_rq, struct task_struct *task);
int (*needs_post_schedule) (struct rq *this_rq);
void (*post_schedule) (struct rq *this_rq);
void (*task_wake_up) (struct rq *this_rq, struct task_struct *task);
void (*set_cpus_allowed)(struct task_struct *p,
const struct cpumask *newmask);
void (*rq_online)(struct rq *rq);
void (*rq_offline)(struct rq *rq);
#endif
void (*set_curr_task) (struct rq *rq);
void (*task_tick) (struct rq *rq, struct task_struct *p, int queued);
void (*task_new) (struct rq *rq, struct task_struct *p);
void (*switched_from) (struct rq *this_rq, struct task_struct *task,
int running);
void (*switched_to) (struct rq *this_rq, struct task_struct *task,
int running);
void (*prio_changed) (struct rq *this_rq, struct task_struct *task,
int oldprio, int running);
#ifdef CONFIG_FAIR_GROUP_SCHED
void (*moved_group) (struct task_struct *p);
#endif
};
static const struct sched_class fair_sched_class; // 公开调度类
static const struct sched_class idle_sched_class; // 空闲调度类
static const struct sched_class rt_sched_class; // 实时调度类
Linux
Estratégia de escalonamento: decidir quando e como selecionar um novo processo para CPU
execução
SCHED_NORMAL
: Estratégia comum de escalonamento de processos, permitindo que entidades de escalonamento sejamcfs
executadas através do escalonadorSCHED_FIFO
: Estratégia de escalonamento de processos em tempo real, algoritmo de escalonamento primeiro a entrar, primeiro a sairSCHED_RR
: Estratégia de agendamento de processos em tempo real, algoritmo de rotação de intervalo de tempoSCHED_BATCH
: Estratégia de agendamento de processo comum, processamento em lote, para que as entidades de agendamentocfs
sejam executadas através do agendadorSCHED_IDLE
cfs
: Estratégia de escalonamento de processo comum, de modo que a entidade de escalonamento execute o escalonador com a prioridade mais baixa
#define SCHED_NORMAL 0
#define SCHED_FIFO 1
#define SCHED_RR 2
#define SCHED_BATCH 3
#define SCHED_IDLE 5
sched_getscheduler()
Uma determinada política de escalonamento de processos pode ser obtida através de chamadas de sistema
Classificação prioritária
Em relação à questão da prioridade , a prioridade é geralmente dividida em prioridade estática e prioridade dinâmica.
- Prioridade estática:
100
Usado para139
representar a prioridade estática de um processo comum. É usado para avaliar o grau de escalonamento entre este processo e outros processos comuns no sistema. Basicamente, determina o intervalo de tempo básico do processo. - Prioridade dinâmica:
100
Utilizada para139
representar a prioridade dinâmica de processos comuns, que é o número utilizado pelo escalonador ao selecionar um novo processo para execução.
Balanceamento de rq em sistemas multiprocessadores
Um princípio: nenhum processo executável pode aparecer em duas ou mais filas de execução ao mesmo tempo
Domínio de escalonamento: é um conjunto cuja carga de trabalho deve ser balanceada pelo kernel. Sua composição é semelhante a uma árvore raiz. Cada domínio de escalonamento é dividido em um ou mais grupos por vez, e cada grupo é um subconjunto cpu
do domínio de escalonamento pendente.cpu
Todos os descritores cpu
físicos do sistema são colocados em cada variávelsched_domain
cpu
phys_domains
static DEFINE_PER_CPU(struct static_sched_domain, phys_domains);
A inicialização deles está em cada diretório da máquina
/* sched_domains SD_NODE_INIT for SGI IP27 machines */
#define SD_NODE_INIT (struct sched_domain) {
\
.parent = NULL, \
.child = NULL, \
.groups = NULL, \
.min_interval = 8, \
.max_interval = 32, \
.busy_factor = 32, \
.imbalance_pct = 125, \
.cache_nice_tries = 1, \
.flags = SD_LOAD_BALANCE \
| SD_BALANCE_EXEC \
| SD_WAKE_BALANCE, \
.last_balance = jiffies, \
.balance_interval = 1, \
.nr_balance_failed = 0, \
}