Abrufen von Zeitstempeln mit hoher Auflösung

Windows stellt APIs bereit, mit denen Sie hochauflösende Zeitstempel abrufen oder Zeitintervalle messen können. Die primäre API für nativen Code ist QueryPerformanceCounter (QPC). Für Gerätetreiber lautet die Kernelmodus-API KeQueryPerformanceCounter. Für verwalteten Code verwendet die System.Diagnostics.Stopwatch-KlasseQPC als genaue Zeitbasis.

QPC ist unabhängig von einem externen Zeitverweis und wird nicht mit synchronisiert. Verwenden Sie GetSystemTimePreciseAsFileTime, um Zeitstempel abzurufen, die mit einem externen Zeitverweis synchronisiert werden können, z. B. koordinierte Weltzeit (UTC) für die Verwendung in hochauflösenden Tageszeitmessungen.

Zeitstempel und Zeitintervallmessungen sind integraler Bestandteil von Computer- und Netzwerkleistungsmessungen. Diese Leistungsmessungsvorgänge umfassen die Berechnung von Antwortzeit, Durchsatz und Latenz sowie die Ausführung von Profilerstellungscode. Jeder dieser Vorgänge umfasst eine Messung von Aktivitäten, die während eines Zeitintervalls auftreten, das durch ein Start- und ein Endereignis definiert wird, das unabhängig von einer externen Tageszeitreferenz sein kann.

QPC ist in der Regel die beste Methode, um Ereignisse zu zeitstempeln und kleine Zeitintervalle zu messen, die auf demselben System oder virtuellen Computer auftreten. Erwägen Sie die Verwendung von GetSystemTimePreciseAsFileTime , wenn Sie Ereignisse auf mehreren Computern zeitstempeln möchten, vorausgesetzt, dass jeder Computer an einem Zeitsynchronisierungsschema wie Network Time Protocol (NTP) teilnimmt. QPC hilft Ihnen, Probleme zu vermeiden, die bei anderen Zeitmessungsansätzen auftreten können, z. B. das direkte Lesen des Zeitstempelzählers (Time Stamp Counter, TSC) des Prozessors.

QPC-Unterstützung in Windows-Versionen

QPC wurde in Windows 2000 und Windows XP eingeführt und wurde weiterentwickelt, um die Vorteile der Verbesserungen der Hardwareplattform und der Prozessoren zu nutzen. Hier werden die Merkmale von QPC unter verschiedenen Windows-Versionen beschrieben, damit Sie Software verwalten können, die unter diesen Windows-Versionen ausgeführt wird.

Windows XP und Windows 2000

QPC ist unter Windows XP und Windows 2000 verfügbar und funktioniert auf den meisten Systemen gut. Das BIOS einiger Hardwaresysteme hat jedoch die Hardware-CPU-Merkmale nicht ordnungsgemäß angegeben (ein nicht invarianter TSC), und einige Multicore- oder Mehrprozessorsysteme verwendeten Prozessoren mit TSCs, die nicht kernübergreifend synchronisiert werden konnten. Systeme mit fehlerhafter Firmware, die diese Windows-Versionen ausführen, bieten möglicherweise nicht den gleichen QPC-Wert auf verschiedenen Kernen, wenn sie den TSC als Grundlage für QPC verwenden.

Windows Vista und Windows Server 2008

Alle Computer, die mit Windows Vista und Windows Server 2008 ausgeliefert wurden, verwendeten einen Plattformzähler (High Precision Event Timer(HPET)) oder den ACPI Power Management Timer (PM-Timer) als Basis für QPC. Solche Plattformtimer weisen eine höhere Zugriffslatenz als der TSC auf und werden von mehreren Prozessoren gemeinsam genutzt. Dies schränkt die Skalierbarkeit von QPC ein, wenn es gleichzeitig von mehreren Prozessoren aufgerufen wird.

Windows 7 und Windows Server 2008 R2

Die meisten Windows 7- und Windows Server 2008 R2-Computer verfügen über Prozessoren mit TSCs mit konstanter Rate und verwenden diese Indikatoren als Grundlage für QPC. TSCs sind hochauflösende Hardwareindikatoren pro Prozessor, auf die mit sehr geringer Latenz und Mehraufwand zugegriffen werden kann (je nach Prozessortyp in der Reihenfolge von 10s oder 100s von Computerzyklen). Windows 7 und Windows Server 2008 R2 verwenden TSCs als Basis von QPC auf Ein-Uhr-Domänensystemen, bei denen das Betriebssystem (oder der Hypervisor) die einzelnen TSCs während der Systeminitialisierung über alle Prozessoren hinweg eng synchronisieren kann. Auf solchen Systemen sind die Kosten für das Lesen des Leistungsindikators im Vergleich zu Systemen, die einen Plattformzähler verwenden, erheblich niedriger. Darüber hinaus entsteht kein zusätzlicher Mehraufwand für gleichzeitige Anrufe und Benutzermodusabfragen, die häufig Systemaufrufe umgehen, was den Mehraufwand weiter verringert. Auf Systemen, auf denen der TSC nicht für die Zeiterfassung geeignet ist, wählt Windows automatisch einen Plattformzähler (entweder den HPET-Timer oder den ACPI PM-Timer) als Grundlage für QPC aus.

Windows 8, Windows 8.1, Windows Server 2012 und Windows Server 2012 R2

Windows 8, Windows 8.1, Windows Server 2012 und Windows Server 2012 R2 verwenden TSCs als Basis für den Leistungsindikator. Der TSC-Synchronisierungsalgorithmus wurde erheblich verbessert, um große Systeme mit vielen Prozessoren besser unterzubringen. Darüber hinaus wurde unterstützung für die neue api für die genaue Tageszeit hinzugefügt, die das Abrufen präziser Zeitstempel der Wanduhr vom Betriebssystem ermöglicht. Weitere Informationen finden Sie unter GetSystemTimePreciseAsFileTime. Bei Windows RT und Windows 11 und Windows 10 Geräten, die Arm-Prozessoren verwenden, basiert der Leistungsindikator entweder auf einem proprietären Plattformzähler oder auf dem Systemzähler, der vom Arm Generic Timer bereitgestellt wird, sofern die Plattform so ausgestattet ist.

