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:
In function 'nanotime':
error: 'CLOCK_REALTIME' undeclared (first use in this function)
error: (Each undeclared identifier is reported only once
error: for each function it appears in.)
Es scheint, dass dies clock_gettime
nicht in Mac OS X implementiert ist. Gibt es ein alternatives Mittel, um die Epochenzeit in Nanosekunden zu ermitteln ? Ist leider gettimeofday
in Mikrosekunden .
#include <time.h>
?clock_gettime
ist nicht in Mac OS X implementiert.clock_gettime
, während Linux tut.clock_gettime()
direkt unterstützt wird - wie in dieser Antwort von James Wald angegeben .Antworten:
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:
#include <mach/mach_time.h> #define ORWL_NANO (+1.0E-9) #define ORWL_GIGA UINT64_C(1000000000) static double orwl_timebase = 0.0; static uint64_t orwl_timestart = 0; struct timespec orwl_gettime(void) { // be more careful in a multithreaded environement if (!orwl_timestart) { mach_timebase_info_data_t tb = { 0 }; mach_timebase_info(&tb); orwl_timebase = tb.numer; orwl_timebase /= tb.denom; orwl_timestart = mach_absolute_time(); } struct timespec t; double diff = (mach_absolute_time() - orwl_timestart) * orwl_timebase; t.tv_sec = diff * ORWL_NANO; t.tv_nsec = diff - (t.tv_sec * ORWL_GIGA); return t; }
quelle
gettimeofday
undmach_absolute_time
zu Beginn Ihres Programms nehmen und dann die Dinge addieren.Nachdem ich stundenlang verschiedene Antworten, Blogs und Header durchgesehen hatte, fand ich einen tragbaren Weg, um die aktuelle Zeit zu ermitteln:
#include <time.h> #include <sys/time.h> #ifdef __MACH__ #include <mach/clock.h> #include <mach/mach.h> #endif struct timespec ts; #ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time clock_serv_t cclock; mach_timespec_t mts; host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); clock_get_time(cclock, &mts); mach_port_deallocate(mach_task_self(), cclock); ts.tv_sec = mts.tv_sec; ts.tv_nsec = mts.tv_nsec; #else clock_gettime(CLOCK_REALTIME, &ts); #endif
oder sehen Sie sich diese Liste an: https://gist.github.com/1087739
Hoffe das spart jemandem Zeit. Prost!
quelle
__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.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.
/* Ratings of alternatives to clock_gettime() to use with pthread timed waits: Solution 1 "gettimeofday": Complexity : simple Portability : POSIX 1 timespec : easy to convert from timeval to timespec granularity : 1000 ns, call : 120 ns, Rating : the best. Solution 2 "host_get_clock_service, clock_get_time": Complexity : simple (error handling?) Portability : Mac specific (is it always available?) timespec : yes (struct timespec return) granularity : 1000 ns (don't be fooled by timespec format) call time : 6000 ns Rating : the worst. Solution 3 "mach_absolute_time + gettimeofday once": Complexity : simple..average (requires initialisation) Portability : Mac specific. Always available timespec : system clock can be converted to timespec without float-math granularity : 1 ns. call time : 90 ns unoptimised. Rating : not bad, but do we really need nanoseconds timeout? References: - OS X is UNIX System 3 [U03] certified http://www.opengroup.org/homepage-items/c987.html - UNIX System 3 <--> POSIX 1 <--> IEEE Std 1003.1-1988 http://en.wikipedia.org/wiki/POSIX http://www.unix.org/version3/ - gettimeofday() is mandatory on U03, clock_..() functions are optional on U03, clock_..() are part of POSIX Realtime extensions http://www.unix.org/version3/inttables.pdf - clock_gettime() is not available on MacMini OS X (Xcode > Preferences > Downloads > Command Line Tools = Installed) - OS X recommends to use gettimeofday to calculate values for timespec https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/pthread_cond_timedwait.3.html - timeval holds microseconds, timespec - nanoseconds http://www.gnu.org/software/libc/manual/html_node/Elapsed-Time.html - microtime() is used by kernel to implement gettimeofday() http://ftp.tw.freebsd.org/pub/branches/7.0-stable/src/sys/kern/kern_time.c - mach_absolute_time() is really fast http://www.opensource.apple.com/source/Libc/Libc-320.1.3/i386/mach/mach_absolute_time.c - Only 9 deciaml digits have meaning when int nanoseconds converted to double seconds Tutorial: Performance and Time post uses .12 precision for nanoseconds http://www.macresearch.org/tutorial_performance_and_time Example: Three ways to prepare absolute time 1500 milliseconds in the future to use with pthread timed functions. Output, N = 3, stock MacMini, OSX 10.7.5, 2.3GHz i5, 2GB 1333MHz DDR3: inittime.tv_sec = 1390659993 inittime.tv_nsec = 361539000 initclock = 76672695144136 get_abs_future_time_0() : 1390659994.861599000 get_abs_future_time_0() : 1390659994.861599000 get_abs_future_time_0() : 1390659994.861599000 get_abs_future_time_1() : 1390659994.861618000 get_abs_future_time_1() : 1390659994.861634000 get_abs_future_time_1() : 1390659994.861642000 get_abs_future_time_2() : 1390659994.861643671 get_abs_future_time_2() : 1390659994.861643877 get_abs_future_time_2() : 1390659994.861643972 */ #include <stdio.h> #include <stdlib.h> #include <time.h> #include <sys/time.h> /* gettimeofday */ #include <mach/mach_time.h> /* mach_absolute_time */ #include <mach/mach.h> /* host_get_clock_service, mach_... */ #include <mach/clock.h> /* clock_get_time */ #define BILLION 1000000000L #define MILLION 1000000L #define NORMALISE_TIMESPEC( ts, uint_milli ) \ do { \ ts.tv_sec += uint_milli / 1000u; \ ts.tv_nsec += (uint_milli % 1000u) * MILLION; \ ts.tv_sec += ts.tv_nsec / BILLION; \ ts.tv_nsec = ts.tv_nsec % BILLION; \ } while (0) static mach_timebase_info_data_t timebase = { 0, 0 }; /* numer = 0, denom = 0 */ static struct timespec inittime = { 0, 0 }; /* nanoseconds since 1-Jan-1970 to init() */ static uint64_t initclock; /* ticks since boot to init() */ void init() { struct timeval micro; /* microseconds since 1 Jan 1970 */ if (mach_timebase_info(&timebase) != 0) abort(); /* very unlikely error */ if (gettimeofday(µ, NULL) != 0) abort(); /* very unlikely error */ initclock = mach_absolute_time(); inittime.tv_sec = micro.tv_sec; inittime.tv_nsec = micro.tv_usec * 1000; printf("\tinittime.tv_sec = %ld\n", inittime.tv_sec); printf("\tinittime.tv_nsec = %ld\n", inittime.tv_nsec); printf("\tinitclock = %ld\n", (long)initclock); } /* * Get absolute future time for pthread timed calls * Solution 1: microseconds granularity */ struct timespec get_abs_future_time_coarse(unsigned milli) { struct timespec future; /* ns since 1 Jan 1970 to 1500 ms in the future */ struct timeval micro = {0, 0}; /* 1 Jan 1970 */ (void) gettimeofday(µ, NULL); future.tv_sec = micro.tv_sec; future.tv_nsec = micro.tv_usec * 1000; NORMALISE_TIMESPEC( future, milli ); return future; } /* * Solution 2: via clock service */ struct timespec get_abs_future_time_served(unsigned milli) { struct timespec future; clock_serv_t cclock; mach_timespec_t mts; host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); clock_get_time(cclock, &mts); mach_port_deallocate(mach_task_self(), cclock); future.tv_sec = mts.tv_sec; future.tv_nsec = mts.tv_nsec; NORMALISE_TIMESPEC( future, milli ); return future; } /* * Solution 3: nanosecond granularity */ struct timespec get_abs_future_time_fine(unsigned milli) { struct timespec future; /* ns since 1 Jan 1970 to 1500 ms in future */ uint64_t clock; /* ticks since init */ uint64_t nano; /* nanoseconds since init */ clock = mach_absolute_time() - initclock; nano = clock * (uint64_t)timebase.numer / (uint64_t)timebase.denom; future = inittime; future.tv_sec += nano / BILLION; future.tv_nsec += nano % BILLION; NORMALISE_TIMESPEC( future, milli ); return future; } #define N 3 int main() { int i, j; struct timespec time[3][N]; struct timespec (*get_abs_future_time[])(unsigned milli) = { &get_abs_future_time_coarse, &get_abs_future_time_served, &get_abs_future_time_fine }; init(); for (j = 0; j < 3; j++) for (i = 0; i < N; i++) time[j][i] = get_abs_future_time[j](1500); /* now() + 1500 ms */ for (j = 0; j < 3; j++) for (i = 0; i < N; i++) printf("get_abs_future_time_%d() : %10ld.%09ld\n", j, time[j][i].tv_sec, time[j][i].tv_nsec); return 0; }
quelle
mach_absolute_time()
Plus der Multiplikation mitinfo.numer / info.denom
mehr oder weniger 33 ns pro Aufruf: Benchmark: gist.github.com/aktau/9f52f812200d8d69a5d1 libuv issue: github.com/joyent/libuv/pull/1325#if defined(__MACH__) && !defined(CLOCK_REALTIME) #include <sys/time.h> #define CLOCK_REALTIME 0 // clock_gettime is not implemented on older versions of OS X (< 10.12). // If implemented, CLOCK_REALTIME will have already been defined. int clock_gettime(int /*clk_id*/, struct timespec* t) { struct timeval now; int rv = gettimeofday(&now, NULL); if (rv) return rv; t->tv_sec = now.tv_sec; t->tv_nsec = now.tv_usec * 1000; return 0; } #endif
quelle
clock_gettime
selten (nie) eine Nanosekundegettimeofday
beträ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.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 Funktion
mach_absolute_time
.Hier ist eine etwas frühere Version des Beispielcodes von dieser Seite, die alles mit Mach-Aufrufen erledigt (die aktuelle Version verwendet
AbsoluteToNanoseconds
CoreServices). 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_time
ist sehr schnell.uint64_t GetPIDTimeInNanoseconds(void) { uint64_t start; uint64_t end; uint64_t elapsed; uint64_t elapsedNano; static mach_timebase_info_data_t sTimebaseInfo; // Start the clock. start = mach_absolute_time(); // Call getpid. This will produce inaccurate results because // we're only making a single system call. For more accurate // results you should call getpid multiple times and average // the results. (void) getpid(); // Stop the clock. end = mach_absolute_time(); // Calculate the duration. elapsed = end - start; // Convert to nanoseconds. // If this is the first time we've run, get the timebase. // We can use denom == 0 to indicate that sTimebaseInfo is // uninitialised because it makes no sense to have a zero // denominator is a fraction. if ( sTimebaseInfo.denom == 0 ) { (void) mach_timebase_info(&sTimebaseInfo); } // Do the maths. We hope that the multiplication doesn't // overflow; the price you pay for working in fixed point. elapsedNano = elapsed * sTimebaseInfo.numer / sTimebaseInfo.denom; printf("multiplier %u / %u\n", sTimebaseInfo.numer, sTimebaseInfo.denom); return elapsedNano; }
quelle
Beachten Sie, dass macOS Sierra 10.12 jetzt clock_gettime () unterstützt:
#include <stdio.h> #include <time.h> int main() { struct timespec res; struct timespec time; clock_getres(CLOCK_REALTIME, &res); clock_gettime(CLOCK_REALTIME, &time); printf("CLOCK_REALTIME: res.tv_sec=%lu res.tv_nsec=%lu\n", res.tv_sec, res.tv_nsec); printf("CLOCK_REALTIME: time.tv_sec=%lu time.tv_nsec=%lu\n", time.tv_sec, time.tv_nsec); }
Es liefert Nanosekunden; Die Auflösung beträgt jedoch 1000, sodass sie (in) effektiv auf Mikrosekunden beschränkt ist:
CLOCK_REALTIME: res.tv_sec=0 res.tv_nsec=1000 CLOCK_REALTIME: time.tv_sec=1475279260 time.tv_nsec=525627000
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.
quelle
Use of undeclared identifier 'CLOCK_REALTIME'
xcode-slect --install
!clock_gettime
erstellen, 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.Danke für deine Beiträge
Ich denke, Sie können die folgenden Zeilen hinzufügen
#ifdef __MACH__ #include <mach/mach_time.h> #define CLOCK_REALTIME 0 #define CLOCK_MONOTONIC 0 int clock_gettime(int clk_id, struct timespec *t){ mach_timebase_info_data_t timebase; mach_timebase_info(&timebase); uint64_t time; time = mach_absolute_time(); double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom); double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9); t->tv_sec = seconds; t->tv_nsec = nseconds; return 0; } #else #include <time.h> #endif
Lassen Sie mich wissen, was Sie für Latenz und Granularität erhalten
quelle
mach_timebase_info
Aufruf 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ürmach_absolute_time()
, bei denen es sich im Grunde nur um Sampling handeltrdtsc
.Maristic hat hier bisher die beste Antwort. Lassen Sie mich vereinfachen und eine Bemerkung hinzufügen.
#include
undInit()
:#include <mach/mach_time.h> double conversion_factor; void Init() { mach_timebase_info_data_t timebase; mach_timebase_info(&timebase); conversion_factor = (double)timebase.numer / (double)timebase.denom; }
Benutzen als:
uint64_t t1, t2; Init(); t1 = mach_absolute_time(); /* profiled code here */ t2 = mach_absolute_time(); double duration_ns = (double)(t2 - t1) * conversion_factor;
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 Codezeiten10000
und Ihr Profil auch mitgettimeofday()
, was portabel ist (POSIX) und die Latenz von100ns +/- 0.5ns
(wenn auch nur1us
Granularität) hat.quelle
mach_absolute_time
kann alles in einem 64-Bit-Bereich zurückgeben. Nur neugierig.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.
quelle
gettimeofday
ist 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.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 Anrufmach_absolute_time
erforderlich ist und dann wieder in a konvertiert wirdstruct timespec
. Das Umgehen eines Anrufs anmach_absolute_time
sollte die Leistung verbessern.Ich habe ein kleines Github-Repo (PosixMachTiming) mit dem Code erstellt, der auf dem externen
clock_port
und einem ähnlichen Thread basiert . PosixMachTiming emuliertclock_gettime
fürCLOCK_REALTIME
undCLOCK_MONOTONIC
. Es emuliert auch die Funktionclock_nanosleep
fü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?quelle
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:#include <stdint.h> #include <mach/mach_time.h> #include <iostream> using namespace std; int main() { uint64_t now, then; uint64_t abs; then = mach_absolute_time(); // return nanoseconds now = mach_absolute_time(); abs = now - then; cout << "nanoseconds = " << abs << endl; }
quelle
Ich habe eine andere tragbare Lösung gefunden.
Deklarieren Sie in einer Header-Datei (oder sogar in Ihrer Quelldatei):
/* If compiled on DARWIN/Apple platforms. */ #ifdef DARWIN #define CLOCK_REALTIME 0x2d4e1588 #define CLOCK_MONOTONIC 0x0 #endif /* DARWIN */
Und das Hinzufügen der Funktionsimplementierung:
#ifdef DARWIN /* * Bellow we provide an alternative for clock_gettime, * which is not implemented in Mac OS X. */ static inline int clock_gettime(int clock_id, struct timespec *ts) { struct timeval tv; if (clock_id != CLOCK_REALTIME) { errno = EINVAL; return -1; } if (gettimeofday(&tv, NULL) < 0) { return -1; } ts->tv_sec = tv.tv_sec; ts->tv_nsec = tv.tv_usec * 1000; return 0; } #endif /* DARWIN */
Vergessen Sie nicht einzuschließen
<time.h>
.quelle
void clock_get_uptime(uint64_t *result); void clock_get_system_microtime( uint32_t *secs, uint32_t *microsecs); void clock_get_system_nanotime( uint32_t *secs, uint32_t *nanosecs); void clock_get_calendar_microtime( uint32_t *secs, uint32_t *microsecs); void clock_get_calendar_nanotime( uint32_t *secs, uint32_t *nanosecs);
Für MacOS finden Sie gute Informationen auf der Entwicklerseite https://developer.apple.com/library/content/documentation/Darwin/Conceptual/KernelProgramming/services/services.html
quelle