clock_gettime Alternative unter Mac OS X.

68

Beim Kompilieren eines Programms, das ich unter Mac OS X geschrieben habe, nachdem ich die erforderlichen Bibliotheken über MacPorts installiert habe, wird folgende Fehlermeldung angezeigt:

Es scheint, dass dies clock_gettimenicht in Mac OS X implementiert ist. Gibt es ein alternatives Mittel, um die Epochenzeit in Nanosekunden zu ermitteln ? Ist leider gettimeofdayin Mikrosekunden .

Delan Azabani
quelle
1
In meiner Dokumentation heißt es: "Alle Implementierungen unterstützen die systemweite Echtzeituhr, die durch CLOCK_REALTIME identifiziert wird." Hast du #include <time.h>?
PMG
4
Das hat nicht geholfen. clock_gettimeist nicht in Mac OS X implementiert.
Delan Azabani
6
Ich weiß. Es befindet sich in meiner Linker-Befehlszeile. Ich komme überhaupt nicht zur Verbindungsphase. Mac OS X hat nicht clock_gettime, während Linux tut.
Delan Azabani
2
Ich habe einen schnellen Wrapper dafür geschrieben: gist.github.com/alfwatt/3588c5aa1f7a1ef7a3bb
alfwatt
9
Beachten Sie, dass macOS Sierra 10.12 (September 2016, XCode 8) und höher clock_gettime()direkt unterstützt wird - wie in dieser Antwort von James Wald angegeben .
Jonathan Leffler

Antworten:

32

Tatsächlich scheint es nicht für MacOS vor Sierra 10.12 implementiert zu sein. Vielleicht möchten Sie sich diesen Blogeintrag ansehen . Die Hauptidee ist im folgenden Code-Snippet:

Jens Gustedt
quelle
4
Ich möchte jedoch keine monotone Zeit, sondern die Echtzeit seit der Epoche in Nanosekunden.
Delan Azabani
3
@ Delan, ich verstehe nicht, warum du das willst, das ist nutzlose Präzision für etwas, das in der Größenordnung von Jahren zählt. Normalerweise benötigen Sie Nanosekunden, um eine Funktion oder so zeitlich zu steuern. Dann reicht es aus, sich vorher und nachher Zeit zu nehmen, wie es in diesem Blog gemacht wird. Aber Sie können das immer simulieren, indem Sie gettimeofdayund mach_absolute_timezu Beginn Ihres Programms nehmen und dann die Dinge addieren.
Jens Gustedt
10
Verwechseln Sie niemals monoton und in Echtzeit. Echtzeit kann springen, wenn ein NTP-Daemon die Systemuhr korrigiert. Das sind wirklich zwei völlig verschiedene Dinge.
mic_e
2
"Blogeintrag" ist jetzt kaputt :(
P Marecki
3
Verwenden Sie stattdessen diesen Link: web.archive.org/web/20100517095152/http://www.wand.net.nz/…
Brian Cannard
128

Nachdem ich stundenlang verschiedene Antworten, Blogs und Header durchgesehen hatte, fand ich einen tragbaren Weg, um die aktuelle Zeit zu ermitteln:

oder sehen Sie sich diese Liste an: https://gist.github.com/1087739

Hoffe das spart jemandem Zeit. Prost!

jbenet
quelle
3
ist host_get_clock_service teuer? Würde es sich lohnen, es für den Prozess zwischenzuspeichern? ist es wiederverwendbar? Thread sicher? Danke - :)
Peterk
1
Dazu gehören auch: #ifdef __MACH__ #include <mach / clock.h> #include <mach / mach.h> #endif
Nikolay Vyahhi
3
@ NikolayVyahhi Ja! Ich habe sie im Kern. Da Sie sie nicht gefunden haben, ist es vielleicht am besten, sie der Antwort hinzuzufügen.
Jbenet
4
Hat vielleicht jemand den obigen __MACH__Code zeitlich festgelegt ? Mit einem unabhängigen Mikrosekunden-Timer (gut getestet) habe ich den Eindruck, dass zwei Aufrufe des obigen Codes ~ 25 Mikrosekunden kosten.
P Marecki
1
Kennt jemand die Antwort auf die Frage von @peterk? In meinen Tests scheint es, als würde das Zwischenspeichern die Leistung verdoppeln. Muss ich es jedoch pro Thread zwischenspeichern, oder kann ich eines erstellen und es für alle meine Threads freigeben?
Robbie_c
35

Keine der oben genannten Lösungen beantwortet die Frage. Entweder geben sie Ihnen keine absolute Unix-Zeit oder ihre Genauigkeit beträgt 1 Mikrosekunde. Die beliebteste Lösung von jbenet ist langsam (~ 6000 ns) und zählt nicht in Nanosekunden, obwohl die Rückkehr dies nahelegt. Unten finden Sie einen Test für zwei von jbenet und Dmitri B vorgeschlagene Lösungen sowie meine Meinung dazu. Sie können den Code ohne Änderungen ausführen.

