std.systeminfo — Systeminformationen
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.
