Script de shell & “nvidia-smi” - precisa de comando / sinalização correta!

1

Eu tenho um problema com relação a um shell script e ao comando "nvidia-smi"!

Eu fiz um script que protege contra o superaquecimento da CPU no meu Ubuntu Server 14.04.2. Os scripts funcionam muito bem, mas também preciso que funcione nas minhas 4 GPUs. Eu sou bastante verde quando se trata de scripts bash, então eu tenho procurado por comandos que tornariam mais fácil para mim editar o script. Eu encontrei e testei muitos deles, mas nenhum parece me dar a saída que eu preciso! Eu vou te mostrar os comandos e a saída abaixo. E os scripts também.

O que eu preciso é de um comando que liste as GPUs da mesma forma que o comando "sensors" de "lm-sensors" faz. Para que eu possa usar "grep" para selecionar uma GPU e definir a variável "newstring" (a temperatura de dois dígitos). Eu tenho tentado por um par de dias, mas não tive sorte. Principalmente porque o comando "nvidia-smi -lso" e / ou "nvidia-smi -lsa" não existe mais. Acho que foi um comando experimental.

Aqui estão os comandos que encontrei e testei & amp; a saída:

Este comando mostra o número do soquete da GPU que eu poderia colocar na string "str", mas o problema é que a temp. está na próxima linha. Eu tenho mexido na bandeira "A 1", mas não consegui colocar no script:

# nvidia-smi -q -d temperature | grep GPU
Attached GPUs                       : 4
GPU 0000:01:00.0
        GPU Current Temp            : 57 C
        GPU Shutdown Temp           : N/A
        GPU Slowdown Temp           : N/A
GPU 0000:02:00.0
        GPU Current Temp            : 47 C
        GPU Shutdown Temp           : N/A
        GPU Slowdown Temp           : N/A
GPU 0000:03:00.0
        GPU Current Temp            : 47 C
        GPU Shutdown Temp           : N/A
        GPU Slowdown Temp           : N/A
GPU 0000:04:00.0
        GPU Current Temp            : 48 C
        GPU Shutdown Temp           : N/A
        GPU Slowdown Temp           : N/A

Este comando mostra a temperatura na primeira linha, mas não há um número de GPU!?

# nvidia-smi -q -d temperature | grep "GPU Current Temp"
        GPU Current Temp            : 58 C
        GPU Current Temp            : 47 C
        GPU Current Temp            : 47 C
        GPU Current Temp            : 48 C

Este comando mostra o número da GPU que você selecionou, mas ainda não há saída mostrando o numer / socket / ID da GPU!?

# nvidia-smi -q --gpu=0 | grep "GPU Current Temp"
GPU Current Temp            : 59 C

E este comando mostra o número da GPU e os resultados na mesma linha !! Mas sem temperatura !!

# nvidia-smi -L
GPU 0: GeForce GTX 750 Ti (UUID: GPU-9785c7c7-732f-1f51-..........)
GPU 1: GeForce GTX 750 (UUID: GPU-b2b1a4a-4dca-0c7f-..........)
GPU 2: GeForce GTX 750 (UUID: GPU-5e6b8efd-7531-777c-..........)
GPU 3: GeForce GTX 750 Ti (UUID: GPU-5b2b1a2f-3635-2a1c-..........)

E um comando que mostra todas as 4 temp. da GPU. sem mais nada. Mas ainda preciso do número / socket / ID da GPU!?

# nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader
58
47
47
48

O que eu estou desejando! Se eu conseguisse um comando que fizesse uma saída como essa, seria o cara mais feliz do mundo:

GPU 0: GeForce GTX 750 Ti   GPU Current Temp            : 58 C
GPU 1: GeForce GTX 750   GPU Current Temp            : 47 C
GPU 2: GeForce GTX 750   GPU Current Temp            : 47 C
GPU 3: GeForce GTX 750 Ti   GPU Current Temp            : 48 C

Aqui está a saída que "sensores" de "lm-sensors". Como você pode ver a informação da unidade e a temperatura está na mesma linha:

