MLFQ, O(1) y CFS: el scheduler de Linux
🎯 Al terminar podrás
- Describir una cola multinivel y una MLFQ con sus 5 parámetros, y simular una MLFQ a mano.
- Explicar el scheduler O(1) de Linux: 140 niveles y las colas active y expired.
- Explicar CFS: qué es
vruntime, por qué se usa un árbol rojo-negro y cómo influye elnice. - Seguir la traza CFS/MLFQ de la sem. 12 y predecir el próximo paso.
Antes necesitas: Algoritmos a mano (RR y prioridad)
- Visual mira el diagrama o la tabla y explica qué cambia en cada paso
- Simulador predice el estado antes de pulsar el paso siguiente
- Feynman explícalo en voz alta sin mirar y compara con la lista
Colas multinivel (MLQ)
Sección titulada «Colas multinivel (MLQ)»La cola de listos se parte en varias colas, cada una con su algoritmo. Por ejemplo, la de primer plano (interactivos) con RR y la de fondo (batch) con FCFS. El proceso queda fijo en su cola. Entre colas hay que decidir también:
- Prioridad fija: primero se atiende toda la cola de primer plano y después la de fondo. Hay riesgo de starvation.
- Reparto de tiempo: cada cola recibe una fracción de la CPU, por ejemplo 80 % para primer plano con RR y 20 % para fondo con FCFS.
Colas multinivel con realimentación (MLFQ)
Sección titulada «Colas multinivel con realimentación (MLFQ)»Ahora el proceso puede moverse entre colas, y así se implementa también el aging. Una MLFQ queda definida por 5 parámetros:
- el número de colas;
- el algoritmo de cada cola;
- cuándo subir (promover) un proceso;
- cuándo bajarlo (degradar);
- en qué cola entra un proceso nuevo o que vuelve de una E/S.
Ejemplo de las diapositivas: Q0 es RR con 8 ms, Q1 es RR con 16 ms y Q2 es FCFS. Un trabajo nuevo entra a Q0; si no termina en 8 ms, baja a Q1; si no termina en 16 ms más, baja a Q2. Una cola inferior solo se atiende si las superiores están vacías.
Por qué favorece a los IO-bound: un proceso interactivo usa la CPU un instante y se bloquea antes de agotar el quantum, así que no baja y sigue en la cola rápida. Uno CPU-bound agota quantum tras quantum y se hunde. MLFQ aprende el tipo de proceso por su historia, sin conocer las ráfagas por adelantado.
Varias CPUs: balanceo de carga
Sección titulada «Varias CPUs: balanceo de carga»Con multiprocesadores simétricos (SMP) hay que mantener todas las CPUs ocupadas:
- Push migration: una tarea periódica revisa la carga de cada CPU y empuja procesos de las sobrecargadas a las libres.
- Pull migration: una CPU desocupada jala un proceso que espera en otra.
El hyperthreading (varios hilos por núcleo) aprovecha los memory stalls: mientras un hilo espera un dato de memoria, el otro avanza.
Linux O(1) (antes de 2.6.23)
Sección titulada «Linux O(1) (antes de 2.6.23)»| Idea | Detalle |
|---|---|
| Parecido a MLFQ | 140 niveles de prioridad: 0–99 de tiempo real/kernel y 100–139 de usuario |
| Todo en O(1) | elegir, insertar y quitar no dependen del número de procesos |
| Active / expired | en cada nivel hay una cola active y otra expired; el que agota su quantum pasa a expired; cuando active se vacía, se intercambian los punteros |
| RR dentro de cada cola | con quanta distintos según el nivel |
| Heurísticas | sube la prioridad a los IO-bound y a los que sufren starvation; muchas reglas ad hoc |
Antes de eso (Linux 2.4) la cola de listos no estaba ordenada: insertar era O(1), pero elegir exigía recorrerla entera, O(n), con un único lock. En multinúcleo, ese lock generaba mucha contención.
CFS (Linux 2.6.23 en adelante)
Sección titulada «CFS (Linux 2.6.23 en adelante)»- Cada tarea lleva su
vruntime: el tiempo de CPU que recibió, ponderado por su prioridad. - Siguiente tarea = la de menor
vruntime. - Las tareas listas de cada núcleo están en un árbol rojo-negro ordenado por
vruntime. La siguiente es el nodo más a la izquierda. Insertar y quitar cuestan O(log N). - Una tarea nueva recibe el
vruntimemínimo del árbol: corre pronto, pero no acapara la CPU, porque en seguida otra tendrá el mínimo. - No hay quantum fijo: se calcula una target latency (el intervalo en el que cada tarea debería correr al menos una vez) que crece si hay muchas tareas.
- Hay clases de scheduling con prioridad entre ellas: primero tiempo real y después la clase normal (CFS).
- Un árbol por núcleo evita la contención de locks entre núcleos, pero obliga a balancear la carga.
El ejemplo clásico: un render de video y un procesador de texto empiezan con vruntime 0. El render acumula vruntime sin parar; el editor casi no, porque pasa bloqueado esperando el teclado. Cuando llega una tecla, el editor despierta como el nodo más a la izquierda y corre de inmediato. CFS favorece a los interactivos sin heurísticas especiales.
Prioridades con nice
Sección titulada «Prioridades con nice»nice va de −20 (más prioridad) a +19 (menos). Cada tarea tiene un peso (la tabla prio_to_weight: nice 0 = 1024, nice 1 = 820, nice 5 = 335, nice −5 = 3121…) y el vruntime crece así:
- nice = 0: el
vruntimecrece igual que el tiempo real. - nice < 0: crece más lento (peso mayor), así que la tarea sigue siendo «la más a la izquierda» por más tiempo y recibe más CPU.
- nice > 0: crece más rápido, y recibe menos CPU.
Cada nivel de nice cambia la CPU en ≈ 10 % (multiplicador ≈ 1.25 entre niveles).
Peldaño 2 · Complétalofaltan pasos clave: llénalos tú
Complétalo: dos tareas CPU-bound, nice 0 y nice 1
Pesos: 1024 y 820. A largo plazo cada una recibe CPU en proporción a su peso. La de nice 0 recibe 1024 / (1024 + 820) = ? y la de nice 1, ?
Comparar
1024 / 1844 ≈ 55.5 % y 820 / 1844 ≈ 44.5 %. La diferencia relativa es 1024/820 ≈ 1.25: el «10 % por nivel» del comentario del kernel (−10 % para una, +10 % para la otra, ≈ 25 % de distancia entre ambas).
Peldaño 3 · Solosin ayuda; luego compara
Solo: ¿cuánto sube el vruntime en 10 ms de CPU?
Calcula Δvruntime para una tarea con nice 5 (peso 335) y otra con nice −5 (peso 3121).
Comparar
- nice 5: 10 × 1024 / 335 ≈ 30.6 ms virtuales. Avanza tres veces más rápido que el reloj, así que pronto deja de ser la menor.
- nice −5: 10 × 1024 / 3121 ≈ 3.3 ms virtuales. Puede correr unas tres veces más antes de que otra la alcance.
Las diapositivas cierran con EEVDF, el reemplazo de CFS (Linux 6.6 en adelante), sin entrar en detalle.
La traza CFS/MLFQ de la sem. 12, explicada
Sección titulada «La traza CFS/MLFQ de la sem. 12, explicada»Los datos iniciales que se deducen de la traza (la suma de lo ejecutado por cada tarea) son:
| Tarea | vruntime inicial | Ráfaga total |
|---|---|---|
| T1 | 10 | 15 ms |
| T2 | 5 | 10 ms |
| T3 | 15 | 20 ms |
| T4 | 8 | 12 ms |
| T5 | 20 | 25 ms |
CFS con time slice de 5 ms y nice 0 en todas (el vruntime sube lo mismo que el tiempo ejecutado). Reproduje los 17 pasos con un script y coinciden exactamente con el PDF si los empates se resuelven por el número de tarea más bajo:
| Paso | Elige (vruntime) | Corre | vruntime nuevo / le queda | Reloj |
|---|---|---|---|---|
| 1 | T2 (5) | 5 | 10 / 5 | 5 |
| 2 | T4 (8) | 5 | 13 / 7 | 10 |
| 3 | T1 (10) — empata con T2 (10) | 5 | 15 / 10 | 15 |
| 4 | T2 (10) | 5 | T2 termina | 20 |
| 5 | T4 (13) | 5 | 18 / 2 | 25 |
| 6 | T1 (15) — empata con T3 (15) | 5 | 20 / 5 | 30 |
| 7 | T3 (15) | 5 | 20 / 15 | 35 |
| 8 | T4 (18) | 2 | T4 termina | 37 |
| 9 | T1 (20) — empata con T3 y T5 (20) | 5 | T1 termina | 42 |
| 10 | T3 (20) | 5 | 25 / 10 | 47 |
| 11 | T5 (20) | 5 | 25 / 20 | 52 |
| 12–14 | T3 y T5 se alternan | T3 termina en el paso 14 | 67 | |
| 15–17 | solo queda T5 | 5 + 5 + 5 | T5 termina | 82 |
Fines: T2 = 20, T4 = 37, T1 = 42, T3 = 67, T5 = 82 (82 = 15 + 10 + 20 + 12 + 25, la suma de las ráfagas).
MLFQ con Q0 = 8 ms, Q1 = 16 ms y Q2 = 32 ms. Ojo: en la traza las tareas no empiezan todas en Q0 (T2 y T4 están en Q0, T1 en Q1, T3 y T5 en Q2). Es una situación inicial dada, distinta de la regla «toda tarea nueva entra a Q0»: lee bien el enunciado.
| Paso | Cola | Corre | Qué pasa | Reloj |
|---|---|---|---|---|
| 1 | Q0 | T2, 8 ms | le quedan 2 → baja a Q1 (detrás de T1) | 8 |
| 2 | Q0 | T4, 8 ms | le quedan 4 → baja a Q1 | 16 |
| 3 | Q1 | T1, 15 ms | cabe en 16 → termina | 31 |
| 4 | Q1 | T2, 2 ms | termina | 33 |
| 5 | Q1 | T4, 4 ms | termina | 37 |
| 6 | Q2 | T3, 20 ms | cabe en 32 → termina | 57 |
| 7 | Q2 | T5, 25 ms | termina | 82 |
Peldaño 4 · Variantecambia una condición: ¿sigue valiendo lo anterior?
Variante: la misma MLFQ, pero con las 5 tareas entrando a Q0 (orden T1, T2, T3, T4, T5)
Simula a mano. ¿Quién termina primero ahora?
Comparar (verificado con un script)
Ronda en Q0 (8 ms cada una): T1 0–8 · T2 8–16 · T3 16–24 · T4 24–32 · T5 32–40. Nadie cabe en 8, así que todas bajan a Q1. Les quedan T1 7, T2 2, T3 12, T4 4 y T5 17.
Q1 (16 ms): T1 40–47 (termina) · T2 47–49 (termina) · T3 49–61 (termina) · T4 61–65 (termina) · T5 65–81 (le queda 1, baja a Q2).
Q2: T5 81–82.
T1 termina primero (47) y T5 sigue último (82). Comparado con la traza, T2 termina en 49 en vez de 33: al entrar todos en Q0, los largos también reciben su turno rápido antes de que los cortos terminen.
Autoevaluación
0/6 correctas · 0 respondidas📈 ¿Qué tan bien lo dominas?
Elige pensando en lo que hiciste, no en lo que leíste. Para marcar 3 tienes que haber resuelto un ejercicio nuevo sin pistas y haberlo justificado. Si solo lo leíste y sientes que «ya entendí», todavía es un 1.
Fuente ·sem_12/Sema12_11-OST-Scheduling.pdf (diap. 48–64) · sem_12/Trace_Visualized.pdf · Reconstrucción de la traza y la variante MLFQ: propias, verificadas con un script