← Planificación de la CPU Bloque 8 · Planificación en multiprocesadores · Tema 29 de 44

Tema 29

Afinidad y balanceo de carga

En un sistema con varios núcleos, dos objetivos compiten: mantener un proceso en el mismo núcleo para aprovechar la caché (afinidad) y distribuir los procesos entre los núcleos para equilibrar la carga (balanceo). En este tema verás por qué la afinidad importa, cómo se balancea la carga, el trade-off entre ambos y cómo Linux resuelve el problema con los dominios de planificación.

1. Qué es la afinidad de caché

La afinidad de caché (cache affinity) es la tendencia de un proceso a ejecutarse en el mismo procesador (o núcleo) donde se ejecutó anteriormente, para aprovechar los datos que quedaron en la caché de ese procesador.

Cuando un proceso se ejecuta en un núcleo, sus datos (instrucciones, variables, estructuras) se cargan en la caché L1, L2 y L3 de ese núcleo. Si el proceso se ejecuta de nuevo en el mismo núcleo, esos datos ya están en la caché y se accede a ellos rápidamente. Si se migra a otro núcleo, la caché está fría (cold) y hay que recargar todos los datos, lo que causa cache misses.

La afinidad de caché es especialmente importante para procesos con grandes working sets (conjuntos de datos que usan frecuentemente). Un proceso que accede a 1 MB de datos tendrá muchos cache misses si se migra a otro núcleo.

2. Por qué importa la afinidad

El costo de perder la afinidad de caché puede ser significativo:

Nivel de cachéTiempo de accesoCosto de miss
L11-4 ciclos~10-40 ciclos (acceso a L2)
L210-20 ciclos~100 ciclos (acceso a L3)
L330-50 ciclos~200-300 ciclos (acceso a RAM)

Un proceso que pierde su caché L1 puede tardar 10-40 veces más en acceder a sus datos. Si el proceso accede a la caché miles de veces por milisegundo, el impacto es enorme.

Estudios han mostrado que la migración de un proceso entre núcleos puede causar una degradación del rendimiento del 10-30 %, dependiendo del tamaño del working set y del patrón de acceso.

La afinidad no es solo rendimiento

La afinidad de caché también afecta a la energía: acceder a la caché consume menos energía que acceder a la RAM. Mantener la afinidad reduce el consumo de energía.

3. Qué es el balanceo de carga

El balanceo de carga (load balancing) es el proceso de distribuir los procesos entre los procesadores para que todos tengan una carga similar. El objetivo es evitar que un procesador esté sobrecargado mientras otro está ocioso.

El balanceo de carga es necesario porque:

Sin balanceo, un procesador puede estar al 100 % mientras otro está al 0 %. El throughput del sistema se reduce porque los procesos en el procesador ocupado esperan más.

4. El trade-off: afinidad vs balanceo

La afinidad y el balanceo compiten:

El equilibrio depende de:

El equilibrio es dinámico

No hay un punto fijo de equilibrio. El sistema debe ajustar dinámicamente la frecuencia de migración según la carga de trabajo y el desequilibrio.

5. Cómo migran los procesos

La migración de un proceso de un núcleo a otro implica:

  1. Seleccionar el proceso a migrar. Se elige un proceso de la cola del núcleo más cargado. seleccionar
  2. Quitarlo de la cola origen. Se elimina de la cola del núcleo origen. quitar
  3. Añadirlo a la cola destino. Se añade a la cola del núcleo menos cargado. añadir
  4. Actualizar la afinidad. Se actualiza la afinidad del proceso para que prefiera el nuevo núcleo. afinidad

La migración tiene un costo: el proceso pierde su caché y debe recargar sus datos en el nuevo núcleo. Por eso, no se migra un proceso si el beneficio del balanceo no compensa el costo de la migración.

Linux usa una heurística: solo migra un proceso si el desequilibrio de carga es significativo (por ejemplo, si un núcleo tiene el doble de carga que otro).

6. Tipos de balanceo

