std.cpu — CPU-Erkennung, SIMD und Dispatch

Zurück zur Unit-Übersicht · std.cpu.features · std.cpu.dispatch · std.sched · std.systeminfo

Übersicht über den CPU-Namensraum: zwei Units, die zur Laufzeit die SIMD-Fähigkeiten der CPU erkennen (SSE2, SSE4.1, AVX2) und darauf aufbauend einen Rechen-Pfad auswählen sowie 16-Byte-ausgerichtete float32-Arrays bereitstellen. Grundlage für SIMD-beschleunigtes Rechnen (Arbeitspaket WP-GPU-02).

std.cpu selbst ist keine Unit, sondern ein Verzeichnis — import std.cpu; scheitert mit Modul nicht gefunden. Importiert wird immer eine konkrete Unit wie std.cpu.dispatch. Einen Wildcard-Import (import std.cpu.*;) gibt es nicht.

Quelle: std/cpu/

<WRAP center round important 90%> Entwicklungsstand: Beide Units gehören zu WP-GPU-02 und sind in aktiver Entwicklung. Der Scalar-Fallback in std.cpu.dispatch rechnet falsch (f32-Bitmuster werden als Integer behandelt), und der SSE2-Pfad ruft intern den Scalar-Pfad auf. Echte SIMD-Instruktionen (ADDPS/VADDPS) emittiert der Compiler-Codegen (CGN_BINOP SIMD), nicht die Stdlib. GPU-Units (std.gpu.*) existieren noch nicht (WP-GPU-07–09, geplant). </WRAP>


Units im Überblick

Unit Import Beschreibung
std.cpu.features import std.cpu.features; Feature-Erkennung via /proc/cpuinfo: SSE2, SSE4.1, AVX2 als Bitmaske; Ergebnis wird gecacht
std.cpu.dispatch import std.cpu.dispatch; Dispatch-Level (AVX2 → SSE2 → Scalar), 16-Byte-ausgerichtete f32-Arrays via mmap, elementweise Arithmetik

std.cpu.dispatch zieht std.cpu.features automatisch mit — für den Normalfall genügt der Import von dispatch.


Wann welche Unit

Aufgabe Unit Kernfunktionen
Prüfen ob AVX2 / SSE4.1 / SSE2 vorhanden ist std.cpu.features CpuFeatureDetect, CpuHasAVX2, CpuHasSSE41, CpuHasSSE2
Rechen-Pfad zur Laufzeit wählen std.cpu.dispatch CpuDispatchLevel
Ausgerichtetes f32-Array anlegen std.cpu.dispatch SimdAlloc, SimdLen
Elementweise f32-Arithmetik std.cpu.dispatch SimdAdd, SimdSub, SimdMul, SimdDiv
Einzelne Elemente lesen/schreiben std.cpu.dispatch SimdGet, SimdSet
Prozess auf einen Kern pinnen, Priorität setzen std.sched SchedSetAffinity, CpuSetAdd, GetCurrentCPU, SetPriority
Kernanzahl und CPU-Zeiten des Systems lesen std.systeminfo GetLogicalCores, GetPhysicalCores, GetCpuUserTime/SystemTime/IdleTime
Arbeit auf mehrere Kerne verteilen std.thread Threads, Mutex, Condition Variables

Begriffe

  • SIMD (Single Instruction, Multiple Data) — eine Instruktion rechnet gleichzeitig auf mehreren Werten. SSE2 arbeitet mit 128-Bit-Registern (4 × f32), AVX2 mit 256 Bit (8 × f32).
  • Dispatch — die Auswahl des Codepfads zur Laufzeit statt zur Übersetzungszeit. Ein Binary läuft damit auf alter und neuer Hardware und nutzt trotzdem die schnellste verfügbare Erweiterung.
  • Ausrichtung (Alignment) — SIMD-Ladebefehle erwarten Daten an 16-Byte-Grenzen. SimdAlloc rundet den mmap-Zeiger entsprechend auf und legt die Elementanzahl bei ptr-8 ab.
  • f32 als BitmusterSimdGet / SimdSet reichen rohe 32-Bit-IEEE-754-Muster in einem int64 durch, ohne Typkonvertierung (1.0f = 0x3F800000).

Erkennungsweg

/proc/cpuinfo ──CpuFeatureDetect──► Bitmaske (CPU_FEAT_SSE2|SSE41|AVX2)
                                         │  (gecacht, ein Syscall)
                                         ▼
                                CpuDispatchLevel ──► AVX2 | SSE2 | Scalar
                                         │
                              SimdAlloc / SimdAdd … auf f32-Arrays

Die Erkennung liest /proc/cpuinfokein direkter cpuid-Befehl. Damit ist der gesamte Namensraum Linux-only; auf macOS, Windows und Bare-Metal liefert CpuFeatureDetect 0. Der Cache lässt sich nicht zurücksetzen, CPU-Hotplug oder Migration werden nicht erkannt. AVX-512 wird nicht geprüft.


Einstiegsbeispiel

import std.cpu.dispatch;
import std.io;

fn main(): int64 {
    var lvl: int64 := CpuDispatchLevel();
    if (lvl == CPU_DISPATCH_AVX2) {
        PrintLn("Dispatch: AVX2 (256 Bit)");
    } else if (lvl == CPU_DISPATCH_SSE2) {
        PrintLn("Dispatch: SSE2 (128 Bit)");
    } else {
        PrintLn("Dispatch: Scalar");
    }

    // f32-Arrays: Bits 1.0 = 0x3F800000, 2.0 = 0x40000000
    var a: int64 := SimdAlloc(4);
    var b: int64 := SimdAlloc(4);
    var i: int64 := 0;
    while (i < 4) {
        SimdSet(a, i, 0x3F800000);
        SimdSet(b, i, 0x40000000);
        i := i + 1;
    }

    var result: int64 := SimdAdd(a, b);
    PrintLn(StrConcat(IntToStr(SimdLen(result)), " Elemente berechnet"));

    // Kein SimdFree: Arrays bleiben bis Prozessende belegt
    return 0;
}


Fallstricke

Thema Details
Scalar-Fallback rechnet falsch f32-Bitmuster werden als Integer addiert — Ergebnisse sind nur auf dem Codegen-Pfad korrekt
SSE2-Pfad = Scalar-Pfad SimdAdd ruft bei SSE2 intern SimdAddScalar auf
Kein SimdFree Arrays werden erst beim Prozessende vom Kernel zurückgefordert; für eine eigene Freigabe n*4+24 Byte ab dem Basis-Mapping rechnen
Keine Bounds-Checks SimdGet(arr, i) prüft i nicht gegen SimdLen(arr)
Kein Typ-Safety bei f32 Werte sind rohe Bitmuster in int64; eine f32⟺int64-Helper-Unit fehlt in der Stdlib
Linux only /proc/cpuinfo und mmap vorausgesetzt
Kein AVX-512 Nur SSE2, SSE4.1 und AVX2 werden erkannt
Kernzahlen woanders Logische/physische Kerne liefert std.systeminfo, nicht std.cpu

Verwandte Seiten

Letzte Aktualisierung: 2026-09-02 — Übersichtsseite neu angelegt.