Información blog

Linux, tutoriales, noticias, sistemas, redes y seguridad informática, entre otras cosas.

lunes, 24 de abril de 2017

Asignación de programas a un núcleo con taskset

En el día de hoy, es prácticamente imposible no pensar en la existencia de CPUs con múltiples núcleos. Es más, hoy en día un ordenador potente suele llevar múltiples procesadores que tienen múltiples núcleos. A mayor la el número de éstos, mayor la cantidad de tareas simultáneas que pueden ser realizadas por el equipo sin que éste se sienta "forzado", lo cual dependiendo del tipo de uso que le queramos dar a nuestro equipo. En caso de no entender muy bien este concepto, recomiendo leer primero: controlando la salud del equipo con bash; pues aquí se explica detalladamente dicho concepto. Teniendo dicho punto claro, es obvio que si bien cuantos más núcleos tengamos, mejor; no siempre tendremos toda la potencia deseada, ya sea porque nuestro hardware no es potente o debido a que estamos ejecutando una gran cantidad de procesos que hacen que los procesadores estén trabajando a toda potencia.

procesador_portada

Si bien la cantidad de procesos es proporcional a la cantidad de tareas que le ordenemos realizar al equipo y dicho punto únicamente se puede corregir disminuyendo éstos o aumentando la cantidad de procesadores/núcleos (lo cual conllevaría generalmente a cambiar la placa base, con su correspondiente desembolso económico); lo que sí que podemos gestionar es qué tareas son gestionadas por qué núcleo. Haciendo que algunos estén más "holgados" que otros y que tengamos la seguridad de que, al menos ciertas tareas se puedan desenvolver con relativa rapidez. Esta tarea se logra gracias a la herramienta taskset; herramienta que, no solo nos permite saber en qué núcleo se está ejecutando una tarea en concreto, sino que también nos permite hacer que dicha tarea se ejecute en otro núcleo.

Lo primero y más importante que necesitamos conocer para situarnos y tener una noción de lo que estamos manejando, es la cantidad de procesadores/núcleos que tiene nuestro equipo, ya que dicha cantidad nos servirá de base para saber cómo gestionar los procesos. Dicha cantidad se puede conocer con este sencillo comando:

cat /proc/cpuinfo |grep processor |wc -l

El resultado obtenido sería el número de procesadores o núcleos que tiene el sistema, número que podemos usar como base para las futuras gestiones.

A sabiendas de dicho número, procederíamos a revisar qué procesos tenemos ahora mismo en ejecución; revisión que se realizaría mediante el conocido comando:

ps -e

De dicho comando obtendríamos el listado de procesos activos, procesos entre cuyos datos nos importarían dos en concreto, el nombre y el PID (Process ID); un pequeño fragmento de ejemplo de la salida de dicho comando sería este:

salida_ps_e
Fragmento de salida del comando ps -e

A sabiendas de estos datos, pasaríamos a conocer primero el núcleo en el que se está ejecutando el proceso que nos interesa, por ejemplo SSH. En este caso el PID del proceso SSH sería el 905 con lo que escribiríamos lo siguiente:

taskset -p 905

El cual en mi caso devuelve este resultado:

máscara de afinidad actual del pid 905: 1

Si os fijáis bien, lo que dice no es el número de núcleo (que empieza en 0) sino la máscara de afinidad; que si bien viene a decir lo mismo, lo expresa de diferente forma. La máscara de afinidad devuelve el núcleo que está usando en formato de máscara de bits hexadecimal, lo que significa que habría que convertir dicha máscara a binario para después ver qué núcleo está corriendo dicho proceso. En este caso se estaría usando el primer núcleo, es decir que estaría usando el núcleo con ID 0. En caso de no querer hacer la conversión, podéis consultar el ID directamente mediante el comando:

taskset -pc 905

Cuya salida sería:

lista de afinidad actual del pid 905: 0


Obviamente, con esta herramienta no solo podemos consultar el núcleo usado por el proceso, sino que también podemos modificarlo para hacer que tenga la posibilidad de usarlos todos (no implica que tenga que usar todos a la fuerza, sino que pueda usar todos en caso de ser necesario debido a una gran carga de trabajo) o para que únicamente use un núcleo en concreto. Para ello se usaría la sintaxis de a continuación:

tasket -pc Núcleos_a_usar PID

Por ejemplo, si deseásemos que el proceso SSH use únicamente los núcleo con ID 1 y 3, haríamos:

taskset -pc 1,3 905

Gracias a este simple comando, habremos cambiado le preferencia de los núcleos a usar por el proceso SSH con PID 905.


Por otro lado, taskset no solo nos permite modificar el núcleo usado por un proceso ya existente, sino que también nos permite lanzar un proceso nuevo forzándole qué núcleos usar. Por ejemplo ejecutar el programa apache2 únicamente haciendo uso del núcleo con ID 0 haríamos:

taskset -c 0 /etc/init.d/apache2 start


El problema de los métodos usados hasta ahora es que si bien son perfectamente válidos, no nos aseguran que el núcleo en cuestión esté reservado para la tarea que hemos especificado. Por ejemplo, podemos haber forzado a que un proceso use el núcleo con ID 0, pero ello no nos garantiza que el resto de procesos no esté usando dicho núcleo, a menos que claro está forcemos al resto de procesos a que usen otro núcleo, lo cual es muy poco práctico.

Afortunadamente podemos decir durante el proceso de arranque que nos reserve uno o varios núcleos; es decir que no sean usados dichos núcleos a menos que nosotros se lo digamos específicamente. Esto tiene la ventaja de que nos garantiza que dichos núcleos están libres para las tareas especiales, pero por otro lado tiene la desventaja de que esos núcleos dejarán de estar disponibles para el resto de tareas, haciendo que tal vez, en momentos de gran carga de trabajo para el equipo, notemos esa falta de "potencia". Aún así es una opción interesante que es importante conocer. Para aislar dichos procesadores, tendríamos que esperar en el arranque a que aparezca el GRUB; allí tendríamos pulsar la tecla E para editarlo. En dicha edición lo que nos interesa editar es la línea que finaliza con ro quiet; a la cual habría que añadirle al final el parámetro isocpus= ID_procesadores; por ejemplo:

isocpus=2,3

Finalmente para arrancar con este cambio tendríamos que pulsar F10 o ctrl + X, haciendo que cualquier proceso que se ejecute de manera "natural" nunca utilice los núcleos con ID 2 o 3, pues estos dos núcleos solamente serán usados en caso de que nosotros lo forcemos.

Como veis la herramienta taskset es muy versátil y puede ayudarnos a optimizar algunos procesos y reservar ciertos núcleos para las tareas de mayor relevancia, lo cual puede ayudarnos a tener la seguridad de que éstas serán ejecutadas sin inconveniente alguno.

Espero que os haya resultado útil.

Saludos.