# -----------------------------------------------------------
# coretemp-isa-0000
# Adapter: ISA adapter
# Physical id 0:  +56.0°C  (high = +80.0°C, crit = +100.0°C)
# Core 0:         +56.0°C  (high = +80.0°C, crit = +100.0°C)
# Core 1:         +54.0°C  (high = +80.0°C, crit = +100.0°C)
# Core 2:         +54.0°C  (high = +80.0°C, crit = +100.0°C)
# Core 3:         +52.0°C  (high = +80.0°C, crit = +100.0°C)
# -----------------------------------------------------------

Aqui está a parte do script que precisa ser alterada. Como mencionado no topo, isso funciona usando o comando "sensores" da aplicação "lm-sensors". "lm-sensors" não mostra a temperatura da GPU. Ao executar o CUDA e o driver anexado, precisamos de outro comando para obter a GPU listada e a temp. mostrando. Você pode saber outra maneira de corrigir o meu problema, se por favor não hesite em me mostrar.:

[...]
echo "JOB RUN AT $(date)"
echo "======================================="

echo ''
echo 'CPU Warning Limit set to => '$1
echo 'CPU Shutdown Limit set to => '$2
echo ''
echo ''

sensors

echo ''
echo ''

for i in 0 1 2 3
do

  str=$(sensors | grep "Core $i:")
  newstr=${str:17:2}

  if [ ${newstr} -ge $1 ]
  then
    echo '===================================================================='         >>/home/......../logs/watchdogcputemp.log
    echo $(date)                                                                        >>/home/......../logs/watchdogcputemp.log
    echo ''                                                                             >>/home/......../logs/watchdogcputemp.log
    echo ' STATUS WARNING - NOTIFYING : TEMPERATURE CORE' $i 'EXCEEDED' $1 '=>' $newstr >>/home/......../logs/watchdogcputemp.log
    echo ' ACTION : EMAIL SENT'                                                         >>/home/......../logs/watchdogcputemp.log
    echo ''                                                                             >>/home/......../logs/watchdogcputemp.log
    echo '===================================================================='         >>/home/......../logs/watchdogcputemp.log

# Status Warning Email Sending Code
# WatchdogCpuTemp Alert! Status Warning - Notifying!"

/usr/bin/msmtp -d --read-recipients </home/......../shellscripts/messages/watchdogcputempwarning.txt

    echo 'Email Sent.....'
  fi
[...]

Espero que exista um guru do script, pronto para resolver este problema Tenham um ótimo final de semana!

Atenciosamente, Dan Hansen Dinamarca

.

    
por user246252 20.06.2015 / 02:57

5 respostas

1
O

awk é uma ótima ferramenta para todos os fins, perfeita para isso. Para cada linha de entrada ele executa todos os comandos correspondentes. Aqui eu canalizo a saída de dois seus comandos no awk. Quando coincide com as linhas que começam com GPU 0: it divide a linha em 2 partes no caractere "(" e salva a primeira parte (x [1]) em um array indexado pelo número gpu, obtido do campo 2 ($ 2: fields são separados por espaço em branco).

Quando coincide com as linhas GPU 0000:01:00.0 , divide o campo 2 em 3 partes em o caractere ":" e salva a segunda parte menos 1 como o número da gpu.

Quando corresponder a linhas com GPU Current Temp , salve a quinta e a sexta. campos (concatenados com um espaço) em outro array, indexados pelo variável "global" gpu definida por uma linha anterior.

No final da entrada (END) nós imprimimos as matrizes, agora elas têm todas as informações.

mynvidia(){

 ( nvidia-smi -L
   nvidia-smi -q -d temperature | grep GPU
 ) | 
 awk '
 /^GPU [0-9]:/     { gpu=0+$2; split($0,x,"("); gputype[gpu]=x[1]; }
 /^GPU 00/         { split($2,x,":"); gpu=x[2]-1; }
 /GPU Current Temp/{ temperature[gpu] = $5 " " $6; }
 END               { for(gpu=0;gpu<99;gpu++)
                     if(gputype[gpu]!="")
                      printf "%-30s GPU Current Temp: %s\n",gputype[gpu],temperature[gpu]
                   }'
}

