PEP 418 – Hinzufügen von Funktionen für monotonische Zeit, Performance Counter und Prozesszeit
- Autor:
- Cameron Simpson <cs at cskk.id.au>, Jim J. Jewett <jimjjewett at gmail.com>, Stephen J. Turnbull <stephen at xemacs.org>, Victor Stinner <vstinner at python.org>
- Status:
- Final
- Typ:
- Standards Track
- Erstellt:
- 26. März 2012
- Python-Version:
- 3.3
Inhaltsverzeichnis
- Zusammenfassung
- Begründung
- Python-Funktionen
- Alternativen: API-Design
- Glossar
- Hardware-Uhren
- NTP-Anpassung
- Betriebssystem-Zeitfunktionen
- System-Standby
- Fußnoten
- Links
- Akzeptanz
- Referenzen
- Urheberrecht
Zusammenfassung
Dieser PEP schlägt die Hinzufügung der Funktionen time.get_clock_info(name), time.monotonic(), time.perf_counter() und time.process_time() zu Python 3.3 vor.
Begründung
Wenn ein Programm die Systemzeit zur Planung von Ereignissen oder zur Implementierung von Timeouts verwendet, kann es fehlschlagen, Ereignisse zum richtigen Zeitpunkt auszuführen oder den Timeout zu früh oder zu spät zu stoppen, wenn die Systemzeit manuell geändert oder automatisch von NTP angepasst wird. Eine monotone Uhr sollte stattdessen verwendet werden, um nicht von Systemzeitaktualisierungen betroffen zu sein: time.monotonic().
Um die Leistung einer Funktion zu messen, kann time.clock() verwendet werden, aber sie ist unter Windows und Unix sehr unterschiedlich. Unter Windows beinhaltet time.clock() die während des Schlafens verstrichene Zeit, während dies unter Unix nicht der Fall ist. Die Auflösung von time.clock() ist unter Windows sehr gut, unter Unix jedoch sehr schlecht. Die neue Funktion time.perf_counter() sollte stattdessen verwendet werden, um immer den präzisesten Performance Counter mit portablem Verhalten zu erhalten (z. B. Zeit im Schlafmodus einschließen).
Bis jetzt bot Python keine portable Funktion zur Messung der CPU-Zeit. time.clock() kann unter Unix verwendet werden, hat aber eine schlechte Auflösung. resource.getrusage() oder os.times() können auch unter Unix verwendet werden, erfordern jedoch die Summe der im Kernel- und Benutzerraum verbrachten Zeit. Die neue Funktion time.process_time() fungiert als portabler Zähler, der immer die CPU-Zeit misst (ohne die während des Schlafens verstrichene Zeit) und die bestmögliche Auflösung hat.
Jedes Betriebssystem implementiert Uhren und Performance Counter unterschiedlich, und es ist nützlich zu wissen, welche Funktion genau verwendet wird und welche Eigenschaften die Uhr hat, wie z. B. ihre Auflösung. Die neue Funktion time.get_clock_info() bietet Zugriff auf alle verfügbaren Informationen über jede Python-Zeitfunktion.
Neue Funktionen
time.monotonic(): Timeout und Planung, nicht betroffen von Systemzeitaktualisierungentime.perf_counter(): Benchmarking, präziseste Uhr für kurze Zeittime.process_time(): Profiling, CPU-Zeit des Prozesses
Benutzer neuer Funktionen
- time.monotonic(): concurrent.futures, multiprocessing, queue, subprocess, telnet und threading-Module zur Implementierung von Timeouts
- time.perf_counter(): trace und timeit-Module, pybench-Programm
- time.process_time(): profile-Modul
- time.get_clock_info(): pybench-Programm zur Anzeige von Informationen über den Timer, wie z. B. die Auflösung
Die Funktion time.clock() ist veraltet, da sie nicht portabel ist: Sie verhält sich je nach Betriebssystem unterschiedlich. time.perf_counter() oder time.process_time() sollten stattdessen verwendet werden, je nach Ihren Anforderungen. time.clock() ist als veraltet markiert, ist aber nicht zur Entfernung vorgesehen.
Einschränkungen
- Das Verhalten von Uhren nach einem System-Suspend wird in der Dokumentation der neuen Funktionen nicht definiert. Das Verhalten hängt vom Betriebssystem ab: siehe Abschnitt Monotone Uhren unten. Einige neuere Betriebssysteme stellen zwei Uhren bereit, eine, die die während des System-Suspend verbrachte Zeit einschließt, und eine, die diese Zeit nicht einschließt. Die meisten Betriebssysteme stellen nur eine Art von Uhr bereit.
- time.monotonic() und time.perf_counter() können angepasst werden oder auch nicht. Beispielsweise wird
CLOCK_MONOTONICunter Linux geslewt, währendGetTickCount()unter Windows nicht angepasst wird.time.get_clock_info('monotonic')['adjustable']kann verwendet werden, um zu überprüfen, ob die monotone Uhr verstellbar ist oder nicht. - Es wird keine time.thread_time()-Funktion von diesem PEP vorgeschlagen, da sie von der Python-Standardbibliothek nicht benötigt wird und keine häufig nachgefragte Funktion ist. Eine solche Funktion wäre nur unter Windows und Linux verfügbar. Unter Linux ist es möglich,
time.clock_gettime(CLOCK_THREAD_CPUTIME_ID)zu verwenden. Unter Windows können ctypes oder ein anderes Modul verwendet werden, um die FunktionGetThreadTimes()aufzurufen.
Python-Funktionen
Neue Funktionen
time.get_clock_info(name)
Holt Informationen über die angegebene Uhr. Unterstützte Uhrnamen
"clock":time.clock()"monotonic":time.monotonic()"perf_counter":time.perf_counter()"process_time":time.process_time()"time":time.time()
Gibt ein time.clock_info-Objekt zurück, das die folgenden Attribute hat
implementation(str): Name der zugrunde liegenden Betriebssystemfunktion. Beispiele:"QueryPerformanceCounter()","clock_gettime(CLOCK_REALTIME)".monotonic(bool): True, wenn die Uhr nicht zurücklaufen kann.adjustable(bool):True, wenn die Uhr automatisch (z. B. von einem NTP-Daemon) oder manuell vom Systemadministrator geändert werden kann,Falseandernfallsresolution(float): Auflösung in Sekunden der Uhr.
time.monotonic()
Monotone Uhr, d. h. sie kann nicht zurücklaufen. Sie wird von Systemzeitaktualisierungen nicht beeinflusst. Der Bezugspunkt des zurückgegebenen Wertes ist undefiniert, so dass nur die Differenz zwischen den Ergebnissen aufeinanderfolgender Aufrufe gültig ist und eine Anzahl von Sekunden darstellt.
Unter Windows-Versionen vor Vista erkennt time.monotonic() Überläufe des GetTickCount()-Integers (32 Bit, Überlauf nach 49,7 Tagen). Es erhöht eine interne Epoche (Referenzzeit) um 232, jedes Mal, wenn ein Überlauf erkannt wird. Die Epoche wird im prozesslokalen Zustand gespeichert, daher kann der Wert von time.monotonic() in zwei Python-Prozessen, die länger als 49 Tage laufen, unterschiedlich sein. Bei neueren Windows-Versionen und auf anderen Betriebssystemen ist time.monotonic() systemweit.
Verfügbarkeit: Windows, Mac OS X, Linux, FreeBSD, OpenBSD, Solaris. Nicht verfügbar auf GNU/Hurd.
Pseudocode [2]
if os.name == 'nt':
# GetTickCount64() requires Windows Vista, Server 2008 or later
if hasattr(_time, 'GetTickCount64'):
def monotonic():
return _time.GetTickCount64() * 1e-3
else:
def monotonic():
ticks = _time.GetTickCount()
if ticks < monotonic.last:
# Integer overflow detected
monotonic.delta += 2**32
monotonic.last = ticks
return (ticks + monotonic.delta) * 1e-3
monotonic.last = 0
monotonic.delta = 0
elif sys.platform == 'darwin':
def monotonic():
if monotonic.factor is None:
factor = _time.mach_timebase_info()
monotonic.factor = timebase[0] / timebase[1] * 1e-9
return _time.mach_absolute_time() * monotonic.factor
monotonic.factor = None
elif hasattr(time, "clock_gettime") and hasattr(time, "CLOCK_HIGHRES"):
def monotonic():
return time.clock_gettime(time.CLOCK_HIGHRES)
elif hasattr(time, "clock_gettime") and hasattr(time, "CLOCK_MONOTONIC"):
def monotonic():
return time.clock_gettime(time.CLOCK_MONOTONIC)
Unter Windows wird QueryPerformanceCounter() nicht verwendet, obwohl es eine bessere Auflösung als GetTickCount() hat. Es ist unzuverlässig und hat zu viele Probleme.
time.perf_counter()
Performance-Zähler mit der höchstmöglichen Auflösung zur Messung kurzer Dauern. Er schließt die während des Schlafens verstrichene Zeit ein und ist systemweit. Der Bezugspunkt des zurückgegebenen Wertes ist undefiniert, sodass nur die Differenz zwischen den Ergebnissen aufeinanderfolgender Aufrufe gültig ist und eine Anzahl von Sekunden darstellt.
Er ist auf allen Plattformen verfügbar.
Pseudocode
if os.name == 'nt':
def _win_perf_counter():
if _win_perf_counter.frequency is None:
_win_perf_counter.frequency = _time.QueryPerformanceFrequency()
return _time.QueryPerformanceCounter() / _win_perf_counter.frequency
_win_perf_counter.frequency = None
def perf_counter():
if perf_counter.use_performance_counter:
try:
return _win_perf_counter()
except OSError:
# QueryPerformanceFrequency() fails if the installed
# hardware does not support a high-resolution performance
# counter
perf_counter.use_performance_counter = False
if perf_counter.use_monotonic:
# The monotonic clock is preferred over the system time
try:
return time.monotonic()
except OSError:
perf_counter.use_monotonic = False
return time.time()
perf_counter.use_performance_counter = (os.name == 'nt')
perf_counter.use_monotonic = hasattr(time, 'monotonic')
time.process_time()
Summe der System- und Benutzer-CPU-Zeit des aktuellen Prozesses. Sie schließt die während des Schlafens verstrichene Zeit nicht ein. Sie ist per Definition prozessweit. Der Bezugspunkt des zurückgegebenen Wertes ist undefiniert, sodass nur die Differenz zwischen den Ergebnissen aufeinanderfolgender Aufrufe gültig ist.
Er ist auf allen Plattformen verfügbar.
Pseudocode [2]
if os.name == 'nt':
def process_time():
handle = _time.GetCurrentProcess()
process_times = _time.GetProcessTimes(handle)
return (process_times['UserTime'] + process_times['KernelTime']) * 1e-7
else:
try:
import resource
except ImportError:
has_resource = False
else:
has_resource = True
def process_time():
if process_time.clock_id is not None:
try:
return time.clock_gettime(process_time.clock_id)
except OSError:
process_time.clock_id = None
if process_time.use_getrusage:
try:
usage = resource.getrusage(resource.RUSAGE_SELF)
return usage[0] + usage[1]
except OSError:
process_time.use_getrusage = False
if process_time.use_times:
try:
times = _time.times()
cpu_time = times.tms_utime + times.tms_stime
return cpu_time / process_time.ticks_per_seconds
except OSError:
process_time.use_getrusage = False
return _time.clock()
if (hasattr(time, 'clock_gettime')
and hasattr(time, 'CLOCK_PROF')):
process_time.clock_id = time.CLOCK_PROF
elif (hasattr(time, 'clock_gettime')
and hasattr(time, 'CLOCK_PROCESS_CPUTIME_ID')):
process_time.clock_id = time.CLOCK_PROCESS_CPUTIME_ID
else:
process_time.clock_id = None
process_time.use_getrusage = has_resource
process_time.use_times = hasattr(_time, 'times')
if process_time.use_times:
# sysconf("SC_CLK_TCK"), or the HZ constant, or 60
process_time.ticks_per_seconds = _times.ticks_per_seconds
Bestehende Funktionen
time.time()
Die Systemzeit, die normalerweise die bürgerliche Zeit ist. Sie ist per Definition systemweit. Sie kann manuell vom Systemadministrator oder automatisch von einem NTP-Daemon eingestellt werden.
Sie ist auf allen Plattformen verfügbar und kann nicht fehlschlagen.
Pseudocode [2]
if os.name == "nt":
def time():
return _time.GetSystemTimeAsFileTime()
else:
def time():
if hasattr(time, "clock_gettime"):
try:
return time.clock_gettime(time.CLOCK_REALTIME)
except OSError:
# CLOCK_REALTIME is not supported (unlikely)
pass
if hasattr(_time, "gettimeofday"):
try:
return _time.gettimeofday()
except OSError:
# gettimeofday() should not fail
pass
if hasattr(_time, "ftime"):
return _time.ftime()
else:
return _time.time()
time.sleep()
Setzt die Ausführung für die angegebene Anzahl von Sekunden aus. Die tatsächliche Aussetzungszeit kann kürzer sein als die angeforderte, da jedes aufgefangene Signal time.sleep() nach der Ausführung der Routine zum Abfangen dieses Signals beendet. Außerdem kann die Aussetzungszeit aufgrund der Planung anderer Aktivitäten im System beliebig länger als angefordert sein.
Pseudocode [2]
try:
import select
except ImportError:
has_select = False
else:
has_select = hasattr(select, "select")
if has_select:
def sleep(seconds):
return select.select([], [], [], seconds)
elif hasattr(_time, "delay"):
def sleep(seconds):
milliseconds = int(seconds * 1000)
_time.delay(milliseconds)
elif os.name == "nt":
def sleep(seconds):
milliseconds = int(seconds * 1000)
win32api.ResetEvent(hInterruptEvent);
win32api.WaitForSingleObject(sleep.sigint_event, milliseconds)
sleep.sigint_event = win32api.CreateEvent(NULL, TRUE, FALSE, FALSE)
# SetEvent(sleep.sigint_event) will be called by the signal handler of SIGINT
elif os.name == "os2":
def sleep(seconds):
milliseconds = int(seconds * 1000)
DosSleep(milliseconds)
else:
def sleep(seconds):
seconds = int(seconds)
_time.sleep(seconds)
Veraltete Funktion
time.clock()
Unter Unix gibt die aktuelle Prozessorzeit als Gleitkommazahl in Sekunden zurück. Sie ist per Definition prozessweit. Die Auflösung und die genaue Bedeutung von „Prozessorzeit“ hängen von der C-Funktion mit demselben Namen ab, aber in jedem Fall ist dies die Funktion, die für das Benchmarking von Python oder die Zeitmessung von Algorithmen verwendet werden sollte.
Unter Windows gibt diese Funktion die Wandzeit in Sekunden zurück, die seit dem ersten Aufruf dieser Funktion verstrichen ist, als Gleitkommazahl, basierend auf der Win32-Funktion QueryPerformanceCounter(). Die Auflösung ist typischerweise besser als eine Mikrosekunde. Sie ist systemweit.
Pseudocode [2]
if os.name == 'nt':
def clock():
try:
return _win_perf_counter()
except OSError:
# QueryPerformanceFrequency() fails if the installed
# hardware does not support a high-resolution performance
# counter
pass
return _time.clock()
else:
clock = _time.clock
Alternativen: API-Design
Andere Namen für time.monotonic()
- time.counter()
- time.metronomic()
- time.seconds()
- time.steady(): „steady“ ist mehrdeutig: Es bedeutet für verschiedene Personen unterschiedliche Dinge. Zum Beispiel wird unter Linux CLOCK_MONOTONIC angepasst. Wenn wir die Echtzeit als Referenzuhr verwenden, könnten wir sagen, dass CLOCK_MONOTONIC steady ist. Aber CLOCK_MONOTONIC wird bei System-Suspend ausgesetzt, während die Echtzeit jegliche Zeit im Suspend einschließt.
- time.timeout_clock()
- time.wallclock(): time.monotonic() ist nicht die Systemzeit, auch bekannt als „Wall Clock“, sondern eine monotone Uhr mit einem nicht spezifizierten Startpunkt.
Der Name „time.try_monotonic()“ wurde auch für eine ältere Version von time.monotonic() vorgeschlagen, die auf die Systemzeit zurückfiel, wenn keine monotone Uhr verfügbar war.
Andere Namen für time.perf_counter()
- time.high_precision()
- time.highres()
- time.hires()
- time.performance_counter()
- time.timer()
Nur Betriebssystem-Uhren freigeben
Um keine High-Level-Uhren definieren zu müssen, was eine schwierige Aufgabe ist, ist ein einfacherer Ansatz, nur Betriebssystem-Uhren freizugeben. time.clock_gettime() und verwandte Uhrenbezeichner wurden bereits zu Python 3.3 hinzugefügt, z. B.
time.monotonic(): Fallback auf Systemzeit
Wenn keine monotone Uhr verfügbar ist, fällt time.monotonic() auf die Systemzeit zurück.
Probleme
- Es ist schwierig, eine solche Funktion korrekt in der Dokumentation zu definieren: Ist sie monoton? Ist sie steady? Ist sie angepasst?
- Einige Benutzer möchten entscheiden, was zu tun ist, wenn keine monotone Uhr verfügbar ist: eine andere Uhr verwenden, einen Fehler anzeigen oder etwas anderes tun.
Verschiedene APIs wurden vorgeschlagen, um eine solche Funktion zu definieren.
Eine Funktion mit einem Flag: time.monotonic(fallback=True)
- time.monotonic(fallback=True) fällt auf die Systemzeit zurück, wenn keine monotone Uhr verfügbar ist oder wenn die monotone Uhr fehlschlägt.
- time.monotonic(fallback=False) löst OSError aus, wenn die monotone Uhr fehlschlägt, und NotImplementedError, wenn das System keine monotone Uhr bereitstellt
Ein Keyword-Argument, das als Konstante im Aufrufer übergeben wird, ist normalerweise eine schlechte API.
Das Auslösen von NotImplementedError für eine Funktion ist in Python ungewöhnlich und sollte vermieden werden.
Eine time.monotonic()-Funktion, kein Flag
time.monotonic() gibt (time: float, is_monotonic: bool) zurück.
Eine Alternative ist die Verwendung eines Funktionsattributs: time.monotonic.is_monotonic. Der Attributwert wäre None vor dem ersten Aufruf von time.monotonic().
Auswahl der Uhr anhand einer Liste von Kriterien
Der als PEP vorgeschlagene Ansatz bietet einige neue Uhren, aber ihre Garantien sind bewusst lose, um nützliche Uhren auf verschiedenen Plattformen anzubieten. Dies bettet absichtlich Richtlinien in die Aufrufe ein, und der Aufrufer muss daher eine Richtlinie wählen.
Der Ansatz „Uhr auswählen“ schlägt eine zusätzliche API vor, damit Aufrufer bei Bedarf ihre eigenen Richtlinien implementieren können, indem die meisten Plattformuhren verfügbar gemacht werden und der Aufrufer unter ihnen wählen kann. Die von der PEP vorgeschlagenen Uhren werden weiterhin für die gängigen einfachen Anwendungsfälle verfügbar sein.
Dazu werden zwei Einrichtungen benötigt: eine Aufzählung von Uhren und Metadaten über die Uhren, damit der Benutzer ihre Eignung bewerten kann.
Die primäre Schnittstelle ist eine Funktion, die einfache Entscheidungen ermöglicht: Der Aufrufer kann time.get_clock(*flags) mit einer beliebigen Kombination von Flags verwenden. Dies beinhaltet mindestens
- time.MONOTONIC: Uhr kann nicht zurücklaufen
- time.STEADY: Uhrrate ist konstant
- time.ADJUSTED: Uhr kann angepasst werden, z. B. von NTP
- time.HIGHRES: Uhr mit höchster Auflösung
Sie gibt ein Uhr-Objekt mit einer .now()-Methode zurück, die die aktuelle Zeit liefert. Das Uhr-Objekt ist mit Metadaten annotiert, die den Uhr-Funktionssatz beschreiben; sein .flags-Feld enthält mindestens alle angeforderten Flags.
time.get_clock() gibt None zurück, wenn keine passende Uhr gefunden wird. Aufrufe können also mit dem Oder-Operator verkettet werden. Beispiel für eine einfache Richtlinienentscheidung
T = get_clock(MONOTONIC) or get_clock(STEADY) or get_clock()
t = T.now()
Die verfügbaren Uhren beinhalten immer mindestens einen Wrapper für time.time(), sodass ein letzter Aufruf ohne Flags immer verwendet werden kann, um eine funktionierende Uhr zu erhalten.
Beispiele für Flags von Systemuhren
- QueryPerformanceCounter: MONOTONIC | HIGHRES
- GetTickCount: MONOTONIC | STEADY
- CLOCK_MONOTONIC: MONOTONIC | STEADY (oder nur MONOTONIC unter Linux)
- CLOCK_MONOTONIC_RAW: MONOTONIC | STEADY
- gettimeofday(): (kein Flag)
Die Uhr-Objekte enthalten weitere Metadaten, einschließlich der Uhr-Flags mit zusätzlichen Funktions-Flags über die oben genannten hinaus, den Namen der zugrunde liegenden Betriebssystemfunktion und die Uhr-Präzision.
time.get_clock() wählt immer noch eine einzelne Uhr aus; eine Enumerationsmöglichkeit ist ebenfalls erforderlich. Die offensichtlichste Methode ist, time.get_clocks() mit derselben Signatur wie time.get_clock() anzubieten, aber eine Sequenz aller Uhren zurückzugeben, die den angeforderten Flags entsprechen. Das Anfordern keiner Flags würde somit alle verfügbaren Uhren auflisten, was dem Aufrufer ermöglicht, eine beliebige Wahl unter ihnen basierend auf ihren Metadaten zu treffen.
Beispiel für eine teilweise Implementierung: clockutils.py.
Umgehen von Betriebssystemfehlern?
Sollte Python sicherstellen, dass eine monotone Uhr wirklich monoton ist, indem das Maximum mit dem Uhrwert und dem vorherigen Wert berechnet wird?
Da es relativ einfach ist, den letzten zurückgegebenen Wert mithilfe einer statischen Variablen zu cachen, könnte es interessant sein, dies zu verwenden, um sicherzustellen, dass die zurückgegebenen Werte tatsächlich monoton sind.
- Virtuelle Maschinen bieten weniger zuverlässige Uhren.
- QueryPerformanceCounter() hat bekannte Fehler (nur einer ist noch nicht behoben)
Python kann nur einen bestimmten bekannten Betriebssystemfehler umgehen: KB274323 enthält ein Codebeispiel zur Umgehung des Fehlers (Verwendung von GetTickCount(), um den QueryPerformanceCounter()-Sprung zu erkennen).
Probleme mit dem „Korrigieren“ von Nicht-Monotonien
- Wenn die Uhr versehentlich um eine Stunde vorgestellt und dann wieder zurückgestellt wird, hätte man eine Stunde lang keine nützliche Uhr
- Der Cache wird nicht zwischen Prozessen geteilt, sodass verschiedene Prozesse nicht denselben Uhrwert sehen würden
Glossar
- Genauigkeit:
- Das Ausmaß der Abweichung von Messungen eines bestimmten Instruments von den wahren Werten. Siehe auch Genauigkeit und Präzision. Ungenauigkeiten bei Uhren können durch mangelnde Präzision, Drift oder eine falsche Anfangseinstellung der Uhr verursacht werden (z. B. ist die Zeitmessung von Threads inhärent ungenau, da eine perfekte Synchronisation beim Zurücksetzen von Zählern sehr schwierig ist).
- Angepasst:
- Zurücksetzen einer Uhr auf die richtige Zeit. Dies kann entweder mit einem <Schritt> oder durch <Slewing> erfolgen.
- Bürgerliche Zeit:
- Tageszeit; extern zum System. 10:45:13 Uhr ist eine bürgerliche Zeit; 45 Sekunden nicht. Bereitgestellt durch die vorhandene Funktion
time.localtime()undtime.gmtime(). Wird von diesem PEP nicht geändert. - Uhr:
- Ein Instrument zur Messung der Zeit. Verschiedene Uhren haben unterschiedliche Eigenschaften; zum Beispiel kann eine Uhr mit Nanosekunden-<Präzision> nach einigen Minuten zu <driften> beginnen, während eine weniger präzise Uhr tagelang genau blieb. Dieser PEP befasst sich hauptsächlich mit Uhren, die die Einheit Sekunden verwenden.
- Zähler:
- Eine Uhr, die jedes Mal inkrementiert, wenn ein bestimmtes Ereignis eintritt. Ein Zähler ist streng monoton, aber keine monotone Uhr. Er kann verwendet werden, um einen eindeutigen (und geordneten) Zeitstempel zu generieren, aber diese Zeitstempel können nicht auf <bürgerliche Zeit> abgebildet werden; die Tick-Erstellung kann sprunghaft sein, mit mehreren Fortschritten in derselben Millisekunde, gefolgt von mehreren Tagen ohne Fortschritt.
- CPU-Zeit:
- Eine Messung, wie viel CPU-Aufwand für eine bestimmte Aufgabe aufgewendet wurde. CPU-Sekunden werden oft normalisiert (sodass in derselben tatsächlichen Sekunde eine variable Anzahl auftreten kann). CPU-Sekunden können beim Profiling wichtig sein, sie sind jedoch nicht direkt mit der Benutzerreaktionszeit vergleichbar und auch nicht direkt mit (Echtzeit-)Sekunden vergleichbar.
- Drift:
- Der angesammelte Fehler gegenüber der „wahren“ Zeit, wie sie extern zum System definiert ist. Drift kann durch mangelnde Präzision oder durch eine Differenz zwischen der durchschnittlichen Rate, mit der die Uhrzeit voranschreitet, und der Echtzeit verursacht werden.
- Epoche:
- Der Bezugspunkt einer Uhr. Für Uhren, die <bürgerliche Zeit> liefern, ist dies oft Mitternacht am Tag (und Jahr), als der 1. Januar 1970 begann. Für eine <clock_monotonic>-Uhr kann die Epoche undefiniert sein (als None dargestellt).
- Latenz:
- Verzögerung. Bis ein Uhraufruf zurückkehrt, ist die <Echtzeit> fortgeschritten, möglicherweise um mehr als die Präzision der Uhr.
- Monoton:
- Die Eigenschaften, die in der Praxis von einer monotonen Uhr erwartet werden. Bewegt sich in höchstens einer Richtung; für Uhren ist diese Richtung vorwärts. Die <Uhr> sollte auch <steady> sein und in eine Sekundeneinheit umwandelbar sein. Die Kompromisse beinhalten oft das Fehlen einer definierten <Epoche> oder die Abbildung auf <bürgerliche Zeit>.
- Präzision:
- Das Ausmaß der Abweichung von Messungen desselben physikalischen Wertes durch ein einzelnes Instrument. Ungenauigkeiten bei Uhren können durch Schwankungen der Rate verursacht werden, mit der die Uhrzeit relativ zur Echtzeit voranschreitet, einschließlich der Anpassung der Uhr durch Slewing.
- Prozesszeit:
- Zeit, die seit Beginn des Prozesses verstrichen ist. Sie wird typischerweise in <CPU-Zeit> und nicht in <Echtzeit> gemessen und schreitet typischerweise nicht fort, während der Prozess ausgesetzt ist.
- Echtzeit:
- Zeit in der realen Welt. Sie unterscheidet sich von der <bürgerlichen Zeit>, da sie nicht <angepasst> ist, aber ansonsten im Gleichschritt voranschreiten sollte. Sie steht nicht im Zusammenhang mit der „Echtzeit“ von „Echtzeit-[Betriebs-]Systemen“. Sie wird manchmal als „Wall Clock Time“ bezeichnet, um diese Mehrdeutigkeit zu vermeiden; leider führt dies zu verschiedenen Mehrdeutigkeiten.
- Resolution:
- Der kleinste Unterschied zwischen zwei physikalischen Werten, der zu einer anderen Messung durch ein gegebenes Instrument führt.
- Slew:
- Eine leichte Änderung der Geschwindigkeit einer Uhr, die normalerweise dazu dient, <Drift> gegenüber einer externen Autorität zu korrigieren.
- Stabilität:
- Persistenz der Genauigkeit. Ein Maß für den erwarteten <Drift>.
- Steady:
- Eine Uhr mit hoher <Stabilität> und relativ hoher <Genauigkeit> und <Präzision>. In der Praxis wird sie oft verwendet, um eine <clock_monotonic>-Uhr anzuzeigen, legt aber größeren Wert auf die Konsistenz der Dauer zwischen aufeinanderfolgenden Ticks.
- Schritt:
- Eine augenblickliche Änderung der dargestellten Zeit. Anstatt die Uhr zu beschleunigen oder zu verlangsamen (<Slew>), wird ein einziger Offset dauerhaft hinzugefügt.
- Systemzeit:
- Zeit, wie sie vom Betriebssystem dargestellt wird.
- Thread-Zeit:
- Zeit, die seit Beginn des Threads verstrichen ist. Sie wird typischerweise in <CPU-Zeit> und nicht in <Echtzeit> gemessen und schreitet typischerweise nicht fort, während der Thread untätig ist.
- Wallclock:
- Was die Wanduhr anzeigt. Dies wird typischerweise als Synonym für <Echtzeit> verwendet; leider ist die Wanduhrzeit selbst mehrdeutig.
Hardware-Uhren
Liste der Hardware-Uhren
- HPET: Ein High Precision Event Timer (HPET) Chip besteht aus einem 64-Bit-Hochzähler (Hauptzähler), der mit mindestens 10 MHz zählt, und einer Reihe von bis zu 256 Komparatoren (mindestens 3). Jedes HPET kann bis zu 32 Timer haben. HPET kann etwa 3 Sekunden Drift pro Tag verursachen.
- TSC (Time Stamp Counter): Historisch gesehen erhöhte sich der TSC bei jedem internen Prozessor-Taktzyklus, aber jetzt ist die Rate normalerweise konstant (auch wenn der Prozessor die Frequenz ändert) und entspricht normalerweise der maximalen Prozessor-Frequenz. Mehrere Kerne haben unterschiedliche TSC-Werte. Die Ruhezustandsfunktion des Systems setzt den TSC-Wert zurück. Die RDTSC-Instruktion kann verwendet werden, um diesen Zähler zu lesen. CPU-Frequenzskalierung zur Energieeinsparung.
- ACPI Power Management Timer: ACPI 24-Bit-Timer mit einer Frequenz von 3,5 MHz (3.579.545 Hz).
- Cyclone: Der Cyclone-Timer verwendet einen 32-Bit-Zähler auf IBM Extended X-Architecture (EXA) Chipsätzen, die Computer mit IBM „Summit“-Chipsätzen (z. B. x440) umfassen. Dies ist in IA32- und IA64-Architekturen verfügbar.
- PIT (programmierbarer Interrupt-Timer): Intel 8253/8254 Chipsätze mit einer konfigurierbaren Frequenz im Bereich von 18,2 Hz bis 1,2 MHz. Er verwendet einen 16-Bit-Zähler.
- RTC (Echtzeituhr). Die meisten RTCs verwenden einen Quarzoszillator mit einer Frequenz von 32.768 Hz.
Linux clocksource
Es gab 4 Implementierungen der Zeit im Linux-Kernel: UTIME (1996), Timer-Rad (1997), HRT (2001) und hrtimers (2007). Letzteres ist das Ergebnis des „high-res-timers“-Projekts, das 2001 von George Anzinger initiiert wurde, mit Beiträgen von Thomas Gleixner und Douglas Niehaus. Die hrtimers-Implementierung wurde in Linux 2.6.21 integriert, veröffentlicht im Jahr 2007.
hrtimers unterstützt verschiedene Taktquellen. Es weist jeder Quelle eine Priorität zu, um zu entscheiden, welche verwendet wird. Linux unterstützt die folgenden Taktquellen
- tsc
- hpet
- pit
- pmtmr: ACPI Power Management Timer
- cyclone
Hochauflösende Timer werden nicht auf allen Hardware-Architekturen unterstützt. Sie werden mindestens auf x86/x86_64, ARM und PowerPC bereitgestellt.
clock_getres() gibt 1 Nanosekunde für CLOCK_REALTIME und CLOCK_MONOTONIC zurück, unabhängig von der zugrunde liegenden Taktquelle. Lesen Sie Re: clock_getres() and real resolution von Thomas Gleixner (9. Februar 2012) für eine Erklärung.
Das Verzeichnis /sys/devices/system/clocksource/clocksource0 enthält zwei nützliche Dateien
available_clocksource: Liste der verfügbaren Taktquellencurrent_clocksource: aktuell verwendete Taktquelle. Es ist möglich, die aktuelle Taktquelle zu ändern, indem der Name einer Taktquelle in diese Datei geschrieben wird.
/proc/timer_list enthält die Liste aller Hardware-Timer.
Lesen Sie auch die time(7) Manual Page: „Übersicht über Zeit und Timer“.
FreeBSD timecounter
kern.timecounter.choice listet verfügbare Hardware-Uhren mit ihrer Priorität auf. Das sysctl-Programm kann verwendet werden, um den timecounter zu ändern. Beispiel
# dmesg | grep Timecounter
Timecounter "i8254" frequency 1193182 Hz quality 0
Timecounter "ACPI-safe" frequency 3579545 Hz quality 850
Timecounter "HPET" frequency 100000000 Hz quality 900
Timecounter "TSC" frequency 3411154800 Hz quality 800
Timecounters tick every 10.000 msec
# sysctl kern.timecounter.choice
kern.timecounter.choice: TSC(800) HPET(900) ACPI-safe(850) i8254(0) dummy(-1000000)
# sysctl kern.timecounter.hardware="ACPI-fast"
kern.timecounter.hardware: HPET -> ACPI-fast
Verfügbare Uhren
- „TSC“: Time Stamp Counter des Prozessors
- „HPET“: High Precision Event Timer
- „ACPI-fast“: ACPI Power Management Timer (Fast-Modus)
- „ACPI-safe“: ACPI Power Management Timer (Sicherer Modus)
- „i8254“: PIT mit Intel 8254 Chipsatz
Der Commit 222222 (Mai 2011) hat die Qualität des ACPI-Fast-Timecounters auf 900 und die des HPET-Timecounters auf 950 reduziert: „HPET auf modernen Plattformen hat normalerweise eine bessere Auflösung und geringere Latenz als ACPI-Timer“.
Lesen Sie Timecounters: Efficient and precise timekeeping in SMP kernels von Poul-Henning Kamp (2002) für das FreeBSD-Projekt.
Performance
Das Lesen einer Hardware-Uhr hat Kosten. Die folgende Tabelle vergleicht die Leistung verschiedener Hardware-Uhren unter Linux 3.3 mit Intel Core i7-2600 bei 3,40 GHz (8 Kerne). Das Programm bench_time.c wurde verwendet, um diese Tabellen zu füllen.
| Funktion | TSC | ACPI PM | HPET |
|---|---|---|---|
| time() | 2 ns | 2 ns | 2 ns |
| CLOCK_REALTIME_COARSE | 10 ns | 10 ns | 10 ns |
| CLOCK_MONOTONIC_COARSE | 12 ns | 13 ns | 12 ns |
| CLOCK_THREAD_CPUTIME_ID | 134 ns | 135 ns | 135 ns |
| CLOCK_PROCESS_CPUTIME_ID | 127 ns | 129 ns | 129 ns |
| clock() | 146 ns | 146 ns | 143 ns |
| gettimeofday() | 23 ns | 726 ns | 637 ns |
| CLOCK_MONOTONIC_RAW | 31 ns | 716 ns | 607 ns |
| CLOCK_REALTIME | 27 ns | 707 ns | 629 ns |
| CLOCK_MONOTONIC | 27 ns | 723 ns | 635 ns |
FreeBSD 8.0 in KVM mit Hardware-Virtualisierung
| Funktion | TSC | ACPI-Safe | HPET | i8254 |
|---|---|---|---|---|
| time() | 191 ns | 188 ns | 189 ns | 188 ns |
| CLOCK_SECOND | 187 ns | 184 ns | 187 ns | 183 ns |
| CLOCK_REALTIME_FAST | 189 ns | 180 ns | 187 ns | 190 ns |
| CLOCK_UPTIME_FAST | 191 ns | 185 ns | 186 ns | 196 ns |
| CLOCK_MONOTONIC_FAST | 188 ns | 187 ns | 188 ns | 189 ns |
| CLOCK_THREAD_CPUTIME_ID | 208 ns | 206 ns | 207 ns | 220 ns |
| CLOCK_VIRTUAL | 280 ns | 279 ns | 283 ns | 296 ns |
| CLOCK_PROF | 289 ns | 280 ns | 282 ns | 286 ns |
| clock() | 342 ns | 340 ns | 337 ns | 344 ns |
| CLOCK_UPTIME_PRECISE | 197 ns | 10380 ns | 4402 ns | 4097 ns |
| CLOCK_REALTIME | 196 ns | 10376 ns | 4337 ns | 4054 ns |
| CLOCK_MONOTONIC_PRECISE | 198 ns | 10493 ns | 4413 ns | 3958 ns |
| CLOCK_UPTIME | 197 ns | 10523 ns | 4458 ns | 4058 ns |
| gettimeofday() | 202 ns | 10524 ns | 4186 ns | 3962 ns |
| CLOCK_REALTIME_PRECISE | 197 ns | 10599 ns | 4394 ns | 4060 ns |
| CLOCK_MONOTONIC | 201 ns | 10766 ns | 4498 ns | 3943 ns |
Jede Funktion wurde 100.000 Mal aufgerufen und CLOCK_MONOTONIC wurde verwendet, um die Zeit vor und nach dem Aufruf zu ermitteln. Das Benchmark wurde 5 Mal ausgeführt, wobei die minimale Zeit beibehalten wurde.
NTP-Anpassung
NTP hat verschiedene Methoden zur Anpassung einer Uhr
- „Slewing“: Ändern der Uhrenfrequenz auf etwas schneller oder langsamer (was mit
adjtime()erfolgt). Da die Slew-Rate auf 0,5 Millisekunden pro Sekunde begrenzt ist, erfordert jede Sekunde der Anpassung ein Amortisationsintervall von 2000 Sekunden. Somit kann eine Anpassung von vielen Sekunden Stunden oder Tage dauern, um amortisiert zu werden. - „Stepping“: Sprung um einen großen Betrag in einem einzigen diskreten Schritt (was mit
settimeofday()erfolgt)
Standardmäßig wird die Zeit geslewt, wenn der Offset weniger als 128 ms beträgt, andernfalls wird sie gestuft.
Slewing ist im Allgemeinen wünschenswert (d. h. wir sollten CLOCK_MONOTONIC verwenden, nicht CLOCK_MONOTONIC_RAW), wenn man „reale“ Zeit messen möchte (und nicht ein zeitähnliches Objekt wie CPU-Zyklen). Das liegt daran, dass die Uhr auf der anderen Seite der NTP-Verbindung wahrscheinlich besser die Zeit hält: Hoffentlich bewirkt die vierunddreißigtausend Dollar teure Cesium-Zeitmessgüte etwas Besseres als der 3-Dollar-Quarzkristall Ihres PCs, schließlich.
Weitere Details finden Sie in der Dokumentation des NTP-Daemons.
Betriebssystem-Zeitfunktionen
Monotone Uhren
| Name | C-Auflösung | Angepasst | Schlaf einschließen | Suspendierung einschließen |
|---|---|---|---|---|
| gethrtime() | 1 ns | Nein | Ja | Ja |
| CLOCK_HIGHRES | 1 ns | Nein | Ja | Ja |
| CLOCK_MONOTONIC | 1 ns | Geslewt unter Linux | Ja | Nein |
| CLOCK_MONOTONIC_COARSE | 1 ns | Geslewt unter Linux | Ja | Nein |
| CLOCK_MONOTONIC_RAW | 1 ns | Nein | Ja | Nein |
| CLOCK_BOOTTIME | 1 ns | ? | Ja | Ja |
| CLOCK_UPTIME | 1 ns | Nein | Ja | ? |
| mach_absolute_time() | 1 ns | Nein | Ja | Nein |
| QueryPerformanceCounter() | - | Nein | Ja | ? |
| GetTickCount[64]() | 1 ms | Nein | Ja | Ja |
| timeGetTime() | 1 ms | Nein | Ja | ? |
Die Spalte „C Resolution“ gibt die Auflösung der zugrunde liegenden C-Struktur an.
Beispiele für die Auflösung von Uhren auf x86_64
| Name | Betriebssystem | OS-Auflösung | Python-Auflösung |
|---|---|---|---|
| QueryPerformanceCounter | Windows Seven | 10 ns | 10 ns |
| CLOCK_HIGHRES | SunOS 5.11 | 2 ns | 265 ns |
| CLOCK_MONOTONIC | Linux 3.0 | 1 ns | 322 ns |
| CLOCK_MONOTONIC_RAW | Linux 3.3 | 1 ns | 628 ns |
| CLOCK_BOOTTIME | Linux 3.3 | 1 ns | 628 ns |
| mach_absolute_time() | Mac OS 10.6 | 1 ns | 3 µs |
| CLOCK_MONOTONIC | FreeBSD 8.2 | 11 ns | 5 µs |
| CLOCK_MONOTONIC | OpenBSD 5.0 | 10 ms | 5 µs |
| CLOCK_UPTIME | FreeBSD 8.2 | 11 ns | 6 µs |
| CLOCK_MONOTONIC_COARSE | Linux 3.3 | 1 ms | 1 ms |
| CLOCK_MONOTONIC_COARSE | Linux 3.0 | 4 ms | 4 ms |
| GetTickCount64() | Windows Seven | 16 ms | 15 ms |
Die „OS Resolution“ ist die vom Betriebssystem angezeigte Auflösung. Die „Python Resolution“ ist die kleinste Differenz zwischen zwei Aufrufen der Zeitfunktion, berechnet in Python mit dem Programm clock_resolution.py.
mach_absolute_time
Mac OS X bietet eine monotone Uhr: mach_absolute_time(). Sie basiert auf der absoluten verstrichenen Zeit seit dem Systemstart. Sie wird nicht angepasst und kann nicht eingestellt werden.
mach_timebase_info() gibt einen Bruch zur Umrechnung des Zählerwerts in Nanosekunden zurück. Siehe auch das Technical Q&A QA1398.
mach_absolute_time() stoppt während eines Ruhezustands auf einer PowerPC-CPU, aber nicht auf einer Intel-CPU: Different behaviour of mach_absolute_time() on i386/ppc.
CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_BOOTTIME
CLOCK_MONOTONIC und CLOCK_MONOTONIC_RAW stellen eine monotone Zeit seit einem nicht spezifizierten Ausgangspunkt dar. Sie können nicht gesetzt werden. Die Auflösung kann mit clock_getres() gelesen werden.
Dokumentation: siehe die Handbuchseite Ihres Betriebssystems. Beispiele
CLOCK_MONOTONIC ist mindestens auf den folgenden Betriebssystemen verfügbar
- DragonFly BSD, FreeBSD >= 5.0, OpenBSD, NetBSD
- Linux
- Solaris
Die folgenden Betriebssysteme unterstützen CLOCK_MONOTONIC nicht
- GNU/Hurd (siehe offene Probleme/ clock_gettime)
- Mac OS X
- Windows
Unter Linux kann NTP die Rate von CLOCK_MONOTONIC anpassen (slewed), aber sie kann nicht rückwärts springen.
CLOCK_MONOTONIC_RAW ist spezifisch für Linux. Es ist ähnlich wie CLOCK_MONOTONIC, bietet aber Zugriff auf eine rohe, hardwarebasierte Zeit, die keinen NTP-Anpassungen unterliegt. CLOCK_MONOTONIC_RAW erfordert Linux 2.6.28 oder neuer.
Linux 2.6.39 und glibc 2.14 führen eine neue Uhr ein: CLOCK_BOOTTIME. CLOCK_BOOTTIME ist identisch mit CLOCK_MONOTONIC, mit der Ausnahme, dass sie auch die Zeit einschließt, die im Ruhezustand verbracht wurde. Lesen Sie auch Waking systems from suspend (März 2011).
CLOCK_MONOTONIC stoppt, während der Computer im Ruhezustand ist.
Linux bietet seit Linux 2.6.32 auch CLOCK_MONOTONIC_COARSE. Es ist ähnlich wie CLOCK_MONOTONIC, weniger präzise, aber schneller.
clock_gettime() schlägt fehl, wenn das System die angegebene Uhr nicht unterstützt, auch wenn die Standard-C-Bibliothek sie unterstützt. Zum Beispiel erfordert CLOCK_MONOTONIC_RAW eine Kernelversion 2.6.28 oder neuer.
Windows: QueryPerformanceCounter
Hochauflösender Performance-Zähler. Er ist monoton. Die Frequenz des Zählers kann mit QueryPerformanceFrequency() gelesen werden. Die Auflösung ist 1 / QueryPerformanceFrequency().
Er hat eine viel höhere Auflösung, aber eine geringere Langzeitpräzision als die Uhren von GetTickCount() und timeGetTime(). Zum Beispiel wird er im Vergleich zu den Uhren mit geringer Präzision abweichen.
Dokumentation
Hardware-Uhren, die von QueryPerformanceCounter verwendet werden
- Windows XP: RDTSC-Instruktion von Intel-Prozessoren, die Taktfrequenz ist die Frequenz des Prozessors (zwischen 200 MHz und 3 GHz, heutzutage meist größer als 1 GHz).
- Windows 2000: ACPI-Stromverwaltungs-Timer, Frequenz = 3.549.545 Hz. Er kann über das Flag "/usepmtimer" in boot.ini erzwungen werden.
QueryPerformanceFrequency() sollte nur einmal aufgerufen werden: die Frequenz ändert sich nicht, während das System läuft. Er schlägt fehl, wenn die installierte Hardware keinen hochauflösenden Performance-Zähler unterstützt.
QueryPerformanceCounter() kann nicht angepasst werden: SetSystemTimeAdjustment() passt nur die Systemzeit an.
Fehler
- Der Wert des Performance-Zählers kann aufgrund eines Hardwarefehlers unerwartet vorwärtssprungen. Siehe KB274323.
- Auf VirtualBox inkrementiert QueryPerformanceCounter() den oberen Teil nicht jedes Mal, wenn der untere Teil überläuft. Siehe Monotonic timers (2009).
- VirtualBox hatte einen Fehler in seinem HPET-virtualisierten Gerät: QueryPerformanceCounter() sprang um ca. 42 Sekunden vorwärts (Issue #8707).
- Windows XP hatte einen Fehler (siehe KB896256): auf einem Mehrprozessorcomputer gab QueryPerformanceCounter() für jeden Prozessor einen anderen Wert zurück. Der Fehler wurde in Windows XP SP2 behoben.
- Probleme mit Prozessoren mit variabler Frequenz: Die Frequenz wird je nach Arbeitslast geändert, um den Speicherverbrauch zu reduzieren.
- Chromium verwendet QueryPerformanceCounter() nicht auf Athlon X2 CPUs (Modell 15), da "QueryPerformanceCounter unzuverlässig ist" (siehe base/time_win.cc im Chromium-Quellcode)
Windows: GetTickCount(), GetTickCount64()
GetTickCount() und GetTickCount64() sind monoton, können nicht fehlschlagen und werden nicht von SetSystemTimeAdjustment() angepasst. MSDN-Dokumentation: GetTickCount(), GetTickCount64(). Die Auflösung kann mit GetSystemTimeAdjustment() gelesen werden.
Die von GetTickCount() oder GetTickCount64() abgerufene verstrichene Zeit schließt die Zeit ein, die das System im Ruhezustand oder Ruhezustand verbringt.
GetTickCount64() wurde zu Windows Vista und Windows Server 2008 hinzugefügt.
Es ist möglich, die Präzision mit der undokumentierten Funktion NtSetTimerResolution() zu verbessern. Es gibt Anwendungen, die diese undokumentierte Funktion verwenden, Beispiel: Timer Resolution.
WaitForSingleObject() verwendet denselben Timer wie GetTickCount() mit derselben Präzision.
Windows: timeGetTime
Die Funktion timeGetTime() ruft die Systemzeit in Millisekunden ab. Die Systemzeit ist die seit dem Start von Windows verstrichene Zeit. Lesen Sie die timeGetTime() Dokumentation.
Der Rückgabetyp von timeGetTime() ist eine 32-Bit-Ganzzahl ohne Vorzeichen. Wie GetTickCount() rollt timeGetTime() nach 2^32 Millisekunden (49,7 Tage) über.
Die von timeGetTime() abgerufene verstrichene Zeit schließt die Zeit ein, die das System im Ruhezustand verbringt.
Die Standardpräzision der Funktion timeGetTime() kann fünf Millisekunden oder mehr betragen, je nach Computer.
timeBeginPeriod() kann verwendet werden, um die Präzision von timeGetTime() auf bis zu 1 Millisekunde zu erhöhen, dies wirkt sich jedoch negativ auf den Stromverbrauch aus. Das Aufrufen von timeBeginPeriod() beeinflusst auch die Granularität einiger anderer Zeitaufrufe, wie z. B. CreateWaitableTimer(), WaitForSingleObject() und Sleep().
Hinweis
timeGetTime() und timeBeginPeriod() sind Teil der Windows-Multimedia-Bibliothek und erfordern daher die Verlinkung des Programms gegen winmm oder das dynamische Laden der Bibliothek.
Solaris: CLOCK_HIGHRES
Das Solaris-Betriebssystem verfügt über eine CLOCK_HIGHRES-Uhr, die versucht, eine optimale Hardwarequelle zu verwenden, und möglicherweise eine Auflösung nahe der Nanosekunde liefert. CLOCK_HIGHRES ist die nicht einstellbare, hochauflösende Uhr. Für mit einem clockid_t-Wert von CLOCK_HIGHRES erstellte Timer versucht das System, eine optimale Hardwarequelle zu verwenden.
Die Auflösung von CLOCK_HIGHRES kann mit clock_getres() gelesen werden.
Solaris: gethrtime
Die Funktion gethrtime() gibt die aktuelle hochauflösende Echtzeit zurück. Die Zeit wird in Nanosekunden seit einer beliebigen Zeit in der Vergangenheit ausgedrückt; sie steht in keiner Korrelation zur Tageszeit und unterliegt daher keiner Zurücksetzung oder Abweichung durch adjtime() oder settimeofday(). Die HiRes-Uhr ist ideal für Leistungsmessungsaufgaben geeignet, bei denen eine kostengünstige, genaue Intervallzeitmessung erforderlich ist.
Die Linearität von gethrtime() wird über einen Suspend-Resume-Zyklus nicht beibehalten (Bug 4272663).
Lesen Sie die Handbuchseite gethrtime() von Solaris 11.
Auf Solaris ist gethrtime() dasselbe wie clock_gettime(CLOCK_MONOTONIC).
Systemzeit
| Name | C-Auflösung | Schlaf einschließen | Suspendierung einschließen |
|---|---|---|---|
| CLOCK_REALTIME | 1 ns | Ja | Ja |
| CLOCK_REALTIME_COARSE | 1 ns | Ja | Ja |
| GetSystemTimeAsFileTime | 100 ns | Ja | Ja |
| gettimeofday() | 1 µs | Ja | Ja |
| ftime() | 1 ms | Ja | Ja |
| time() | 1 Sek. | Ja | Ja |
Die Spalte „C Resolution“ gibt die Auflösung der zugrunde liegenden C-Struktur an.
Beispiele für die Auflösung von Uhren auf x86_64
| Name | Betriebssystem | OS-Auflösung | Python-Auflösung |
|---|---|---|---|
| CLOCK_REALTIME | SunOS 5.11 | 10 ms | 238 ns |
| CLOCK_REALTIME | Linux 3.0 | 1 ns | 238 ns |
| gettimeofday() | Mac OS 10.6 | 1 µs | 4 µs |
| CLOCK_REALTIME | FreeBSD 8.2 | 11 ns | 6 µs |
| CLOCK_REALTIME | OpenBSD 5.0 | 10 ms | 5 µs |
| CLOCK_REALTIME_COARSE | Linux 3.3 | 1 ms | 1 ms |
| CLOCK_REALTIME_COARSE | Linux 3.0 | 4 ms | 4 ms |
| GetSystemTimeAsFileTime() | Windows Seven | 16 ms | 1 ms |
| ftime() | Windows Seven | - | 1 ms |
Die „OS Resolution“ ist die vom Betriebssystem angezeigte Auflösung. Die „Python Resolution“ ist die kleinste Differenz zwischen zwei Aufrufen der Zeitfunktion, berechnet in Python mit dem Programm clock_resolution.py.
Windows: GetSystemTimeAsFileTime
Die Systemzeit kann mit GetSystemTimeAsFileTime(), ftime() und time() gelesen werden. Die Auflösung der Systemzeit kann mit GetSystemTimeAdjustment() gelesen werden.
Lesen Sie die GetSystemTimeAsFileTime() Dokumentation.
Die Systemzeit kann mit SetSystemTime() gesetzt werden.
Systemzeit unter UNIX
gettimeofday(), ftime(), time() und clock_gettime(CLOCK_REALTIME) geben die Systemzeit zurück. Die Auflösung von CLOCK_REALTIME kann mit clock_getres() gelesen werden.
Die Systemzeit kann mit settimeofday() oder clock_settime(CLOCK_REALTIME) gesetzt werden.
Linux bietet seit Linux 2.6.32 auch CLOCK_REALTIME_COARSE. Es ist ähnlich wie CLOCK_REALTIME, weniger präzise, aber schneller.
Alexander Shishkin schlug eine API für Linux vor, um benachrichtigt zu werden, wenn die Systemzeit geändert wird: timerfd: add TFD_NOTIFY_CLOCK_SET to watch for clock changes (4. Version der API, März 2011). Die API wurde noch nicht akzeptiert, aber CLOCK_BOOTTIME bietet eine ähnliche Funktion.
Prozesszeit
Die Prozesszeit kann nicht gesetzt werden. Sie ist nicht monoton: die Uhren stoppen, während der Prozess im Leerlauf ist.
| Name | C-Auflösung | Schlaf einschließen | Suspendierung einschließen |
|---|---|---|---|
| GetProcessTimes() | 100 ns | Nein | Nein |
| CLOCK_PROCESS_CPUTIME_ID | 1 ns | Nein | Nein |
| getrusage(RUSAGE_SELF) | 1 µs | Nein | Nein |
| times() | - | Nein | Nein |
| clock() | - | Ja unter Windows, Nein sonst | Nein |
Die Spalte „C Resolution“ gibt die Auflösung der zugrunde liegenden C-Struktur an.
Beispiele für die Auflösung von Uhren auf x86_64
| Name | Betriebssystem | OS-Auflösung | Python-Auflösung |
|---|---|---|---|
| CLOCK_PROCESS_CPUTIME_ID | Linux 3.3 | 1 ns | 1 ns |
| CLOCK_PROF | FreeBSD 8.2 | 10 ms | 1 µs |
| getrusage(RUSAGE_SELF) | FreeBSD 8.2 | - | 1 µs |
| getrusage(RUSAGE_SELF) | SunOS 5.11 | - | 1 µs |
| CLOCK_PROCESS_CPUTIME_ID | Linux 3.0 | 1 ns | 1 µs |
| getrusage(RUSAGE_SELF) | Mac OS 10.6 | - | 5 µs |
| clock() | Mac OS 10.6 | 1 µs | 5 µs |
| CLOCK_PROF | OpenBSD 5.0 | - | 5 µs |
| getrusage(RUSAGE_SELF) | Linux 3.0 | - | 4 ms |
| getrusage(RUSAGE_SELF) | OpenBSD 5.0 | - | 8 ms |
| clock() | FreeBSD 8.2 | 8 ms | 8 ms |
| clock() | Linux 3.0 | 1 µs | 10 ms |
| times() | Linux 3.0 | 10 ms | 10 ms |
| clock() | OpenBSD 5.0 | 10 ms | 10 ms |
| times() | OpenBSD 5.0 | 10 ms | 10 ms |
| times() | Mac OS 10.6 | 10 ms | 10 ms |
| clock() | SunOS 5.11 | 1 µs | 10 ms |
| times() | SunOS 5.11 | 1 µs | 10 ms |
| GetProcessTimes() | Windows Seven | 16 ms | 16 ms |
| clock() | Windows Seven | 1 ms | 1 ms |
Die „OS Resolution“ ist die vom Betriebssystem angezeigte Auflösung. Die „Python Resolution“ ist die kleinste Differenz zwischen zwei Aufrufen der Zeitfunktion, berechnet in Python mit dem Programm clock_resolution.py.
Funktionen
- Windows: GetProcessTimes(). Die Auflösung kann mit GetSystemTimeAdjustment() gelesen werden.
- clock_gettime(CLOCK_PROCESS_CPUTIME_ID): Hochauflösende Pro-Prozess-Uhr der CPU. Die Auflösung kann mit clock_getres() gelesen werden.
- clock(). Die Auflösung ist 1 / CLOCKS_PER_SEC.
- Windows: Die seit Beginn des Prozesses verstrichene Wanduhrzeit (verstrichene Zeit in Sekunden mal CLOCKS_PER_SEC). Beinhaltet die während des Ruhezustands verstrichene Zeit. Kann fehlschlagen.
- UNIX: Gibt eine Annäherung an die vom Programm verwendete Prozessorzeit zurück.
- getrusage(RUSAGE_SELF) gibt eine Struktur der Ressourcennutzung des aktuellen Prozesses zurück. ru_utime ist Benutzer-CPU-Zeit und ru_stime ist System-CPU-Zeit.
- times(): Struktur der Prozesszeiten. Die Auflösung ist 1 / ticks_per_seconds, wobei ticks_per_seconds sysconf(_SC_CLK_TCK) oder die Konstante HZ ist.
Der Python-Quellcode enthält eine portable Bibliothek, um die Prozesszeit (CPU-Zeit) zu erhalten (Tools/pybench/systimes.py).
Siehe auch die QueryProcessCycleTime() Funktion (Summe der Taktzyklen aller Threads) und clock_getcpuclockid().
Thread-Zeit
Die Thread-Zeit kann nicht gesetzt werden. Sie ist nicht monoton: die Uhren stoppen, während der Thread im Leerlauf ist.
| Name | C-Auflösung | Schlaf einschließen | Suspendierung einschließen |
|---|---|---|---|
| CLOCK_THREAD_CPUTIME_ID | 1 ns | Ja | Epochenwechsel |
| GetThreadTimes() | 100 ns | Nein | ? |
Die Spalte „C Resolution“ gibt die Auflösung der zugrunde liegenden C-Struktur an.
Beispiele für die Auflösung von Uhren auf x86_64
| Name | Betriebssystem | OS-Auflösung | Python-Auflösung |
|---|---|---|---|
| CLOCK_THREAD_CPUTIME_ID | FreeBSD 8.2 | 1 µs | 1 µs |
| CLOCK_THREAD_CPUTIME_ID | Linux 3.3 | 1 ns | 649 ns |
| GetThreadTimes() | Windows Seven | 16 ms | 16 ms |
Die „OS Resolution“ ist die vom Betriebssystem angezeigte Auflösung. Die „Python Resolution“ ist die kleinste Differenz zwischen zwei Aufrufen der Zeitfunktion, berechnet in Python mit dem Programm clock_resolution.py.
Funktionen
- Windows: GetThreadTimes(). Die Auflösung kann mit GetSystemTimeAdjustment() gelesen werden.
- clock_gettime(CLOCK_THREAD_CPUTIME_ID): Threadspezifische CPU-Zeit-Uhr. Sie verwendet eine Anzahl von CPU-Zyklen, nicht eine Anzahl von Sekunden. Die Auflösung kann mit clock_getres() gelesen werden.
Siehe auch die QueryThreadCycleTime() Funktion (Taktzyklus für den angegebenen Thread) und pthread_getcpuclockid().
Windows: QueryUnbiasedInterruptTime
Ermittelt die aktuelle unverzerrte Interruptzeit aus der verzerrten Interruptzeit und der aktuellen Schlafverzerrungsmenge. Diese Zeit wird nicht von Schlafübergängen des Energiemanagements beeinflusst.
Die von der Funktion QueryUnbiasedInterruptTime abgerufene verstrichene Zeit schließt nur die Zeit ein, die das System im Arbeitszustand verbringt. QueryUnbiasedInterruptTime() ist nicht monoton.
QueryUnbiasedInterruptTime() wurde in Windows 7 eingeführt.
Siehe auch QueryIdleProcessorCycleTime() Funktion (Taktzyklus für den Idle-Thread jedes Prozessors)
Schlafmodus
Setzt die Ausführung des Prozesses für die angegebene Anzahl von Sekunden aus. Sleep wird nicht von Systemzeitaktualisierungen beeinflusst. Sleep wird während des Systemruhezustands angehalten. Wenn ein Prozess beispielsweise 60 Sekunden schläft und das System während des Schlafs für 30 Sekunden angehalten wird, beträgt die Schlafdauer in Echtzeit 90 Sekunden.
Sleep kann durch ein Signal unterbrochen werden: die Funktion schlägt mit EINTR fehl.
| Name | C-Auflösung |
|---|---|
| nanosleep() | 1 ns |
| clock_nanosleep() | 1 ns |
| usleep() | 1 µs |
| delay() | 1 µs |
| sleep() | 1 Sek. |
Andere Funktionen
| Name | C-Auflösung |
|---|---|
| sigtimedwait() | 1 ns |
| pthread_cond_timedwait() | 1 ns |
| sem_timedwait() | 1 ns |
| select() | 1 µs |
| epoll() | 1 ms |
| poll() | 1 ms |
| WaitForSingleObject() | 1 ms |
Die Spalte „C Resolution“ gibt die Auflösung der zugrunde liegenden C-Struktur an.
Funktionen
- sleep(Sekunden)
- usleep(Mikrosekunden)
- nanosleep(Nanosekunden, verbleibend): Linux-Manpage von nanosleep()
- delay(Millisekunden)
clock_nanosleep
clock_nanosleep(clock_id, flags, nanoseconds, remaining): Linux-Manpage von clock_nanosleep().
Wenn flags TIMER_ABSTIME ist, wird die Anfrage als absolute Zeit interpretiert, gemessen von der Uhr clock_id. Wenn die Anfrage kleiner oder gleich dem aktuellen Wert der Uhr ist, gibt clock_nanosleep() sofort zurück, ohne den aufrufenden Thread zu suspendieren.
POSIX.1 besagt, dass das Ändern des Wertes der CLOCK_REALTIME-Uhr über clock_settime(2) keine Auswirkungen auf einen Thread hat, der auf einer relativen clock_nanosleep() blockiert ist.
select()
select(nfds, readfds, writefds, exceptfs, timeout).
Seit Linux 2.6.28 verwendet select() hochauflösende Timer zur Behandlung des Timeouts. Ein Prozess hat ein "slack"-Attribut zur Konfiguration der Präzision des Timeouts, das Standard-Slack beträgt 50 Mikrosekunden. Vor Linux 2.6.28 wurden Timeouts für select() vom Hauptzeitgebersystem mit einer Auflösung im Jiffy-Level behandelt. Lesen Sie auch High- (aber nicht zu hoch-) resolution timeouts und Timer slack.
Andere Funktionen
- poll(), epoll()
- sigtimedwait(). POSIX: "Wenn die Monotonic Clock Option unterstützt wird, soll die CLOCK_MONOTONIC Uhr verwendet werden, um das Zeitintervall zu messen, das durch das Timeout-Argument angegeben ist."
- pthread_cond_timedwait(), pthread_condattr_setclock(). "Der Standardwert des Uhrenattributs bezieht sich auf die Systemzeit."
- sem_timedwait(): "Wenn die Timers Option unterstützt wird, basiert das Timeout auf der CLOCK_REALTIME Uhr. Wenn die Timers Option nicht unterstützt wird, basiert das Timeout auf der Systemzeit, wie sie von der time()-Funktion zurückgegeben wird. Die Präzision des Timeouts ist die Präzision der Uhr, auf der es basiert."
- WaitForSingleObject(): verwendet denselben Timer wie GetTickCount() mit derselben Präzision.
System-Standby
Der ACPI-Stromsparmodus "S3" ist ein System-Standby-Modus, auch "Suspend to RAM" genannt. Der RAM bleibt mit Strom versorgt.
Unter Windows wird die WM_POWERBROADCAST Nachricht an Windows-Anwendungen gesendet, um sie über Energieverwaltungsereignisse zu informieren (z. B. der Besitzerstatus hat sich geändert).
Für Mac OS X lesen Sie Registrieren und Abmelden für Sleep- und Wake-Benachrichtigungen (Technical Q&A QA1340).
Fußnoten
Links
Zugehörige Python-Themen
- Issue #12822: NewGIL sollte CLOCK_MONOTONIC verwenden, wenn möglich.
- Issue #14222: time.steady() zur Implementierung von Timeouts verwenden
- Issue #14309: time.clock() veraltet machen
- Issue #14397: GetTickCount/GetTickCount64 anstelle von QueryPerformanceCounter für monotone Uhr verwenden
- Issue #14428: Implementierung von PEP 418
- Issue #14555: clock_gettime/settime/getres: Mehr Uhr-Identifikatoren hinzufügen
Bibliotheken, die monotone Uhren bereitstellen
- Java: System.nanoTime
- Qt-Bibliothek: QElapsedTimer
- glib-Bibliothek: g_get_monotonic_time() verwendet GetTickCount64()/GetTickCount() unter Windows, clock_gettime(CLOCK_MONOTONIC) unter UNIX oder greift auf die Systemuhr zurück
- python-monotonic-time (github)
- Monoclock.nano_count() verwendet clock_gettime(CLOCK_MONOTONIC) und gibt eine Anzahl von Nanosekunden zurück
- monotonic_clock von Thomas Habets
- Perl: Time::HiRes stellt clock_gettime(CLOCK_MONOTONIC) bereit
- Ruby: AbsoluteTime.now: verwendet clock_gettime(CLOCK_MONOTONIC), mach_absolute_time() oder gettimeofday(). Die Methode "AbsoluteTime.monotonic?" gibt an, ob AbsoluteTime.now monoton ist oder nicht.
- libpthread: POSIX-Thread-Bibliothek für Windows (clock.c)
- Boost.Chrono verwendet
- system_clock
- mac = gettimeofday()
- posix = clock_gettime(CLOCK_REALTIME)
- win = GetSystemTimeAsFileTime()
- steady_clock
- mac = mach_absolute_time()
- posix = clock_gettime(CLOCK_MONOTONIC)
- win = QueryPerformanceCounter()
- high_resolution_clock
- steady_clock, wenn verfügbar system_clock, sonst
- system_clock
Zeit
- Twisted Issue #2424: Füge eine Reactor-Option hinzu, um mit einer monotonen Uhr zu starten
- gettimeofday() sollte niemals zur Zeitmessung verwendet werden von Thomas Habets (2010-09-05)
- hrtimers – Subsystem für Kernel-Timer mit hoher Auflösung
- C++ Timeout Specification von Lawrence Crowl (2010-08-19)
- Windows: Game Timing and Multicore Processors von Chuck Walbourn (Dezember 2005)
- Implement a Continuously Updating, High-Resolution Time Provider for Windows von Johan Nilsson (März 2004)
- clockspeed verwendet einen Hardware-Tick-Zähler, um eine anhaltend schnelle oder langsame Systemzeit zu kompensieren, von D. J. Bernstein (1998)
- Retrieving system time listet Hardware-Uhren und Zeitfunktionen mit ihrer Auflösung und Epoche oder Reichweite auf
- Unter Windows interpoliert die JavaScript-Laufzeitumgebung von Firefox GetSystemTimeAsFileTime() mit QueryPerformanceCounter(), um eine höhere Auflösung zu erzielen. Siehe Bug 363258 - schlechte Millisekundenauflösung für (new Date).getTime() / Date.now() unter Windows.
- When microseconds matter: How the IBM High Resolution Time Stamp Facility accurately measures itty bits of time, von W. Nathaniel Mills, III (Apr 2002)
- Win32 Performance Measurement Options von Matthew Wilson (Mai 2003)
- Counter Availability and Characteristics for Feed-forward Based Synchronization von Timothy Broomhead, Julien Ridoux, Darryl Veitch (2009)
- Probleme mit System Management Interrupt (SMI)
- System Management Interrupt Free Hardware von Keith Mannthey (2009)
- IBM Real-Time “SMI Free” Mode Driver von Keith Mannthey (Feb 2009)
- Behebung von Echtzeitproblemen, die durch SMI unter Ubuntu verursacht werden
- [RFC] Simple SMI Detector von Jon Masters (Jan 2009)
- [PATCH 2.6.34-rc3] A nonintrusive SMI sniffer for x86 von Joe Korty (2010-04)
Akzeptanz
Das PEP wurde am 2012-04-28 von Guido van Rossum akzeptiert [1]. Die PEP-Implementierung wurde seitdem in das Repository übernommen.
Referenzen
Urheberrecht
Dieses Dokument wurde gemeinfrei erklärt.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0418.rst
Zuletzt geändert: 2025-02-01 08:55:40 GMT