Prioridades de procesos en Linux: PRI vs NI
Hoy entraremos en detalles de la gestión de prioridades del planificador de procesos del núcleo Linux. Específicamente, veremos la diferencia entre PRIority y NIce.
Anteriormente hemos comentado la gestión de procesos del núcleo Linux, sus estados y prioridades asociadas. En esa oportunidad introdujimos los conceptos de prioridad real (PRI) y prioridad asignada al proceso (NI).
Este tema fue grabado como una clase en el curso de Administración GNU/Linux para certificación LPIC-1, y ha sido objeto de varias consultas de los alumnos del curso.
PRI y NI: gestión de prioridades de procesos
En el artículo anterior, y en el curso, expliqué que comandos como top
o htop
muestran dos columnas de prioridades de los procesos que están en ejecución en el sistema, como se puede ver en la siguiente captura.
Comenté que los rangos de dichas prioridades son:
- PRI: (Prioridad dinámica) desde 0 (alta prioridad) hasta 39 (baja prioridad)
- NI: (Prioridad estática) desde -20 (alta prioridad) hasta +19 (baja prioridad)
Estos números representan las prioridades de usuario, y son las que un administrador de sistemas puede modificar.
Ahora bien, para entender cómo funcionan ambas, y qué diferencia tienen, es necesario recapitular sobre el planificador de procesos del núcleo Linux.
La planificación de procesos en Linux
Linux planifica los procesos, es decir, les da tiempo de ejecución en el o los procesadores, basándose en sus prioridades.
Así, de la cola de procesos listos para entrar al procesador, Linux seleccionará aquellos procesos con mayor prioridad. Aquí estamos hablando de la prioridad PRI.
Cuando ejecutamos un proceso nuevo, se lanza con una prioridad por defecto (o una prioridad determinada si lo hacemos mediante el comando nice
). Esa prioridad inicial de un proceso es la prioridad NI.
La realidad es que, cuando se lanza un proceso, se asigna una prioridad NI
determinada, y con ella se calcula la prioridad PRI
que va a utilizar el planificador de procesos, de esta manera:
PRI = 20 + NI
Si la prioridad por defecto NI
es de 0, entonces la prioridad del proceso dentro del sistema será PRI=20
.
Si lanzamos un proceso con mayor prioridad, por ejemplo, NI=-10
, la prioridad del proceso en el sistema será PRI=10
.
¿Qué sentido tiene esto de dos prioridades de procesos?
Aquí el tema de por qué el sistema administra dos prioridades por cada uno de los procesos.
Supongamos que lanzamos un proceso con muy baja prioridad de usuario, por ejemplo, NICE=19
. En este caso, el sistema le asignará una prioridad PRI=39
.
Ahora bien, como vimos en el artículo anterior, los procesos que se planifican, es decir, que pasan a ejecutarse realmente en un procesador, se encolan en la denominada cola de procesos listos. El diagrama de colas de procesos es el siguiente (recuperado de aquel artículo, y de mi trabajo final de grado).
El planificador de procesos seleccionará de la cola de listos aquellos procesos que tengan una prioridad suficientemente elevada.
Así es que, si de manera predeterminada, los procesos del sistema tienen prioridades estándares de PRI=20
, descartando los procesos de tiempo real (RT), nuestro proceso nunca entraría a ejecutarse, puesto que el planificador siempre encontraría otro proceso con mayor prioridad.
Por otro lado, ¿qué ocurre con un proceso de usuario que tiene una prioridad muy alta?
Supongamos que lanzamos un proceso como yes
, o algo que consuma recursos, y le damos la mayor prioridad de usuario posible, NICE=-20
, lo que obtiene un PRI=0
.
Este proceso monopolizaría un procesador de la computadora, y eso no está nada bien.
El planificador y la solución a estos problemas
Para solucionar estos conflictos, el núcleo Linux utiliza una variable contador (counter) en la estructura de datos que gestiona el estado de cada proceso del sistema.
Este contador inicialmente, cuando el proceso es lanzado, almacena la prioridad con la que fue planificado. En la medida en que el proceso está en ejecución, su counter
va disminuyendo con cada ciclo del reloj, de modo que la prioridad relativa del mismo se reduce respecto del tiempo que lleva en ejecución el proceso.
Cuando el contador llega a 0, se restablece con el valor inicial de prioridad del proceso, logrando que el mismo vuelva a ejecución.
Así, los procesos con mayor prioridad no pueden nunca monopolizar el uso de la CPU, y los procesos de menor prioridad tienen la chance, en algún momento, de entrar al procesador.
De esta forma, el counter
afecta a la prioridad PRI
del proceso, y cuando se hace 0, el proceso vuelve a ser re-planificado con su prioridad original, NI
.
Existen algunas variantes de algoritmo de planificación en el núcleo Linux. Desde la v2.6.23 del kernel se utiliza el planificador «Completely Fair Scheduler» (CFS). Para entender esto del counter y las prioridades es necesario adentrarse un poco en el código fuente del kernel. Si les interesa este tema no tienen mas que escribirme y publico algo al respecto.
La anterior es una explicación muy general del planificador y, por carecer de detalles, peca con algunas imprecisiones. Para entender a fondo el planificador, deberíamos primero analizar algunas estructuras de datos administradas por el núcleo Linux… queda para más adelante 🙂
Procesos de tiempo real (RT – Real Time)
Esto que acabamos de ver corresponde a los procesos de usuario, cuyas prioridades PRI
van de 0 a 39.
Los procesos de tiempo real no utilizan el valor NICE
, y calculan su prioridad PRI
de al siguiente forma:
PRI = -1 - rt_priority
Donde rt_priority
es un valor que va de 1 a 99.
Así, si a un proceso se le asigna una prioridad de tiempo real igual a 20, su prioridad real en para el planificador será PRI = -21
. El proceso que se lance con una prioridad igual a 99 tendrá prioridad de tiempo real PRI = -100
, y será el proceso con mayor prioridad dentro del sistema operativo.
Políticas de planificación de procesos en Linux
El kernel provee 5 políticas de planificación de procesos, a saber:
- Para procesos de Usuario:
SCHED_OTHER
: política round-robin estándar de planificación.SCHED_BATCH
: política para ejecución de procesos por lotesSCHED_IDLE
: para ejecutar procesos de muy baja prioridad en segundo plano.
- Para procesos de Tiempo Real (RT):
SCHED_FIFO
: política first-in, first-out.SCHED_RR
: política Round-Robin.
Podemos utilizar el comando chrt
para obtener la configuración de políticas de planificación de nuestro kernel:
Esta lista muestra las prioridades máximas y mínimas para cada una de las políticas de planificación. Aquí se ve que las políticas FIFO y RR, utilizadas para procesos de tiempo real, varían entre 1 y 99, mientras que las de procesos de usuario son 0.
En otra oportunidad podemos profundizar sobre estas políticas de planificación de procesos, y cómo afectan al rendimiento del sistema.
Conclusiones
Y hemos llegado al final! Un final que es casi un principio de mucho contenido xD
Hemos visto qué son las prioridades de los procesos en el núcleo Linux, y qué diferencia existe entre las prioridades PRI y NI que vemos en la salida de comandos como top
/htop
.
Estos temas dan para mucho, por lo que hemos dejado la puerta abierta para seguir profundizando en algunos aspectos de planificación de procesos en el núcleo Linux para no extender demasiado este artículo.
Si les interesan estos temas no tienen mas que avisarme y seguimos profundizando con más contenido.
Espero que les resulte interesante!
Hasta la próxima!