Ich muss die CPU-Auslastung pro Kern als Prozentsatz aus einem Shell-Skript melden, aberIch kann zB mpstat eine Sekunde lang nicht ausführen. Grundsätzlich denke ich, dass die top
Anzeige der Informationen nach dem Drücken 1
das ist, was ich will, aber ich kann top nicht so konfigurieren, dass dies im Batch-Modus angezeigt wird (zumindest weiß ich nicht, wie das geht). Ich könnte eine ~/.toprc
Datei mit der Konfiguration erstellen, aber dann muss ich hoffen, dass die Benutzer nicht damit herumspielen.
Ich habe mir die Ausgabe angesehen mpstat
und analysiert, aber sie unterstützt nur Sekunden als Intervallzeit. Mein Skript wird über SNMP aufgerufen und wenn ich 1 Sekunde auf die Antwort warte, wird ein Timeout generiert, also ist das keine Option.
Gibt es andere Möglichkeiten, die CPU-Auslastung pro Kern zu ermitteln? Ich habe über das Parsen gelesen /proc/stat
, aber ich denke, das ist eher der letzte Ausweg.
Antwort1
Es gibt mehrere Möglichkeiten, eine Abfrage der CPU-Auslastung im Sekundentakt durchzuführen, entweder mithilfe eines Dienstprogramms wie dstat (Beispiel unten) oder durch direkte Abfrage von /proc/stat (Beispiel ebenfalls unten).
Lassen Sie uns die Vor- und Nachteile beider durchgehen, bevor wir zu den technischen Beispielen übergehen.
Um dstat zu verwenden, müssen Sie eine schnelle Crontab (*/1 * * * *) ausführen und das Ergebnis an eine Statistikdatei weiterleiten, die Sie überprüfen können. Der Vorteil ist, dass Ihre SNMP-Timeouts kein Problem darstellen. Der Nachteil ist, dass es nicht wirklich sofort passiert und das Ausführen der Crontab, wenn Sie diese Daten nicht wirklich suchen, Auswirkungen hat. Die Auswirkungen sind möglicherweise vernachlässigbar, aber sie sind immer noch vorhanden.
Um /proc/stat zu verwenden, müssen Sie den Inhalt von /proc/stat zweimal abfragen. Der Inhalt von /proc/stat ist kumulativ vom Start an. Die Ergebnisse der ersten und zweiten Abfrage müssen also voneinander abgezogen werden, und dann kann die Berechnung für die aktuelle Last durchgeführt werden. Der Nachteil ist, dass es bei dieser Berechnung zu einer gewissen Verzögerung kommen muss. Im folgenden Beispiel habe ich die Verzögerung auf unter eine Sekunde reduziert. Dies würde Ihren Anforderungen entsprechen, die Datenproben liegen jedoch so nah beieinander, dass ich nicht sicher bin, wie absolut genau dies ist.
Verwenden von dstat; Fügen Sie diese Zeile zu /etc/crontab hinzu:
*/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
Dies aktualisiert nur einmal pro Minute. Wenn Sie häufigere Updates wünschen, fügen Sie eine zweite Zeile hinzu und stellen Sie dem Befehl sleep 30 voran, wie
*/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
Es ist möglich, Cron noch weiter zu verwenden (zu missbrauchen) und Ergebnisse in weniger als einer Sekunde zu erzielen, aber das ist ein ganz anderes Thema.
Erläuterung:
dstat -c -C 0 --noheaders --nocolor 1 0
-c zeigt nur CPU-Daten
-C wähle CPU0. Nummerierung ändern, um andere CPU auszuwählen
--noheaders --nocolor (impliziert --noupdate) vereinfacht, was wir sehen
1 eine Sekunde Verzögerung beim Lesen der Statistiken
1 Beenden nach dem zweiten Lesen der Statistiken. Geben Sie ihm Zeit, sich nach dem Aufruf zu beruhigen.
grep -v "-\|u"
Nicht-Datenzeilen entfernen
awk 'NR == 2'
Wählen Sie die zweite Zeile aus.
tr -s " "
Entfernen Sie die zusätzlichen Leerzeichen, die auf dem Bildschirm zwar gut aussehen, aber nicht für die Systemnutzung geeignet sind.
Schnitt -d \ -f 4
-d \ (nach der durch \ (Escape) abgegrenzten Zeile steht ein Leerzeichen. -f 4 Leerlauf auswählen. Ja, optisch ist es 3, aber das Leerzeichen am Zeilenanfang zählt als Feld und verfälscht die Feldzählung.
$ (( ))
Bash-Rechenoperationen, wobei der Systemleerlauf von 100 abgezogen wird.
Verwenden von /proc/stat;
Speichern als 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
Antwort2
Eine andere Möglichkeit, die Rohwerte zu erhalten, wäre grep cpu0 /proc/stat
. Dort sehen Sie die Anzahl der Ticks in jedem Zustand. man proc
Für die Details zur Interpretation gehen Sie wie folgt vor. Wenn Sie es als Prozentsatz haben möchten, müssen Sie sie zusammenzählen und dividieren, zum Beispiel entlang der Linien von wasJohn W. Gillschlägt vor.
Antwort3
Hier ist einBash-basiertBeispielskript (mit /proc/stat) mit Erklärungen. Es kann so schnell laufen, wie Sie es brauchen. Speichern Sie als /tmp/cpuLoad.sh, dann "chmod +x /tmp/cpuLoad.sh" und führen Sie zuletzt aus: /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
Antwort4
Es stellt sich heraus, dass einige der auf RedHat installierten MIBs alle hier benötigten Informationen bereitstellen. Da mein Ziel darin besteht, diese Werte unter einer OID über SNMP bereitzustellen, kann ich SNMP nutzen und die Informationen verarbeiten.
Der Gesamt-CPU-Durchschnitt wird wie folgt berechnet 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}'
}
Wir können snmpwalk verwenden, um die Auslastung aller einzelnen CPUs abzurufen und dann den Maximalwert zu extrahieren:
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
}