Die dritte Lösung zählt in Nanosekunden und gibt Ihnen eine relativ schnelle absolute Unix-Zeit (~ 90 ns). Also, wenn jemand es nützlich findet - bitte lassen Sie es uns alle hier wissen :-). Ich werde mich an die von Dmitri B halten (Lösung Nr. 1 im Code) - sie passt besser zu meinen Bedürfnissen.

Ich brauchte eine Alternative in kommerzieller Qualität zu clock_gettime (), um pthread_… timed .. -Aufrufe zu tätigen, und fand diese Diskussion sehr hilfreich. Danke Leute.

Sergey D.
quelle
1
Nur als FYI. Auf meinem System dauert ein Aufruf zum mach_absolute_time()Plus der Multiplikation mit info.numer / info.denommehr oder weniger 33 ns pro Aufruf: Benchmark: gist.github.com/aktau/9f52f812200d8d69a5d1 libuv issue: github.com/joyent/libuv/pull/1325
Aktau
30
Dmitri Bouianov
quelle
8
Wenn Sie CLOCK_REALTIME oder CLOCK_MONOTONIC verwenden, sollten Sie auch diese definieren: #define CLOCK_REALTIME 0 #define CLOCK_MONOTONIC 0
nat chouf
5
Weil a) die Genauigkeit 1000x niedriger ist (obwohl das nicht so schlecht ist, da die Granularität der tatsächlich zurückgegebenen Zeit clock_gettimeselten (nie) eine Nanosekunde gettimeofdaybeträgt ) und b) die zurückgegebene Zeit unterschiedlich und nicht monoton ist. Es kann wild springen (z. B. wenn Sommerzeit stattfindet) oder es kann sogar etwas langsamer / schneller (!) Laufen, nachdem die Zeitserver-Synchronisierung stattgefunden hat, bei der der Zeitdienst möglicherweise kleine abrupte Zeitänderungen vermeiden möchte.
das Schwein
4
Leider ist die Tageszeit keine monotone Uhr. (Die monotone Uhr existiert speziell, um alle Probleme zu vermeiden, die mit einer Uhrzeit verbunden sind, einschließlich Administratoren oder NTP, die die Zeit, Schaltsekunden, Zeitzonen usw. ändern.)
Dave Pacheco
21

Alles, was Sie brauchen, ist in Technische Fragen und Antworten beschrieben. QA1398: Technische Fragen und Antworten QA1398: Mach Absolute Zeiteinheiten , im Grunde ist die gewünschte Funktionmach_absolute_time .

Hier ist eine etwas frühere Version des Beispielcodes von dieser Seite, die alles mit Mach-Aufrufen erledigt (die aktuelle Version verwendet AbsoluteToNanosecondsCoreServices). In aktuellem OS X (dh bei Snow Leopard auf x86_64) sind die absoluten Zeitwerte tatsächlich in Nanosekunden angegeben und erfordern daher überhaupt keine Konvertierung. Wenn Sie also gut sind und tragbaren Code schreiben, konvertieren Sie, aber wenn Sie nur etwas schnelles und schmutziges für sich selbst tun, brauchen Sie sich nicht darum zu kümmern.

FWIW mach_absolute_timeist sehr schnell.

Charphacy
quelle
15

Beachten Sie, dass macOS Sierra 10.12 jetzt clock_gettime () unterstützt:

Es liefert Nanosekunden; Die Auflösung beträgt jedoch 1000, sodass sie (in) effektiv auf Mikrosekunden beschränkt ist:

Sie benötigen XCode 8 oder höher, um diese Funktion nutzen zu können. Code, der zur Verwendung dieser Funktion kompiliert wurde, kann unter Versionen von Mac OS X (10.11 oder früher) nicht ausgeführt werden.

James Wald
quelle
1
Ich bin auf macOS 10.12, kann aber die oben genannten nicht kompilieren. Ich bekommeUse of undeclared identifier 'CLOCK_REALTIME'
Necktwi
1
Seltsam, das sollte verfügbar sein mit: #include <time.h>. Versuchen Sie "xcode-select --install", um die Befehlszeilen-Entwicklertools zu aktualisieren.
James Wald
Ja, mein Xcode ist v7. Es tut mir weh, den 4 GB Xcode8 herunterzuladen. Ich bin paranoid in Bezug auf die von xcode-slect --install!
Necktwi
@ JamesWald: Ich habe einen Kommentar unter die Frage gesetzt, der auf Ihre Antwort verweist. Eine positive Bewertung des Kommentars würde seine Sichtbarkeit verbessern (mehrere positive Bewertungen wären sogar noch besser).
Jonathan Leffler
2
Ein Wort der Vorsicht: Wenn Sie mit XCode 8 (oder höher) clock_gettimeerstellen, aber Zielversionen von OSX älter als 10.12 verwenden, finden Sie das Symbol zur Kompilierungszeit. Wenn Sie jedoch die Binärdatei auf 10.11 oder niedriger ausführen, wird "dyld: Symbol nicht gefunden" angezeigt : _clock_gettime ", weil der Compiler ein schwaches Symbol generiert hat.
Anon
9

