Zeit und Genauigkeit (unter Windows)

Und wieder haben wir auf Winterzeit umgestellt … der richtige Zeitpunkt sich wieder mal über Zeit den Kopf zu zerbrechen.

Ein Thema, das ich bisher immer ausgespart hatte, war “Genauigkeit” und wie man sie erhöhen kann.


Es ist schon fast lustig, wenn man weiß, dass die früheren PCs (damals vor 30 Jahren) ziemlich genaue RTC (Real-Time-Clock) Chips verbaut hatten, während die Betriebssysteme nur “ungefähre” Zeitangaben speicherten.

Heute sind die RTCs in unseren Maschinen der letzte Dreck und weichen schon nach ein paar Stunden um Sekunden ab, während die Betriebssysteme die Zeit auf Bruchteile von Millisekunden genau ermitteln können müssen.

Der Grund für den Verfall der RTC Chips liegt vermutlich darin begründet, dass heute eine Internetanbindung samt NTP Synchronisierung erwartet wird.

Und der Grund für die genauen Zeitablesungen sind Anwendungen, die möglichst in Echtzeit auf Ereignisse reagieren sollen.

GetSystemTime() und GetSystemTimeAsFileTime()

Mit GetSystemTime() nutzt man die API, die überall vorhanden ist, von Windows NT4/95 bis heute und auch Windows CE stellt sie bereit.

Doch meistens braucht man die Zeit nicht als Datumsangabe wie in SYSTEMTIME definiert, sondern als Integer-Zeitstempel, und das läuft in Windows unter FILETIME als UINT64 Typ in Nanosekunden seit 1.1. 1601.
Hier hilft SystemTimeToFileTime() und damit kann man dann endlich rechnen.

Die bessere Methode ist allerdings gleich die API GetSystemTimeAsFileTime(), denn Zeit wird Windows-intern gleich als FILETIME behandelt und GetSystemTime() nutzt eben diese andere Funktion um daraus ein Datum zu machen.

Allerdings ist diese API nicht in Windows CE definiert, weshalb ich bisher stets mit GetSystemTime gearbeitet habe.
Doch da WinCE jetzt nicht gerade “die wichtigste Plattform” ist, bin ich ebenfalls zu GetSystemTimeAsFileTime() gewechselt, und habe für die CE-Welt eine einfache Umleitung hinterlassen:

1static void GetSystemTimeAsFileTime(FILETIME* ptr_ftm)
2{
3  SYSTEMTIME stm;
4  GetSystemTime(&stm);
5  SystemTimeToFileTime(&stm, ptr_ftm);
6}

Wie gut, dass Raymond Chen das Thema Zeit-APIs aufgegriffen hatte.

Genauigkeit erhöhen

Windows hat die Genauigkeit seiner klassischen Zeit-APIs auf ungefähr 15 Millisekunden angegeben, was vor 20-30 Jahren bei CPUs mit ein paar hundert Megahertz vielleicht noch OK war, heute ist das beim Logging allerdings schon problematisch.

Mir ist das bisher nie so wichtig gewesen, doch im Job bei der Arbeit mit Kameras und Bilderkennung, ist das extrem wichtig, dass man bei der Synchronisation von zwei Systemen auch möglichst exakte Zeitstempel braucht. +/- 15 Millisekunden ist da eine Ewigkeit.

Mit der (uralten) Multimedia-API timeBeginPeriod(1) kann man Windows dazu zwingen, die Reaktion von Warte-Routinen auf 1 Millisekunde herunterzusetzen, denn auch ein Sleep(1) wartet bis zu 10 Millisekunden, bis das Programm fortgesetzt wird.
Doch die Zeit-APIs werden auch mit timeBeginPeriod() nur alle 15 Millisekunden aktualisiert.

Seit Windows 10 ist die Genauigkeit der Windows Zeit-APIs auch auf etwa 1 ms verbessert worden, doch für ältere Betriebssysteme hat sich ein interessanter Hack etabliert:

Man startet einen Thread mit höherer Priorität und liest dort in einer Schleife die Zeit und einen Performance-Counter aus.
Die Zeit-Funktion wird wiederholt den gleichen Zeitstempel zurückliefern, bis die “Ungenauigkeit” durch ein Update des Systems unterbrochen wird. Genau zu diesem Zeitpunkt speichert man sich den Wert des Performance-Counters ab und kann dann bei den weiteren Iterationen die Differenz der Performance-Counter Werte zum letzten “genauen” Zeitstempel addieren.

Zu den Themen wurden schon vor 20 Jahren Artikel verfasst.

Und ich habe ein Codebeispiel im Blog Classroom angelegt, das den Unterschied zwischen normalen und “hi-res” Zeitablesungen aufzeigt.

Fazit

Timer und Zeitablesungen, sind für mich aktuell keine hohe Priorität. Denn wenn etwas schnell erledigt werden soll, passiert das bei mir synchron ohne künstliche Wartezeiten. Und wenn der Benutzer etwas “sehen” will, dann sind Genauigkeiten von 15 Millisekunden aus meiner Sicht weiter ausreichend.

Aber zugegeben … es wäre vielleicht nicht schlecht, wenn ich mir auch eine Timer-Klasse anlege, um solche Betriebssystem-Details abstrahiert und damit die Genauigkeit erhöht.

Man darf dabei aber nicht vergessen, dass solche Schritte Seiteneffekte haben, wie z.B. der Erhöhung der Timer-Genauigkeit für alle Prozesse oder dass die CPU Last in Summe ansteigt.
Mit Standardeinstellungen sollte ein solches Hi-res Feature also nicht aktiviert werden.

📧 📋 🐘 | 🔔
 

Meine Dokus über:
 
Weitere externe Links zu:
Alle extern verlinkten Webseiten stehen nicht in Zusammenhang mit opengate.at.
Für deren Inhalt wird keine Haftung übernommen.



Wenn sich eine triviale Erkenntnis mit Dummheit in der Interpretation paart, dann gibt es in der Regel Kollateralschäden in der Anwendung.
frei zitiert nach A. Van der Bellen
... also dann paaren wir mal eine komplexe Erkenntnis mit Klugheit in der Interpretation!