Obtenha carga de CPU por núcleo no script de shell

2

Eu preciso informar a carga da CPU por núcleo como uma porcentagem de um script de shell, mas não posso executar, por exemplo, mpstat por um segundo . Basicamente eu acho que o infos top está mostrando depois de pressionar 1 é o que eu quero, mas não consigo configurar top para mostrar isso no modo batch (pelo menos não sei como). Eu poderia criar um arquivo ~/.toprc com a configuração, mas eu tenho que esperar que os usuários não mexam com isso.

Eu olhei para mpstat e analisei a saída, mas isso suporta apenas segundos como tempo de intervalo. Meu script é chamado via SNMP e espera 1s porque a resposta gerará um tempo limite, portanto, isso não é uma opção.

Existem outras maneiras de obter o carregamento da CPU por núcleo? Eu li sobre parsing /proc/stat , mas acho que isso é mais um último recurso.

    
por Jens 29.09.2016 / 13:56

4 respostas

1

Acontece que alguns dos MIBs instalados no RedHat fornecem todas as informações necessárias aqui. Como meu objetivo é fornecer esses valores em um OID via SNMP, posso usar o SNMP e processar as informações.

A média de todos os processadores é calculada como 100-idle :

function allCpuLoad {
    # get system idle value from
    # snmpget -v2c -cmdaf localhost UCD-SNMP-MIB::ssCpuIdle.0
    # UCD-SNMP-MIB::ssCpuIdle.0 = INTEGER: 93
    # and compute load by substracting it from 100.0 
    snmpget -v2c -cmdaf localhost UCD-SNMP-MIB::ssCpuIdle.0|cut -f4 -d' '| awk '{printf "%d", 100 - $1}'
}

Podemos usar o snmpwalk para obter a carga de todos os processadores individuais e depois extrair o valor máximo:

function maxCpuLoad {
    # get load of all cpus
    # snmpwalk -v2c -cmdaf localhost HOST-RESOURCES-MIB::hrProcessorLoad
    # HOST-RESOURCES-MIB::hrProcessorLoad.196608 = INTEGER: 1
    # HOST-RESOURCES-MIB::hrProcessorLoad.196609 = INTEGER: 1
    # HOST-RESOURCES-MIB::hrProcessorLoad.196610 = INTEGER: 1
    # HOST-RESOURCES-MIB::hrProcessorLoad.196611 = INTEGER: 1
    # HOST-RESOURCES-MIB::hrProcessorLoad.196612 = INTEGER: 6
    # HOST-RESOURCES-MIB::hrProcessorLoad.196613 = INTEGER: 1
    # HOST-RESOURCES-MIB::hrProcessorLoad.196614 = INTEGER: 1
    # HOST-RESOURCES-MIB::hrProcessorLoad.196615 = INTEGER: 1
    # HOST-RESOURCES-MIB::hrProcessorLoad.196616 = INTEGER: 1
    # HOST-RESOURCES-MIB::hrProcessorLoad.196617 = INTEGER: 27
    # HOST-RESOURCES-MIB::hrProcessorLoad.196618 = INTEGER: 4
    # HOST-RESOURCES-MIB::hrProcessorLoad.196619 = INTEGER: 0
    # HOST-RESOURCES-MIB::hrProcessorLoad.196620 = INTEGER: 1
    # HOST-RESOURCES-MIB::hrProcessorLoad.196621 = INTEGER: 0
    # HOST-RESOURCES-MIB::hrProcessorLoad.196622 = INTEGER: 0
    # HOST-RESOURCES-MIB::hrProcessorLoad.196623 = INTEGER: 1
    # and get maximum value only
    snmpwalk -v2c -cmdaf localhost HOST-RESOURCES-MIB::hrProcessorLoad|cut -f 4 -d' '|sort -n -r|head -n1
}
    
por 06.10.2016 / 15:51
2

Outra maneira de obter os valores brutos seria grep cpu0 /proc/stat . Lá você vê o número de ticks em cada estado. Do man proc para os detalhes da interpretação. Se você quiser, como uma porcentagem, você precisa juntá-las e dividir, por exemplo, ao longo das linhas do que John W. Gill sugere.

    
por 29.09.2016 / 23:26
2

Existem várias maneiras de realizar polling sub-sccond do carregamento de cpu, usando um utilitário, como dstat (exemplo abaixo) ou por polling direto / proc / stat (exemplo também abaixo).

Vamos analisar os prós e contras de ambos antes de passarmos aos exemplos técnicos.

Para usar o dstat, você precisará executar um crontab rápido (* / 1 * * * *) e canalizar o resultado para um arquivo de estatísticas que possa ser verificado. A vantagem é que seus tempos limite de SNMP não serão um problema, a desvantagem, não é realmente instantânea, e a execução do crontab quando você não está realmente procurando esses dados tem um impacto. O impacto pode ser insignificante, mas ainda assim está lá.

