Lo que necesito
Quiero monitorear los recursos del sistema (es decir, el uso de memoria y CPU) por aplicación, no solo por proceso. Así como el Administrador de tareas de Windows agrupa los recursos según el "proceso madre que llama", también me gusta verlo así. Hoy en día, aplicaciones como Firefox y vscode generan muchos procesos secundarios y quiero obtener una descripción general rápida y completa de su uso.
La solución puede ser una GUI o TUI, un script bash o un gran resumen. Realmente no me importa. Para que funcione, imagino que podría alimentarlo con el pid del proceso madre o el nombre de un ejecutable como medio de filtrado.
Ejemplo
El Administrador de tareas agrupa/acumula recursos del sistema del navegador Chrome
Lo que intenté
- Lo intenté
htop
, pero solo me muestra un árbol donde el proceso de llamada tiene su propia memoria enumerada, no las que llamó. - Probé el
gnome-system-monitor
, pero es lo mismo. - Intenté un poco con
ps
yfree
pero no encontré el conjunto correcto de argumentos/canalizaciones para que hagan lo que quiero.
Me dejó perplejo no poder buscar en Google una solución para eso. ¿Quizás haya una razón para ello?
Alguien tiene una idea? ¡Se lo agradecería mucho!
Respuesta1
El siguiente script requiere muchas mejoras adicionales, pero creo que puede servir como base.
Empecé a escribir comentarios, pero por ahora no puedo terminarlos. Usaré ediciones en mi respuesta para agregar nuevos comentarios y corregir errores cuando tenga más tiempo libre.
En mi entorno funciona bien. Llamé a este script mytop y lo puse en /usr/local/bin para poder completar la pestaña del comando bash. Puede colocar mytop en su directorio ~/bin (si ~/bin no está en su $PATH, agréguelo), o en cualquier lugar de su máquina. Por supuesto, se debe configurar el bit de ejecución, con chmod u+x mytop.
#!/bin/bash
# mytop -ver 1.0
# script name (default is: 'mytop')
s_name=$(basename $0)
# version
ver="1.0"
# set default time between mytop iterations
sec_delay=3
# set default mytop repetitions/iterations
mt_rep=1000000
# Help function explaining syntax, options, ...
Help()
{
# Display Help
echo
echo "Show Totals of %CPU and &MEM using 'top' command."
echo
echo "Syntax:"
echo " $s_name [-h|-V]"
echo " $s_name [[-d <S>][-n <N>] <APP_NAME>"]
echo
echo "Options:"
echo " -h Print this Help."
echo " -d S Delay/wait S seconds between iterations (default: 3 seconds)."
echo " -n N Run/iterate 'mytop' N times (default: 3 times)."
echo " -V Print version."
echo
echo "Examples:"
echo " mytop -V"
echo " mytop -d1 -n5 chromium"
echo
echo 'Use CTRL+C for exit!'
echo
}
# Handling options from command line arguments
while getopts ":hn:d:V" option; do
case $option in
h) # display Help
Help
exit;;
V) # print version
echo "$s_name $ver"
exit;;
n) # set how many times 'mytop' will repeat/iterate
mt_rep=$OPTARG;;
d) # set delays in seconds
sec_delay=$OPTARG;;
\?)
echo "$s_name: inapropriate: '$1'."
echo "Usage:"
echo " $s_name [-h|-V|-d<S> -n<N> <APP_NAME>]"
exit;;
esac
done
# If no arguments given just display Help function and exit
if [[ $# -eq 0 ]]; then
Help
exit
else
# If last argument starts with '-' exit from app
if [[ ${@:$#} =~ -+.* ]]; then
echo ${s_name}: error: Last argument must be the name of the application that you want to track. >&2
exit 1
else
app_name=${@:$#}
fi
fi
# Set 'dashes' literally
#t_dsh='-----------------------------------------------------------'
# or set them with printf command
t_dsh=$(printf '%0.s-' {1..59})
# Not in use
#if [[ -z $mt_rep ]] 2>/dev/null; then
# r_endless=1
# mt_rep=1000
#else
# r_endless=0
#fi
i=0
while [[ $i -lt $mt_rep ]]; do
#if [[ "$r_endless" == "0" ]]; then ((i++)); fi
((i++))
# Handle pids of app you want to track by removing 'mytop' pids
# get s_name (mytop) pids
pgrep $s_name > /tmp/mt_pids
# get app_name pids -all of them --not desired behaviour
pgrep -f $app_name > /tmp/app_name_pids
# get app_name without mytop pids --desired behaviour
for e in $(cat /tmp/mt_pids); do sed -i "/$e/d" /tmp/app_name_pids; done
if [[ ! -s "/tmp/app_name_pids" ]]; then echo "1000000" > /tmp/app_name_pids; fi
# top -b -n1 -p; -b for output without ANSI formating; -n1 for just one iteration of 'top'; -p for feeding processes from 'pgrep' command
# Use LC_NUMERIC if your 'top' command outputs 'commas' instead 'dots' - with LC_NUMERIC you will get 'dots' during this script
LC_NUMERIC=en_US.UTF-8 top -b -n1 -p $(cat /tmp/app_name_pids | xargs | tr ' ' ,) > /tmp/pstemp
wc_l=$(wc -l < /tmp/pstemp)
cpu_use=$(tail -n +8 /tmp/pstemp | tr -s ' ' | sed 's/^ *//' | cut -d' ' -f9 | xargs | tr ' ' + | bc)
if [[ "$cpu_use" == "0" ]]; then
cpu_use="0.0"
else
if (( $(bc <<< "$cpu_use < 1") )); then cpu_use="0$cpu_use"; fi
fi
mem_use=$(tail -n +8 /tmp/pstemp | tr -s ' ' | sed 's/^ *//' | cut -d' ' -f10 | xargs | tr ' ' + | bc)
if [[ "$mem_use" == "0" ]]; then
mem_use="0.0"
else
if (( $(bc <<< "$mem_use < 1") )); then mem_use="0$mem_use"; fi
fi
echo -en "\033[2J\033[0;0f"
# Use 'echo ...' above or 'tput ...' below (chose the one that works for you)
#tput cup 0 0 && tput ed
# Align Totals under %CPU and %MEM columns
if (( $(bc <<< "$cpu_use < 1") )); then
sed "${wc_l}a \\\n\nTotal (%CPU/%MEM): $(printf " %29s")$cpu_use $mem_use\n${t_dsh}" /tmp/pstemp
elif (( $(bc <<< "$cpu_use < 100") )); then
sed "${wc_l}a \\\n\nTotal (%CPU/%MEM): $(printf " %28s")$cpu_use $mem_use\n${t_dsh}" /tmp/pstemp
else
sed "${wc_l}a \\\n\nTotal (%CPU/%MEM): $(printf " %27s")$cpu_use $mem_use\n${t_dsh}" /tmp/pstemp
fi
if [[ $i -lt $mt_rep ]]; then sleep $sec_delay; fi
done