photo-limones.jpg

En multitud de ocasiones, mientras estamos trabajando con nuestro ordenador, o incluso con un servidor remoto, se presenta la necesidad de saber la memoria ocupada o la CPU consumida por un determinado proceso.

Para ello tenemos herramientas como top o ps (entre otras) que nos permiten conocer dicha información. Podemos encontrar multitud de tutoriales para ambos comandos, sólo daré una pincelada aquí.

ps

Casi siempre que uso ps suelo hacerlo de la siguiente manera:

$ ps ax

para así mostrar todos los procesos que están corriendo actualmente, y si queremos obtener información sobre memoria y CPU podremos ejecutar:

$ ps axl

o

$ ps axo pid,pcpu,pmem,size,cmd

Si queremos obtener más datos como ID de proceso (pid), % de CPU (pcpu), % de memoria (pmem), tamaño en memoria (size), comando que genera el proceso (cmd).

top

Desde aquí podemos ver en tiempo real los procesos que están ejecutándose en la máquina (se va actualizando en el tiempo) y podemos ordenarlos por varios criterios pulsando (<) y (>) además de filtrarlos, matarlos, etc. Para salir, debemos pulsar q.

Screenshot-24-05-2016-01.png

Otros administradores

Por supuesto, también tenemos administradores gráficos de tareas, por ejemplo, aquí tenemos un pantallazo del administrador de tareas de KDE:

Screenshot-25-05-2016-02.png

Con muchas opciones.

Agrupando procesos

Pero en la vida del sysadmin, en ocasiones tenemos la necesidad de saber lo que ocupan todos los procesos con el mismo nombre. Porque, muchas veces, un mismo programa lanza varios procesos homónimos que corren de forma concurrente. Podemos verlo, por ejemplo, cuando ejecutamos Chrome o Chromium, Spotify, procesos de Apache, PHP, o incluso cuando tenemos muchas sesiones de terminal abiertas y queremos saber cuánta memoria ocupan todas juntas.

Para eso, podemos utilizar el siguiente script:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#!/bin/bash

GROUP_ARG=$1
HUMAN=0
case $GROUP_ARG in
     "rss")
    GROUPABLE="rss"
    HUMAN=1
    ;;
     "size")
    GROUPABLE="size"
    HUMAN=1
    ;;
     "pmem")
    GROUPABLE="pmem"
    HUMAN=0
    ;;
     "pcpu")
    GROUPABLE="pcpu"
    HUMAN=0
    ;;
     *)
    echo "Bad argument!"
    exit
esac

ps -axo pid,$GROUPABLE,cmd | awk '
function human(x) {
         s="KiB MiB GiB TiB EiB PiB"
         while (x>=1024 && length(s)>1)
               {
               x/=1024;
               s=substr(s,5)
           }
         s=substr(s,0,3)
         return sprintf( "%.2f%s", x, s)
}
BEGIN {
    i=0
}
{
    if (!procesos[$3])
    {
        procesos[$3]=i
        pids[i]=$1 ""
        group[i]=$2
        i++

    }
    else
    {
        n = procesos[$3]
        pids[n]=pids[n] ", " $1 ""
        group[n]+=$2
    }
}
END {
    for (p in procesos)
    {
        i = procesos[p];
                if ('$HUMAN')
                printf "%s %s (%s)\n", p, human(group[i]), pids[i]
        else
                printf "%s %s (%s)\n", p, group[i], pids[i]
    }
}
';

Cuando lo ejecutemos, debemos pasar un argumento: rss (tamaño de la parte residente en memoria del proceso), size (tamaño virtual del programa), pmem (% de memoria), pcpu (% de CPU) dependiendo del criterio que vamos a agrupar.

Si observamos, el script hace una llamada a ps -axo pid,(parametro),cmd por lo que recibiremos sólo 3 elementos de cada proceso, su identificador, el elemento que queremos agrupar y la línea de comandos invocada para correr el proceso. Todo eso se lo pasamos a awk que procesará línea por línea dicha información.

Dentro de awk, tenemos la función human, que transformará tamaños de KiB a unidades superiores (para que los tamaños sean más fáciles de leer, por ejemplo 1048576KiB = 1GiB). Awk, manejará 3 arrays, procesos, pids y group. Procesos[] asignará a cada cmd un índice consecutivo. pids[] asignará a cada índice una lista de IDs de procesos separados por comas, al final será una cadena de texto y group[] asignará a cada índice un número que será la suma de todos los argumentos que agrupemos (ya sabemos, memoria, cpu…). Lo que awk hará en cada iteración será buscar si ya ha visto un proceso con ese nombre, en caso afirmativo añadirá la información de la línea actual a los arrays del proceso, de otro modo, añadirá un elemento a cada array con información del proceso que acabamos de ver.

Para finalizar, una vez se haya recopilado la información, se recorrerá el array de procesos para imprimir en pantalla la información formateada y, en el caso de que la información a agrupar sea un tamaño (memoria), lo pondremos en formato humano (función human de arriba) para facilitar la legibilidad.

Ejemplos de uso

Yo he llamado al programa groupps. Para ejecutarlo puedo hacer:

$ ./groups size

y me mostrará el espacio ocupado por todos los procesos. Aunque podemos usar grep para filtrar esta información, por ejemplo, para ver cuánto ocupan todos los procesos de php-cgi-5.5 que tengo actualmente corriendo:

$ ./groups size | grep php-cgi-5.5
/opt/phpfarm/inst/bin/php-cgi-5.5.19 101.23MiB (4790, 4791, 4792, 4793, 4846, 4847, 4848, 4849, 4850, 4851, 4852, 4853, 28576, 28640, 28641, 28642)

En este caso veo que la suma del tamaño de todos los procesos de php es de 101.23MiB. Tenemos que tener

O puedo ver la CPU total consumida por los procesos de Spotify:

$ ./groupps pmem | grep spotify
/usr/share/spotify/spotify 12.3 (31847, 31849, 31863, 31879)

En este caso un 12.3%

Sobre este script

Este script lo incluiré en gscripts muy pronto, junto con una colección de scripts para hacer nuestra vida con la terminal más fácil.

 

Foto: Hoach Le Dihn

Fuente: poesiabinaria

¿Quién está en línea?

Hay 15648 invitados y ningún miembro en línea