Anleitung zum Abrufen von Zeitstempeln

Windows hat und wird weiterhin in die Bereitstellung eines zuverlässigen und effizienten Leistungsindikators investieren. Wenn Sie Zeitstempel mit einer Auflösung von mindestens 1 Mikrosekunde benötigen und die Zeitstempel nicht mit einem externen Zeitverweis synchronisiert werden müssen, wählen Sie QueryPerformanceCounter, KeQueryPerformanceCounter oder KeQueryInterruptTimePrecise aus. Wenn Sie UTC-synchronisierte Zeitstempel mit einer Auflösung von 1 Mikrosekunde oder höher benötigen, wählen Sie GetSystemTimePreciseAsFileTime oder KeQuerySystemTimePrecise aus.

Auf einer relativ kleinen Anzahl von Plattformen, die das TSC-Register nicht als QPC-Basis verwenden können, kann z. B. aus Gründen, die in Hardware-Timerinformationen erläutert werden, der Erwerb von hochauflösenden Zeitstempeln erheblich teurer sein als das Erwerben von Zeitstempeln mit geringerer Auflösung. Wenn eine Auflösung von 10 bis 16 Millisekunden ausreicht, können Sie GetTickCount64, QueryInterruptTime, QueryUnbiasedInterruptTime, KeQueryInterruptTime oder KeQueryUnbiasedInterruptTime verwenden, um Zeitstempel abzurufen, die nicht mit einem externen Zeitverweis synchronisiert sind. Verwenden Sie für UTC-synchronisierte Zeitstempel GetSystemTimeAsFileTime oder KeQuerySystemTime. Wenn eine höhere Auflösung erforderlich ist, können Sie stattdessen QueryInterruptTimePrecise, QueryUnbiasedInterruptTimePrecise oder KeQueryInterruptTimePrecise verwenden, um Zeitstempel abzurufen.

Im Allgemeinen sind die Leistungsindikatorergebnisse für alle Prozessoren in Mehrkern- und Mehrprozessorsystemen konsistent, auch wenn sie an verschiedenen Threads oder Prozessen gemessen werden. Hier sind einige Ausnahmen von dieser Regel:

  • Vor Windows Vista-Betriebssystemen, die auf bestimmten Prozessoren ausgeführt werden, können diese Konsistenz aus einem der folgenden Gründe verletzen:

    • Die Hardwareprozessoren verfügen über einen nicht invarianten TSC, und das BIOS gibt diese Bedingung nicht richtig an.
    • Der verwendete TSC-Synchronisierungsalgorithmus eignet sich nicht für Systeme mit einer großen Anzahl von Prozessoren.
  • Wenn Sie Leistungsindikatorenergebnisse vergleichen, die aus verschiedenen Threads abgerufen werden, sollten Sie Werte, die sich um ± 1 Tick unterscheiden, eine mehrdeutige Reihenfolge aufweisen. Wenn die Zeitstempel aus demselben Thread stammen, gilt diese ± 1 Tick Unsicherheit nicht. In diesem Kontext bezieht sich der Begriff Tick auf einen Zeitraum von 1 ÷ (die Häufigkeit des Leistungsindikators, der aus QueryPerformanceFrequency abgerufen wurde).

Wenn Sie den Leistungsindikator auf großen Serversystemen mit Domänen mit mehreren Takten verwenden, die nicht in der Hardware synchronisiert sind, stellt Windows fest, dass der TSC nicht zu Zeitsteuerungszwecken verwendet werden kann, und wählt einen Plattformzähler als Grundlage für QPC aus. Dieses Szenario liefert zwar weiterhin zuverlässige Zeitstempel, aber die Zugriffslatenz und Skalierbarkeit wirken sich negativ auf die Zugriffslatenz und Skalierbarkeit aus. Wie bereits in der vorherigen Verwendungsanleitung beschrieben, verwenden Sie daher nur die APIs, die eine Mikrosekunde oder eine bessere Auflösung bereitstellen, wenn eine solche Auflösung erforderlich ist. Der TSC wird als Basis für QPC auf Domänensystemen mit mehreren Takten verwendet, die die Hardwaresynchronisierung aller Prozessoruhrdomänen enthalten, da sie dadurch effektiv als Einuhrdomänensystem funktionieren.

Die Häufigkeit des Leistungsindikators wird beim Systemstart festgelegt und ist für alle Prozessoren konsistent, sodass Sie nur die Häufigkeit von QueryPerformanceFrequency abfragen müssen, während die Anwendung initialisiert, und dann das Ergebnis zwischenspeichern müssen.

Virtualisierung

Es wird erwartet, dass der Leistungsindikator auf allen virtuellen Gastcomputern zuverlässig funktioniert, die auf ordnungsgemäß implementierten Hypervisoren ausgeführt werden. Hypervisoren, die der Hypervisor-Version 1.0-Schnittstelle entsprechen und die Referenzzeitaufhellung anzeigen, können jedoch einen erheblich geringeren Aufwand bieten. Weitere Informationen zu Hypervisorschnittstellen und Aufklärungen finden Sie unter Hypervisorspezifikationen.

Direkte TSC-Nutzung

Es wird dringend davon abgeraten, die RDTSC - oder RDTSCP-Prozessoranweisung zum direkten Abfragen des TSC zu verwenden, da Sie für einige Versionen von Windows, für Livemigrationen virtueller Computer und für Hardwaresysteme ohne invariante oder eng synchronisierte TSCs keine zuverlässigen Ergebnisse erhalten. Stattdessen empfehlen wir Ihnen, QPC zu verwenden, um die Abstraktion, Konsistenz und Portabilität zu nutzen, die es bietet.

Beispiele für den Erwerb von Zeitstempeln

Die verschiedenen Codebeispiele in diesen Abschnitten zeigen, wie Zeitstempel abgerufen werden.

Verwenden von QPC im nativen Code

In diesem Beispiel wird gezeigt, wie QPC in nativem C- und C++-Code verwendet wird.

LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds;
LARGE_INTEGER Frequency;