Danke für deine Beiträge

Ich denke, Sie können die folgenden Zeilen hinzufügen

Lassen Sie mich wissen, was Sie für Latenz und Granularität erhalten

ilciavo
quelle
3
Es wäre besser, wenn Sie den mach_timebase_infoAufruf zwischenspeichern würden (möglicherweise mit einer statischen Variablen, um ihn aufgeräumt zu halten). mach_timebase_info()ist ein Systemaufruf und dauert ~ 180ns auf meinem Computer. Im Gegensatz zu den ~ 22ns für mach_absolute_time(), bei denen es sich im Grunde nur um Sampling handelt rdtsc.
Aktau
4

Maristic hat hier bisher die beste Antwort. Lassen Sie mich vereinfachen und eine Bemerkung hinzufügen. #includeund Init():

Benutzen als:

Ein solcher Timer hat eine Latenz von 65ns +/- 2ns(2 GHz CPU). Verwenden Sie diese Option, wenn Sie eine "zeitliche Entwicklung" der einzelnen Ausführung benötigen. Andernfalls schleifen Sie Ihre Codezeiten 10000und Ihr Profil auch mit gettimeofday(), was portabel ist (POSIX) und die Latenz von 100ns +/- 0.5ns(wenn auch nur 1usGranularität) hat.

P Marecki
quelle
1
Haben Sie eine Vorstellung davon, wie sich die Umstellung auf die Präzision verdoppelt? AFAIK a double hat nur eine Genauigkeit von 53 Bit und mach_absolute_timekann alles in einem 64-Bit-Bereich zurückgeben. Nur neugierig.
Aktau
3

Ich habe die Version mit clock_get_time ausprobiert und den Aufruf host_get_clock_service zwischengespeichert. Es ist viel langsamer als gettimeofday, es dauert mehrere Mikrosekunden pro Aufruf. Und was noch schlimmer ist, der Rückgabewert hat Schritte von 1000, dh es ist immer noch eine Mikrosekunden-Granularität.

Ich würde empfehlen, gettimeofday zu verwenden und tv_usec mit 1000 zu multiplizieren.

Bernd Paysan
quelle
1
Die von zurückgegebene Zeit gettimeofdayist möglicherweise nicht monoton. Es kann wild springen (z. B. wenn Sommerzeit stattfindet) oder es kann sogar etwas langsamer / schneller (!) Laufen, nachdem die Zeitserver-Synchronisierung stattgefunden hat, bei der der Zeitdienst möglicherweise kleine abrupte Zeitänderungen vermeiden möchte.
das Schwein
2

Basierend auf der Open Source- Datei mach_absolute_time.c können wir sehen, dass die Zeile angibt , dass extern mach_port_t clock_port;bereits ein Mach-Port für die monotone Zeit initialisiert wurde. Auf diesen Clock-Port kann direkt zugegriffen werden, ohne dass ein Anruf mach_absolute_timeerforderlich ist und dann wieder in a konvertiert wird struct timespec. Das Umgehen eines Anrufs an mach_absolute_timesollte die Leistung verbessern.

Ich habe ein kleines Github-Repo (PosixMachTiming) mit dem Code erstellt, der auf dem externen clock_portund einem ähnlichen Thread basiert . PosixMachTiming emuliert clock_gettimefür CLOCK_REALTIMEund CLOCK_MONOTONIC. Es emuliert auch die Funktion clock_nanosleepfür die absolute monotone Zeit. Bitte probieren Sie es aus und sehen Sie, wie die Leistung verglichen wird. Vielleicht möchten Sie Vergleichstests erstellen oder andere POSIX-Uhren / -Funktionen emulieren?

ChisholmKyle
quelle
1

Ab mindestens so groß wie Mountain Lion weit zurück, mach_absolute_time()kehrt ns und nicht die absolute Zeit (die die Anzahl der Buszyklen war).

Der folgende Code auf meinem MacBook Pro (2 GHz Core i7) zeigte, dass die mach_absolute_time()durchschnittliche Anrufdauer über 10 Läufe 39 Minuten betrug (min. 35, max. 45). Dies ist im Grunde die Zeit zwischen der Rückgabe der beiden Aufrufe an mach_absolute_time (). ca. 1 Aufruf:

Jon Spencer
quelle
2
IIRC, die gesamte Intel-Hardware verwendet Nanosekunden, und die gesamte PowerPC-Hardware verwendet Buszyklen unabhängig von der Betriebssystemversion, aber der G5 hat möglicherweise Nanosekunden verwendet - ich vergesse.
Dgatwood
0

Ich habe eine andere tragbare Lösung gefunden.

Deklarieren Sie in einer Header-Datei (oder sogar in Ihrer Quelldatei):

Und das Hinzufügen der Funktionsimplementierung:

Vergessen Sie nicht einzuschließen <time.h>.


quelle
0

Für MacOS finden Sie gute Informationen auf der Entwicklerseite https://developer.apple.com/library/content/documentation/Darwin/Conceptual/KernelProgramming/services/services.html

Alex Paniutin
quelle