シェルスクリプトでは、コアあたりのCPU負荷をパーセントで報告する必要がありますが、たとえば、mpstatをしばらく実行することはできません。。デフォルトでは、押されたtop
ときに表示される情報が私が望むものだと思います1
が、この情報をバッチモードで表示するように上部を設定することはできません(少なくとも方法はわかりません)。構成を使用してファイルを作成できますが、~/.toprc
ユーザーがその構成を台無しにしないことを願っています。
出力を表示してmpstat
解析しましたが、これは間隔時間として秒のみをサポートします。私のスクリプトはSNMPを介して呼び出され、応答を1秒間待つとタイムアウトが発生するため、これはオプションではありません。
コアあたりのCPU負荷を取得する他の方法はありますか?私はparsingについて読みました/proc/stat
が、これが最後の手段に近いと思います。
答え1
dstat(以下の例)などのユーティリティを使用したり、/ proc / statを直接ポーリング(下の例)など、CPU負荷を1秒未満でポーリングする方法はいくつかあります。
技術的な例に進む前に、2つの長所と短所を検討してみましょう。
dstat を使用するには、クイック crontab( */1 * * * * ) を実行し、結果を確認できる統計ファイルにパイプする必要があります。利点は、SNMPタイムアウトが問題にならないことです。欠点は、実際には即時ではなく、実際にこのデータを探していないときにcrontabを実行すると影響を与える可能性があることです。その影響はわずかかもしれませんが、まだ存在します。
/proc/statを使用するには、/proc/statの内容を2回ポーリングする必要があります。 /proc/statの内容はブートから蓄積されます。したがって、現在の負荷を計算するには、最初のポーリングと2番目のポーリングの結果を減算する必要があります。欠点は、この計算を可能にするには一定の形式の遅延が必要であることです。次の例では、待機時間を1秒未満のレベルに短縮しました。これは必要に応じて行われますが、データサンプルが非常に近いので、精度がどれほど絶対であるかはわかりません。
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
1分に1回だけ更新されます。より頻繁に更新するには、2行目を追加し、コマンドの前にスリープ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をさらに使用(乱用)して1秒未満の結果を得ることもできますが、これはまったく異なるトピックです。
説明する:
dstat -c -C 0 --noheaders --nocolor 1 0
-cはCPUデータのみを表示します。
-C は CPU0 を選択します。別のCPUを選択するには、番号を変更してください。
--noheaders --nocolor(-noupdate 暗黙) 表示される内容を単純化します。
1統計の読み取りが1秒遅れます。
1 2番目の統計を読み、終了します。通話後に落ち着く時間をください。
grep -v "-\|u"
データではなく行を削除する
awk 'NR == 2'
2番目の行を選択します。
tr-s""
画面には見えますが、システムの使用には適していない余分なスペースを切り取ります。
切り取り -d\-f 4
-d \(\(エスケープ) スペースの後にスペースが続きます。 -f 4 はアイドルを選択します。
$(())
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
答え2
生の値を取得する別の方法は、grep cpu0 /proc/stat
各状態のティック数を見ることができる。man proc
詳しく説明してください。パーセントが必要な場合は、それらを一緒に追加して分割する必要があります。たとえば、どのような線に従うべきですか?ジョン・ギル提案。
答え3
ここに一つあります。バッシュベースサンプルスクリプト(/proc/statの使用)説明と。必要な速度で動作します。 /tmp/cpuLoad.shとして保存し、「chmod +x /tmp/cpuLoad.sh」を実行し、最後に/tmp/cpuLoad.shを実行します。
#!/bin/bash
interval=0.25; ##loop interval in seconds
##so settings below
lCpus=(); ##store last readings
lCount=0; ## loop counter
while :; do {
cCpu=(); ##current cpu
cCpus=(); ##all cpus
values=$(grep -E "cpu[0-9]+\s" /proc/stat);
for value in $values; do {
if [[ $value =~ ^cpu[0-9]+ ]]; then
if [[ ${#cCpu[@]} > 0 ]]; then
cCpus[${cCpu[1]}]="${cCpu[@]}"
fi
cCpu[0]=$value; ##name
cCpu[1]=${#cCpus[@]}; ##cpu index
cCpu[2]=0; ##cpu idle ticks
cCpu[3]=0; ##cpu busy ticks
i=0; ## column index
else
((i=i+1));
if ([ $i == 4 ] || [ $i == 5 ]); then
# position 4 is the idle, position 5 is the i/o wait (also idle introduced 2.5.41) src https://www.idnt.net/en-US/kb/941772
((cCpu[2]=cCpu[2] + value));
else
((cCpu[3]=cCpu[3] + value));
fi
fi
} done
##include the last cpu
cCpus[${cCpu[1]}]="${cCpu[@]}"
output="Loop $lCount";
x=0;
for cpu in "${cCpus[@]}"; do {
if [[ $lCount > 0 ]]; then
cCpu=($cpu);
lCpu=(${lCpus[$x]});
dTotal=$(((${cCpu[2]} + ${cCpu[3]}) - (${lCpu[2]} + ${lCpu[3]})));
dUsed=$((dTotal - (${cCpu[2]} - ${lCpu[2]})));
if [[ $dTotal == 0 ]]; then
dTotal=1; ##dividing by 0 is never a good idea
fi
output="$output, ${cCpu[0]}: $((100 * dUsed / dTotal))%";
fi
##store the reading so we can do a delta next round
lCpus[$x]=$cpu;
((x=x+1));
} done
if [[ $lCount > 0 ]]; then
echo $output;
fi
sleep $interval;
((lCount=lCount+1));
} done
答え4
RedHatにインストールされた一部のMIBは、ここで必要なすべての情報を提供することがわかりました。私の目標は、SNMPを介してOIDの下にこれらの値を提供することであるため、SNMPを利用して情報を処理できます。
すべてのCPUの平均は次のように計算されます100-idle
。
function allCpuLoad {
# get system idle value from
# snmpget -v2c -cmdaf localhost UCD-SNMP-MIB::ssCpuIdle.0
# UCD-SNMP-MIB::ssCpuIdle.0 = INTEGER: 93
# and compute load by substracting it from 100.0
snmpget -v2c -cmdaf localhost UCD-SNMP-MIB::ssCpuIdle.0|cut -f4 -d' '| awk '{printf "%d", 100 - $1}'
}
snmpwalkを使用してすべての個々のCPUの負荷を取得し、最大値を抽出できます。
function maxCpuLoad {
# get load of all cpus
# snmpwalk -v2c -cmdaf localhost HOST-RESOURCES-MIB::hrProcessorLoad
# HOST-RESOURCES-MIB::hrProcessorLoad.196608 = INTEGER: 1
# HOST-RESOURCES-MIB::hrProcessorLoad.196609 = INTEGER: 1
# HOST-RESOURCES-MIB::hrProcessorLoad.196610 = INTEGER: 1
# HOST-RESOURCES-MIB::hrProcessorLoad.196611 = INTEGER: 1
# HOST-RESOURCES-MIB::hrProcessorLoad.196612 = INTEGER: 6
# HOST-RESOURCES-MIB::hrProcessorLoad.196613 = INTEGER: 1
# HOST-RESOURCES-MIB::hrProcessorLoad.196614 = INTEGER: 1
# HOST-RESOURCES-MIB::hrProcessorLoad.196615 = INTEGER: 1
# HOST-RESOURCES-MIB::hrProcessorLoad.196616 = INTEGER: 1
# HOST-RESOURCES-MIB::hrProcessorLoad.196617 = INTEGER: 27
# HOST-RESOURCES-MIB::hrProcessorLoad.196618 = INTEGER: 4
# HOST-RESOURCES-MIB::hrProcessorLoad.196619 = INTEGER: 0
# HOST-RESOURCES-MIB::hrProcessorLoad.196620 = INTEGER: 1
# HOST-RESOURCES-MIB::hrProcessorLoad.196621 = INTEGER: 0
# HOST-RESOURCES-MIB::hrProcessorLoad.196622 = INTEGER: 0
# HOST-RESOURCES-MIB::hrProcessorLoad.196623 = INTEGER: 1
# and get maximum value only
snmpwalk -v2c -cmdaf localhost HOST-RESOURCES-MIB::hrProcessorLoad|cut -f 4 -d' '|sort -n -r|head -n1
}