Linux

在 shell 腳本中獲取每核 CPU 負載

  • September 14, 2021

我需要從 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的建議。

引用自:https://unix.stackexchange.com/questions/313178