Estructura de datos del planificador CFS

En la sección anterior aprendimos sobre los principios de diseño del CFS, incluida la introducción del CFS, cómo el CFS logra la justicia y cómo funciona el CFS. En esta sección, nos enfocamos en analizar algunas estructuras de datos comunes involucradas en el planificador de CFS, hacer un resumen simple de estas estructuras de datos y clasificar la relación entre las diversas estructuras de datos.

Programación

El programador CFS se introdujo en Linux2.6.23. En ese momento, se propuso el concepto de clase de programación. La clase de programación es modularizar la estrategia de programación y tener una especie de sensación orientada a objetos. Primero observe la estructura de datos de la clase de programación, la clase de programación está representada por la estructura de datos de estructura sched_class

struct sched_class {
	const struct sched_class *next;

	void (*enqueue_task) (struct rq *rq, struct task_struct *p, int flags);
	void (*dequeue_task) (struct rq *rq, struct task_struct *p, int flags);

	void (*check_preempt_curr)(struct rq *rq, struct task_struct *p, int flags);

	/*
	 * It is the responsibility of the pick_next_task() method that will
	 * return the next task to call put_prev_task() on the @prev task or
	 * something equivalent.
	 *
	 * May return RETRY_TASK when it finds a higher prio class has runnable
	 * tasks.
	 */
	struct task_struct * (*pick_next_task)(struct rq *rq,
					       struct task_struct *prev,
					       struct rq_flags *rf);
	void (*put_prev_task)(struct rq *rq, struct task_struct *p);
	void (*set_curr_task)(struct rq *rq);
	void (*task_tick)(struct rq *rq, struct task_struct *p, int queued);

Debido a la gran cantidad de miembros sched_class, primero presentamos algunos de los más utilizados. Se puede ver que las clases de programación son básicamente punteros de función, y estos punteros de función respectivamente representan diferentes significados.

  • next se usa para señalar una clase de programación en el siguiente nivel. Se proporciona una clase de programación en el kernel para cada estrategia de programación, y estas clases de programación se vinculan entre sí a través del siguiente miembro
  • enqueue_task: se usa para agregar un proceso a la cola lista, al tiempo que aumenta el número de procesos que puede ejecutar
  • dequeue_task: se usa para eliminar un proceso de la cola lista mientras se reduce la cantidad de procesos que se pueden ejecutar
  • check_preempt_curr: se utiliza para detectar cuándo el estado de un proceso está configurado como ejecutable, verifique si el proceso actual puede ser adelantado
  • pick_next_task: selecciona el siguiente proceso más adecuado en la cola de ejecución para ejecutar
  • put_prev_task: obtiene el proceso antes del proceso actual
  • set_curr_task: se usa para establecer el estado de programación del proceso actual, etc.
  • task_tick: la función tick en cada clase de programación se programará en cada tic del reloj

El kernel de Linux proporciona esas clases de programación

extern const struct sched_class stop_sched_class;
extern const struct sched_class dl_sched_class;
extern const struct sched_class rt_sched_class;
extern const struct sched_class fair_sched_class;
extern const struct sched_class idle_sched_class;

 El kernel de Linux define cinco clases de programación, y cada programación tiene una estrategia de programación correspondiente, y cada estrategia de programación corresponde al lugar donde se programa el proceso.

/*
 * Scheduling policies
 */
#define SCHED_NORMAL		0
#define SCHED_FIFO		1
#define SCHED_RR		2
#define SCHED_BATCH		3
/* SCHED_ISO: reserved but not implemented yet */
#define SCHED_IDLE		5
#define SCHED_DEADLINE		6

También se proporcionan seis estrategias de programación. A continuación se muestra la relación entre las estrategias de programación y las clases de programación.

Programación Estrategia de programación Objeto de programación
stop_sched_class (detener la clase de programación) Ninguno Proceso de inactividad
dl_sched_class (clase de horario muerto) SCHED_DEADLINE proceso dl
rt_sched_class (clase de programación en tiempo real) SCHED_RR o SCHED_FIFO Proceso en tiempo real
fair_sched_class (clase de programación justa) SCHED_NORMAL o SCHED_BATCH Proceso ordinario
idle_sched_class (clase de programación inactiva) SCHED_IDLE proceso inactivo

Al mismo tiempo, existe una relación prioritaria entre estas clases de programación.

#ifdef CONFIG_SMP
#define sched_class_highest (&stop_sched_class)
#else
#define sched_class_highest (&dl_sched_class)
#endif
#define for_each_class(class) \
   for (class = sched_class_highest; class; class = class->next)

Si se define SMP, la prioridad más alta es la clase de parada de programación. Relación de prioridad de la clase de programación

stop_sched_class> dl_sched_class> rt_sched_class> fair_sched_class> idle_shced_class

Entidad de programación

struct sched_entity {
	/* For load-balancing: */
	struct load_weight		load;
	unsigned long			runnable_weight;
	struct rb_node			run_node;
	struct list_head		group_node;
	unsigned int			on_rq;

	u64				exec_start;
	u64				sum_exec_runtime;
	u64				vruntime;
	u64				prev_sum_exec_runtime;

	u64				nr_migrations;