str=$(mynvidia | grep "GPU $i:")
newstr=${str:49:2}
# ... echo "$str"

Aqui está a saída da função mynvidia em um script:

GPU 0: GeForce GTX 750 Ti      GPU Current Temp: 57 C
GPU 1: GeForce GTX 750         GPU Current Temp: 47 C
GPU 2: GeForce GTX 750         GPU Current Temp: 47 C
GPU 3: GeForce GTX 750 Ti      GPU Current Temp: 48 C
    
por meuh 20.06.2015 / 12:17
1

Tudo o que você precisa fazer é remover a nova linha de todas as linhas, começando com GPU . Você poderia usar esse forro perl que remove linhas novas de linhas cujos primeiros três caracteres são GPU :

$ nvidia-smi -q -d temperature | grep GPU | perl -pe '/^GPU/ && s/\n//' | grep ^GPU
GPU 0000:01:00.0        GPU Current Temp            : 57 C
GPU 0000:02:00.0        GPU Current Temp            : 47 C
GPU 0000:03:00.0        GPU Current Temp            : 47 C
GPU 0000:04:00.0        GPU Current Temp            : 48 C

Como alternativa, você pode fazer tudo em awk :

$ nvidia-smi -q -d temperature | awk '{if(/C$/){print last,$0};last=$0};' 
GPU 0000:01:00.0         GPU Current Temp            : 57 C
GPU 0000:02:00.0         GPU Current Temp            : 47 C
GPU 0000:03:00.0         GPU Current Temp            : 47 C
GPU 0000:04:00.0         GPU Current Temp            : 48 C

Isso simplesmente verifica se a linha atual termina com C e, em caso afirmativo, imprime ( $0 ) junto com a linha anterior. last=$0 salva a linha atual como last para disponibilizá-la quando a próxima linha é processada.

Aqui está a mesma lógica implementada no Perl:

$ nvidia-smi -q -d temperature | perl -lne 'print "$last $_" if /C$/; $last=$_' file 
GPU 0000:01:00.0         GPU Current Temp            : 57 C
GPU 0000:02:00.0         GPU Current Temp            : 47 C
GPU 0000:03:00.0         GPU Current Temp            : 47 C
GPU 0000:04:00.0         GPU Current Temp            : 48 C

Finalmente, como você está fazendo isso em um shell script, você também pode obter a saída desejada diretamente do bash:

$ nvidia-smi -q -d temperature | while read line; do 
    [[ $line =~ C$ ]] && printf "%s : %s\n" "$last" "$line";
    last="$line"; done
GPU 0000:01:00.0 : GPU Current Temp            : 57 C
GPU 0000:02:00.0 : GPU Current Temp            : 47 C
GPU 0000:03:00.0 : GPU Current Temp            : 47 C
GPU 0000:04:00.0 : GPU Current Temp            : 48 C
    
por terdon 20.06.2015 / 15:22
0

Obrigado pela sua resposta !! Isso parece resolver meu problema !! A segunda sugestão usando awk não parecia da mesma maneira aqui no meu sistema, mas sua primeira sugestão foi simplesmente perfeita! Eu repito PERFEITO !! Muito obrigado por isso meu amigo. Isso realmente me ajuda. Eu tenho que dizer que você resolve a questão muito bem e eu vou manter as outras sugestões para uso posterior !! Mais uma vez, muito obrigado pela sua ajuda meu amigo!

Para os outros verem eu vou aprender sobre isso aqui estão os resultados no meu Ubuntu Server 14.04

Este se parece com isso no meu sistema:

# nvidia-smi -q -d temperature | awk '{if(/C$/){print last,$0};last=$0};'
    Temperature         GPU Current Temp            : 53 C
    Temperature         GPU Current Temp            : 45 C
    Temperature         GPU Current Temp            : 52 C
    Temperature         GPU Current Temp            : 51 C

E este, que é apenas PERFEITO, se parece com isso no meu sistema:

