"Christmas - the time to fix the computers of your loved ones" « Lord Wyrm

Unter Linux die CPU Last in % anzeigen (nicht-interaktiv, MIT Kernellast!)

GrandAdmiralThrawn 12.09.2016 - 15:36 1928 13 Thread rating
Posts

GrandAdmiralThrawn

XP Nazi
Avatar
Registered: Aug 2000
Location: BRUCK!
Posts: 3534
Grüß euch!

Ich versuch grade mir einfachen Code in bash zu bauen, der mir die Gesamtlast einer CPU über alle Threads bzw. Kerne in % ausgibt. Mein aktueller Ansatz ist folgender:

Code:
echo -ne 'cpu load: ' $((`ps -A -o pcpu | tail -n+2 | paste -sd+ | bc | \\
 cut -d'.' -f1` / `cat /proc/cpuinfo | grep processor | wc -l`))'%. '
(Ist nur ein Teil einer größeren Kette von Kommandos, daher ned so auf die Ausgabeformatierung schauen..)

Ich rechne mir also die Last aller logischen CPUs aus der ps Ausgabe aus, kürze das auf einen Integer und dividiere die Last durch die Anzahl der logischen CPUs im System, ausgelesen aus /proc/cpuinfo.

Ok, Problem ist, der zeigt mir keine Kernellasten an, sondern nur Userspace Load. Auch aus top bekomme ich nur Userspace Load?! htop kann Kernellasten AUCH anzeigen, und macht's korrekt. htop haut aber wieder nichts auf die Shellausgabe raus, d.h. ich kann htops Ausgabe nicht in ein Skript einbauen.

Die Sache ist die: Wenn ich einen Rechenjob losschicke, passt ja alles so. Nur wenn ich virtuelle Maschinen hochjage und da drin Last produziere, dann ist das am Host draußen natürlich im Kernelspace! Und das erfasse ich so nicht.

Frage: Wie bekomme ich einen realen Snapshot der CPU Last unter Linux in Prozent (User + Kernel), wenn ich die Info nicht-interaktiv in einem Skript weiterverarbeiten möchte?

thx!

COLOSSUS

# pkill -9 .
Avatar
Registered: Dec 2000
Location: Wien || Stmk
Posts: 11005
ich weisz nicht, ob ich die Frage verstehe, aber `mpstat 1 1` und `top -b -n1` (beide ggf. mit zusaetzliche Optionen zur Beeinflussung der Ausgabe) kennst du?

GrandAdmiralThrawn

XP Nazi
Avatar
Registered: Aug 2000
Location: BRUCK!
Posts: 3534
Ich hab mpstat (und top) probiert und keine von Kernelmodulen verursachten Lasten damit ausgegeben bekommen, ich werd's aber morgen nochmal probieren.

Sache is die: Wenn eine virtuelle Maschine Last verursacht, dann ist die bei mir im Kernelspace (da sind halt irgendwelche Kernelmodule geladen die dann den Code innerhalb der VM ausführen). Da konnte ich alle Kerne auslasten, z.B. top hat mir das einfach nicht angezeigt. Wenn ich k.A., den GCC oder so anwerfe, kann ich die Last sofort bestimmen.

Aber ich schau's mir wie gesagt morgen nochmal mit den von dir angegebenen Optionen an...
Bearbeitet von GrandAdmiralThrawn am 12.09.2016, 18:55

COLOSSUS

# pkill -9 .
Avatar
Registered: Dec 2000
Location: Wien || Stmk
Posts: 11005
Auch Kernel-Thread-CPU-Accounting schlaegt sich in procfs an den zu erwartenden Stellen nieder, und wird dementsprechend korrekt von top, mpstat und Konsorten (als "System Time") ausgewertet.

Edith meint noch: Wenn du die interessanten PIDs vorab weiszt, ist `pidstat` das Tool der Wahl.

Oder du liest /proc/<pid>/stat selbst; ist mit scanf(3) unkompliziert.
Bearbeitet von COLOSSUS am 12.09.2016, 19:56

GrandAdmiralThrawn

XP Nazi
Avatar
Registered: Aug 2000
Location: BRUCK!
Posts: 3534
Hmm, muß ich mir morgen anschauen, solange ich einen hinreichend genauen Prozentwert (also sowas wie "78%") draus ermitteln kann, indem ich die entsprechenden Kernel/Userspace Lasten mit der Bash zusammenrechne, würde mir das schon reichen.