QueryPerformanceFrequency(&Frequency); 
QueryPerformanceCounter(&StartingTime);

// Activity to be timed

QueryPerformanceCounter(&EndingTime);
ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;


//
// We now have the elapsed number of ticks, along with the
// number of ticks-per-second. We use these values
// to convert to the number of elapsed microseconds.
// To guard against loss-of-precision, we convert
// to microseconds *before* dividing by ticks-per-second.
//

ElapsedMicroseconds.QuadPart *= 1000000;
ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;

Abrufen von Zeitstempeln mit hoher Auflösung aus verwaltetem Code

In diesem Beispiel wird gezeigt, wie Sie die System.Diagnostics.Stopwatch-Klasse mit verwaltetem Code verwenden.

using System.Diagnostics;

long StartingTime = Stopwatch.GetTimestamp();

// Activity to be timed

long EndingTime  = Stopwatch.GetTimestamp();
long ElapsedTime = EndingTime - StartingTime;

double ElapsedSeconds = ElapsedTime * (1.0 / Stopwatch.Frequency);

Die System.Diagnostics.Stopwatch-Klasse bietet auch mehrere praktische Methoden zum Durchführen von Zeitintervallmessungen.

Verwenden von QPC aus dem Kernelmodus

Der Windows-Kernel ermöglicht den Kernelmoduszugriff auf den Leistungsindikator über KeQueryPerformanceCounter , aus dem sowohl der Leistungsindikator als auch die Leistungshäufigkeit abgerufen werden können. KeQueryPerformanceCounter ist nur im Kernelmodus verfügbar und wird für Autoren von Gerätetreibern und anderen Kernelmoduskomponenten bereitgestellt.

In diesem Beispiel wird gezeigt, wie Sie KeQueryPerformanceCounter im Kernelmodus C und C++ verwenden.

LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds;
LARGE_INTEGER Frequency;

StartingTime = KeQueryPerformanceCounter(&Frequency);

// Activity to be timed

EndingTime = KeQueryPerformanceCounter(NULL);
ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;
ElapsedMicroseconds.QuadPart *= 1000000;
ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;

Allgemeine Häufig gestellte Fragen zu QPC und TSC

Hier finden Sie Antworten auf häufig gestellte Fragen zu QPC und TSCs im Allgemeinen.

Ist QueryPerformanceCounter() identisch mit der Win32 GetTickCount()- oder GetTickCount64()-Funktion?

Nein. GetTickCount und GetTickCount64 beziehen sich nicht auf QPC. GetTickCount und GetTickCount64 geben die Anzahl von Millisekunden seit dem Start des Systems zurück.

Sollte ich QPC verwenden oder die RDTSC/RDTSCP-Anweisungen direkt aufrufen?

Um Fehler und Portabilitätsprobleme zu vermeiden, empfehlen wir Ihnen dringend, QPC anstelle des TSC-Registers oder der RDTSC - oder RDTSCP-Prozessoranweisungen zu verwenden.

Wie ist die Beziehung von QPC zu einer externen Zeitepoche? Kann sie mit einer externen Epoche wie UTC synchronisiert werden?

QPC basiert auf einem Hardwareindikator, der nicht mit einem externen Zeitverweis wie UTC synchronisiert werden kann. Verwenden Sie GetSystemTimePreciseAsFileTime für präzise Zeitstempel, die mit einer externen UTC-Referenz synchronisiert werden können.

Wirkt sich QPC auf Sommerzeit, Schaltsekunden, Zeitzonen oder Systemzeitänderungen des Administrators aus?

Nein. QPC ist völlig unabhängig von der Systemzeit und UTC.

Wird die QPC-Genauigkeit durch Änderungen der Prozessorhäufigkeit beeinflusst, die durch das Energiemanagement oder die Turbo Boost-Technologie verursacht werden?

Nein. Wenn der Prozessor über eine invariante TSC verfügt, ist der QPC von diesen Änderungen nicht betroffen. Wenn der Prozessor keinen invarianten TSC aufweist, rückgängig machen QPC zu einem Plattformhardwaretimer, der nicht durch Änderungen der Prozessorhäufigkeit oder Turbo Boost-Technologie beeinträchtigt wird.

Funktioniert QPC zuverlässig auf Mehrprozessorsystemen, Mehrkernsystemen und Systemen mit Hyperthreading?

Ja.

Gewusst wie feststellen und überprüfen, ob QPC auf meinem Computer funktioniert?

Sie müssen diese Überprüfungen nicht durchführen.

Welche Prozessoren verfügen über nicht invariante TSCs? Wie kann ich überprüfen, ob mein System über eine nicht invariante TSC verfügt?

Sie müssen diese Überprüfung nicht selbst durchführen. Windows-Betriebssysteme führen bei der Systeminitialisierung mehrere Überprüfungen durch, um zu ermitteln, ob der TSC als Grundlage für QPC geeignet ist. Zu Referenzzwecken können Sie jedoch ermitteln, ob Ihr Prozessor über eine invariante TSC verfügt, indem Sie eine der folgenden Verwenden:

  • das Coreinfo.exe-Hilfsprogramm von Windows Sysinternals
  • Überprüfen der von der CPUID-Anweisung zurückgegebenen Werte in Bezug auf die TSC-Merkmale
  • Dokumentation des Prozessorherstellers

Im Folgenden werden die TSC-INVARIANT-Informationen angezeigt, die vom Windows Sysinternals Coreinfo.exe-Hilfsprogramm (www.sysinternals.com) bereitgestellt werden. Ein Sternchen bedeutet "True".

> Coreinfo.exe 

Coreinfo v3.2 - Dump information on system CPU and memory topology
Copyright (C) 2008-2012 Mark Russinovich
Sysinternals - www.sysinternals.com

 <unrelated text removed>

RDTSCP          * Supports RDTSCP instruction
TSC             * Supports RDTSC instruction
TSC-DEADLINE    - Local APIC supports one-shot deadline timer
TSC-INVARIANT   * TSC runs at constant rate

Funktioniert QPC zuverlässig auf Windows RT Hardwareplattformen?

Ja.

