Obtenha o uso de memória/CPU por aplicativo

Obtenha o uso de memória/CPU por aplicativo

O que eu preciso

Quero monitorar os recursos do sistema (ou seja, uso de memória e CPU) por aplicativo - não apenas por processo. Assim como o Gerenciador de Tarefas do Windows agrupa recursos pelo "processo mãe de chamada", também gosto de ver assim. Hoje em dia, aplicativos como Firefox e vscode geram muitos processos filhos e quero obter uma visão geral rápida e completa de seu uso.

A solução pode ser uma GUI ou TUI, um script bash ou um grande one-liner. Eu realmente não me importo. Para funcionar, imagino que poderia alimentá-lo com o pid do processo mãe ou com o nome de um executável como forma de filtragem.

Exemplo

O Gerenciador de Tarefas agrupa/acumula recursos do sistema do navegador Chrome

O que eu tentei

  • Eu tentei htop, mas só me mostra uma árvore onde o processo de chamada tem sua própria memória listada - não aquelas que ele chamou.
  • Eu tentei o gnome-system-monitor, mas é o mesmo.
  • Eu tentei um pouco com pse freemas não encontrei o conjunto correto de argumentos/canais para fazê-los fazer o que eu quero.

Fiquei perplexo por não conseguir pesquisar no Google uma solução para isso. Talvez haja uma razão para isso?

Alguém tem uma ideia? Eu apreciaria isso muito!

Responder1

Este script abaixo requer muitas melhorias adicionais, mas acho que pode servir de base.
Comecei a escrever comentários, mas por enquanto não consegui terminar. Usarei edições em minha resposta para adicionar novos comentários e corrigir bugs quando tiver mais tempo livre.
No meu ambiente funciona bem. Chamei esse script de mytop e coloquei-o em /usr/local/bin para que eu tenha a conclusão da guia do comando bash nele. Você pode colocar mytop em seu diretório ~/bin (se ~/bin não estiver em seu $PATH, adicione-o) ou em qualquer lugar em sua máquina. É claro que o bit de execução deve ser definido, com 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

informação relacionada