Die PIDs sind leider nicht zielführend, weil ich es nicht pro Prozeß, sondern pro komplette Maschine ausgeben will (also die gesamte CPU Last auf einer Box).

GrandAdmiralThrawn

XP Nazi
Avatar
Registered: Aug 2000
Location: BRUCK!
Posts: 3534
Hmm, per mpstat bekomme ich es, da hast du Recht. Per top nicht wie gezeigt, weil top einfach seltsam zählt, siehe unten. Najo, bei 33% Load im Kernel (4 von 12 Threads) zeigt mir mpstat 1 1 jedenfalls folgendes:

Code:
8:56:44 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
08:56:45 AM  all    1.16    0.00   34.75    0.00    0.00    0.00    0.00    0.00   64.09

Mixe ich Userspace Load dazu, um den Rest auszulasten:

Code:
08:58:16 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
08:58:17 AM  all   16.60   46.46   32.36    0.00    0.00    0.17    0.00    0.00    4.42
Average:     all   16.60   46.46   32.36    0.00    0.00    0.17    0.00    0.00    4.42

Also das bringt mir dann doch die gewünschten Werte, danke!

Nur top non-interaktiv einzubinden ist tricky. Der braucht immer eine "Iteration" oder so bis er die Werte aktualisiert hat (Startwerte scheinen irgendwo in der Nähe von 100%id und nahe-0% für den Rest zu liegen).

Starte ich top interaktiv, brauche ich nur ein wenig zu warten und es passt.

Selbst wenn ich die Delaytime brutal runterdrehe, klappt es per top NICHT mit -n1, also z.B. per:

Code:
$ top -d 00.01 -n1

Das läßt es so erscheinen, als wär keine Load da. Was jedoch schon geht, ist das:

Code:
$ top -d 00.01 -n2

Lasse ich top erst nach 2 Pages terminieren, zeigt er sinnvolle Werte an. Nur die erste Page ist Bogus. Siehe hier, wieder mit ~33% Kernel Load, man beachte die erste Ausgabezeile:

Code:
$ top -d 00.01 -n5 | grep Cpu\(s\)
Cpu(s):  0.9%us,  2.5%sy,  0.5%ni, 96.0%id,  0.1%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu(s):  4.2%us, 37.5%sy,  0.0%ni, 58.3%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu(s):  4.0%us, 40.0%sy,  0.0%ni, 56.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu(s):  4.2%us, 33.3%sy,  0.0%ni, 62.5%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu(s):  0.0%us, 39.1%sy,  0.0%ni, 60.9%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

Auch wieder was gelernt...
Bearbeitet von GrandAdmiralThrawn am 13.09.2016, 09:18

COLOSSUS

# pkill -9 .
Avatar
Registered: Dec 2000
Location: Wien || Stmk
Posts: 11005
Dass du bei so kurzen Beobachtungszeitraeumen nur Werte rauskriegst, die scheinbar keinen Sinn ergeben, ist nur logisch und eine Folge aus der Art und Weise, wie das Accounting dieser Werte kernelseitig funktioniert: Linux fuehrt immer nur Absolutwerte fuer z. B. "time-slices on-CPU" (und diesen Wert z. B. auch noch in Abhaengigkeit der Tickrate des Schedulers) per PID, und das Berechnen von Werten wie "relative Auslastung der CPU durch PIDn", oder auch "Reads/s" oder "Writes/s" fuer Block-I/O-Statistiken, muss man aus diesen periodisch manifestierten Werten "haendisch" errechnen.

Wenn du dir Tools wie iostat anschaust:

Code:
Linux 4.6.0-0.bpo.1-amd64 (redacted) 	09/13/2016 	_x86_64_	(56 CPU)

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
nvme0n1           0.06     2.57  451.64  659.19     3.94    41.96    84.63     4.30    3.87    0.21    6.38   0.07   7.43

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
nvme0n1           0.00     0.00  250.00    5.00     0.99     0.01     8.00     0.03    0.13    0.11    0.80   0.13   3.20

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
nvme0n1           0.00     0.00  243.00    4.00     0.96     0.01     8.05     0.03    0.11    0.12    0.00   0.11   2.80