Wie oft rollt QPC?

Nicht weniger als 100 Jahre ab dem letzten Systemstart, und möglicherweise länger basierend auf dem zugrunde liegenden hardwarebasierten Timer. Für die meisten Anwendungen ist der Rollover kein Problem.

Was sind die Berechnungskosten für den Aufruf von QPC?

Die Berechnungskosten für den Aufruf von QPC werden in erster Linie von der zugrunde liegenden Hardwareplattform bestimmt. Wenn das TSC-Register als Grundlage für QPC verwendet wird, werden die Berechnungskosten in erster Linie davon bestimmt, wie lange der Prozessor benötigt, um eine RDTSC-Anweisung zu verarbeiten. Diese Zeit reicht von 10s von CPU-Zyklen bis zu mehreren hundert CPU-Zyklen, abhängig vom verwendeten Prozessor. Wenn das TSC nicht verwendet werden kann, wählt das System eine andere Hardwarezeitbasis aus. Da sich diese Zeitbasen auf der Hauptplatine befinden (z. B. auf der PCI South Bridge oder PCH), sind die Berechnungskosten pro Aufruf höher als die TSC und liegen je nach Prozessorgeschwindigkeit und anderen Hardwarefaktoren häufig in der Nähe von 0,8 bis 1,0 Mikrosekunden. Diese Kosten werden durch die Zeit bestimmt, die für den Zugriff auf das Hardwaregerät auf der Hauptplatine erforderlich ist.

Erfordert QPC einen Kernelübergang (Systemaufruf)?

Ein Kernelübergang ist nicht erforderlich, wenn das System das TSC-Register als Grundlage für QPC verwenden kann. Wenn das System eine andere Zeitbasis verwenden muss, z. B. den HPET- oder PM-Timer, ist ein Systemaufruf erforderlich.

Ist der Leistungsindikator monoton (nicht abnehmend)?

Ja. QPC geht nicht rückwärts.

Kann der Leistungsindikator verwendet werden, um Ereignisse rechtzeitig zu ordnen?

Ja. Beim Vergleichen von Leistungsindikatorergebnissen, die aus verschiedenen Threads abgerufen werden, weisen Werte, die sich durch ± 1-Tick unterscheiden, eine mehrdeutige Reihenfolge auf, als hätten sie einen identischen Zeitstempel.

Wie genau ist der Leistungsindikator?

Die Antwort hängt von einer Vielzahl von Faktoren ab. Weitere Informationen finden Sie unter Merkmale der Hardwareuhr auf niedriger Ebene.

Häufig gestellte Fragen zur Programmierung mit QPC und TSC

Hier finden Sie Antworten auf häufig gestellte Fragen zur Programmierung mit QPC und TSCs.

Ich muss die QPC-Ausgabe in Millisekunden konvertieren. Wie kann ich Genauigkeitseinbußen bei der Konvertierung in Double oder Float vermeiden?

Beim Ausführen von Berechnungen für ganzzahlige Leistungsindikatoren sind mehrere Punkte zu beachten:

  • Die ganzzahlige Division verliert den Rest. Dies kann in einigen Fällen zu Genauigkeitsverlusten führen.
  • Die Konvertierung zwischen ganzzahligen 64-Bit-Werten und Gleitkomma (double) kann zu Genauigkeitsverlusten führen, da die Gleitkomma-Mantisse nicht alle möglichen integralen Werte darstellen kann.
  • Die Multiplikation von 64-Bit-Ganzzahlen kann zu einem Ganzzahlüberlauf führen.

Grundsätzlich gilt, dass diese Berechnungen und Konvertierungen so lange wie möglich verzögert werden, um zu vermeiden, dass die aufgetretenen Fehler verschlimmert werden.

Wie kann ich QPC in 100 Nanosekunden-Ticks konvertieren, damit ich sie zu einer FILETIME hinzufügen kann?

Eine Dateizeit ist ein 64-Bit-Wert, der die Anzahl der Intervalle von 100 Nanosekunden darstellt, die seit dem 1. Januar 1601 koordinierte Weltzeit (UTC) um 12:00 Uhr verstrichen sind. Dateizeiten werden von Win32-API-Aufrufen verwendet, die Tageszeit zurückgeben, z. B . GetSystemTimeAsFileTime und GetSystemTimePreciseAsFileTime. Im Gegensatz dazu gibt QueryPerformanceCounter Werte zurück, die die Zeit in Einheiten von 1/(die Häufigkeit des Leistungsindikators aus QueryPerformanceFrequency) darstellen. Die Konvertierung zwischen den beiden erfordert die Berechnung des Verhältnisses des QPC-Intervalls und der Intervalle von 100 Nanosekunden. Achten Sie darauf, die Genauigkeit zu vermeiden, da die Werte klein sein können (0,0000001 / 0,000000340).

Warum ist der von QPC zurückgegebene Zeitstempel eine ganze Zahl mit Vorzeichen?

Berechnungen, die QPC-Zeitstempel enthalten, können eine Subtraktion beinhalten. Mithilfe eines signierten Werts können Sie Berechnungen verarbeiten, die negative Werte ergeben können.

Wie erhalte ich hochauflösende Zeitstempel aus verwaltetem Code?

Rufen Sie die Stopwatch.GetTimeStamp-Methode aus der System.Diagnostics.Stopwatch-Klasse auf. Ein Beispiel zur Verwendung von Stopwatch.GetTimeStamp finden Sie unter Abrufen von Zeitstempeln mit hoher Auflösung aus verwaltetem Code.

Unter welchen Umständen gibt QueryPerformanceFrequency FALSE oder QueryPerformanceCounter null zurück?

Dies tritt auf keinem System auf, auf dem Windows XP oder höher ausgeführt wird.

Muss ich die Threadaffinität auf einen einzelnen Kern festlegen, um QPC zu verwenden?

Nein. Weitere Informationen finden Sie unter Leitfaden zum Erfassen von Zeitstempeln. Dieses Szenario ist weder notwendig noch wünschenswert. Die Ausführung dieses Szenarios kann sich negativ auf die Leistung Ihrer Anwendung auswirken, indem Sie die Verarbeitung auf einen Kern beschränken oder einen Engpass auf einem einzelnen Kern erstellen, wenn mehrere Threads ihre Affinität beim Aufrufen von QueryPerformanceCounter auf denselben Kern festlegen.

