Was ich brauche
Ich möchte Systemressourcen (nämlich Speicher- und CPU-Auslastung) nach Anwendung überwachen – nicht nur nach Prozess. So wie der Windows Task-Manager Ressourcen nach dem „aufrufenden Mutterprozess“ gruppiert, möchte ich es auch so sehen. Heutzutage erzeugen Anwendungen wie Firefox und vscode viele untergeordnete Prozesse und ich möchte einen schnellen und vollständigen Überblick über deren Nutzung erhalten.
Die Lösung kann eine GUI oder TUI, ein Bash-Skript oder ein großer Einzeiler sein. Mir ist das eigentlich egal. Damit es funktioniert, könnte ich es theoretisch mit der PID des Mutterprozesses oder dem Namen einer ausführbaren Datei füttern, um es zu filtern.
Beispiel
Task-Manager gruppiert/sammelt Systemressourcen des Chrome-Browsers
Was ich versucht habe
- Ich habe es versucht
htop
, aber es wird mir nur ein Baum angezeigt, in dem der aufrufende Prozess seinen eigenen Speicher aufgelistet hat – nicht die, die er aufgerufen hat. - Ich habe das versucht
gnome-system-monitor
, aber es ist dasselbe. - Ich habe ein bisschen mit
ps
und herumprobiertfree
, aber nicht den richtigen Satz an Argumenten/Pipes gefunden, um sie das tun zu lassen, was ich will.
Ich bin ratlos, dass ich dafür keine Lösung googeln konnte. Vielleicht gibt es dafür einen Grund?
Hat jemand eine Idee? Ich wäre sehr dankbar!
Antwort1
Das folgende Skript erfordert viele zusätzliche Verbesserungen, aber ich denke, es kann als Grundlage dienen.
Ich habe angefangen, Kommentare zu schreiben, kann es aber vorerst nicht beenden. Ich werde Änderungen an meiner Antwort verwenden, um neue Kommentare hinzuzufügen und Fehler zu beheben, wenn ich mehr Freizeit habe.
In meiner Umgebung funktioniert es einwandfrei. Ich habe dieses Skript mytop genannt und es in /usr/local/bin abgelegt, damit ich die Tab-Vervollständigung des Bash-Befehls darauf habe. Sie können mytop in Ihr ~/bin-Verzeichnis (wenn ~/bin nicht in Ihrem $PATH ist, fügen Sie es hinzu) oder an einen beliebigen Ort auf Ihrem Computer legen. Natürlich muss das Execute-Bit mit chmod u+x mytop gesetzt sein.
#!/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