Dann ergibt sich der erste Record in diesen drei aus dem Mittel der bisher akkumulierten Statistiken, geteilt durch die Uptime des Hosts. Erst ab dem zweiten Record ist der Bericht "live", bzw. ergibt sich aus dem Delta zur vorangegangenen Messung der absoluten Zahlen.
Bearbeitet von COLOSSUS am 13.09.2016, 10:28

GrandAdmiralThrawn

XP Nazi
Avatar
Registered: Aug 2000
Location: BRUCK!
Posts: 3534
Ok, alles klar. Habe dazu auch noch etwas nachgelesen und alles was ich finden konnte waren eben ähnliche Aussagen, daß man also einen Beobachtungszeitraum braucht.

Für's erste schaut meine Lösung jetzt Mal so aus (Zurückgegriffen auf bc, weil bash kann scheints keine Floats?), benutzt habe ich dennoch top, weil's schneller ist als mpstat:

Code:
$ read -r -a loadarray <<< `top -d 00.01 -n2 | grep Cpu\\(s\\) | head -2 | tail -1` \\
 && cpuload=0 && for i in {1,2,3,5,6,7,8}; do cpuload=$(echo $cpuload + `echo \\
 "${loadarray[$i]}" | cut -d'%' -f1` | bc); done && echo -ne "$cpuload%" && unset \\
 cpuload loadarray
34.8%
Schaut perfekt aus? Scheint jedenfalls genau das zu tun was ich will, auch wenn "etwas zackiger" ganz nett wäre.

Aber danke für die Hilfe!
Bearbeitet von GrandAdmiralThrawn am 13.09.2016, 10:56

COLOSSUS

# pkill -9 .
Avatar
Registered: Dec 2000
Location: Wien || Stmk
Posts: 11005
Bourne Shell kann nur Ganzzahlarithmetik, ja.