Merkmale der Hardwareuhr auf niedriger Ebene

In diesen Abschnitten werden merkmale der Hardwareuhr auf niedriger Ebene dargestellt.

Absolute Uhren und Differenzuhren

Absolute Uhren bieten genaue Tageszeitmesswerte. Sie basieren in der Regel auf koordinierter Weltzeit (UTC), und daher hängt ihre Genauigkeit teilweise davon ab, wie gut sie mit einem externen Zeitbezug synchronisiert werden. Differenzuhren messen Zeitintervalle und basieren in der Regel nicht auf einer externen Zeitepoche. QPC ist eine Differenzuhr und wird nicht mit einer externen Zeitepoche oder einem externen Verweis synchronisiert. Wenn Sie QPC für Zeitintervallmessungen verwenden, erhalten Sie in der Regel eine bessere Genauigkeit als die Verwendung von Zeitstempeln, die von einer absoluten Uhr abgeleitet werden. Dies liegt daran, dass die Synchronisierung der Zeit einer absoluten Uhr Phasen- und Häufigkeitsverschiebungen einleiten kann, die die Unsicherheit von kurzfristigen Zeit-Intervallmessungen erhöhen.

Auflösung, Genauigkeit, Genauigkeit und Stabilität

QPC verwendet einen Hardwareindikator als Grundlage. Hardwaretimer bestehen aus drei Teilen: einem Tick-Generator, einem Zähler, der die Ticks zählt, und einem Mittel zum Abrufen des Zählerwerts. Die Eigenschaften dieser drei Komponenten bestimmen die Auflösung, Genauigkeit, Genauigkeit und Stabilität von QPC.

Wenn ein Hardwaregenerator Ticks mit konstanter Rate bereitstellt, können Zeitintervalle durch einfaches Zählen dieser Ticks gemessen werden. Die Rate, mit der die Ticks generiert werden, wird als Frequenz bezeichnet und in Hertz (Hz) ausgedrückt. Das Reziproz der Häufigkeit wird als Perioden- oder Tickintervall bezeichnet und wird in einer entsprechenden Zeiteinheit des Internationalen Einheitensystems (SI) ausgedrückt (z. B. Sekunde, Millisekunde, Mikrosekunde oder Nanosekunde).

Zeitintervall

Die Auflösung des Timers entspricht dem Punkt. Die Auflösung bestimmt die Fähigkeit, zwischen zwei beliebigen Zeitstempeln zu unterscheiden, und setzt eine Untergrenze auf die kleinsten Zeitintervalle, die gemessen werden können. Dies wird manchmal als Tickauflösung bezeichnet.

Die digitale Zeitmessung führt zu einer Messunsicherheit von ± 1 Tick, da der digitale Zähler in diskreten Schritten voranschreitet, während die Zeit kontinuierlich voranschreitet. Diese Unsicherheit wird als Quantisierungsfehler bezeichnet. Bei typischen Zeitintervallmessungen kann dieser Effekt häufig ignoriert werden, da der Quantisierungsfehler viel kleiner als das gemessene Zeitintervall ist.

digitale Zeitmessung

Wenn der gemessene Zeitraum jedoch klein ist und sich der Auflösung des Timers annähert, müssen Sie diesen Quantisierungsfehler berücksichtigen. Die Größe des aufgetretenen Fehlers ist die von einer Taktperiode.

Die folgenden beiden Diagramme veranschaulichen die Auswirkungen der ± 1 Tick Unsicherheit mithilfe eines Timers mit einer Auflösung von 1 Zeiteinheit.

Tick-Unsicherheit

QueryPerformanceFrequency gibt die Häufigkeit von QPC zurück, und der Zeitraum und die Auflösung sind gleich dem Kehrwert dieses Werts. Die Häufigkeit des Leistungsindikators, die QueryPerformanceFrequency zurückgibt, wird während der Systeminitialisierung bestimmt und ändert sich nicht, während das System ausgeführt wird.

Hinweis

Häufig gibt QueryPerformanceFrequency nicht die tatsächliche Häufigkeit des Hardware-Tick-Generators zurück. In einigen älteren Versionen von Windows gibt QueryPerformanceFrequency beispielsweise die TSC-Häufigkeit geteilt durch 1024 zurück. Und wenn sie unter einem Hypervisor ausgeführt wird, der die Hypervisor-Schnittstelle der Version 1.0 implementiert (oder immer in einigen neueren Versionen von Windows), wird die Leistungsindikatorhäufigkeit auf 10 MHz festgelegt. Gehen Sie daher nicht davon aus, dass QueryPerformanceFrequency einen Wert zurückgibt, der von der Hardwarehäufigkeit abgeleitet ist.

 

QueryPerformanceCounter liest den Leistungsindikator und gibt die Gesamtzahl der Ticks zurück, die seit dem Starten des Windows-Betriebssystems aufgetreten sind, einschließlich der Zeit, zu der sich der Computer in einem Ruhezustand befand, z. B. Standby, Ruhezustand oder verbundener Standbymodus.

In diesen Beispielen wird gezeigt, wie Sie das Tickintervall und die Auflösung berechnen und die Anzahl der Teilstriche in einen Zeitwert konvertieren.

Beispiel 1

QueryPerformanceFrequency gibt den Wert 3.125.000 auf einem bestimmten Computer zurück. Wie sieht das Tick-Intervall und die Auflösung von QPC-Messungen auf diesem Computer aus? Das Tick-Intervall oder der Zeitraum ist der Kehrwert von 3.125.000, d. h. 0,000000320 (320 Nanosekunden). Daher stellt jeder Tick die Übergabe von 320 Nanosekunden dar. Zeitintervalle, die kleiner als 320 Nanosekunden sind, können auf diesem Computer nicht gemessen werden.

Teilstrichintervall = 1/(Leistungshäufigkeit)

Teilstrichintervall = 1/3.125.000 = 320 ns

