Что мне нужно
Я хочу отслеживать системные ресурсы (а именно память и использование процессора) по приложениям, а не только по процессам. Так же, как диспетчер задач Windows группирует ресурсы по "вызывающему материнскому процессу", мне тоже нравится это видеть. В настоящее время приложения, такие как firefox и vscode, порождают много дочерних процессов, и я хочу получить быстрый и полный обзор их использования.
Решением может быть GUI или TUI, скрипт bash или большой однострочный. Мне все равно. Чтобы это работало, я думаю, я мог бы скормить ему pid материнского процесса или имя исполняемого файла в качестве средства фильтрации.
Пример
Диспетчер задач группирует/аккумулирует системные ресурсы браузера Chrome
Что я пробовал
- Я попробовал
htop
, но он показывает мне только дерево, в котором у вызывающего процесса перечислены его собственные области памяти, а не те, которые он вызвал. - Я попробовал
gnome-system-monitor
, но результат тот же. - Я немного попробовал с
ps
и ,free
но не нашел правильного набора аргументов / каналов, чтобы заставить их делать то, что мне нужно.
Меня озадачило, что я не смог найти решение этой проблемы в Google. Может быть, есть на то причина?
Есть у кого-нибудь идеи? Буду очень признателен!
решение1
Этот скрипт ниже требует множества дополнительных улучшений, но я думаю, что он может послужить основой.
Я начал писать комментарии, но пока не могу их закончить. Я буду использовать правки в своем ответе, чтобы добавлять новые комментарии и исправлять ошибки, когда у меня будет больше свободного времени.
В моей среде он работает нормально. Я назвал этот скрипт mytop и поместил его в /usr/local/bin, чтобы у меня была возможность автодополнения команд bash. Вы можете поместить mytop в свой каталог ~/bin (если ~/bin нет в вашем $PATH, добавьте его) или в любое другое место на вашей машине. Конечно, бит выполнения должен быть установлен с помощью 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