TipoCuándo se ejecutaVentajaDesventaja
PeriódicoCada cierto tiempo (por ejemplo, cada 100 ms).Simple, predecible.Puede ser demasiado frecuente o infrecuente.
Por eventoCuando un núcleo queda ocioso.Reacciona rápido al desequilibrio.Puede causar migraciones innecesarias.
Por umbralCuando el desequilibrio supera un umbral.Solo migra cuando es necesario.Hay que elegir el umbral.

Linux usa una combinación: balanceo periódico (cada cierto tiempo) y por evento (cuando un CPU queda ocioso). El balanceo por evento es más reactivo y se ejecuta cuando un CPU no tiene trabajo.

7. Dominios de planificación

Los dominios de planificación (scheduling domains) son grupos de CPUs que se balancean entre sí. Linux organiza los CPUs en una jerarquía de dominios: primero se balancea entre CPUs del mismo socket (que comparten caché L3), luego entre sockets del mismo nodo NUMA, y finalmente entre nodos NUMA.

La jerarquía permite balancear de forma eficiente: primero se intenta balancear dentro del mismo socket (bajo costo, porque comparten caché), y solo si es necesario se balancea entre sockets (mayor costo).

Cada dominio tiene sus propios parámetros: intervalo de balanceo, umbral de desequilibrio, etc. Los dominios más cercanos (mismo socket) se balancean con más frecuencia que los más lejanos (entre nodos NUMA).

La jerarquía reduce el costo

Al balancear primero dentro del mismo socket, Linux minimiza las migraciones costosas (entre sockets o nodos NUMA). La mayoría de las migraciones son locales y tienen bajo costo.

8. Cómo lo hace Linux

Linux implementa la afinidad y el balanceo de la siguiente manera:

Las herramientas taskset y numactl permiten controlar la afinidad desde la línea de comandos.

9. Simulador interactivo

Este simulador muestra el trade-off entre afinidad y balanceo. Con afinidad activada, los procesos se mantienen en el mismo CPU (mejor caché, pero posible desbalanceo). Sin afinidad, se distribuyen libremente (mejor balanceo, pero pérdida de caché):

Simulador · afinidad vs balanceo

CPU 0

CPU 1

ProcesoLlegadaRáfagaCPUInicioFinRetorno

10. Resumen

11. Preguntas de repaso

Intenta responder cada una antes de abrir la respuesta.

1. ¿Qué es la afinidad de caché?

La tendencia de un proceso a ejecutarse en el mismo procesador para aprovechar la caché.

2. ¿Por qué importa la afinidad?

Porque migrar un proceso pierde la caché, causando cache misses y degradación del rendimiento.

3. ¿Qué es el balanceo de carga?

Distribuir los procesos entre los procesadores para equilibrar la carga.

4. ¿Cuál es el trade-off principal?

Afinidad (mejor rendimiento por proceso) vs balanceo (mejor distribución).

5. ¿Qué es la migración de un proceso?

Mover un proceso de un núcleo a otro para equilibrar la carga.

6. ¿Qué tipos de balanceo existen?

Periódico, por evento y por umbral.

7. ¿Qué son los dominios de planificación?

Grupos de CPUs que se balancean entre sí, organizados en jerarquía.

8. ¿Qué es la afinidad suave?

El planificador intenta mantener el proceso en el mismo CPU pero no lo garantiza.

9. ¿Qué es la afinidad dura?

El proceso se fija a un CPU específico y solo se ejecuta ahí.

10. ¿Cómo se controla la afinidad dura en Linux?

Con taskset o sched_setaffinity.

Para practicar

  1. Ejecuta el simulador con y sin afinidad y compara los Gantt.
  2. Diseña un caso donde el desbalanceo sea evidente sin afinidad.
  3. Explica por qué la jerarquía de dominios reduce el costo del balanceo.
  4. Implementa la afinidad suave en el simulador por núcleo.
  5. Investiga cómo taskset funciona en Linux.
  6. Explica el trade-off entre migración frecuente y afinidad.