Beispiel 2

Auf demselben Computer wie im vorherigen Beispiel beträgt die Differenz der Von zwei aufeinander folgenden QPC-Aufrufen zurückgegebenen Werte 5. Wie viel Zeit ist zwischen den beiden Aufrufen verstrichen? 5 Ticks multipliziert mit 320 Nanosekunden ergeben 1,6 Mikrosekunden.

ElapsedTime = Ticks * Tick Interval

ElapsedTime = 5 * 320 ns = 1,6 μs

Der Zugriff (lese) des Tick-Zählers über die Software dauert lange, und diese Zugriffszeit kann die Genauigkeit der Zeitmessung verringern. Dies liegt daran, dass die minimale Intervallzeit (das kleinste Zeitintervall, das gemessen werden kann) die größere Der Auflösung und die Zugriffszeit ist.

Precision = MAX [ Resolution, AccessTime]

Betrachten Sie beispielsweise einen hypothetischen Hardwaretimer mit einer Auflösung von 100 Nanosekunden und einer Zugriffszeit von 800 Nanosekunden. Dies kann der Fall sein, wenn der Plattformtimer anstelle des TSC-Registers als Grundlage für QPC verwendet wurde. Die Genauigkeit würde also 800 Nanosekunden und nicht 100 Nanosekunden betragen, wie in dieser Berechnung gezeigt.

Genauigkeit = MAX [800 ns,100 ns] = 800 ns

Diese beiden Abbildungen veranschaulichen diesen Effekt.

qpc-Zugriffszeit

Wenn die Zugriffszeit größer als die Auflösung ist, versuchen Sie nicht, die Genauigkeit durch Raten zu verbessern. Anders ausgedrückt: Es ist ein Fehler, davon auszugehen, dass der Zeitstempel genau in der Mitte, am Anfang oder am Ende des Anrufs genommen wird.

Betrachten Sie dagegen das folgende Beispiel, in dem die QPC-Zugriffszeit nur 20 Nanosekunden und die Hardwareuhrauflösung 100 Nanosekunden beträgt. Dies kann der Fall sein, wenn das TSC-Register als Grundlage für QPC verwendet wurde. Hier wird die Genauigkeit durch die Taktauflösung begrenzt.

qpc-Genauigkeit

In der Praxis können Sie Zeitquellen finden, deren Zeit zum Lesen des Zählers größer oder kleiner als die Auflösung ist. In beiden Fällen ist die Genauigkeit die größere der beiden.

Diese Tabelle enthält Informationen über die ungefähre Auflösung, die Zugriffszeit und die Genauigkeit einer Vielzahl von Uhren. Beachten Sie, dass einige der Werte je nach Prozessoren, Hardwareplattformen und Prozessorgeschwindigkeit variieren.

Uhrquelle Nominale Taktfrequenz Uhrauflösung Zugriffszeit (typisch) Precision
PC RTC 64 Hz 15,625 Millisekunden
Abfrageleistungsindikator mit TSC mit einer Prozessortaktfrequenz von 3 GHz 3 MHz 333 Nanosekunden 30 Nanosekunden 333 Nanosekunden
RDTSC-Computeranweisung für ein System mit einer Zykluszeit von 3 GHz 3 GHz 333 Pikosekunden 30 Nanosekunden 30 Nanosekunden

 

Da QPC einen Hardwarezähler verwendet, erhalten Sie kenntnisse über die Funktionen und Einschränkungen von QPC, wenn Sie einige grundlegende Merkmale von Hardwareindikatoren kennen.

Der am häufigsten verwendete Hardware-Tick-Generator ist ein Kristalloszillator. Der Kristall ist ein kleines Stück Quarz oder ein anderes keramisches Material, das piezoelektrische Eigenschaften aufweist, die eine kostengünstige Frequenzreferenz mit ausgezeichneter Stabilität und Genauigkeit bieten. Diese Häufigkeit wird verwendet, um die von der Uhr gezählten Ticks zu generieren.

Die Genauigkeit eines Timers bezieht sich auf den Grad der Konformität mit einem true- oder Standardwert. Dies hängt in erster Linie von der Fähigkeit des Kristalloszillators ab, Ticks mit der angegebenen Frequenz bereitzustellen. Wenn die Frequenz der Oszillation zu hoch ist, wird die Uhr "schnell laufen", und die gemessenen Intervalle erscheinen länger als sie tatsächlich sind; Und wenn die Frequenz zu niedrig ist, wird die Uhr langsam ausgeführt, und die gemessenen Intervalle erscheinen kürzer als sie tatsächlich sind.

Bei typischen Zeitintervallmessungen für kurze Dauer (z. B. Antwortzeitmessungen, Netzwerklatenzmessungen usw.) ist die Genauigkeit des Hardwareoszillators in der Regel ausreichend. Bei einigen Messungen ist jedoch die Genauigkeit der Oszillatorfrequenz wichtig, insbesondere für lange Zeitintervalle oder wenn Sie Messungen auf verschiedenen Maschinen vergleichen möchten. Im weiteren Verlauf dieses Abschnitts werden die Auswirkungen der Oszillatorgenauigkeit untersucht.

Die Schwingungsfrequenz der Kristalle wird während des Herstellungsprozesses festgelegt und vom Hersteller in Form einer angegebenen Frequenz plus oder minus einer Fertigungstoleranz angegeben, die in "Parts per million" (ppm) ausgedrückt wird, der als maximaler Frequenzoffset bezeichnet wird. Ein Kristall mit einer angegebenen Frequenz von 1.000.000 Hz und einem maximalen Frequenzoffset von ± 10 ppm würde innerhalb der Spezifikationsgrenzen liegen, wenn seine tatsächliche Frequenz zwischen 999.990 Hz und 1.000.010 Hz liegt.

Indem wir die Ausdrucksteile pro Million durch Mikrosekunden pro Sekunde ersetzen, können wir diesen Frequenzoffsetfehler auf Zeitintervallmessungen anwenden. Ein Oszillator mit einem Offset von + 10 ppm hätte einen Fehler von 10 Mikrosekunden pro Sekunde. Dementsprechend würde bei der Messung eines Intervalls von 1 Sekunde schnell ausgeführt und ein Intervall von 1 Sekunde als 0,999990 Sekunden gemessen.

