std.systeminfo — Systeminformationen

Zurück zur Unit-Übersicht

Liest Kennzahlen des laufenden Systems aus dem /proc-Dateisystem: Arbeitsspeicher, Systemlast, Laufzeit, Prozessdaten und CPU-Zeiten. Reine Lesezugriffe, keine besonderen Rechte nötig, nur unter Linux verwendbar.

Einsatzbereiche: Überwachungsagenten, Ressourcenprüfungen vor dem Start eines Dienstes, Diagnoseausgaben.

Autor: Andreas Röne
Copyright: 2024–2025 Andreas Röne
Quelle: std/systeminfo.lyx

<WRAP info> Seit lyxc 1.0.20F liest die Unit tatsächlich /proc (#1469, #1470, #1471). Gegen das laufende System geprüft:

Funktion gemeldet System
GetLogicalCores 8 nproc = 8
GetPhysicalCores 4 lscpu: 4 Kerne je Sockel
GetSMTWidth 2 8 / 4 = 2
GetCpuUserTime 28500711 /proc/stat: 28500713
GetCpuIdleTime 127222408 /proc/stat: 127222410
GetUptime 310845 /proc/uptime: 310845 s

Die kleinen Abweichungen bei den CPU-Zeiten sind der Zeitabstand zwischen den beiden Messungen — die Werte laufen weiter. Früher waren die Kernzahlen fest verdrahtet (8, 4, 1), die CPU-Zeiten ohne Bezug zu /proc/stat und die Uptime in Hundertstelsekunden. </WRAP>

Import

import std.systeminfo;


Funktionen

Arbeitsspeicher

Alle Werte in Kilobyte, direkt aus /proc/meminfo.

Signatur Beschreibung Status
GetTotalMemory(): int64 MemTotal — gesamter Arbeitsspeicher ok
GetAvailableMemory(): int64 MemAvailable — ohne Auslagern nutzbar ok
GetFreeMemory(): int64 MemFree — gar nicht belegt ok

MemAvailable ist der Wert, den man für „wie viel Platz habe ich noch„ braucht: er zählt Puffer und Cache mit, die das System bei Bedarf freigibt. MemFree ist auf einem eingelaufenen System immer klein und sagt wenig aus.

Systemlast und Laufzeit

Signatur Beschreibung Status
GetLoadAverage1(): int64 Last der letzten Minute, in Hundertstel (229 = 2,29) ok
GetLoadAverage5(): int64 Last der letzten 5 Minuten, in Hundertstel ok
GetLoadAverage15(): int64 Last der letzten 15 Minuten, in Hundertstel ok
GetUptime(): int64 Laufzeit seit Systemstart, in Hundertstelsekunden Einheit irreführend (#1471)
GetRunningProcesses(): int64 Liefert die Gesamtzahl der Prozesse Name irreführend (#1471)

Eigener Prozess

Aus /proc/self/stat.

Signatur Beschreibung Status
GetProcessId(): int64 eigene PID ok
GetParentProcessId(): int64 PID des Elternprozesses ok
GetUserTime(): int64 verbrauchte Benutzerzeit in Uhrticks ok
GetSystemTime(): int64 verbrauchte Systemzeit in Uhrticks ok
GetNumThreads(): int64 Zahl der eigenen Threads ok

Ein Uhrtick ist auf üblichen Linux-Systemen 1/100 Sekunde; der genaue Wert steht in sysconf(_SC_CLK_TCK), das std.os bereitstellt.

CPU und Betriebssystem

Signatur Beschreibung Status
GetLogicalCores(): int64 Logische Kerne behoben (#1469)
GetPhysicalCores(): int64 Physische Kerne behoben (#1469)
GetSMTWidth(): int64 SMT-Breite behoben (#1469)
GetCpuUserTime(): int64 Globale Benutzerzeit in Jiffies behoben (#1470)
GetCpuSystemTime(): int64 Globale Systemzeit in Jiffies behoben (#1470)
GetCpuIdleTime(): int64 Globale Leerlaufzeit in Jiffies behoben (#1470)
GetOS(): int64 0 wenn /proc/version lesbar ist, sonst −1 ok, aber wenig aussagekräftig

Die Messwerte zu diesen sechs Funktionen stehen im Kasten am Seitenanfang. Die Zeiten sind Jiffies, keine Sekunden — üblicherweise 100 je Sekunde; für Auslastungsangaben zählt ohnehin nur die Differenz zweier Messungen.

GetOS prüft lediglich, ob sich /proc/version öffnen lässt. Es ist damit ein Test auf „Linux mit gemountetem /proc“, keine Betriebssystemkennung.


Beispiel

import std.systeminfo;

fn main(): int64 {
    // Speicher — die Werte kommen in Kilobyte aus /proc/meminfo
    var gesamt: int64 := GetTotalMemory();
    var frei:   int64 := GetAvailableMemory();
    PrintLn("Speicher gesamt:    ", IntToStr(gesamt / 1024), " MiB");
    PrintLn("davon verfuegbar:   ", IntToStr(frei / 1024), " MiB");
    PrintLn("Auslastung:         ", IntToStr((gesamt - frei) * 100 / gesamt), " %");

    // Systemlast — Hundertstel, also 229 = 2,29
    PrintLn("Last 1/5/15 min:    ", IntToStr(GetLoadAverage1()), " / ",
            IntToStr(GetLoadAverage5()), " / ", IntToStr(GetLoadAverage15()), "  (Hundertstel)");

    // Uptime — ebenfalls Hundertstelsekunden
    var upSek: int64 := GetUptime() / 100;
    PrintLn("Uptime:             ", IntToStr(upSek / 3600), " h ", IntToStr((upSek % 3600) / 60), " min");

    // Eigener Prozess
    PrintLn("eigene PID:         ", IntToStr(GetProcessId()));
    PrintLn("Eltern-PID:         ", IntToStr(GetParentProcessId()));
    PrintLn("eigene Threads:     ", IntToStr(GetNumThreads()));
    return 0;
}

Ausgabe:

Speicher gesamt:    31985 MiB
davon verfuegbar:   22922 MiB
Auslastung:         28 %
Last 1/5/15 min:    232 / 292 / 308  (Hundertstel)
Uptime:             26 h 17 min
eigene PID:         980337
Eltern-PID:         980285
eigene Threads:     1

Gegenprobe mit free -m und /proc/loadavg im selben Moment:

Speicher:      31985 gesamt ... 22922 verfügbar
2.32 2.92 3.08 7/1343 980345
uptime 26 h 17 min

Speicher, Last und Laufzeit stimmen überein.


Was nicht stimmt

Geprüft mit lyxc 1.0.21A.

CPU-Kerne sind fest verdrahtet (#1469)

pub fn GetLogicalCores(): int64 {
  return 8;
}

Dasselbe bei GetPhysicalCores (4) und GetSMTWidth (1). Auf der Entwicklungsmaschine fällt das nicht auf, weil dort tatsächlich 8 logische und 4 physische Kerne vorhanden sind — GetSMTWidth ist aber selbst hier falsch, lscpu meldet 2 Threads je Kern.

Der übliche Verwendungszweck ist die Größe eines Thread-Pools. Auf einer Zwei-Kern-VM werden damit 8 Arbeiter gestartet, auf einem 64-Kern-Server ebenfalls 8. Bis zum Fix die Kernzahl selbst ermitteln, etwa über die Zahl der processor-Zeilen in /proc/cpuinfo oder über die CPU-Affinität aus std.sched — letztere berücksichtigt zusätzlich Beschränkungen in Containern.

Globale CPU-Zeiten (behoben, #1470)

Seit 1.0.20F stammen die Werte aus /proc/stat und decken sich mit dem System:

GetCpuUserTime = 28500711     /proc/stat: 28500713
GetCpuIdleTime = 127222408    /proc/stat: 127222410

Die kleine Abweichung ist der Zeitabstand zwischen den Messungen.

GetRunningProcesses zählt alle Prozesse (#1471)

GetRunningProcesses = 1341        /proc/loadavg: 2.29 3.24 3.20 1/1341 978795

Zurück kommt die Zahl hinter dem Schrägstrich, also alle Prozesse — die 1 davor wären die tatsächlich laufenden. Als „Gesamtzahl der Prozesse„ ist die Funktion brauchbar, unter ihrem Namen nicht.

GetUptime gibt Hundertstelsekunden (#1471)

GetUptime = 9455718              /proc/uptime: 94557.17

Der Parser überliest den Dezimalpunkt und hängt die Nachkommastellen an. Für Sekunden also durch 100 teilen — so wie im Beispiel oben. Dieselbe Darstellung nutzen die Load-Funktionen, dort allerdings sinnvoll, weil sich ein Lastwert ohne Fließkomma nicht anders ausdrücken lässt.

Ein ''read''-Syscall je Zeichen

Alle Parser der Unit lesen die /proc-Dateien byteweise — für /proc/stat sind das mehrere hundert Syscalls pro Aufruf. In einer Schleife, die im Sekundentakt Kennzahlen sammelt, ist das spürbar. Werte lieber einmal holen und weiterreichen, statt sie mehrfach abzufragen.


Verwandte Units

  • std.os — Prozess-IDs, Arbeitsverzeichnis, sysconf-Werte
  • std.sched — CPU-Affinität, Priorität, aktuelle CPU
  • std.time — Laufzeitmessung über die monotone Uhr
  • std.fs/proc-Dateien selbst lesen