Para usar / proc / stat, você deve pesquisar o conteúdo de / proc / stat duas vezes. O conteúdo de / proc / stat é cumulativo desde a inicialização. Portanto, os resultados da primeira sondagem e da segunda sondagem precisam ser subtraídos uns dos outros e, em seguida, o cálculo da carga atual pode ser feito. A desvantagem é que deve haver alguma forma de atraso para fazer esse cálculo. No exemplo abaixo, o atraso caiu para menos de um segundo. Isso atenderia às suas necessidades, mas as amostras de dados são tão próximas que não sei ao certo como a precisão é absoluta.

Usando dstat; Adicione esta linha ao / etc / crontab:

*/1  *  *  *  *  root    echo $((100-'dstat -c -C0 --noheaders --nocolor 1 1 | grep -v "\-\|u" | awk 'NR == 2' | tr -s " " | cut -d \  -f 4')) > /tmp/cpuload

Isso só é atualizado uma vez a cada minuto. Se você quiser atualizações mais frequentes, adicione uma segunda linha e prefira o comando com sleep 30, como

*/1  *  *  *  *   root    sleep 30; echo $((100-'dstat -c -C0 --noheaders --nocolor 1 1 | grep -v "\-\|u" | awk 'NR == 2' | tr -s " " | cut -d \  -f 4')) > /tmp/cpuload

É possível usar o cronômetro (abuso) ainda mais longe e chegar a resultados secundários, mas esse é outro assunto totalmente diferente.

explicação:

dstat -c -C 0 --noheaders --nocolor 1 0

-c mostra apenas dados da cpu

-C selecione cpu0. mude a numeração para selecionar outra cpu

- noheaders --nocolor (implied --noupdate) simplifica o que vemos

1 atraso de um segundo na leitura de estatísticas

1 saída após segunda leitura das estatísticas. Dando tempo para se estabelecer após a invocação.

grep -v "-\|u"

remover linhas de dados não

awk 'NR == 2'

selecione a segunda linha.

tr -s " "

reduza os espaços extras que parecem bonitos na tela, mas não para uso do sistema

cut -d \ -f 4

-d \ (há um espaço após a linha delineada do espaço \ (escape)   -f 4 selecione a inatividade. sim, é visualmente 3, mas o espaço no início da linha conta como um campo, eliminando a contagem de campo.

$ (( ))

operações aritméticas bash, subtraindo o sistema ocioso de 100.

Usando / proc / stat;

Salvar como cpuload.sh;

#!/bin/bash

#Calculation delay. Without a delay, there is no way to determine current 
#values. The content or /proc/stat is cumulitative from last boot.  
# in seconds; sleep must be able to support float values
dly=3

function calculate {

#load arrays
IFS=' ' read -r -a firstarr <<< "$1"
IFS=' ' read -r -a secondarr <<< "$2"

#clear name fields in array so that calculations don't get messy
firstarr[0]=0 ;
secondarr[0]=0 ;

#clear values 
firsttotcpu=0
secondtotcpu=0

#calculate the begining interrupt counts
for f in ${firstarr[@]}; 
    do 
        let firsttotcpu+=$f; 
done
firstidle=$((${firstarr[4]}+${firstarr[5]})); 

#calculate the ending interrupt counts
for l in ${secondarr[@]}; 
    do
        let secondtotcpu+=$l; 
    done; 
secondidle=$((${secondarr[4]}+${secondarr[5]})); 

#calculate the relative change counts
insttotcpu=$(( secondtotcpu - firsttotcpu ))
instidle=$(( secondidle - firstidle ))

#calculate the utilization percentage. must be done external to bash as it's a
#floating calculation
cpu_load=$( echo | awk -v tot=$insttotcpu -v idl=$instidle ' { print ( ( ( tot - idl ) / tot ) * 100 ) } ' )

echo -n $cpu_load " " 


} 
export -f calculate

#main execution

oldIFS=$IFS

IFS=$'\n' cpu_start=( $( grep cpu /proc/stat ) );

#must delay to get difference
sleep $dly

IFS=$'\n' cpu_end=( $( grep cpu /proc/stat ) );

cpucount=${#cpu_start[@]}

#uncomment this for loop to enable printing the cpu name above the percentages
#for i in ${cpu_start[@]};
#    do
#        IFS=' ' read -r -a name <<< "$i"
#        echo -n ${name[0]} " "
#done
#echo ""

for (( i=0; i<$cpucount; i++ ))
    do
        calculate "${cpu_start[$i]}" "${cpu_end[$i]}"

done

echo ""

IFS=$oldIFS
    
por 29.09.2016 / 18:23
1
mpstat -P ALL -u | tail -n +5 | awk '{print (100-$12)}'

explicação:

mpstat

informa estatísticas do processador

-P ALL

para todos os núcleos

-u

mostra a utilização (estatísticas de / proc em vez de medições ao vivo)

tail -n +5 

comece com a linha 5

awk '{print (100-$12)}'

imprima o 12º valor de cada linha subtraída de 100

    
por 30.09.2016 / 08:38