Shell 脚本和“nvidia-smi”-需要正确的命令/标志!

Shell 脚本和“nvidia-smi”-需要正确的命令/标志!

我遇到了有关 shell 脚本和“nvidia-smi”命令的问题!

我编写了一个脚本,用于防止 Ubuntu Server 14.04.2 上的 CPU 过热。该脚本运行良好,但我需要让它在我的 4 个 GPU 上也能运行。我对 bash 脚本还不是很了解,所以我一直在寻找可以让我轻松编辑脚本的命令。我找到并测试了很多命令,但似乎没有一个能给我所需的输出!我将在下面向您展示命令和输出。还有脚本。

我需要的是一个可以像“lm-sensors”中的“sensors”命令一样列出 GPU 的命令。这样我就可以使用“grep”选择 GPU 并设置变量“newstring”(temp. 两位数字)。我尝试了几天,但一直没有成功。主要是因为命令“nvidia-smi -lso”和/或“nvidia-smi -lsa”不再存在。我认为这是一个实验性的命令。

以下是我找到并测试过的命令和输出:

此命令显示 GPU 插槽编号,我可以将其放入字符串“str”中,但问题是 temp。在下一行。我一直在摆弄标志“A 1”,但无法将其放入脚本中:

# 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

此命令在第一行显示温度,但没有 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

此命令显示您选择的 GPU 编号,但仍然没有显示 GPU 编号/插槽/ID 的输出!?

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

此命令在同一行显示 GPU 编号和结果!但是没有温度!

# 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-..........)

还有一个命令,显示所有 4 个 GPU 的温度,没有其他任何内容。但我仍然需要 GPU 编号/插槽/ID!?

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

我希望得到什么!如果我能得到一个产生如下输出的命令,我会是最幸福的人:

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

以下是“lm-sensors”中“sensors”的输出。如您所见,单位信息和温度在同一行:

# -----------------------------------------------------------
# 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)
# -----------------------------------------------------------

这是需要更改的脚本部分。如上文所述,使用应用程序“lm-sensors”中的命令“sensors”即可实现此操作。运行 CUDA 并连接驱动程序时,“lm-sensors”不会显示 GPU 温度,因此我们需要另一个命令来列出 GPU 并显示温度。您可能知道另一种解决我的问题的方法,请随时告诉我:

[...]
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
[...]

我希望有一位 bash-script 专家可以解决这个问题,祝你周末愉快!

谨致问候, 丹·汉森 丹麦

答案1

awk是一款非常适合此用途的万能工具。对于每个输入行,它都会执行所有匹配的命令。在这里,我将两个命令的输出通过管道传输到 awk。当它匹配行开头时,GPU 0:它会在“(”字符处将该行拆分为 2 个部分,并将第一部分 (x[1]) 保存在由从字段 2 获得的 gpu 编号索引的数组中($2:字段由空格分隔)。

当它匹配行时,GPU 0000:01:00.0它会在“:”字符处将字段 2 分成 3 个部分,并将第 2 部分减 1 保存为 gpu 编号。

当它与行匹配时,GPU Current Temp将第 5 和第 6 个字段(用空格连接)保存到另一个数组中,由前一行设置的“全局”变量 gpu 索引。

在输入结束时(END),我们打印数组,现在它们拥有所有信息。

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"

以下是脚本中函数 mynvidia 的输出:

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

答案2

你真正需要做的就是删除所有以 开头的行中的换行符GPU。你可以使用这个 perl 单行程序,它删除前三个字符为 的行中的换行符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

或者,您可以按照以下步骤完成整个操作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

它只是检查当前行是否以 a 结尾C,如果是,则将其$0与上一行一起打印()。last=$0将当前行保存为,以便last在处理下一行时可用。

以下是用 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

最后,既然您无论如何都是在 shell 脚本中执行此操作,那么您也可以直接从 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

答案3

感谢您的回复!!这似乎解决了我的问题!!第二个使用 awk 的建议在我的系统上看起来不一样,但您的第一个建议非常完美!我再说一遍,完美!!非常感谢我的朋友。这真的帮助了我。我不得不说,您很好地解决了这个问题,我会保留其他建议以供将来使用!!再次感谢您的帮助,我的朋友!

为了让其他人看到并学习这一点,以下是我在 Ubuntu Server 14.04 上的结果

在我的系统上它看起来像这样:

# 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

这个简直完美,在我的系统上看起来像这样:

# 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

这里我得到了脚本中“grep”的 GPU 文本。我得到了 GPU 插槽 ID,最后但并非最不重要的是,我得到了同一行中的温度!这正是我想要的。我谦卑地鞠躬 ;)

我希望遇到同样问题的人可以使用它来解决他们的问题。

谨致问候,丹

答案4

也许您知道如何解决这个问题。我已经测试了我重新安装的脚本,但我在处理 2 个变量时遇到了困难。我需要在“str”中设置 GPU 编号,在“newstr”中设置温度。第一个字符串似乎运行良好,“grep”正在运行,但当遇到第二个字符串时,它就停止了。我已经数了 101 次空格。您知道这是不是问题所在吗?是否需要以其他方式“计算”空格?

这是我的脚本:

#!/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 ''

这是运行脚本时的输出:

# ./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

我尝试了第 4 个建议,即脚本命令,但在测试时,输出再次看起来像这样。没有 GPU 编号。因此,我认为您的第一个建议对我来说是最好的,但我仍然对温度变量“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

所以,Terdon,如果你能以任何方式帮助我完成这项工作,我将不胜感激。如何将温度放入“newstr”。这似乎是我的小脚本中最好的解决方案。

非常期待您的回复;)

相关内容