Ein praktischer Verweis ist, dass ein Frequenzfehler von 100 ppm nach 24 Stunden einen Fehler von 8,64 Sekunden verursacht. Diese Tabelle enthält die Messunsicherheit aufgrund des akkumulierten Fehlers für längere Zeitintervalle.

Dauer des Zeitintervalls Messunsicherheit durch akkumulierten Fehler mit +/- 10 PPM Frequenztoleranz
1 Mikrosekunde ± 10 Picosekunden (10-12)
Eine Millisekunde ± 10 Nanosekunden (10-9)
1 Sekunde ± 10 Mikrosekunden
1 Stunde ± 60 Mikrosekunden
1 Tag ± 0,86 Sekunden
1 Woche ± 6,08 Sekunden

 

Die obige Tabelle zeigt, dass für kleine Zeitintervalle der Häufigkeitsoffsetfehler häufig ignoriert werden kann. Bei langen Zeitintervallen kann jedoch schon ein kleiner Frequenzoffset zu einer erheblichen Messunsicherheit führen.

Kristalloszillatoren, die in PCs und Servern verwendet werden, werden in der Regel mit einer Frequenztoleranz von ± 30 bis 50 Teile pro Million hergestellt, und selten können Kristalle um bis zu 500 ppm abgeschaltet werden. Obwohl Kristalle mit viel engeren Frequenzoffsettoleranzen verfügbar sind, sind sie teurer und werden daher in den meisten Computern nicht verwendet.

Um die negativen Auswirkungen dieses Frequenzoffsetfehlers zu verringern, verwenden aktuelle Versionen von Windows, insbesondere Windows 8, mehrere Hardwaretimer, um den Frequenzoffset zu erkennen und so weit wie möglich zu kompensieren. Dieser Kalibrierungsvorgang wird ausgeführt, wenn Windows gestartet wird.

Wie die folgenden Beispiele zeigen, beeinflusst der Frequenzoffsetfehler einer Hardwareuhr die erreichbare Genauigkeit, und die Auflösung der Uhr kann weniger wichtig sein.

Frequenzoffsetfehler beeinflussen die erreichbare Genauigkeit

Beispiel 1

Angenommen, Sie führen Zeitintervallmessungen mithilfe eines 1 MHz-Oszillators durch, der eine Auflösung von 1 Mikrosekunde und einen maximalen Frequenzoffsetfehler von ±50 ppm aufweist. Nehmen wir nun an, der Offset ist genau +50 ppm. Dies bedeutet, dass die tatsächliche Frequenz 1.000.050 Hz betragen würde. Wenn wir ein Zeitintervall von 24 Stunden gemessen haben, wäre unsere Messung 4,3 Sekunden zu kurz (23:59:55,700000 gemessen gegenüber 24:00:00,000000 tatsächlich).

Sekunden an einem Tag = 86400

Frequenzoffsetfehler = 50 ppm = 0,00005

86.400 Sekunden * 0,00005 = 4,3 Sekunden

Beispiel 2

Angenommen, der Prozessor-TSC-Takt wird von einem Kristalloszillator gesteuert und weist eine angegebene Frequenz von 3 GHz auf. Dies bedeutet, dass die Auflösung 1/3.000.000.000 oder etwa 333 Pikosekunden sein würde. Angenommen, der Kristall, der zum Steuern der Prozessoruhr verwendet wird, weist eine Häufigkeitstoleranz von ±50 ppm auf und ist tatsächlich +50 ppm. Trotz der beeindruckenden Auflösung ist eine Zeitintervallmessung von 24 Stunden immer noch 4,3 Sekunden zu kurz. (23:59:55,700000000000000 gemessen gegenüber 24:00:00.0000000000 tatsächlich).

Sekunden an einem Tag = 86400

Frequenzoffsetfehler = 50 ppm = 0,00005

86.400 Sekunden * 0,00005 = 4,3 Sekunden

Dies zeigt, dass eine hochauflösende TSC-Uhr nicht unbedingt genauere Messungen liefert als eine Uhr mit niedrigerer Auflösung.

Beispiel 3

Erwägen Sie, zwei verschiedene Computer zu verwenden, um das gleiche 24-Stunden-Zeitintervall zu messen. Beide Computer verfügen über einen Oszillator mit einem maximalen Frequenzoffset von ± 50 ppm. Wie weit kann die Messung des gleichen Zeitintervalls auf diesen beiden Systemen liegen? Wie in den vorherigen Beispielen ergibt ± 50 ppm nach 24 Stunden einen maximalen Fehler von ± 4,3 Sekunden. Wenn ein System 4,3 Sekunden schnell und das andere 4,3 Sekunden langsam ausgeführt wird, kann der maximale Fehler nach 24 Stunden 8,6 Sekunden betragen.

Sekunden an einem Tag = 86400

Frequenzoffsetfehler = ±50 ppm = ±0.00005

±(86.400 Sekunden * 0,00005) = ±4,3 Sekunden

Maximaler Offset zwischen den beiden Systemen = 8,6 Sekunden

Zusammenfassend wird der Frequenzoffsetfehler bei der Messung langer Zeitintervalle und beim Vergleich von Messungen zwischen verschiedenen Systemen immer wichtiger.

Die Stabilität eines Timers beschreibt, ob sich die Tickhäufigkeit im Laufe der Zeit ändert, z. B. durch Temperaturänderungen. Quarzkristalle, die als Zeckengeneratoren auf Computern verwendet werden, zeigen kleine Änderungen der Häufigkeit als Funktion der Temperatur. Der durch thermische Drift verursachte Fehler ist in der Regel klein im Vergleich zum Frequenzoffsetfehler für allgemeine Temperaturbereiche. Entwickler von Software für tragbare Geräte oder Geräte, die großen Temperaturschwankungen ausgesetzt sind, müssen diesen Effekt jedoch möglicherweise berücksichtigen.

Hardware-Timerinformationen

TSC Register (x86 und x64)

