Como obter o uso de cpu para cada núcleo com um script bash usando ferramentas padrão * nix

4

Estou escrevendo um script para imprimir as estatísticas do sistema na minha barra de status dwm usando xsetroot . Tudo funciona como esperado. O que eu estou atualmente perdendo é uma maneira fácil que usa apenas% padrão*nix ferramentas para me dar a carga atual para cada núcleo no meu sistema (eu tenho 4 núcleos.). Não consigo descobrir como fazer isso, por exemplo usando top . Todos os outros posts que encontrei neste site até agora apenas lidam com a carga média. Alguém já fez isso antes?

A principal razão que eu quero para cada núcleo único é ter uma ferramenta barata e grosseira para verificar se um programa está executando algum código que escrevi em paralelo (por exemplo, um para cada loop).

    
por lord.garbage 31.08.2014 / 03:25

4 respostas

4

Calculando a média por uso de núcleo de /proc/stat

A melhor solução que usei até agora é usar bc para considerar a aritmética de ponto flutuante:

# Calculate average cpu usage per core.
#      user  nice system   idle iowait irq softirq steal guest guest_nice
# cpu0 30404 2382   6277 554768   6061   0      19    0      0          0
A=($(sed -n '2,5p' /proc/stat))
# user         + nice     + system   + idle
B0=$((${A[1]}  + ${A[2]}  + ${A[3]}  + ${A[4]}))
B1=$((${A[12]} + ${A[13]} + ${A[14]} + ${A[15]}))
B2=$((${A[23]} + ${A[24]} + ${A[25]} + ${A[26]}))
B3=$((${A[34]} + ${A[35]} + ${A[36]} + ${A[37]}))
sleep 2
# user         + nice     + system   + idle
C=($(sed -n '2,5p' /proc/stat))
D0=$((${C[1]}  + ${C[2]}  + ${C[3]}  + ${C[4]}))
D1=$((${C[12]} + ${C[13]} + ${C[14]} + ${C[15]}))
D2=$((${C[23]} + ${C[24]} + ${C[25]} + ${C[26]}))
D3=$((${C[34]} + ${C[35]} + ${C[36]} + ${C[37]}))
# cpu usage per core
E0=$(echo "scale=1; (100 * ($B0 - $D0 - ${A[4]}   + ${C[4]})  / ($B0 - $D0))" | bc)
E1=$(echo "scale=1; (100 * ($B1 - $D1 - ${A[15]}  + ${C[15]}) / ($B1 - $D1))" | bc)
E2=$(echo "scale=1; (100 * ($B2 - $D2 - ${A[26]}  + ${C[26]}) / ($B2 - $D2))" | bc)
E3=$(echo "scale=1; (100 * ($B3 - $D3 - ${A[37]}  + ${C[37]}) / ($B3 - $D3))" | bc)
echo $E0
echo $E1
echo $E2
echo $E3

O uso médio de cpu por núcleo pode ser calculado diretamente de /proc/stat (Créditos para @mikeserv para a sugestão de usar /proc/stat .):

# Here we make use of bash direct array assignment
A0=($(sed '2q;d' /proc/stat))
A1=($(sed '3q;d' /proc/stat))
A2=($(sed '4q;d' /proc/stat))
A3=($(sed '5q;d' /proc/stat))
# user         + nice     + system   + idle
B0=$((${A0[1]} + ${A0[2]} + ${A0[3]} + ${A0[4]}))
B1=$((${A1[1]} + ${A1[2]} + ${A1[3]} + ${A1[4]}))
B2=$((${A2[1]} + ${A2[2]} + ${A2[3]} + ${A2[4]}))
B3=$((${A3[1]} + ${A3[2]} + ${A3[3]} + ${A3[4]}))
sleep 0.2
C0=($(sed '2q;d' /proc/stat))
C1=($(sed '3q;d' /proc/stat))
C2=($(sed '4q;d' /proc/stat))
C3=($(sed '5q;d' /proc/stat))
# user         + nice     + system   + idle
D0=$((${C0[1]} + ${C0[2]} + ${C0[3]} + ${C0[4]}))
D1=$((${C1[1]} + ${C1[2]} + ${C1[3]} + ${C1[4]}))
D2=$((${C2[1]} + ${C2[2]} + ${C2[3]} + ${C2[4]}))
D3=$((${C3[1]} + ${C3[2]} + ${C3[3]} + ${C3[4]}))
# cpu usage per core
E0=$(((100 * (B0 - D0 - ${A0[4]} + ${C0[4]})) / (B0 - D0)))
E1=$(((100 * (B1 - D1 - ${A1[4]} + ${C1[4]})) / (B1 - D1)))
E2=$(((100 * (B2 - D2 - ${A2[4]} + ${C2[4]})) / (B2 - D2)))
E3=$(((100 * (B3 - D3 - ${A3[4]} + ${C3[4]})) / (B3 - D3)))
echo $E0
echo $E1
echo $E2
echo $E3

ou ainda mais curto, fazendo uso extensivo da atribuição direta de matriz do bash:

# Here we make use of bash direct array assignment by assigning line
# 2 to 4 to one array