# nvidia-smi -q -d temperature | grep GPU | perl -pe '/^GPU/ && s/\n//' | grep ^GPU
GPU 0000:01:00.0        GPU Current Temp            : 53 C
GPU 0000:02:00.0        GPU Current Temp            : 45 C
GPU 0000:03:00.0        GPU Current Temp            : 52 C
GPU 0000:04:00.0        GPU Current Temp            : 51 C

Aqui eu tenho o texto da GPU para "grep" no meu script. Eu tenho o ID do soquete GPU e por último mas não menos importante, eu tenho a temperatura na mesma linha! Exatamente o que eu pedi. Eu humildemente me curvo;)

Espero que outras pessoas com o mesmo problema usem isso para resolver o problema.

Atenciosamente, Dan

    
por user246252 28.06.2015 / 06:21
0

Eu tentei a nova "edição" da sua sugestão e funcionou bem! Parece ótimo. Mas eu estou tentando fazer isso funcionar no script e parece ser difícil ...

Aqui está a saída legal quando executado como um script:

# ./getgputemp.sh
GPU 0: GeForce GTX 750 Ti      GPU Current Temp: 49 C
GPU 1: GeForce GTX 750         GPU Current Temp: 39 C
GPU 2: GeForce GTX 750         GPU Current Temp: 42 C
GPU 3: GeForce GTX 750 Ti      GPU Current Temp: 51 C

Por favor, mostre-me como usá-lo no meu script. Eu tentei várias maneiras e não consigo fazer funcionar. Eu preciso de variáveis para fazer o script funcionar. Eu preciso de "str", que é o GPUnumber e eu preciso de "newstr", que é a temperatura ". Alguma idéia?

O script como está agora:

    #!/bin/bash

    # --- WatchdogGpuTemp.sh v.0.1.6 ---
    # Author: DanHansen[at]Denmark
    # Application: nvidia-smi
    # Filename: watchdoggputemp.sh
    # Logfile: watchdoggputemp.log
    # Message file for status warning: watchdoggputempwarning.txt
    # Message file for status critical: watchdoggputempcritical.txt
    # Work directory: /home/username/shellscripts/
    # Log directory: /home/username/logs/
    # Message directory: /home/username/shellscripts/messages/
    #
    # --- WatchdogGpuTemp.sh v.0.1.6 ---

    echo "JOB RUN AT $(date)"
    echo "======================================="

    echo ''
    echo 'CPU Warning Limit set to => '$1
    echo 'CPU Shutdown Limit set to => '$2
    echo ''
    echo ''


