![Shell 脚本和“nvidia-smi”-需要正确的命令/标志!](https://linux22.com/image/1085397/Shell%20%E8%84%9A%E6%9C%AC%E5%92%8C%E2%80%9Cnvidia-smi%E2%80%9D-%E9%9C%80%E8%A6%81%E6%AD%A3%E7%A1%AE%E7%9A%84%E5%91%BD%E4%BB%A4%2F%E6%A0%87%E5%BF%97%EF%BC%81.png)
我遇到了有关 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”。这似乎是我的小脚本中最好的解决方案。
非常期待您的回复;)