¿Cómo renice todos los hilos (e hijos) de un proceso en Linux?

22

Linux no sigue (todavía) el estándar POSIX.1 que dice que un reniceproceso afecta a "todos los hilos del alcance del sistema en el proceso", porque de acuerdo con el documento pthreads (7) "los hilos no comparten un valor agradable común".

Sin embargo, a veces, puede ser conveniente renice"todo" relacionado con un proceso dado (un ejemplo sería procesos hijos de Apache y todos sus hilos). Asi que,

  • ¿Cómo puedo renicetodos los hilos que pertenecen a un proceso dado?
  • ¿Cómo puedo renicetodos los procesos secundarios que pertenecen a un proceso dado?

Estoy buscando una solución bastante fácil.

Sé que los grupos de procesos a veces pueden ser útiles, sin embargo, no siempre coinciden con lo que quiero hacer: pueden incluir un conjunto de procesos más amplio o diferente.

Usar un cgroupadministrado por systemdtambién podría ser útil, pero incluso si estoy interesado en escucharlo, en su mayoría busco una solución "estándar".

EDITAR: también, man (7) pthreadsdice "todos los hilos en un proceso se colocan en el mismo grupo de hilos; todos los miembros de un grupo de hilos comparten el mismo PID". Entonces, ¿es posible incluso renicealgo que no tenga su propio PID?

Totor
fuente

Respuestas:

19

Puede usar /proc/$PID/taskpara encontrar todos los hilos de un proceso dado, por lo tanto, puede usar

$ ls /proc/$PID/task | xargs renice $PRIO

a renicetodos los hilos que pertenecen a un proceso dado.

