在 shell 腳本中獲取每核 CPU 負載
我需要從 shell 腳本報告每個核心的 CPU 負載百分比,但我不能執行例如 mpstat 一秒鐘。基本上我認為
top
按下後顯示的資訊是1
我想要的,但我無法配置 top 以批處理模式顯示(至少我不知道如何)。我可以使用配置創建一個~/.toprc
文件,但是我必須希望使用者不要弄亂它。我查看
mpstat
並解析了輸出,但這僅支持秒作為間隔時間。我的腳本通過 SNMP 呼叫,等待 1 秒的響應將產生超時,所以這不是一個選項。還有其他方法可以獲得每核 CPU 負載嗎?我讀到了 parsing
/proc/stat
,但我認為這更像是最後的手段。
有幾種方法可以完成對 cpu 負載的 sub-sccond 輪詢,可以使用 dstat 之類的實用程序(下面的範例)或直接輪詢 /proc/stat(下面的範例)。
在繼續討論技術範例之前,讓我們回顧一下兩者的優缺點。
要使用 dstat,您需要執行一個快速的 crontab ( */1 * * * * ) 並將結果通過管道傳輸到您可以檢查的統計文件中。好處是您的 SNMP 超時不會成為問題,壞處是它不是真正即時的,並且在您實際上不查找此數據時執行 crontab 會產生影響。影響可能可以忽略不計,但仍然存在。
要使用 /proc/stat,您必須輪詢 /proc/stat 的內容兩次。/proc/stat 的內容是從啟動時累積的。因此需要將第一次輪詢和第二次輪詢結果相減,然後才能進行目前負載的計算。缺點是必須有某種形式的延遲才能進行此計算。在下面的範例中,我已將延遲降低到亞秒級。這將滿足您的需求,但是數據樣本非常接近,我不確定準確度有多絕對。
使用 dstat; 將此行添加到 /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
這僅每分鐘更新一次。如果您想要更頻繁的更新,請添加第二行並在命令前加上 sleep 30,例如
*/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
甚至可以更遠地使用(濫用)cron 並獲得亞秒級的結果,但這完全是另一個話題。
解釋:
dstat -c -C 0 –noheaders –nocolor 1 0
-c 只顯示cpu數據
-C 選擇 cpu0。更改編號以選擇其他 cpu
–noheaders –nocolor(隱含的 –noupdate)簡化我們所看到的
1 統計數據讀取延遲一秒
1 在第二次讀取統計資訊後退出。給它時間在呼叫後安定下來。
grep -v “-|u”
去除非數據線
awk ‘NR == 2’
選擇第二行。
tr -s""
修剪掉螢幕上看起來不錯但不適合系統使用的多餘空間
剪切 -d \ -f 4
-d \(在\(轉義)空格劃定的行之後有一個空格 -f 4 選擇空閒。是的,它在視覺上是3,但是行首的空格算作一個欄位,而不是欄位計數。
$ (( ))
bash 算術運算,從 100 中減去系統空閒。
使用 /proc/stat;
另存為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
獲取原始值的另一種方法是
grep cpu0 /proc/stat
. 在那裡,您可以看到每個州的刻度數。做man proc
解釋的細節。如果你想要它作為一個百分比,你必須將它們加在一起並除以,例如按照John W. Gill的建議。