A=($(sed -n '2,5p' /proc/stat))
# user         + nice     + system   + idle
B0=$((${A[1]}  + ${A[2]}  + ${A[3]}  + ${A[4]}))
B1=$((${A[12]} + ${A[13]} + ${A[14]} + ${A[15]}))
B2=$((${A[23]} + ${A[24]} + ${A[25]} + ${A[26]}))
B3=$((${A[34]} + ${A[35]} + ${A[36]} + ${A[37]}))
sleep 0.2
# user         + nice     + system   + idle
C=($(sed -n '2,5p' /proc/stat))
D0=$((${C[1]}  + ${C[2]}  + ${C[3]}  + ${C[4]}))
D1=$((${C[12]} + ${C[13]} + ${C[14]} + ${C[15]}))
D2=$((${C[23]} + ${C[24]} + ${C[25]} + ${C[26]}))
D3=$((${C[34]} + ${C[35]} + ${C[36]} + ${C[37]}))
# cpu usage per core
E0=$((100 * (B0 - D0 - ${A[4]}  + ${C[4]})  / (B0 - D0)))
E1=$((100 * (B1 - D1 - ${A[15]} + ${C[15]}) / (B1 - D1)))
E2=$((100 * (B2 - D2 - ${A[26]} + ${C[26]}) / (B2 - D2)))
E3=$((100 * (B3 - D3 - ${A[37]} + ${C[37]}) / (B3 - D3)))
echo $E0
echo $E1
echo $E2
echo $E3

Uma solução baseada em top

Isso também pode ser obtido sem a instalação de uma ferramenta adicional com top (usei isso em uma versão posterior post .) Por padrão top mostra apenas o carregamento médio da cpu quando é iniciado, mas mostrará todos os cpus quando você pressione 1 . Para poder usar a saída cpu de top quando usá-la no modo de saída em lote, precisaremos torná-la o comportamento padrão quando top for iniciado. Isso pode ser feito usando um arquivo ~/.toprc . Felizmente, isso pode ser criado automaticamente: inicie top press 1 e pressione W , o que gerará o arquivo ~/.toprc em sua homefolder. Quando você executar top -bn 1 | grep -F '%Cpu' , verá que top agora gera todos os seus núcleos. Agora já temos tudo de que precisamos para fazer isso funcionar. Todas as informações que preciso estão na coluna 3 da matriz que será a saída de top .

Há apenas um problema: quando o uso da CPU para um núcleo atinge 100% , a matriz que o comando gera moverá a coluna com a carga atual da coluna 3 para a coluna 2 . Assim, com awk '{print $3}' , você verá us, como saída para a coluna 3 . Se você está bem com isso, deixe isso. Se não, você pode ter awk print column 2 também. Será apenas : . Uma solução que evita todas essas armadilhas é:

top -bn 2 | grep -F '%Cpu' | tail -n 4 | gawk '{print $2 $3}' | tr -s '\n\:\,[:alpha:]' ' '

ele retira a saída de todas as novas linhas de caracteres \n , , e letras [:alpha:] e remove todos menos um único espaço em branco -s .

    
por 31.08.2014 / 17:43
7

Isso cria uma matriz bash cujos elementos são as cargas para cada CPU:

loads=($(mpstat -P ALL 1 1 | awk '/Average:/ && $2 ~ /[0-9]/ {print $3}'))

Como as matrizes bash são numeradas começando com zero, a carga da segunda CPU seria impressa com:

echo ${loads[1]}

Isso requer o utilitário mpstat . Para instalá-lo em um sistema parecido com o debian, execute:

apt-get install sysstat

Como funciona

A saída um pouco detalhada produzida por mpstat se parece com:

$ mpstat -P ALL 1 1
Linux 3.2.0-4-amd64 (MyMachine)     08/30/2014      _x86_64_        (2 CPU)

10:12:35 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
10:12:36 PM  all    1.49    0.00    1.49    0.00    0.00    0.00    0.00    0.00   97.01
10:12:36 PM    0    0.00    0.00    2.02    0.00    0.00    0.00    0.00    0.00   97.98
10:12:36 PM    1    1.96    0.00    1.96    0.00    0.00    0.00    0.00    0.00   96.08

Average:     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
Average:     all    1.49    0.00    1.49    0.00    0.00    0.00    0.00    0.00   97.01
Average:       0    0.00    0.00    2.02    0.00    0.00    0.00    0.00    0.00   97.98
Average:       1    1.96    0.00    1.96    0.00    0.00    0.00    0.00    0.00   96.08

onde -P ALL informa mpstat para mostrar todos os processadores e os 1 1 dizem para imprimir a saída a cada segundo e parar após o primeiro segundo.

Para selecionar apenas os valores que queremos, este comando awk é usado:

awk '/Average:/ && $2 ~ /[0-9]/ {print $3}'

Seleciona apenas as linhas finais (aquelas que começam com Average: e, dentre elas, seleciona apenas aquelas cuja segunda coluna é numérica. Para essas linhas, a terceira coluna (cpu load) é impressa.

Devido ao uso de parênteses, a saída do pipeline mpstat - awk é capturada em uma matriz bash.

    
por 31.08.2014 / 07:11
1

você pode ver a frequência de cada núcleo com o seguinte:

$ cat /proc/cpuinfo
    
por 31.08.2014 / 04:48
1

Eu criei esta solução e funciona para mim.

echo print 'top -n 1 | tr -s " " | cut -d$" " -f10 | tail -n +8 | head -n -1 | paste -sd+ | bc'/ 'nproc' | python

Fonte (write up): link

    
por 27.11.2015 / 23:38