Praktischer Leitfaden, um auf gewöhnlichem Windows so nah wie möglich an Soft Real-Time heranzukommen
· Go Komura · Windows-Entwicklung, Soft Real-Time, Design, Messung
Wenn man unter Windows periodische Verarbeitung, Audio-Verarbeitung, Video-Verarbeitung, Messung oder Anlagensteuerung baut – also Prozesse, bei denen „zu spät“ ein Problem ist –, entsteht schnell der Eindruck, „das dürfte unter Windows schwierig sein“. Dieser Eindruck ist halb richtig und halb falsch: Windows ist kein Hard-Real-Time-Betriebssystem, aber wenn Sie Entwurf, Implementierung, Messung und Betrieb sauber durcharbeiten, lässt es sich als Soft Real-Time in einen durchaus praxistauglichen Zustand bringen.
In diesem Artikel geht es um gewöhnliches Windows 10 / 11, ohne die Voraussetzung besonderer RTOS-Erweiterungen, eigener Kernel-Treiber oder dedizierter Controller. Es ist ein praxisnahes Thema: Wie weit lassen sich Latenz und Jitter mit einer User-Mode-App auf einem gewöhnlichen Desktop- oder Notebook-PC herunterdrücken? Bei Audio, Video, periodischer Steuerung und Datenerfassung unterscheiden sich die Details, aber die typischen Problemstellen sind weitgehend gleich, weshalb wir diese gemeinsamen Punkte diesmal in Form einer Checkliste zusammengefasst haben.
Zielgruppe und die Sprache der Codebeispiele
Dieser Artikel richtet sich an Entwickler, die unter Windows Prozesse bauen, bei denen „zu spät“ ein Problem ist (periodische Steuerung, Audio/Video, Messung, Anlagensteuerung). Vorausgesetzt wird Entwicklung im User-Mode; die Implementierung von Kernel-Mode-Treibern liegt außerhalb des Rahmens.
Die Sprache der Codebeispiele teilt sich wie folgt auf.
| Inhalt | Sprache | Ort |
|---|---|---|
| Teile, die Win32-APIs direkt aufrufen – periodische Schleife, MMCSS, Power-QoS | C++ (Win32) | 4.1, 4.3, 4.5 |
| Dieselben Win32-APIs, aus C# aufgerufen | C# (P/Invoke) | 4.5 |
| Zeitmessung, GC, Hinweise zu Allokationen | .NET (C#) | „.NET-seitige Prüfpunkte“ in 4.4, 5.2 |
Die Ursachenanalyse bis Kapitel 3 und der Hauptteil der Checkliste in Kapitel 4 sind sprachunabhängig. Wer ausschließlich C# verwendet, kann den C++-Code einfach als Erklärung lesen, „welche API in welcher Reihenfolge aufgerufen wird“ – das genügt.
Inhaltsverzeichnis
- Zuerst das Fazit (in einem Satz)
- 1.1. Kurzübersicht nach Periodenbereich (wo Sie einsteigen sollten)
- Was „Soft Real-Time“ auf gewöhnlichem Windows bedeutet
- 2.1. Was dieser Artikel mit „gewöhnlichem Windows“ meint
- 2.2. Was möglich ist und ab wo es schwierig wird
- 2.3. Kurz vorab: die Begriffe
- Die Hauptursachen für Latenz und Jitter
- 3.1. Scheduler und Priorität
- 3.2. DPC / ISR und Treiber
- 3.3. Page Faults und Speicher
- 3.4. Timer-Auflösung und Energieverwaltung
- 3.5. Core-Wechsel und Wärme
- Praktische Checkliste, um Verzögerungen auf gewöhnlichem Windows zu reduzieren
- 4.1. Periodische Schleife und Wartemethode
- 4.2. fast path / slow path und Queue fester Länge
- 4.3. Priorität / MMCSS / Background Mode
- 4.4. Speicher / GC / Erstkosten
- 4.5. Energieeinstellungen / EcoQoS / Timer-Auflösung
- 4.6. CPU-Platzierung / Core-Wechsel / Wärme
- 4.7. Treiber / DPC / ISR / externe Störungen isolieren
- Messung und Bewertung
- 5.1. Was aufgezeichnet werden sollte
- 5.2. Wie p99 / p99.9 / max zu lesen sind
- 5.3. Womit gemessen wird
- 5.4. Die Vorgehensweise beim Testen
- Grobe Entscheidungshilfe
- Zusammenfassung
- Quellen
1. Zuerst das Fazit (in einem Satz)
- Was auf gewöhnlichem Windows angestrebt wird, ist keine Hard-Real-Time-Garantie, sondern eine Soft-Real-Time-Konfiguration, die „selten zu spät kommt und dabei nicht zusammenbricht, wenn es doch passiert“.
- Am wirkungsvollsten ist es, den Hot Path kurz, fest in der Länge und nicht-blockierend zu halten.
- Trennen Sie den fast path (Erfassung / Steuerung) vom slow path (Speicherung / Kommunikation / UI) und verbinden Sie beide über eine Queue fester Länge.
- Die periodische Schleife läuft nicht auf
Sleep(1)verlassen, sondern über eine absolute Deadline. - Bei kontinuierlichen Streams wie Audio oder Video prüfen Sie zuerst MMCSS.
- Für die Zeitmessung verwenden Sie QueryPerformanceCounter (QPC), unter .NET
Stopwatch. - Beim Warten bevorzugen Sie ein Geräte-Ereignis oder einen hochauflösenden waitable timer (wartbaren Timer).
timeBeginPeriodverwenden Sie nur, solange es nötig ist. Entwerfen Sie nicht mit der Annahme, dass es dauerhaft aktiv ist.- Im laufenden Betrieb zahlen sich AC-Stromversorgung / der Energiemodus / der Umgang mit EcoQoS / das Aufräumen der Hintergrundlast aus.
- Bewerten Sie nicht nur den Mittelwert, sondern p99 (die Schwelle, ab der bei 100 Messungen der eine langsamste Wert sichtbar wird) / p99.9 / max / die Anzahl der Misses / DPC / ISR / Page Faults / die Queue-Tiefe.
Kurz gesagt: Auf gewöhnlichem Windows wirkt es stärker, die Gründe für Verzögerungen durch den Entwurf zu reduzieren, als die Priorität zu erhöhen. Priorität und Energieeinstellungen sind wichtig, aber allein schaffen sie noch keine Stabilität.
1.1. Kurzübersicht nach Periodenbereich (wo Sie einsteigen sollten)
Da der Artikel lang ist, stellen wir die Kurzübersicht vorab, damit Sie nur die für Ihren Fall passende Zeile lesen können. Der Inhalt, der früher am Ende (Kapitel 6) stand, wurde hierher vorgezogen.
| Periode / Anforderung | Zuerst aufzubauende Struktur | Schwerpunkt-Abschnitte |
|---|---|---|
| Klasse 10–20 ms, gelegentliche Schwankungen sind verkraftbar | Trennung von fast path / slow path, Queue fester Länge, normale bis leicht erhöhte Priorität, ereignisgesteuert. Das reicht oft schon aus | 4.1, 4.2 |
| Klasse 1–5 ms, soll durchgehend Schritt halten | Zusätzlich: allokationsfreier Hot Path, dedizierter Thread, MMCSS oder sorgfältige Prioritätsanpassung, hochauflösender waitable timer, AC-Stromversorgung und überarbeitete Energieeinstellungen | 4.1–4.5 |
| Nähert sich unter 1 ms, darf auch bei langer Laufzeit und hoher Last nichts verfehlen | Mit User-Mode allein auf gewöhnlichem Windows ziemlich schwierig. Zuerst einen Entwurf prüfen, der den kritischen Teil an einen anderen Ort auslagert (geräteseitige Firmware, dedizierter Controller, FPGA, RTOS) | 2.2, 6 |
| Soll alles gleichzeitig mit GUI / Logging / Kommunikation / DB unterbringen | Nicht alles in „einen Prozess, eine Schleife“ packen, sondern Zuständigkeiten trennen. Belange der nachgelagerten Stufe brechen leicht die Deadline der vorgelagerten Stufe | 4.2, 4.3, 6 |
Die Ursachenanalyse und die Vorgehensweise bei der Messung sind unabhängig vom Periodenbereich gleich (Kapitel 3 und 5).
2. Was „Soft Real-Time“ auf gewöhnlichem Windows bedeutet
2.1. Was dieser Artikel mit „gewöhnlichem Windows“ meint
Mit gewöhnlichem Windows ist hier grob Folgendes gemeint.
- Ein typischer Windows 10/11 Desktop- oder Notebook-PC
- Keine eigenen RTOS-Erweiterungen
- Keine eigene Kernel-Mode-Treiberentwicklung
- Eine gewöhnliche User-Mode-App
- Abstimmung über gängige Windows-APIs und -Einstellungen
Es geht also nicht darum, „ein komplettes Spezialgerät für die Echtzeitsteuerung zu bauen“, sondern darum, „wie weit sich das auf einem gewöhnlichen Windows-PC realistisch ausreizen lässt“.
flowchart LR
A["Gewöhnlicher Windows 10 / 11 PC"] --> B["User-Mode-App"]
B --> C["Soft Real-Time anstreben"]
C --> D["Latenz niedrig halten"]
C --> E["Jitter klein halten"]
C --> F["Deadline Misses beobachten und Zusammenbrüche vermeiden"]
G["Null Terminverletzungen garantieren wollen"] -.-> H["RTOS / dedizierter Controller / FPGA / geräteseitige Verarbeitung"]
2.2. Was möglich ist und ab wo es schwierig wird
Auch auf gewöhnlichem Windows lässt sich für Verarbeitung wie die folgende durchaus realistisch ein Zustand herstellen, der „selten zu spät kommt“.
- Periodische Verarbeitung von wenigen Millisekunden bis zu einigen Dutzend Millisekunden
- Pufferbasiertes Audio / Video
- Sensorerfassung und Regelschleifen
- Soft-SPS-artige Verarbeitung mit fester Periode
- Eine Low-Latency-Pipeline, die auf einem eigenen Thread getrennt von der UI läuft
Allerdings bedeutet „geht“ hier nicht, dass sich gelegentliche Latenzspitzen vollständig auf null bringen lassen. Angestrebt wird lediglich dieser Zustand:
- Die Latenz im Normalfall niedrig halten
- Den Jitter klein halten
- Nicht zusammenbrechen, wenn gelegentlich eine Deadline verfehlt wird
- Die Tatsache, dass eine Deadline verfehlt wurde, beobachten können
Umgekehrt wird es mit User-Mode allein auf gewöhnlichem Windows ziemlich schwierig, Anforderungen wie die folgenden zu erfüllen.
- Null Terminverletzungen garantieren
- Wenige hundert Mikrosekunden oder weniger über lange Zeit stabil einhalten
- Mit einer schweren GUI, Netzwerk und Storage koexistieren
- Es im Batteriebetrieb oder unter Energiespar-Priorität durchziehen
- Auch Spitzen, die von Treibern oder Geräten stammen, nicht tolerieren
Hier ist es sicherer, auch in Betracht zu ziehen, nur den wirklich zeitkritischen Teil an geräteseitige Firmware, einen dedizierten Controller, ein FPGA oder ein RTOS auszulagern.
2.3. Kurz vorab: die Begriffe
Klären wir zuerst die in diesem Artikel verwendeten Begriffe.
| Begriff | In einem Satz | Praktische Einordnung |
|---|---|---|
| Soft Real-Time | Gelegentliche Verzögerungen sind möglich, aber der Ansatz zielt darauf, sie klein zu halten und nicht daran zu zerbrechen | Das ist es, was man auf gewöhnlichem Windows zuerst anstrebt |
| Hard Real-Time | Eine Welt, in der null Terminverletzungen garantiert werden müssen | Kein Ziel, das sich mit User-Mode allein auf gewöhnlichem Windows anstreben lässt |
| Jitter | Schwankung der Periode oder der Antwortzeit | Auch bei gutem Mittelwert bedeutet großer Jitter Instabilität im Betrieb |
| Deadline Miss | Verarbeitung, die nicht bis zum geplanten Zeitpunkt fertig wird | Nicht verstecken – zählen und loggen |
| p99 / p99.9 | Kennzahlen, die die langsame Seite der Verteilung betrachten | p99 ist „die Schwelle, ab der bei 100 Messungen der eine langsamste Wert sichtbar wird“ |
| DPC / ISR | Kernel-seitige Verarbeitung rund um Treiber und Interrupts | Dauert sie lange, muss der User-Mode-Thread warten |
| MMCSS | Der Windows-Mechanismus, der CPU-Zeit an zeitkritische Verarbeitung wie Audio/Video verteilt | Stark bei Verarbeitung, deren Puffer nicht leerlaufen darf |
| QPC | Steht für QueryPerformanceCounter |
Grundlage der Messung verstrichener Zeit – ein hochauflösender Zähler, keine Wanduhr |
| waitable timer (wartbarer Timer) | Ein Kernel-Objekt, das zu einem festgelegten Zeitpunkt signalisiert wird. Mit CREATE_WAITABLE_TIMER_HIGH_RESOLUTION bei CreateWaitableTimerExW entsteht die hochauflösende Variante |
Besser als Grundlage für periodisches Warten geeignet als Sleep (4.1) |
| EcoQoS | Ein Zustand, der als „Energiesparen darf priorisiert werden“ eingestuft ist. Dabei wird die CPU-Frequenz gesenkt oder die Arbeit auf energieeffiziente Cores verlagert | Bei zeitkritischer Verarbeitung vermeiden. Ohne explizite Angabe schätzt das Betriebssystem automatisch (4.5) |
IGNORE_TIMER_RESOLUTION |
Die Angabe, dass die Timer-Auflösungsanforderung eines Prozesses ignoriert werden darf (PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION) |
Ist dies aktiv, verpufft die Wirkung von timeBeginPeriod. Unter Windows 11 kann es automatisch greifen, sobald das Fenster verdeckt ist (4.5) |
| CPU Sets | Ein Mechanismus, der Threads oder Prozessen weich vorgibt: „Bitte auf dieser Core-Gruppe laufen“ | Zuerst ausprobieren, bevor man auf eine feste Core-Zuweisung geht (4.6) |
| ETW / WPR / WPA | Die Windows-Standard-Trace-Infrastruktur (ETW) mit ihrem Aufzeichnungswerkzeug (WPR) und der Analyse-GUI (WPA) | Wird verwendet, um Context Switches, DPC/ISR und Page Faults zu untersuchen (5.3) |
| LatencyMon | Ein Drittanbieter-Tool, um treiberbedingte Latenzen zu betrachten | Zeigt die Ausführungszeit von DPC/ISR nach Treiber sortiert, um Verdächtige einzugrenzen (5.3) |
3. Die Hauptursachen für Latenz und Jitter
Die Gründe, warum periodische Verarbeitung auf gewöhnlichem Windows zu spät kommt, laufen meist auf einen der Punkte in diesem Diagramm hinaus.
flowchart TD
Late["Periodische Verarbeitung kommt zu spät"] --> S["Scheduler / Priorität"]
Late --> D["DPC / ISR / Treiber"]
Late --> M["Page Fault / Speicher"]
Late --> T["Timer-Auflösung / Energieverwaltung"]
Late --> C["Core-Wechsel / Wärme"]
3.1. Scheduler und Priorität
Bei Windows-Threads bestimmt die Priorität die Ausführungsreihenfolge. Bei gleicher Priorität läuft es Round-Robin, und sobald ein Thread mit höherer Priorität ausführbar wird, wird ein Thread mit niedrigerer Priorität verdrängt.
Das heißt: Auch wenn Sie den periodischen Thread sorgfältig schreiben, ist es völlig normal, dass Folgendes zuerst läuft:
- Ein anderer Thread
- Ein anderer Prozess
- Interne Verarbeitung des Betriebssystems
- Sicherheitsprodukte
- Geräte-Hilfsverarbeitung
- Hintergrundsynchronisierung
3.2. DPC / ISR und Treiber
Dieser Punkt ist ziemlich wichtig. Selbst wenn die Priorität auf App-Seite sauber eingestellt ist, kann während eines langen DPC (Deferred Procedure Call) oder ISR (Interrupt Service Routine) kein User-Mode-Thread ausgeführt werden.
Häufige Ursachen sind Geräte und Treiber aus diesem Bereich.
- USB
- WLAN / Bluetooth
- Storage
- Audio
- GPU
- ACPI / Energieverwaltung
Auch wenn der App-Code selbst nichts falsch macht, kann er durch Treiber- oder Hardware-Gegebenheiten ausgebremst werden. Wer hier denkt „wenn ich die Priorität der App nur weiter erhöhe, gewinne ich schon“, zieht sich damit meist eine blutige Nase zu.
3.3. Page Faults und Speicher
Tritt im Hot Path ein Page Fault auf (eine benötigte Seite ist nicht im Speicher und muss erst geholt werden), schnellt die Latenz sprunghaft nach oben.
Besonders vermeiden sollten Sie diese Muster.
- Page-Commit beim ersten Zugriff
- Lazy Loading
- Page-in von Memory-Mapped-Dateien
- Mehr dynamische Allokation als nötig
- Große Objekte oder ein fragmentierter Heap
Im Kern der periodischen Verarbeitung ist es genau richtig, den benötigten Speicher vorab zu reservieren und ihn beim Start einmal anzufassen.
3.4. Timer-Auflösung und Energieverwaltung
„Ich will alle 1 ms laufen, also Sleep(1)“ funktioniert in den meisten Fällen nicht.
Die Wartepräzision von Windows wird von Timer-Auflösung, Scheduling und Energiezustand beeinflusst.
Zudem darf man nicht übersehen, dass eine Einstellung, die die Timer-Auflösung erhöht, zwar die Wartepräzision etwas verbessert, aber Nebenwirkungen auf den Stromverbrauch und das Verhalten des Gesamtsystems hat.
3.5. Core-Wechsel und Wärme
Wandert ein Thread zwischen Cores, muss sich der Cache neu aufwärmen. Das handhabt das Betriebssystem selbst oft gut, aber unter hoher Last wird es zu einer Ursache für Schwankungen.
Bei langem Betrieb ist außerdem die Wärme nicht zu vernachlässigen. Setzt Thermal Throttling ein, kann eine bis dahin stabile Periode zusammenbrechen.
4. Praktische Checkliste, um Verzögerungen auf gewöhnlichem Windows zu reduzieren
Ab hier beginnt der praktische Teil. Für die im vorigen Abschnitt gesehenen Ursachen fassen wir in Checklistenform zusammen, was auf gewöhnlichem Windows zu prüfen, was zu vermeiden und was zuerst zu entscheiden ist.
4.1. Periodische Schleife und Wartemethode
Zunächst das klassische Anti-Pattern.
while (running)
{
Sleep(1);
Step();
}
Das ist keine „1-ms-Periode“, sondern eine Schleife, die ungefähr 1 ms oder länger wartet und dann noch die Ausführungszeit von Step() obendrauf legt.
Und der Warte-Overshoot summiert sich dabei unmittelbar.
flowchart LR
subgraph Bad["Relative Zeitbasis"]
B1["Sleep(1)"] --> B2["Step()"]
B2 --> B1
end
B2 --> B3["Wartefehler und Ausführungszeit summieren sich Stück für Stück"]
subgraph Good["Absolute Deadline-Basis"]
G1["next += period"] --> G2["WaitUntil(next - margin)"]
G2 --> G3["Bei Bedarf kurzer Spin"]
G3 --> G4["FastStep()"]
G4 --> G1
end
G4 --> G5["Sammelt kaum Drift an"]
Checkliste
- Die periodische Schleife basiert nicht auf
Sleep(1) - Die Periode läuft über die absolute Deadline mittels
next += period - Beim Warten wird ein Geräte-Ereignis oder ein waitable timer (wartbarer Timer) bevorzugt
- Nur die letzte Feinjustierung ist auf einen ganz kurzen Busy-Spin (Leerlauf-Warteschleife) beschränkt
timeBeginPeriodwird nur solange verwendet, wie nötig, und danach zurückgesetzt- Das Verhalten wurde auch im minimierten / ausgeblendeten / unsichtbaren Zustand geprüft
Eine periodische Schleife ist stabiler, wenn sie über die absolute Deadline statt über relative Zeit läuft.
int64_t next = QpcNow() + periodTicks;
while (running)
{
WaitUntil(next - wakeMarginTicks);
while (QpcNow() < next)
{
CpuRelax(); // Nur am Ende kurz spinnen
}
int64_t started = QpcNow();
FastStep();
int64_t finished = QpcNow();
RecordTiming(next, started, finished);
next += periodTicks;
while (finished > next)
{
++missedDeadlines;
next += periodTicks;
}
}
4.2. fast path / slow path und Queue fester Länge
Die Grundstruktur besteht darin, im fast path nur „deadline-sensitive Arbeit“ zu platzieren und alles andere in den slow path auszulagern.
flowchart LR
Input["Gerät / Erfassungs-Ereignis"] --> Fast["fast path: Erfassung, Steuerung, minimales Kopieren"]
Fast --> Queue["Queue fester Länge"]
Queue --> Slow["slow path: Speicherung, Versand, UI, Aggregation"]
Fast --> Metrics["lateness / miss / Queue-Tiefe aufzeichnen"]
Metrics --> Slow
Im fast path beschränken Sie sich auf etwa diese Aufgaben.
- Datenerfassung
- Berechnung des Steuerwerts
- Minimal notwendiges Kopieren
- Zeitstempel
- Einreihen in die Queue
- Aufzeichnen von Miss / Overrun
Alles andere fällt in den slow path.
Checkliste
- Im Hot Path werden keine Dateien geschrieben, keine Netzwerkversendungen und keine DB-Schreibvorgänge vorgenommen
- Im Hot Path gibt es kein schweres Logging, kein
Flushund keinen synchronen RPC - fast path und slow path sind klar nach Thread oder Zuständigkeit getrennt
- Die Queue hat eine feste Länge
- Die Vorgehensweise bei einem Queue-Überlauf ist vorab festgelegt
- Miss-Anzahl, Drop-Anzahl und Queue-Tiefe werden beobachtet
- UI-Aktualisierung und Log-Aggregation sind auf eine niedrigere Frequenz ausgelagert
Ist die Queue voll, ist es sicherer, die Vorgehensweise nicht offenzulassen.
flowchart TD
Overflow["Queue ist voll"] --> Policy{"Was wird geschützt?"}
Policy -->|Der aktuellste Wert zählt| Latest["Alte Elemente verwerfen, den aktuellsten behalten"]
Policy -->|Jeder Eintrag zählt| All["Alarm / Stopp / Steuerung stromaufwärts"]
Policy -->|Für Logging| Log["Alte Elemente verwerfen, nur die Drop-Anzahl aufzeichnen"]
4.3. Priorität / MMCSS / Background Mode
Die Grundregel bei der Priorität lautet: nicht alles anheben. Auf gewöhnlichem Windows funktioniert es besser, „nur die wichtigen Threads anzuheben und die Hintergrundarbeit konsequent abzusenken“. Background Mode ist ein Mechanismus, der nicht nur die CPU, sondern auch Ressourcen wie I/O in Richtung niedrigerer Priorität behandelt.
flowchart TD
Work["Arbeit aufteilen"] --> Critical["Deadline-sensitive Threads"]
Work --> Worker["Speicherung / Versand / Kompression / Aggregation"]
Work --> UI["UI"]
Critical --> P1["Bei Bedarf höhere Priorität oder MMCSS"]
Worker --> P2["Background Mode / niedrigere Priorität"]
UI --> P3["Normale Priorität"]
P1 --> Warn["Nicht von Anfang an REALTIME_PRIORITY_CLASS verwenden"]
Checkliste
- Nicht alle Threads sind auf hohe Priorität gesetzt
- Nur die wirklich zeitkritischen Threads sind angehoben
- Hintergrundarbeit wie Speicherung, Versand, Kompression und Synchronisierung ist auf Background Mode abgesenkt
- Bei kontinuierlicher Pufferverarbeitung wie Audio, Video, Capture oder Wiedergabe wird MMCSS in Betracht gezogen
- Es wird zuerst pro Thread gedacht, nicht für den gesamten Prozess
REALTIME_PRIORITY_CLASSwird nicht verwendet, bevor die Notwendigkeit eindeutig feststeht
MMCSS (Multimedia Class Scheduler Service) ist besonders wirksam bei Verarbeitung wie Audio/Video, bei der „der Puffer innerhalb einer festen Zeit gefüllt werden soll“. Das entspricht eher dem Windows-Design, als einfach dauerhaft einen hochprioren Thread laufen zu lassen.
So sieht der Code ungefähr aus.
DWORD taskIndex = 0;
HANDLE avrt = AvSetMmThreadCharacteristicsW(L"Pro Audio", &taskIndex);
if (!avrt)
{
throw std::runtime_error("AvSetMmThreadCharacteristicsW failed");
}
// Die zeitkritische Schleife ausführen
if (!AvRevertMmThreadCharacteristics(avrt))
{
throw std::runtime_error("AvRevertMmThreadCharacteristics failed");
}
4.4. Speicher / GC / Erstkosten
Wenn Sie im Hot Path bei jedem Durchlauf new / malloc / List<T>.Add / String-Verkettung / LINQ verwenden, treten irgendwann die Kosten von Freigabe und Umlagerung zutage. GC (Garbage Collection) selbst ist nicht der Übeltäter, aber wenn Sie allokationsintensiven Code schreiben, zeigt sich dessen Auswirkung als Jitter.
flowchart LR
Start["Start"] --> Alloc["Benötigte Puffer reservieren"]
Alloc --> Touch["Einmal anfassen, um die Seiten aufzuwärmen"]
Touch --> Warm["JIT / DLL-Laden / ersten I/O erledigen"]
Warm --> Measure["Danach die eigentliche Messung / den eigentlichen Betrieb"]
Checkliste
- Im Hot Path werden nicht bei jedem Durchlauf Speicher reserviert / freigegeben
- Benötigte Puffer sind beim Start vorab reserviert
- Die Seiten wurden beim Start einmal angefasst, um sie aufzuwärmen
- Erstes JIT, erstes DLL-Laden und erster I/O werden nicht in die eigentliche Messung gemischt
- In der Schleife wachsen keine riesigen Strukturen oder Logs mit variabler Länge
VirtualLockwird, falls überhaupt verwendet, nur auf einen ganz kleinen kritischen Bereich beschränkt
.NET-seitige Prüfpunkte
- Für die Zeitmessung werden
Stopwatch/Stopwatch.GetTimestamp()verwendet - Im Hot Path gibt es kein LINQ, keine String-Verkettung, kein
ToString()und keine Erzeugung riesiger Logs async/awaitwird nicht in den Hot Path hineingetragen- Vor und nach dem Warm-up wird getrennt bewertet
4.5. Energieeinstellungen / EcoQoS / Timer-Auflösung
Dieser Punkt ist unscheinbar, wirkt aber. Selbst wenn der Code optimiert ist, wird das Ergebnis nicht stabil, wenn die übergeordnete Energiesteuerung stark hineinwirkt.
flowchart TD
Power["Energieverwaltung auf gewöhnlichem Windows"] --> AC["Mit AC-Stromversorgung ausführen"]
Power --> Mode["Energiemodus: in Richtung Beste Leistung"]
Power --> Plan["Bei Bedarf ein dediziertes Energieprofil für den Produktivbetrieb"]
Power --> QoS["Zeitkritische Prozesse von EcoQoS fernhalten"]
Power --> Timer["Umgang mit Timer-Auflösungsanforderungen prüfen"]
Checkliste
- Die Produktivbewertung erfolgt zuerst mit AC-Stromversorgung
[Einstellungen] > [System] > [Netzbetrieb & Akku] > [Energiemodus]ist in Richtung Beste Leistung gesetzt- Der Batteriesparmodus bzw. ein energiesparpriorisierter Modus ist während des Betriebs nicht aktiv
- Herstellerspezifische Utilities mit Silent-/Eco-/Batterie-Priorität-Modus wurden geprüft
- Zeitkritische Prozesse sind nicht versehentlich auf EcoQoS (energiesparlastiges QoS) gesetzt
IGNORE_TIMER_RESOLUTIONist auf der zeitkritischen Prozessseite nicht aktiv- Es wurde geprüft, ob die Wirkung der Timer-Auflösungsanforderung sich bei Minimierung / Ausblendung ändert
- Die Energieeinstellungen für den Alltagsgebrauch und für Produktivbetrieb / Messung / Demo sind getrennt
timeBeginPeriod ist nützlich, wenn es organisiert eingesetzt wird, aber kein Allheilmittel.
- Unmittelbar vor Bedarf aufrufen
- Nach Abschluss mit
timeEndPeriodzurücksetzen - Ab Windows 10 Version 2004 ist das Verhalten nicht mehr vollständig global wie früher
- Unter Windows 11 kann bei einem Prozess mit Fenster, das vollständig verdeckt / minimiert / unsichtbar / stumm ist, die hohe Auflösung nicht garantiert sein
- Eine höhere Auflösung erhöht nicht die Präzision von QPC
Ist ein Einfluss von Strom oder QoS zu vermuten, prüfen Sie mit SetProcessInformation den Zustand des Power Throttling.
PROCESS_POWER_THROTTLING_STATE state{};
state.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION;
state.ControlMask =
PROCESS_POWER_THROTTLING_EXECUTION_SPEED |
PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION;
state.StateMask = 0; // HighQoS (leistungsorientiert) + Timer-Auflösungsanforderung respektieren
if (!SetProcessInformation(
GetCurrentProcess(),
ProcessPowerThrottling,
&state,
sizeof(state)))
{
throw std::runtime_error("SetProcessInformation failed");
}
ControlMask legt fest, „welche Mechanismen selbst gesteuert werden“, StateMask, „ob dieser Mechanismus ein- oder ausgeschaltet wird“. Im obigen Beispiel werden zwei Mechanismen zur Steuerung ausgewählt und beide auf „aus“ gesetzt. Das ist also die Erklärung, nicht auf EcoQoS herabzustufen (Richtung HighQoS) und die Timer-Auflösungsanforderung nicht ignorieren zu lassen. Setzt man ControlMask dagegen auf 0, werden beide wieder dem Betriebssystem überlassen (Standardverhalten).
Beim Aufruf aus C#
Soll dasselbe aus C# geschehen, sieht die P/Invoke-Deklaration so aus.
// C# / .NET 8
using System.Runtime.InteropServices;
internal static class PowerQos
{
[StructLayout(LayoutKind.Sequential)]
private struct PROCESS_POWER_THROTTLING_STATE
{
public uint Version;
public uint ControlMask;
public uint StateMask;
}
private const uint PROCESS_POWER_THROTTLING_CURRENT_VERSION = 1;
private const uint PROCESS_POWER_THROTTLING_EXECUTION_SPEED = 0x1;
private const uint PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION = 0x4;
// Der 5. Wert von PROCESS_INFORMATION_CLASS (nullbasiert: 4) ist ProcessPowerThrottling
private const int ProcessPowerThrottling = 4;
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetProcessInformation(
IntPtr hProcess,
int processInformationClass,
ref PROCESS_POWER_THROTTLING_STATE processInformation,
uint processInformationSize);
[DllImport("kernel32.dll")]
private static extern IntPtr GetCurrentProcess();
/// <summary>Hebt sowohl die Einstufung Richtung Energiesparen als auch das Ignorieren der Timer-Auflösungsanforderung auf.</summary>
public static void OptOutOfPowerThrottling()
{
var state = new PROCESS_POWER_THROTTLING_STATE
{
Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION,
ControlMask =
PROCESS_POWER_THROTTLING_EXECUTION_SPEED |
PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION,
StateMask = 0,
};
if (!SetProcessInformation(
GetCurrentProcess(),
ProcessPowerThrottling,
ref state,
(uint)Marshal.SizeOf<PROCESS_POWER_THROTTLING_STATE>()))
{
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
}
}
}
Der Aufruf erfolgt, indem Sie vor Beginn der zeitkritischen Schleife einmal PowerQos.OptOutOfPowerThrottling(); ausführen. Das Prozess-Handle benötigt die Zugriffsrechte PROCESS_SET_INFORMATION, aber mit dem von GetCurrentProcess() zurückgegebenen Pseudo-Handle des eigenen Prozesses gibt es kein Problem.
4.6. CPU-Platzierung / Core-Wechsel / Wärme
Bei der CPU-Platzierung funktioniert es oft besser, nicht sofort auf feste Bindung an bestimmte Cores (Hard Affinity / CPU Pinning) zu setzen, sondern mit einer Angabe zu beginnen, die näher an Soft Affinity liegt: „bitte möglichst auf dieser Core-Gruppe laufen“.
flowchart LR
Measure["Zuerst messen"] --> Ideal["SetThreadIdealProcessor / CPU Sets"]
Ideal --> Check{"Ausreichend verbessert?"}
Check -->|Ja| Keep["Dort stehen bleiben"]
Check -->|Nein| Hard["Zuletzt SetThreadAffinityMask erwägen"]
Measure --> Therm["Gleichzeitig Temperatur / Takt / Langzeitbetrieb prüfen"]
Checkliste
- Die CPU-Platzierung wird erst nach der Messung angepasst
- Es wird nicht sofort auf bestimmte Cores fixiert
- Zuerst werden
SetThreadIdealProcessoroder CPU Sets ausprobiert SetThreadAffinityMaskwird als letztes Mittel behandelt- Temperatur, Takt und Thermal Throttling werden über lange Laufzeit geprüft
- Der Silent- oder Low-Noise-Modus von Notebooks wird geprüft
Als Reihenfolge ist dieser Ablauf sicher.
- Zuerst messen
- Bei Bedarf ideal processor / CPU Sets
- Ist weitere Verbesserung nötig, feste Core-Bindung
Eine feste Core-Bindung sieht nach einer wirksamen Maßnahme aus, verringert aber die Ausweichmöglichkeiten des Betriebssystems – wird sie leichtfertig eingesetzt, kann das die Flexibilität stattdessen verringern.
4.7. Treiber / DPC / ISR / externe Störungen isolieren
Wenn „nur das Maximum gelegentlich explodiert“ oder „der Mittelwert gut ist, aber p99.9 schlecht“ ist, lohnt es sich, auch externe Störungen außerhalb des eigenen App-Codes in Verdacht zu nehmen.
flowchart TD
Spike["late / miss / max Spike ist aufgetreten"] --> Q1{"Ist die eigene Verarbeitungszeit auch lang?"}
Q1 -->|Ja| App["Hot Path verkürzen / Allokationen reduzieren / I/O entfernen"]
Q1 -->|Nein| Q2{"Gibt es DPC / ISR Spitzen?"}
Q2 -->|Ja| Driver["USB / WLAN / Bluetooth / GPU / Audio / Storage / ACPI / Treiberupdates prüfen"]
Q2 -->|Nein| Q3{"Gibt es Page Faults / GC / Erstkosten?"}
Q3 -->|Ja| Mem["Vorab reservieren / Warm-up / Heap-Last reduzieren"]
Q3 -->|Nein| Q4{"Gibt es Einfluss von Batterie / Energiesparen / Wärme?"}
Q4 -->|Ja| Pow["AC-Stromversorgung / Energieeinstellungen / Kühlung / Langzeittest"]
Q4 -->|Nein| ETW["Mit ETW / WPA / LatencyMon tiefer graben"]
Checkliste
- Treiber rund um WLAN / Bluetooth / USB / Storage / GPU / Audio sind geprüft
- Es wurde mit gestoppter unnötiger Cloud-Synchronisierung, Indizierung und automatischen Updates verglichen
- Es wurde auch getestet, ob es bei Minimierung oder abgeschaltetem Bildschirm zu Ausfällen kommt
- Die Tendenz von DPC / ISR wurde mit LatencyMon oder ETW betrachtet
- Es wurde getrennt betrachtet, ob „die eigene Verarbeitung schwer ist“ oder „man von außen ausgebremst wird“
5. Messung und Bewertung
5.1. Was aufgezeichnet werden sollte
Mindestens diese Werte sollten Sie erfassen.
- Geplanter Periodenzeitpunkt
- Tatsächlicher Startzeitpunkt
- Tatsächlicher Endzeitpunkt
- Lateness (wie stark der Start gegenüber dem geplanten Beginn verzögert war)
- Ausführungszeit
- Anzahl der Missed Deadlines
- Anzahl aufeinanderfolgender Missed Deadlines
- Queue-Tiefe
- Drop-Anzahl
- CPU-Auslastung
- Verteilung nach Core
- DPC / ISR Spitzen
- Page Faults
- Temperatur- / Taktschwankungen
Betrachtet man nur den Mittelwert, lässt sich der Kern der Sache schwer erfassen. Was im Produktivbetrieb Probleme macht, sind die gelegentlichen großen Latenzspitzen.
5.2. Wie p99 / p99.9 / max zu lesen sind
Kennzahlen wie p99 dienen dazu, die langsame Seite der Verteilung zu betrachten. Mit dem Mittelwert allein bleiben gelegentliche große Verzögerungen verborgen.
| Kennzahl | Bedeutung | Vorstellung bei 10.000 Messungen |
|---|---|---|
| Mittelwert | Der geglättete Gesamtwert | Spitzen gehen leicht unter |
| p50 | Der mittlere Wert | Nahe am alltäglichen Gefühl |
| p95 | Die Schwelle, ab der die langsamsten 5 % sichtbar werden | Die Grenze nach Ausschluss der langsamsten 500 |
| p99 | Die Schwelle, ab der die langsamsten 1 % sichtbar werden | Die Grenze nach Ausschluss der langsamsten 100 |
| p99.9 | Die Schwelle, ab der die langsamsten 0,1 % sichtbar werden | Die Grenze nach Ausschluss der langsamsten 10 |
| max | Der schlechteste Wert | Der eine langsamste Durchlauf |
Nehmen wir zum Beispiel folgende Werte an (dies ist ein Beispiel, um das Lesen der Kennzahlen zu erklären, keine tatsächliche Messung auf einer bestimmten Hardware).
- Mittelwert: 0,8 ms
- p99: 1,2 ms
- p99.9: 3,5 ms
- max: 28 ms
Das ist ein Zustand, in dem die Verarbeitung normalerweise schnell ist, aber gelegentlich große Spitzen auftreten. Auf gewöhnlichem Windows zeigt sich das eigentliche Problem meist genau in dieser Schleppe von p99 bis max.
Dieser Artikel zeigt die Wirkung der empfohlenen Konfiguration übrigens nicht in Zahlen. Latenz und Jitter ändern sich leicht je nach CPU, Treibern, residenter Software, Energieeinstellungen und Art der Belastung, daher sind Zahlen aus einer fremden Umgebung kein Beleg für die eigene Umgebung. Stattdessen finden Sie hier eine Anleitung, um in Ihrer eigenen Umgebung eine Tabelle derselben Form zu erstellen.
Minimales Vorgehen, um in der eigenen Umgebung p99 zu ermitteln
- Im Hot Path wird nur aufgezeichnet. Mit
Stopwatch.GetTimestamp()(unter C++QueryPerformanceCounter) werden Lateness und Ausführungszeit erfasst und in ein vorab reserviertes Array geschrieben. Mittelwert oder Sortierung dürfen hier nicht berechnet werden - Die Auswertung erfolgt erst, nachdem die Messung gestoppt wurde. Sortieren Sie und entnehmen Sie die Werte an den Perzentil-Positionen
- Wiederholen Sie dasselbe Vorgehen unter verschiedenen Bedingungen: vor/nach dem Warm-up, AC/Batterie, UI im Vordergrund/minimiert, mit/ohne Last durch andere Prozesse (5.4)
- Nach jeder einzelnen Änderung nehmen Sie unter denselben Bedingungen erneut Messwerte auf und vergleichen
// C# / .NET 8. Die Auswertung erfolgt erst, nachdem die Messung gestoppt wurde
using System.Diagnostics;
// Im Hot Path wird nur in das Array geschrieben (keine Allokation)
long[] latenessTicks = new long[100_000];
int count = 0;
// Beispiel: innerhalb der periodischen Schleife
// latenessTicks[count++] = Stopwatch.GetTimestamp() - scheduledTimestamp;
static double PercentileMs(long[] ticks, int count, double percentile)
{
long[] sorted = ticks.AsSpan(0, count).ToArray();
Array.Sort(sorted);
int index = (int)Math.Ceiling(percentile / 100.0 * count) - 1;
index = Math.Clamp(index, 0, count - 1);
return sorted[index] * 1000.0 / Stopwatch.Frequency;
}
// Verwendung
// Console.WriteLine($"p50={PercentileMs(latenessTicks, count, 50):F3}ms");
// Console.WriteLine($"p99={PercentileMs(latenessTicks, count, 99):F3}ms");
// Console.WriteLine($"p99.9={PercentileMs(latenessTicks, count, 99.9):F3}ms");
// Console.WriteLine($"max={PercentileMs(latenessTicks, count, 100):F3}ms");
Stopwatch.Frequency ist die Anzahl der Zählschritte pro Sekunde; teilt man dadurch und multipliziert mit 1000, erhält man Millisekunden. Bei zu wenigen Stichproben hat p99.9 keine Aussagekraft. Wenn Sie über p99.9 sprechen wollen, sammeln Sie mindestens 10.000 Stichproben (idealerweise 100.000).
5.3. Womit gemessen wird
Das Werkzeug-Set ist weitgehend festgelegt.
- In-App-Messung
Zunächst selbst
period / lateness / execution time / queue depth / droperfassen - ETW / WPR / WPA CPU, Context Switches, DPC / ISR, Page Faults untersuchen
- LatencyMon Eine Vermutung zu treiberbedingten Schwankungen eingrenzen
- Temperatur- / Taktüberwachung Wärmeeinflüsse betrachten
flowchart LR
App["In-App-Messung"] --> Dist["p50 / p95 / p99 / p99.9 / max"]
App --> Miss["miss / drop / Queue-Tiefe"]
ETW["ETW / WPR / WPA"] --> Root["Context Switch / DPC / ISR / Page Fault"]
Temp["Temperatur- / Taktüberwachung"] --> Root
Dist --> Decide["Priorität der Verbesserungen festlegen"]
Miss --> Decide
Root --> Decide
Bis zu WPA vorzudringen erfordert etwas Mühe, ist aber ziemlich wirksam, um zu unterscheiden, ob DPC / ISR die Ursache sind oder die eigene Verarbeitung einfach schwer ist.
Bezugsquelle und minimale Nutzung
| Tool | Bezugsquelle | Minimales Vorgehen |
|---|---|---|
| WPR / WPA (Windows Performance Toolkit) | Wird bei der Installation des Windows ADK (Windows Assessment and Deployment Kit) installiert, wenn Sie „Windows Performance Toolkit“ auswählen. Standardort: C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit |
Öffnen Sie die Eingabeaufforderung als Administrator, (1) starten Sie die Aufzeichnung mit wpr -start CPU, (2) lassen Sie den betroffenen Prozess einige Dutzend Sekunden laufen, (3) speichern Sie mit wpr -stop trace.etl "Untersuchung periodischer Verzögerungen". Öffnen Sie anschließend trace.etl mit WPA. Die verfügbaren Profilnamen erhalten Sie mit wpr -profiles |
| LatencyMon | Download von der Website von Resplendence Software. Die Home Edition für Privatanwender ist kostenlos | Starten Sie das Tool, beginnen Sie die Messung und lassen Sie den betroffenen Prozess einige Minuten laufen. Erfasst werden die maximale Verzögerung des Kernel-Timers sowie die ISR-/DPC-Ausführungszeit und Hard Page Faults pro Treiber – notieren Sie sich die Treiber mit auffällig hoher Ausführungszeit |
In WPA schauen Sie zuerst bei den CPU-bezogenen Diagrammen auf die Ausführungszeit von DPC / ISR und Context Switches. Dort erscheint, „welcher Treiber in der Zeit, in der der eigene Thread nicht laufen konnte, die CPU belegt hatte“, sodass Sie das mit den in 5.1 erfassten Verzögerungszeitpunkten abgleichen können.
Dieser Artikel enthält übrigens keine Bildschirmfotos. Da sich das Erscheinungsbild je nach Version leicht ändert, führen Sie die obigen Schritte selbst aus und prüfen Sie es am tatsächlichen Bildschirm.
5.4. Die Vorgehensweise beim Testen
Ein ruhiges Testlabor allein genügt beim Testen nicht. Mindestens diese Bedingungen sollten getrennt betrachtet werden.
- Direkt nach dem Start, vor dem Warm-up
- Nach dem Warm-up
- Langer Dauerbetrieb
- UI im Vordergrund
- UI minimiert / nahezu ausgeblendet
- AC-Stromversorgung
- Batteriebetrieb
- Zustand mit Last auf Netzwerk oder Festplatte
Bewertet man nur im Testlabor, übersieht man leicht Probleme, die im echten Betrieb auftreten. Das Verhalten von gewöhnlichem Windows wird stark von der „Art der Nutzung“ beeinflusst, daher ist es wichtig, unter Bedingungen zu prüfen, die den tatsächlichen Nutzungsbedingungen nahekommen.
6. Grobe Entscheidungshilfe
Die Kurzübersicht nach Periodenbereich wurde nach 1.1 vorgezogen, damit Sie beim Lesen dorthin zurückspringen können. Hier ergänzen wir zwei Entscheidungen, die sich aus dieser Tabelle allein nicht ableiten lassen.
Wo Sie entscheiden, dass „mit gewöhnlichem Windows nicht mehr geht“
Wenn Sie unter 1 ms über lange Zeit und bei hoher Last einhalten müssen, ist es oft schneller, nur den zeitkritischen Teil auszulagern, statt weiter zu tunen. Kandidaten für die Auslagerung sind geräteseitige Firmware, ein dedizierter Controller, ein FPGA oder ein RTOS. Als Entscheidungsgrundlage dienen nicht subjektive Eindrücke, sondern die Zahlen aus Kapitel 5.
- Der Hot Path lässt sich nicht weiter verkürzen, und p99.9 sowie max überschreiten weiterhin die Anforderung
- Die Ursache liegt in externen Störungen (DPC / ISR, Treiber, andere Prozesse) und ist mit Maßnahmen auf App-Seite nicht erreichbar (durch die Eingrenzung in 4.7 bestätigt)
- Die Anforderung lautet nicht mehr „bricht nicht zusammen, wenn gelegentlich verfehlt“, sondern „darf kein einziges Mal verfehlt werden“
Wenn Sie alles in einem Prozess unterbringen wollen
Packt man GUI, Logging, Kommunikation und DB in dieselbe Schleife desselben Prozesses, bricht das, was der nachgelagerte Teil braucht, die Deadline des vorgelagerten Teils. Denn das Warten auf einen Datei-Flush, eine DB-Neuverbindung oder ein UI-Neuzeichnen kann sich jeweils um mehrere Dutzend Millisekunden verlängern. Eine Option ist es, die Trennung von fast path / slow path (4.2) nicht nur auf Thread-, sondern auf Prozessebene auszuweiten. Trennt man die Prozesse, läuft die Periode des vorgelagerten Teils weiter, auch wenn der nachgelagerte Teil hängen bleibt.
7. Zusammenfassung
Es gibt zwei Grundannahmen, die Sie im Kopf behalten sollten.
- Was auf gewöhnlichem Windows angestrebt wird, ist keine Hard-Real-Time-Garantie, sondern eine Soft-Real-Time-Konfiguration: Latenz und Jitter klein halten und nicht zusammenbrechen, wenn eine Terminverletzung auftritt
- Am wirkungsvollsten ist das Aufräumen des Hot Path, mehr als die Anpassung der Priorität
Auf der Implementierungsseite zahlt sich das hier aus.
- fast path und slow path trennen
- Queue fester Länge verwenden und die Vorgehensweise bei Überlauf vorab festlegen
- Mit QPC messen, mit Event / waitable timer (wartbarem Timer) warten
- Im Hot Path Allokation, blockierende I/O und schwere Locks vermeiden
Auf der Betriebsseite zahlt sich das hier aus.
- Mit AC-Stromversorgung betreiben
- Ein separates Energieprofil für den Produktivbetrieb pflegen
- Unnötige Hintergrundlast reduzieren
- Mit p99 / p99.9 / max und der Anzahl der Misses bewerten
Soft Real-Time auf gewöhnlichem Windows wird nicht allein durch die Prioritätseinstellung bestimmt – wenn Sie Entwurf, Implementierung, Energieeinstellungen, Messung und Betrieb getrennt durcharbeiten, lässt sich daraus ein durchaus stabiles System bauen.
8. Quellen
- Multimedia Class Scheduler Service
- AvSetMmThreadCharacteristicsW function
- SetThreadPriority function
- SetPriorityClass function
- timeBeginPeriod function
- CreateWaitableTimerExW function
- Acquiring high-resolution time stamps
- QueryPerformanceCounter function
- GetSystemTimePreciseAsFileTime function
- SetProcessInformation function
- VirtualLock function
- CPU Sets
- SetThreadIdealProcessor function
- SetThreadAffinityMask function
- Processor power management options
- Change the power mode for your Windows PC
- Power settings in Windows 11
- CPU Analysis (WPA / WPT)
- WPR Command-Line Options
- Download and install the Windows ADK
- Quality of Service (EcoQoS / HighQoS)
- PROCESS_POWER_THROTTLING_STATE structure
- LatencyMon - Resplendence Software
Verwandte Artikel
Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.
Code-Design für Geschäftssysteme — Produkt- und Kundencodes festlegen, und Prüfziffern
Ein praxisnaher Leitfaden zur Festlegung des Codesystems eines Geschäftssystems, einschließlich Produkt- und Kundencodes. Behandelt eine ...
Eine Einführung in ADRs (Architecture Decision Records) — Der minimale Weg, „warum wir es so entworfen haben“ in einem kleinen Team festzuhalten
Code erklärt nie, warum er so geschrieben wurde. Wir zeigen, wie Sie mit einem ADR (Architecture Decision Record) — eine Entscheidung, ei...
Wenn man eine Windows-App besser nicht ins Web migriert: Entscheidungstabelle und die pragmatische Lösung der Aufteilung
Der Wunsch, interne Windows-Anwendungen ins Web zu migrieren, nimmt stetig zu. Doch bei Apps mit Gerätekopplung, lokaler Dateiverarbeitun...
Warum Sie unter Windows Ereigniswarten gegenüber Sleep(1) bevorzugen sollten
Unter Windows hängt die Präzision kurzer timed waits von der Granularität der Systemuhr und vom Scheduling ab. Wer auf das Eintreffen von...
Entscheidungstabelle: Nach einer unerwarteten Ausnahme beenden oder fortsetzen?
Wenn eine unerwartete Ausnahme auftritt, ordnet dieser Artikel ein, ob die Anwendung beendet oder fortgesetzt werden sollte – aus der Per...
Verwandte Themen
Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.
Technische Windows-Themen
Portal zu Windows-Entwicklung, Fehleranalyse und der Nutzung bestehender Assets.
Leistungen zu diesem Thema
Dieser Artikel ist direkt mit den folgenden Leistungen verbunden.
Technische Beratung und Design-Review
Klärung von Änderungsstrategie, Entwurf und Umgang mit bestehenden Assets.
Häufige Fragen
Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.
- Kann Windows Echtzeitverarbeitung leisten?
- Eine Hard-Real-Time-Garantie (null Terminverletzungen) ist nicht möglich, aber wenn Entwurf, Implementierung, Messung und Betrieb sauber durchgearbeitet werden, lässt sich als Soft Real-Time ein durchaus praxistauglicher Zustand erreichen. Periodische Verarbeitung im Bereich von wenigen bis einigen Dutzend Millisekunden, pufferbasiertes Audio/Video, Sensorerfassung und Regelschleifen sind auf gewöhnlichem Windows 10/11 realistisch. Werden dagegen null Terminverletzungen oder eine über lange Zeit stabile Einhaltung von wenigen hundert Mikrosekunden oder weniger benötigt, sollte man in Richtung RTOS, dedizierter Controller, FPGA oder geräteseitige Verarbeitung ausweichen.
- Warum sollte man in einer periodischen Verarbeitung kein Sleep(1) verwenden?
- Sleep(1) erzeugt keine „1-ms-Periode“, sondern ein Verhalten, das „ungefähr 1 ms oder mehr wartet und dann die Ausführungszeit noch obendrauf legt“ – und der Warte-Overshoot summiert sich unmittelbar. Stabiler ist es, die periodische Schleife über die absolute Deadline next += period laufen zu lassen, beim Warten ein Geräte-Ereignis oder einen hochauflösenden waitable timer zu bevorzugen und nur die letzte Feinjustierung auf einen ganz kurzen Busy-Spin zu beschränken. timeBeginPeriod wird nur solange verwendet, wie es nötig ist, und danach wieder zurückgesetzt.
- Was hilft am meisten, um Latenz und Jitter zu reduzieren?
- Mehr als das Erhöhen der Priorität hilft es, den Hot Path kurz, fest in der Länge und nicht-blockierend zu halten. Trennen Sie fast path (Erfassung/Steuerung) und slow path (Speicherung/Kommunikation/UI) und verbinden Sie beide über eine Queue fester Länge; im Hot Path vermeiden Sie Dateischreibvorgänge, Netzwerkversand, schweres Logging und Speicherzuweisungen bei jedem Durchlauf. Im laufenden Betrieb zahlen sich AC-Stromversorgung, ein überarbeiteter Energiemodus, die Kontrolle über EcoQoS und das Aufräumen der Hintergrundlast aus.
- Mit welchen Kennzahlen sollte die Stabilität periodischer Verarbeitung bewertet werden?
- Nicht nur mit dem Mittelwert, sondern mit p99, p99.9, max und der Anzahl der Deadline Misses. Liegt der Mittelwert etwa bei 0,8 ms, das Maximum aber bei 28 ms, ist die Verarbeitung normalerweise schnell, hat aber gelegentlich große Ausreißer – und auf gewöhnlichem Windows liegt das eigentliche Problem meist genau in dieser Schleppe von p99 bis max. Ergänzend sollten DPC-/ISR-Spitzen, Page Faults, Queue-Tiefe sowie Temperatur- und Taktschwankungen erfasst und Bedingungen wie vor/nach dem Warm-up, Langzeitbetrieb, minimierter Zustand und Batteriebetrieb getrennt bewertet werden.
Autorenprofil
Profilseite des Artikelautors.
Go Komura
Geschäftsführer von KomuraSoft LLC
Spezialisiert auf Windows-Softwareentwicklung, technische Beratung und Fehleranalyse, insbesondere bei bestehenden Systemen und schwer reproduzierbaren Störungen.