Die Ausgabe von top ist nicht stabil ueber Versionen hinweg und explizit nicht dazu da, sie maschinell zu parsen. Das Script wird dir also spaetestens beim naechsten Dist-Upgrade explodieren. In meiner Version sind die Felder "1,2,3,5,6,7,8", die du da referenzierst, mit tw. nichtnumerischen Werten belegt. Auszerdem faellt dir das alles auseinander, sobald bald ein Wert dreistellig vor dem Komma (100.0) wird, weil dann das Word Splitting beim `read´-Input versagt. Summa summarum: so wuerde ich das nicht implementieren.

Was genau ist jetzt eigentlich das Ziel? Du willst die non-Idle-Time all deiner CPUs in den letzten 0.01 Sekunden wissen?

GrandAdmiralThrawn

XP Nazi
Avatar
Registered: Aug 2000
Location: BRUCK!
Posts: 3534
Die 100% schaffe ich nicht, ich hab's probiert, aber irgendwas is einfach immer, was das zu verhindern scheint. Ich krieg z.B. nie 0.0%sy hin. 100.0%sy aber auch ned. Und was die Portabilität angeht: Mir wurscht. Distros upgrade ich vielleicht alle 8-10 Jahre, aber nicht öfter (CentOS). Und is ja ned so, daß man keine Delimiter oder Feldnummern ändern könnte auf die Schnelle. Das dauert eine Minute und passt.

Und mein Ziel: Ich will die reale, gesamte CPU Auslastung zu einem bestimmten Zeitpunkt in % messen, wobei "alle Threads unter Volllast" = 100%.

Und den ermittelten Wert will ich dann hinschupfen können, wo ich ihn haben will.

Wenn das eleganter geht, dann bitte nur her damit! :)
Bearbeitet von GrandAdmiralThrawn am 13.09.2016, 12:39

COLOSSUS

# pkill -9 .
Avatar
Registered: Dec 2000
Location: Wien || Stmk
Posts: 11005
Auf modernen CPUs mit superfancy Powermanagement, verschiedensten Turbo-States usw. ist die "CPU-Auslastung" sowieso eine Kennzahl, die sehr kiritsch zu beaeugen und zu hinterfragen ist, und ggf. nicht mehr viel mit der tatsaechlichen Auslastung der Rechenwerke zu tun hat. Fuer Intel-CPUs kann man sich da mit i7z behelfen; das wird allerdings nicht mehr gepflegt und kann damit ggf. fuer Skylake und Co. keine zuverlaessigen Angaben mehr treffen. Wenn man sich sonst ueber die CPU-Charakteristika einer Workload informieren moechte, macht man das am besten mit perf.

Damit du irgendeine nette Zahl hast, die du anschauen kannst zum Sichgutfuehlen, wuerde ich das so angehen:

Code:
read -r _{1..12} us sy id wa st < <(vmstat -nw 1 2 | tail -n1); printf '%d%%\\n' "$(($us+$sy))"
Bearbeitet von COLOSSUS am 13.09.2016, 13:01

GrandAdmiralThrawn

XP Nazi
Avatar
Registered: Aug 2000
Location: BRUCK!
Posts: 3534
Hmm, auf andere Linuxversionen / -distros portabler Code is natürlich besser, schon klar.

Ich wollte einfach schnell sehen, ob was frei ist auf der CPU. Wenn ich z.B. "70%" sehe, kann ich mir sicher sein, daß es Reserven gibt, und daß ich einen Rechenjob nachschieben kann (ich mache selbiges auch mit'm RAM, aber in absoluten Zahlen statt %).

Wenn größere Jobs durch sind, krieg ich zwar auch Notifications, aber ich weiß nie was grade alles läuft auf der Kiste, und so seh ich halt schnell Mal ob was frei ist. Ich könnt's auch hinten ans Notify ankleben, um zu sehen ob nach Ende eines großen Jobs immer noch Load auf der Maschine war...

Klar geht das sicher alles irgendwie anders auch, aber wenn ich Mal etwas will, kann ich einfach keine Ruhe geben, auch wenn's nichts wirklich wichtiges/nützliches ist. ;)

Lässig wär's jetzt nur noch, wenn das richtig schnell gehen würd (vmstat braucht auch eine Sekunde, schneller kann es nicht). Auf FreeBSD komm ich z.B. per folgendem sauflott an die Werte für alle Cores, hier beispielhaft mit einem AMD 8-Kerner unter voller Last (load avg ist grade knapp unter 17):

Code:
$ sysctl dev.cpu | grep cx_usage
dev.cpu.7.cx_usage: 100.00% 0.00% last 4967us
dev.cpu.6.cx_usage: 100.00% 0.00% last 6037us
dev.cpu.5.cx_usage: 100.00% 0.00% last 2685us
dev.cpu.4.cx_usage: 100.00% 0.00% last 6968us
dev.cpu.3.cx_usage: 100.00% 0.00% last 4906us
dev.cpu.2.cx_usage: 100.00% 0.00% last 5830us
dev.cpu.1.cx_usage: 100.00% 0.00% last 7376us
dev.cpu.0.cx_usage: 100.00% 0.00% last 2973us
Also da spür ich GAR keine Wartezeit, da kann ich mir das fertige Teil auch in die ~/.bash_profile schmeißen und es stört nicht Mal beim Login... Execution Time 2ms! Das wär jetzt noch das Sahnehäubchen, wenn ich das unter Linux auch in sagen wir <100ms machen könnte, anstatt in 1sec mit vmstat oder ~500ms mit top (k.A. warum der 500ms+ wegfrisst bei "time top -d 00.01 -n2")...

Edit: Äh, vergiß. Die Werte sind auch Bogus, mit ps geht's, oder auch per top, aber ned per sysctl, weil da hab ich auch im Idle "100%"...
Bearbeitet von GrandAdmiralThrawn am 13.09.2016, 15:23

spunz

Super Moderator
tot durch snu-snu
Avatar
Registered: Aug 2000
Location: achse des bösen
Posts: 10527
mit recode kannst du die htop Ausgabe "lesbar" machen. Ein Batch Mode ist schon länger als FR drin, hat sich aber noch nix getan.

htop | recode utf-8 > bla.txt

GrandAdmiralThrawn

XP Nazi
Avatar
Registered: Aug 2000
Location: BRUCK!
Posts: 3534
Ah.. Danke. Auf der Basis sollte ich mir was bauen können, htop mit -d1 starten, für 1-2 Zehntelsekunden am Leben lassen (je nachdem wie lange es braucht um ordentliche Daten zu erhalten), dann killen, die Daten filzen und passt.

Mh!

Werd ich (wenn Zeit ist) morgen Mal ausprobieren, zwecks der Gaudi! :)
Bearbeitet von GrandAdmiralThrawn am 14.09.2016, 19:20
Kontakt | Unser Forum | Über overclockers.at | Impressum | Datenschutz