La misma manera /proc/$PID/task/$PID/childrense puede utilizar para encontrar todos los procesos secundarios (o /proc/$PID/task/*/childrensi desea todos los procesos secundarios de todos los hilos de un proceso dado).

$ cat /proc/$PID/task/$PID/children | xargs renice $PRIO
$ cat /proc/$PID/task/*/children | xargs renice $PRIO
Anton Leontiev
fuente
man (7) pthreadsdice acerca de la implementación actual (NPTL): "todos los subprocesos en un proceso se colocan en el mismo grupo de subprocesos; todos los miembros de un grupo de subprocesos comparten el mismo PID" y "Los subprocesos no comparten un valor agradable común". Entonces, ¿cómo puede cambiar el tamaño de un hilo que no tiene su propio PID, cuando reniceutiliza un PID para hacerlo?
Totor
Intenté renice en una ID de hilo, y se informa 24995 (process ID) old priority 0, new priority -10. 24995 no aparece en ps, por lo que no es un proceso. ¿Tal vez el cambio de hilos realmente funciona?
Stefan Reich
9

Buen valor o acciones de CPU?

Tenga en cuenta que hoy en día, los valores agradables pueden no ser tan relevantes "en todo el sistema", debido a la agrupación automática de tareas, espacialmente cuando se usa systemd . Por favor vea esta respuesta para más detalles.

Diferencia entre hilos y procesos

Pregunta importante sobre Linux, porque la documentación perpetúa dudas (sobre hilos que no tienen su propio PID, por ejemplo).

Nota: esta respuesta explica los hilos de Linux con precisión.

En resumen: el núcleo solo maneja "entidades ejecutables", es decir, algo que se puede ejecutar y programar . Kernel sabio, estas entidades se llaman procesos. Un hilo es solo un tipo de proceso que comparte (al menos) espacio de memoria y manejadores de señal con otro.

Cada uno de estos procesos tiene un identificador único en todo el sistema: el PID (ID del proceso). Para los llamados subprocesos, a veces se llama TID (ID de subproceso), pero desde el punto de vista sysadmin (y kernel!), TID y PID son lo mismo (comparten el mismo espacio de nombres).

Como resultado, puede renice "enhebrar" individualmente porque tienen su propio PID 1 .

Encontrar todos los PIDs renice recursivamente

Necesitamos obtener los PID de todos los procesos ("normales" o "hilo") que son descendientes (hijos o en el grupo de hilos) del proceso a ser percibido. Esto debería ser recursivo (teniendo en cuenta los hijos de los niños).

La respuesta de Anton Leontiev da la pista para hacerlo: todos los nombres de carpetas /proc/$PID/task/son PID de hilos que contienen un childrenarchivo que enumera los posibles procesos secundarios.

Sin embargo, carece de recursividad, por lo que aquí hay un script de shell rápido y sucio para encontrarlos:

#!/bin/sh
[ "$#" -eq 1 -a -d "/proc/$1/task" ] || exit 1

PID_LIST=
findpids() {
        for pid in /proc/$1/task/* ; do
                pid="$(basename "$pid")"
                PID_LIST="$PID_LIST$pid "
                for cpid in $(cat /proc/$1/task/$pid/children) ; do
                        findpids $cpid
                done
        done
}

findpids $1
echo $PID_LIST

Si el proceso PID 1234 es el que desea que sea recursivamente agradable, ahora puede hacer:

renice -n 15 -p $(/path/to/findchildren.sh 1234)

1 Tenga en cuenta que, para el cumplimiento de POSIX, llamar getpid(2)dentro de un subproceso no le dará el ID único (PID) de todo el sistema de esta entidad ejecutable, sino el PID del proceso principal dentro del "grupo de subprocesos". Tendría que llamar en su gettid(2)lugar. Vea esta respuesta para más información.

Totor
fuente
6

No debemos confundir el PID del proceso y la identificación del hilo alguna vez escrito TID o en el comando ps LPW. El scomando tiene opciones para mostrar subprocesos, y debajo topo htoppuede cambiar entre subprocesos y procesar por Hletra. Como dijo anteriormente @Totor, con NPTL, que es la implementación actual con kernel> 2.6, todos los subprocesos tienen el mismo pid, pero tienen un tid distinto. Muestra todos los hilos de un proceso:

$ ps -Ljf <pid>

Estos tid son los nombres de los directorios debajo /proc/<pid>/task, e incluso si renice (1) dice que su argumento predeterminado es un pid cuando se aplica a un pid, renice solo el hilo principal (esto es un error en la implementación de Linux como está escrito en setpriority (2) ) ), también se puede aplicar a un tid y renice el hilo. Es por eso que la respuesta de @Anton es válida.

Pero la mayoría de las veces hay una manera más fácil de lograr el resultado deseado, todos estos hilos comparten el mismo pgid que es el pid del líder del grupo; Puedes cambiar el tamaño por pgid emitiendo:

$ renice -g <pgid>

Si no desea cambiar el proceso de otro proceso que depende del mismo líder del grupo, debe usar la receta de @ Anton:

$ renice <priority> $(ls -1 /proc/<pid>/task)

o:

$renice <priority> $(ps --no-header -Lo tid <pid>)

También es posible que desee saber cuáles son los otros procesos del mismo grupo que el proceso que desea cambiar, es decir, los procesos que comparten tienen el mismo pgid. Puede usar ps (1) , psno permite seleccionar procesos por líder de grupo, pero puede pshacer un grep para hacerlo. Los procesos con pgid 1908serán dados por el comando:

$ ps --no-header axo pid,pgid |sed -n '/^ *[0-9][0-9]*  *1908/s/[0-9][0-9]* *$//p'

o si prefieres awk a sed:

$ ps --no-header axo pid,pgid|awk '{if ($2=="1908") print $1;}'
marcz
fuente
Esto no parece funcionar correctamente en 4.19.4 (Debian Stretch a partir de ahora): $ renice -n 18 -g 8524 renice: failed to get priority for 8524 (process group ID): No such process $ ps --no-header axo pid,pgid|awk '{if ($2=="8524") print $1;}' Considerando que el método de Totor funciona / todavía funciona: $ /bin/ls /proc/8524/task | /usr/bin/xargs renice 19 2739 (process ID) old priority 19, new priority 19 2740 (process ID) old priority 19, new priority 19 ... he confirmado con / proc, htop, pstree, etc. que tengo el top- correcto nivel PID. Tal vez algo ha cambiado en el último año.
Bill McGonigle
No sé cómo hiciste tu prueba @ bill-mcgonigle, acabo de probar con tres núcleos 4.9.0 en Debian Stretch; 4.18.0 y 4.19.0 en pruebas de Debian; Y funciona como dije anteriormente.
marzo
Como dije, Debian Stretch en 4.19.4 con los comandos y resultados mostrados; la diferencia parece ser 4.19.0 frente a 4.19.4, pero me sorprende que haya muchos cambios entre esas versiones menores.
Bill McGonigle
Supongo que su proceso 8524 es el PID de todos los TID o LPW de proceso con subprocesos, pero no el grupo de procesos, por lo que, por supuesto, encontrará todos los subprocesos /proc/8524/taskpero renice -gfallará. Cuando observa un árbol de procesos, una rama está en el mismo grupo de procesos, no solo un proceso enhebrado. Intente nuevamente verificando el resultado de ps -Ljf.
marzo
0

Me gustaría recomendar el uso del argumento -g (grupos de procesos) en lugar de -p (id del proceso) mientras utilizo renice. Hace lo mismo sin el bash-foo.

es decir

(sudo) renice -n <NEW_PRIORITY> -g <MAIN_PROCESS_ID>
usuario12042
fuente
La respuesta de Marcz ya menciona esto.
Totor
-1

Aquí hay un guión mío:

pgrep -v <PROCESS_NAME> | sudo xargs renice <NEW_PRIORITY>
Antonio Petricca
fuente
1
Esto inicia renice en todos los procesos, excepto el que usted nombre. Personalmente considero este comando como peligroso e inadecuado.
Totor
Me pregunto si había querido decir -w no -v
Diablo-D3