Agendador Linux CFS: Princípio e Implementação

A parte conceitual apenas explica CFSo agendador

Destaques do Agendador CFS

conceito básico

Linux 2.6Na minha opinião é uma versão relativamente perfeita, e 2.4o 2.6maior diferencial está na CFSintrodução do agendador

CFSDevido à introdução da prioridade, cpua alocação de recursos (ou seja, o tempo de execução real runtime) é alocada com base no peso. O mapeamento entre peso weighte 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 = 1nã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 vruntimenão muda devido a mudanças no seu próprio peso. Portanto, do ponto de vista macro, o peso de cada entidade escalonadora vruntimedeve 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 = 1nã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 vruntimeinalterado 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 vruntimemenor 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 vruntimena lógica de, e não runtimena lógica de, cfsela garante que cada entidade de agendamento seja vruntimeigual. Se houver uma menor, vruntimeela será agendada primeiro.

A prioridade mais alta é runtimemaior, a prioridade mais baixa runtimeé menor, mas é vruntimea mesma coisa, então neste caso a prioridade mais baixa é na verdade o relógio tem uma taxa de decaimento mais alta

alguns problemas

vruntimeO valor inicial do novo processo é 0?

  • Quando o processo filho é criado, vruntimeo valor inicial é primeiro definido comomin_vruntime
  • Se os bits sched_featuresforem definidos START_DEBIT, vruntimeele min_vruntimeserá aumentado com base em
  • Depois de definir o processo filho vruntime, verifique sched_child_runs_firstos parâmetros. Se for 1, compare o processo pai e o processo filho vruntime. Se o processo pai vruntimefor menor, troque os processos pai e filho vruntime. Isso garante que o processo filho estará antes do processo pai .correr

O valor do processo de hibernação vruntimepermanece inalterado?

Redefina vruntimeo valor quando o processo de hibernação for despertado e min_vruntimedê uma certa compensação com base no valor, mas não muito.


O intervalo de tempo ocupado por um processo pode ser infinitamente pequeno?

CFSDefine 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 CPUpara outro ?CPUvruntime

Quando um processo sai da fila de execução de uma CPU, ele vruntimesubtrai min_vruntimeo valor da fila; e quando um processo entra CPUna fila de execução de outro, ele vruntimeadiciona min_vruntimeo valor dessa fila. Desta forma, os processos permanecem relativamente justos após CPUa migração de um para outroCPUvruntime


vruntimeO que devo fazer se ocorrer acumulação infinita e ocorrer transbordamento?

A árvore rubro-negra não é a menor da árvore rubro-negra key. vruntimeSubtraia a menor para cercar todos os processos com o menor . Em outras palavras, apenas os tamanhos relativos são comparados.vruntime-min_vruntimemin_vruntimekeyvruntimekeyvruntime

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

LinuxClasse 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: CFSAgendador completamente justo
  • idle_sched_class: Cada processador possui um thread ocioso, ou seja, 0número de thread
  • rt_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;    // 实时调度类

LinuxEstratégia de escalonamento: decidir quando e como selecionar um novo processo para CPUexecução

  • SCHED_NORMAL: Estratégia comum de escalonamento de processos, permitindo que entidades de escalonamento sejam cfsexecutadas através do escalonador
  • SCHED_FIFO: Estratégia de escalonamento de processos em tempo real, algoritmo de escalonamento primeiro a entrar, primeiro a sair
  • SCHED_RR: Estratégia de agendamento de processos em tempo real, algoritmo de rotação de intervalo de tempo
  • SCHED_BATCH: Estratégia de agendamento de processo comum, processamento em lote, para que as entidades de agendamento cfssejam executadas através do agendador
  • SCHED_IDLEcfs: 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: 100Usado para 139representar 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: 100Utilizada para 139representar 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 cpudo domínio de escalonamento pendente.cpu

Todos os descritores cpufísicos do sistema são colocados em cada variávelsched_domaincpuphys_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,			\
}

Acho que você gosta

Origin blog.csdn.net/qq_48322523/article/details/129255875
Recomendado
Clasificación