	struct sched_statistics		statistics;

Desde Linux2.6.23, se introdujo el concepto de entidad de programación, que encapsula cierta información importante del proceso. En el algoritmo O (1) anterior, la unidad de programación es task_struct, y después de la introducción de la modularización de programación en Linux2.6.23, la unidad de programación se convierte en la entidad de programación sched_entity

  • la carga es el peso de este proceso
  • run_node: la programación CFS es administrar el proceso a través del árbol rojo-negro, este es el nodo del árbol rojo-negro
  • on_rq: cuando este valor es 1, significa que el proceso está en la cola en ejecución
  • exec_start: registra el tiempo cuando este proceso comienza a ejecutar tareas en la CPU
  • sum_exec_runtime: registra el tiempo total de ejecución de este proceso
  • vruntime: representa el tiempo de ejecución virtual del proceso
  • prev_sum_exec_runtime: registra el tiempo total de ejecución del proceso anterior
  • nr_migrations: número de migraciones de procesos durante el equilibrio de carga
  • estadísticas: estadísticas del proceso

Árbol rojo negro

Todos en el árbol rojo-negro ciertamente no son extraños. El valor del nodo en el lado izquierdo del árbol siempre es menor que el valor del lado derecho del árbol.

En los planificadores O (n) y O (1), la cola de ejecución se administra a través de una lista vinculada de matriz, y la estructura de datos anterior se descarta en la programación CFS, y se utiliza un árbol rojo-negro con el tiempo como valor clave. . La clave de tiempo es el tiempo de ejecución del proceso.

CFS mantiene una lección de árboles rojo-negros ordenados por tiempo.Todos los nodos de árbol rojo-negro se ordenan según el tiempo de ejecución del proceso como la clave. CFS siempre selecciona el nodo más a la izquierda de este árbol rojo y negro cada vez que lo programa, y ​​luego viene a programarlo. A medida que pasa el tiempo, el nodo en el extremo izquierdo se ejecuta como antes, y el tiempo de ejecución del proceso también aumenta. Estos procesos se agregan lentamente al lado derecho del árbol rojo-negro. Todos los procesos en este árbol se programarán en un viaje de ida y vuelta, para lograr la equidad.

Al mismo tiempo, CFS también mantiene el valor mínimo de vruntime cfs.min_vruntime en este árbol, y este valor está aumentando monotónicamente. Este valor se utiliza para rastrear el valor de vruntime más pequeño en la cola de ejecución.

Ejecutar cola

Hay una estructura de datos de estructura de cola de ejecución en cada CPU en el sistema. Esta estructura es una CPU PER. Cada CPU necesita dicha cola de ejecución para evitar que múltiples CPU accedan a una cola de ejecución simultáneamente.

/*
 * This is the main, per-CPU runqueue data structure.
 *
 * Locking rule: those places that want to lock multiple runqueues
 * (such as the load balancing or the thread migration code), lock
 * acquire operations must be ordered by ascending &runqueue.
 */
struct rq {

        unsigned int		nr_running;

	/* capture load from *all* tasks on this CPU: */
	struct load_weight	load;
	unsigned long		nr_load_updates;
	u64			nr_switches;

	struct cfs_rq		cfs;
	struct rt_rq		rt;
	struct dl_rq		dl;

Puede ver en los comentarios que struct rq es una variable por CPU.

  • nr_running: representa el número total de procesos en ejecución en esta cola de ejecución
  • carga: el peso de todos los procesos en esta CPU, los procesos que pueden ejecutarse en esta CPU incluyen procesos en tiempo real, procesos ordinarios, etc.
  • nr_switches: estadísticas de cambio de proceso
  • struct cfs_rq: es una cola de ejecución de la clase de programación CFS
  • struct rt_rq: representa la cola de ejecución de la clase de planificación rt
  • struct dl_rq: representa la cola de ejecución de la clase de programación dl

Una conclusión que se puede extraer es que una estructura rq incluye varios tipos de procesos, incluidos DL, en tiempo real y ordinarios. Al suspender diferentes procesos a diferentes gestión de colas de ejecución.

/* CFS-related fields in a runqueue */
struct cfs_rq {
	struct load_weight	load;
	unsigned long		runnable_weight;
	unsigned int		nr_running;
	unsigned int		h_nr_running;

	u64			exec_clock;
	u64			min_vruntime;

A partir de los comentarios, struct cfs_rq representa la cola de ejecución correspondiente a la estrategia de programación CFS

  • carga: es el peso de este CFS_rq y contiene todos los procesos en la cola lista CFS
  • nr_running: representa el número de procesos que se pueden ejecutar en esta cola de ejecución CFS
  • min_vruntime: este valor representa el tiempo de ejecución mínimo de todos los procesos en la cola de ejecución CFS

Mire el diagrama de relación de la cola de ejecución

Hay una cola de ejecución de struct rq en cada CPU. La estructura de rq se divide en diferentes colas de ejecución de acuerdo con la estrategia de programación de procesos. Por ejemplo, los procesos ordinarios se montarán en cfs_rq. En struct cfs_rq, se define cada entidad de programación. Se agrega una entidad de programación a los nodos del árbol rojo-negro de acuerdo con el valor de vruntime.

187 artículos originales publicados · ganó 108 · 370,000 visitas

Supongo que te gusta

Origin blog.csdn.net/longwang155069/article/details/104551212
Recomendado
Clasificación