( nvidia-smi -L
  nvidia-smi -q -d temperature | grep GPU
) | 
awk '
/^GPU [0-9]:/     { gpu=0+$2; split($0,x,"("); gputype[gpu]=x[1]; }
/^GPU 00/         { split($2,x,":"); gpu=x[2]-1; }
/GPU Current Temp/{ temperature[gpu] = $5 " " $6; }
END               { for(gpu=0;gpu<4;gpu++)
                      printf "%-30s GPU Current Temp: %s\n",gputype[gpu],temperature[gpu]
                  }'


    echo ''
    echo ''

    for i in 1 2 3 4
    do


      str=$( YOUR STUFF AND GREP "GPU $i:)  <------- SET "STR" TO GPU NUMBER
      newstr=${str:49:2}  <------------------------- SET "NEWSTR" TO TEMPERATURE



      if [ ${newstr} -ge $1 ]
      then
        echo '===================================================================='        >>/home/username/logs/watchdoggputemp.log
        echo $(date)                                                                       >>/home/username/logs/watchdoggputemp.log
        echo ''                                                                            >>/home/username/logs/watchdoggputemp.log
        echo ' STATUS WARNING - NOTIFYING : TEMPERATURE GPU' $i 'EXCEEDED' $1 '=>' $newstr >>/home/username/logs/watchdoggputemp.log
        echo ' ACTION : EMAIL SENT'                                                        >>/home/username/logs/watchdoggputemp.log
        echo ''                                                                            >>/home/username/logs/watchdoggputemp.log
        echo '===================================================================='        >>/home/username/logs/watchdoggputemp.log

    # Status Warning Email Sending Code 
    # WatchdogGpuTemp Alert! Status Warning - Notifying!"

    /usr/bin/msmtp -d --read-recipients </home/username/shellscripts/messages/watchdoggputempwarning.txt

        echo 'Email Sent.....'
      fi

      if [ ${newstr} -ge $2 ]
      then
        echo '===================================================================='        >>/home/username/logs/watchdoggputemp.log
        echo $(date)                                                                       >>/home/username/logs/watchdoggputemp.log
        echo ''                                                                            >>/home/username/logs/watchdoggputemp.log
        echo ' STATUS CRITICAL - SHUTDOWN : TEMPERATURE GPU' $i 'EXCEEDED' $2 '=>' $newstr >>/home/username/logs/watchdoggputemp.log
        echo ' ACTION : EMAIL SENT & SYSTEM SHUTDOWN'                                      >>/home/username/logs/watchdoggputemp.log
        echo ''                                                                            >>/home/username/logs/watchdoggputemp.log
        echo '===================================================================='        >>/home/username/logs/watchdoggputemp.log

    # Status Critical Email Sending Code:
    # WatchdogGpuTemp Alert! Status Critical - Shutdown!"

    /usr/bin/msmtp -d --read-recipients </home/username/shellscripts/messages/watchdoggputempcritical.txt

        echo 'Email Sent.....'
        echo 'System will now shutdown.....'
        /sbin/shutdown -h now
        exit

      else
        echo ' Temperature GPU '$i' OK at =>' $newstr
        echo ''
      fi
    done

    echo 'Status - All GPUs are within critical temperature limits'
    echo ''
    
por user246252 28.06.2015 / 12:32
0

Talvez você tenha o conhecimento para corrigir isso. Eu testei meu script reformulado, mas estou lutando com duas variáveis. Preciso definir o número da GPU em "str" e a temperatura em "newstr". Parece ir muito bem com a primeira string e "grep" está funcionando, mas quando se trata do segundo, ele pára. Eu tenho contado os espaços 101 vezes. Você sabe se esse é o problema. Os espaços precisam ser "contados" de outra maneira?

Aqui está meu script:

#!/bin/bash

# --- WatchdogGpuTemp.sh v.0.1.2 ---
# Author: DanHansen[at]Denmark
# Thanks to "Terdon" Ubuntu Forums
# Application: nvidia-smi
# Filename: watchdoggputemp.sh
# Logfile: watchdoggputemp.log
# Message file for status warning: watchdoggputempwarning.txt
# Message file for status critical: watchdoggputempcritical.txt
# Work directory: /home/username/shellscripts/
# Log directory: /home/username/logs/
# Message directory: /home/username/shellscripts/messages/
#
# --- WatchdogGpuTemp.sh v.0.1.2 ---

echo "JOB RUN AT $(date)"
echo "======================================="

echo ''
echo 'CPU Warning Limit set to => '$1
echo 'CPU Shutdown Limit set to => '$2
echo ''
echo ''

nvidia-smi -q -d temperature | grep GPU | perl -pe '/^GPU/ && s/\n//' | grep ^GPU

echo ''
echo ''

for i in 1 2 3 4
do

  str=$(nvidia-smi -q -d temperature | grep GPU | perl -pe '/^GPU/ && s/\n//' | grep ^GPU "GPU 0000:0$i:00.0")
  newstr=${str:54:2}

  if [ ${newstr} -ge $1 ]
  then
    echo '===================================================================='        >>/home/username/logs/watchdoggputemp.log
    echo $(date)                                                                       >>/home/username/logs/watchdoggputemp.log
    echo ''                                                                            >>/home/username/logs/watchdoggputemp.log
    echo ' STATUS WARNING - NOTIFYING : TEMPERATURE GPU' $i 'EXCEEDED' $1 '=>' $newstr >>/home/username/logs/watchdoggputemp.log
    echo ' ACTION : EMAIL SENT'                                                        >>/home/username/logs/watchdoggputemp.log
    echo ''                                                                            >>/home/username/logs/watchdoggputemp.log
    echo '===================================================================='        >>/home/username/logs/watchdoggputemp.log

# Status Warning Email Sending Code 
# WatchdogGpuTemp Alert! Status Warning - Notifying!"

/usr/bin/msmtp -d --read-recipients </home/username/shellscripts/messages/watchdoggputempwarning.txt

    echo 'Email Sent.....'
  fi

  if [ ${newstr} -ge $2 ]
  then
    echo '===================================================================='        >>/home/username/logs/watchdoggputemp.log
    echo $(date)                                                                       >>/home/username/logs/watchdoggputemp.log
    echo ''                                                                            >>/home/username/logs/watchdoggputemp.log
    echo ' STATUS CRITICAL - SHUTDOWN : TEMPERATURE GPU' $i 'EXCEEDED' $2 '=>' $newstr >>/home/username/logs/watchdoggputemp.log
    echo ' ACTION : EMAIL SENT & SYSTEM SHUTDOWN'                                      >>/home/username/logs/watchdoggputemp.log
    echo ''                                                                            >>/home/username/logs/watchdoggputemp.log
    echo '===================================================================='        >>/home/username/logs/watchdoggputemp.log

# Status Critical Email Sending Code:
# WatchdogGpuTemp Alert! Status Critical - Shutdown!"

/usr/bin/msmtp -d --read-recipients </home/username/shellscripts/messages/watchdoggputempcritical.txt

    echo 'Email Sent.....'
    echo 'System will now shutdown.....'
    /sbin/shutdown -h now
    exit

  else
    echo ' Temperature GPU '$i' OK at =>' $newstr
    echo ''
  fi
done

echo 'Status - All GPUs are within critical temperature limits'
echo ''

Aqui está a saída ao executar o script:

# ./watchdoggputemp.sh 55 60
JOB RUN AT Sun Jun 28 10:13:57 CEST 2015
=======================================

CPU Warning Limit set to => 55
CPU Shutdown Limit set to => 60


GPU 0000:01:00.0        GPU Current Temp            : 49 C
GPU 0000:02:00.0        GPU Current Temp            : 46 C
GPU 0000:03:00.0        GPU Current Temp            : 52 C
GPU 0000:04:00.0        GPU Current Temp            : 51 C


grep: GPU 0000:01:00.0: No such file or directory
./watchdoggputemp.sh: line 68: [: -ge: unary operator expected
./watchdoggputemp.sh: line 86: [: -ge: unary operator expected
 Temperature GPU 1 OK at =>

grep: GPU 0000:02:00.0: No such file or directory
./watchdoggputemp.sh: line 68: [: -ge: unary operator expected
./watchdoggputemp.sh: line 86: [: -ge: unary operator expected
 Temperature GPU 2 OK at =>

grep: GPU 0000:03:00.0: No such file or directory
./watchdoggputemp.sh: line 68: [: -ge: unary operator expected
./watchdoggputemp.sh: line 86: [: -ge: unary operator expected
 Temperature GPU 3 OK at =>

grep: GPU 0000:04:00.0: No such file or directory
./watchdoggputemp.sh: line 68: [: -ge: unary operator expected
./watchdoggputemp.sh: line 86: [: -ge: unary operator expected
 Temperature GPU 4 OK at =>

Status - All GPUs are within critical temperature limits

Eu tentei a sugestão 4'th, o comando de script, mas ao testá-lo a saída se parece com isso novamente. Nenhum número de GPU. Portanto, acho que sua primeira sugestão é a melhor para mim, mas ainda luto com a variável de temperatura "newstr".:

# nvidia-smi -q -d temperature | while read line; do [[ $line =~ C$ ]] && printf "%s : %s\n" "$last" "$line"; last="$line"; done
Temperature : GPU Current Temp            : 51 C
Temperature : GPU Current Temp            : 46 C
Temperature : GPU Current Temp            : 53 C
Temperature : GPU Current Temp            : 50 C

Então, Terdon, se houver alguma maneira de você me ajudar do outro lado da linha de chegada aqui, ficarei muito agradecido. Como colocar a temperatura em "newstr". Parece ser a melhor solução no meu pequeno roteiro.

Olhando muito para frente para ouvir de você;)

    
por user246252 28.06.2015 / 10:16