Alle modernen Intel- und AMD-Prozessoren enthalten ein TSC-Register, bei dem es sich um ein 64-Bit-Register handelt, das mit einer hohen Rate erhöht wird, in der Regel gleich dem Prozessortakt. Der Wert dieses Indikators kann durch die RDTSC - oder RDTSCP-Computeranweisungen gelesen werden, wodurch je nach Prozessor sehr niedrige Zugriffszeit und Berechnungskosten in der Reihenfolge von zehn oder Hunderten von Computerzyklen bereitgestellt werden.

Obwohl das TSC-Register wie ein idealer Zeitstempelmechanismus erscheint, sind die folgenden Umstände aufgeführt, in denen es für Zeiterfassungszwecke nicht zuverlässig funktionieren kann:

  • Nicht alle Prozessoren verfügen über verwendbare TSC-Register, sodass die Verwendung des TSC-Registers in Software direkt zu einem Portabilitätsproblem führt. (Windows wählt in diesem Fall eine alternative Zeitquelle für QPC aus, wodurch das Portabilitätsproblem vermieden wird.)
  • Einige Prozessoren können die Häufigkeit der TSC-Uhr variieren oder die Weiterentwicklung des TSC-Registers beenden, was den TSC für Timingzwecke auf diesen Prozessoren ungeeignet macht. Diese Prozessoren sollen über nicht invariante TSC-Register verfügen. (Windows erkennt dies automatisch und wählt eine alternative Zeitquelle für QPC aus.)
  • Selbst wenn ein Virtualisierungshost über eine verwendbare TSC verfügt, kann die Livemigration ausgeführter virtueller Computer, wenn der Zielvirtualisierungshost keine hardwaregestützte TSC-Skalierung aufweist oder diese nutzt, zu einer Änderung der TSC-Häufigkeit führen, die für Gäste sichtbar ist. (Wenn diese Art der Livemigration für einen Gast möglich ist, wird erwartet, dass der Hypervisor das invariante TSC-Featurebit in der CPUID löscht.)
  • Auf Mehrprozessor- oder Mehrkernsystemen können einige Prozessoren und Systeme die Uhren für jeden Kern nicht mit demselben Wert synchronisieren. (Windows erkennt dies automatisch und wählt eine alternative Zeitquelle für QPC aus.)
  • Auf einigen großen Mehrprozessorsystemen können Sie die Prozessoruhren möglicherweise nicht mit demselben Wert synchronisieren, auch wenn der Prozessor über einen invarianten TSC verfügt. (Windows erkennt dies automatisch und wählt eine alternative Zeitquelle für QPC aus.)
  • Einige Prozessoren führen Anweisungen in der richtigen Reihenfolge aus. Dies kann zu falschen Zyklusanzahlen führen, wenn RDTSC zum Timen von Befehlssequenzen verwendet wird, da die RDTSC-Anweisung möglicherweise zu einem anderen Als in Ihrem Programm angegebenen Zeitpunkt ausgeführt wird. Die RDTSCP-Anweisung wurde auf einigen Prozessoren als Reaktion auf dieses Problem eingeführt.

Wie andere Timer basiert der TSC auf einem Kristalloszillator, dessen genaue Häufigkeit im Voraus nicht bekannt ist und der einen Frequenzoffsetfehler aufweist. Damit sie verwendet werden kann, muss sie mithilfe eines anderen Zeitbezugs kalibriert werden.

Während der Systeminitialisierung überprüft Windows, ob der TSC für Timingzwecke geeignet ist, und führt die erforderliche Häufigkeitskalibrierung und Kernsynchronisierung durch.

PM-Uhr (x86 und x64)

Der ACPI-Timer, auch bekannt als PM-Uhr, wurde der Systemarchitektur hinzugefügt, um zuverlässige Zeitstempel unabhängig von der Prozessorgeschwindigkeit bereitzustellen. Da dies das einzige Ziel dieses Timers war, stellt er einen Zeitstempel in einem einzelnen Taktzyklus bereit, bietet aber keine anderen Funktionen.

HPET Timer (x86 und x64)

Der High Precision Event Timer (HPET) wurde gemeinsam von Intel und Microsoft entwickelt, um die Zeitsteuerungsanforderungen von Multimedia- und anderen zeitsensiblen Anwendungen zu erfüllen. Im Gegensatz zum TSC, bei dem es sich um eine Pro-Prozessor-Ressource handelt, ist HPET eine freigegebene, plattformweite Ressource, obwohl ein System möglicherweise mehrere HPETs hat. Der HPET-Support ist seit Windows Vista verfügbar, und die Zertifizierung für Windows 7 und Windows 8 Hardwarelogo erfordert HPET-Unterstützung auf der Hardwareplattform.

Generischer Timersystemzähler (Arm)

Armbasierte Plattformen verfügen nicht über eine TSC-, HPET- oder PM-Uhr wie auf Intel- oder AMD-basierten Plattformen. Stattdessen stellen Arm-Prozessoren den generischen Timer (manchmal auch als generischer Intervalltimer oder GIT bezeichnet) bereit, der ein Systemzählerregister enthält (z. B. CNTVCT_EL0). Der generische Timersystemzähler ist eine plattformweite Zeitquelle mit fester Häufigkeit. Sie beginnt bei null beim Start und steigt mit hoher Geschwindigkeit. In Armv8.6 oder höher wird dies als genau 1 GHz definiert, sollte jedoch durch Lesen des Taktfrequenzregisters bestimmt werden, das durch die Firmware für den frühen Start festgelegt wird. Weitere Informationen finden Sie im Kapitel "Der generische Timer im AArch64-Zustand" in "Arm Architecture Reference Manual for A-profile architecture" (DDI 0487).

Zykluszähler (Arm)

Armbasierte Plattformen bieten ein Leistungsmonitor-Zykluszählerregister (z. B. PMCCNTR_EL0). Dieser Indikator zählt Prozessortaktzyklen. Es ist nicht invariant, und seine Einheiten sind möglicherweise nicht mit Echtzeit korreliert. Es wird nicht empfohlen, dieses Register zum Abrufen von Zeitstempeln zu verwenden.