← Planificación de la CPU Bloque 10 · El planificador de Linux · Tema 39 de 44

Tema 39

CFS: el árbol y los plazos

En el tema anterior viste el vruntime. Ahora verás cómo CFS implementa el reparto equitativo en la práctica: el árbol rojinegro que mantiene los procesos ordenados por vruntime, la latencia objetivo que determina cuánto tiempo se ejecuta cada proceso, la granularidad mínima que evita cambios de contexto excesivos, y el camino hacia EEVDF, el sucesor de CFS.

1. El árbol rojinegro

CFS mantiene los procesos listos en un árbol rojinegro (red-black tree) ordenado por vruntime. El proceso con el menor vruntime está en el extremo izquierdo del árbol. La selección del siguiente proceso es O(1): basta con tomar el mínimo (el nodo más a la izquierda).

Un árbol rojinegro es un árbol binario de búsqueda balanceado. Garantiza que la altura del árbol es O(log n), donde n es el número de procesos. Esto asegura que la inserción y eliminación son O(log n).

El árbol se mantiene en la estructura struct cfs_rq (CFS runqueue) de cada CPU. Cada nodo del árbol es un struct sched_entity que representa a un proceso (o a un grupo de procesos).

¿Por qué rojinegro y no otro árbol?

El árbol rojinegro tiene un buen equilibrio entre simplicidad de implementación y garantías de rendimiento. Es auto-balanceado: después de cada inserción o eliminación, el árbol se rebalancea en O(log n). Es el mismo tipo de árbol que usan los mapas ordenados de muchos lenguajes de programación.

2. Por qué un árbol y no una cola

Una cola FIFO (como en FCFS) no funciona para CFS porque:

Un árbol rojinegro permite:

La alternativa (una lista ordenada) tendría inserción y eliminación en O(n), lo que sería demasiado lento con muchos procesos.

3. La latencia objetivo

La latencia objetivo (target latency) es el tiempo que CFS intenta que pase entre dos ejecuciones consecutivas del mismo proceso. Es el tiempo que un proceso debería esperar para recibir la CPU de nuevo.

Si hay n procesos listos y la latencia objetivo es T, cada proceso recibe T/n de tiempo de CPU. Por ejemplo, con 4 procesos y una latencia objetivo de 20 ms, cada proceso recibe 5 ms.

La latencia objetivo por defecto en Linux es de 6 ms (para sistemas de escritorio) y 12 ms (para servidores). Se puede ajustar con el parámetro sched_latency_ns en /proc/sys/kernel/.

La latencia objetivo determina el equilibrio entre respuesta y overhead:

4. La granularidad mínima

La granularidad mínima (min granularity) es el tiempo mínimo que un proceso puede ejecutarse antes de ser preemptado. Evita que el tiempo de ejecución sea tan corto que el overhead de cambios de contexto sea excesivo.

Si la latencia objetivo dividida por el número de procesos es menor que la granularidad mínima, se usa la granularidad mínima. Por ejemplo, con 100 procesos y una latencia objetivo de 20 ms, cada proceso recibiría 0,2 ms. Si la granularidad mínima es 0,75 ms, cada proceso recibe 0,75 ms y la latencia real es 75 ms.

La granularidad mínima por defecto en Linux es de 0,75 ms (para sistemas de escritorio) y 1,5 ms (para servidores). Se ajusta con sched_min_granularity_ns.

La granularidad mínima protege contra el overhead

Sin la granularidad mínima, con muchos procesos, el tiempo de ejecución sería tan corto que el overhead de cambios de contexto dominaría. La granularidad mínima asegura que cada proceso reciba al menos un tiempo mínimo de CPU.

5. Cómo se calcula el tiempo de ejecución

El tiempo de ejecución de un proceso en CFS se calcula así:

  1. Calcular el tiempo ideal: tiempo_ideal = latencia_objetivo / número_de_procesos. ideal
  2. Aplicar la granularidad mínima: si tiempo_ideal < granularidad_mínima, usar granularidad_mínima. granularidad
  3. Ajustar por peso: el tiempo real se ajusta por el peso del proceso (a través del vruntime). peso

El tiempo de ejecución no es un quantum fijo: se recalcula cada vez que cambia el número de procesos (cuando uno llega o termina). Esto hace que CFS se adapte automáticamente a la carga.

6. Un ejemplo desarrollado

4 procesos listos, latencia objetivo = 20 ms, granularidad mínima = 0,75 ms:

Si llega un quinto proceso:

Si hay 100 procesos:

La latencia objetivo (20 ms) no se cumple con 100 procesos: la latencia real es 75 ms. Esto es un trade-off: con muchos procesos, la latencia real aumenta porque no se puede dar a cada uno menos que la granularidad mínima.

7. Plazos y garantías

CFS no ofrece garantías de plazo como los sistemas de tiempo real. No hay plazos explícitos ni verificación de planificabilidad. Sin embargo, la latencia objetivo proporciona una garantía informal: cada proceso recibirá la CPU al menos cada T unidades de tiempo (donde T es la latencia objetivo o la latencia real, lo que sea mayor).

Esta garantía es «blanda»: no es formal ni verificable, pero en la práctica proporciona una respuesta razonable para los procesos interactivos.

8. El camino hacia EEVDF

En 2023, Linux introdujo EEVDF (Earliest Eligible Virtual Deadline First) como sucesor de CFS. EEVDF mantiene la idea del vruntime pero añade el concepto de plazo virtual (virtual deadline).

En CFS, el planificador solo mira el vruntime para elegir el siguiente proceso. En EEVDF, mira tanto el vruntime (para equidad) como el plazo virtual (para latencia). Esto permite que EEVDF ofrezca mejores garantías de latencia sin sacrificar la equidad.

EEVDF es una evolución de CFS, no un reemplazo completo. Mantiene la misma estructura (árbol rojinegro, vruntime) pero añade información adicional a cada nodo.

9. Qué es EEVDF

EEVDF (Earliest Eligible Virtual Deadline First) es un algoritmo de planificación que combina la equidad de CFS (vruntime) con la garantía de latencia de EDF (plazos). Cada proceso tiene un vruntime (para equidad) y un plazo virtual (para latencia). El planificador elige el proceso elegible (vruntime ≤ vruntime mínimo) con el plazo virtual más cercano.

El concepto de «elegibilidad» es clave: un proceso es elegible si su vruntime es ≤ el vruntime mínimo de todos los procesos. Esto garantiza que un proceso no se ejecute antes de que le toque (equidad). Entre los procesos elegibles, se elige el que tiene el plazo virtual más cercano (latencia).

EEVDF resuelve un problema de CFS: en CFS, un proceso con vruntime muy bajo (porque esperó mucho) puede acaparar la CPU, perjudicando a otros. EEVDF limita esto con el plazo virtual: un proceso solo puede ejecutarse hasta su plazo virtual.

10. CFS vs EEVDF

AspectoCFSEEVDF
Criterio de selecciónMenor vruntimeMenor plazo virtual (entre elegibles)
EquidadSí (vruntime)Sí (vruntime + elegibilidad)
LatenciaInformal (latencia objetivo)Formal (plazo virtual)
ComplejidadMediaMayor
Uso en LinuxHasta 6.6Desde 6.6

EEVDF es una evolución, no un reemplazo. Mantiene las mismas estructuras y conceptos, pero añade el plazo virtual para mejorar la latencia.

11. Observar en Linux

terminal · parámetros de CFS/EEVDF
# Ver la latencia objetivo
$ cat /proc/sys/kernel/sched_latency_ns
6000000

# Ver la granularidad mínima
$ cat /proc/sys/kernel/sched_min_granularity_ns
750000

# Ver si se usa EEVDF
$ uname -r
6.6.87-microsoft-standard-WSL2

# Ver el vruntime de un proceso
$ grep vruntime /proc/self/sched
vruntime                                      :                 12345.67

12. Resumen

13. Preguntas de repaso

Intenta responder cada una antes de abrir la respuesta.

1. ¿Qué estructura de datos usa CFS?

Un árbol rojinegro (red-black tree) ordenado por vruntime.

2. ¿Qué es la latencia objetivo?

El tiempo que CFS intenta que pase entre dos ejecuciones consecutivas del mismo proceso.

3. ¿Qué es la granularidad mínima?

El tiempo mínimo que un proceso puede ejecutarse antes de ser preemptado.

4. ¿Cómo se calcula el tiempo de ejecución?

latencia_objetivo / número_de_procesos, con mínimo de granularidad.

5. ¿Qué es EEVDF?

Earliest Eligible Virtual Deadline First: combina equidad (vruntime) con latencia (plazo virtual).

6. ¿Qué añade EEVDF a CFS?

El concepto de plazo virtual y elegibilidad.

7. ¿Cuándo se usa la granularidad mínima?

Cuando la latencia objetivo / n es menor que la granularidad mínima.

8. ¿Qué parámetro controla la latencia objetivo en Linux?

sched_latency_ns en /proc/sys/kernel/.

9. ¿Qué versión de Linux introdujo EEVDF?

Linux 6.6.

10. ¿Es EEVDF un reemplazo completo de CFS?

No, es una evolución. Mantiene las mismas estructuras y conceptos.

Para practicar

  1. Calcula el tiempo de ejecución para 4 procesos con latencia 20 ms y granularidad 0,75 ms.
  2. Explica qué ocurre con 100 procesos.
  3. Verifica la latencia objetivo de tu sistema con /proc/sys/kernel/sched_latency_ns.
  4. Investiga cómo se implementa el árbol rojinegro en el código del núcleo.
  5. Explica la diferencia entre CFS y EEVDF.
  6. Investiga qué cambios introdujo EEVDF en el código de Linux.