Beim Kompilieren eines Programms, das ich unter Mac OS X geschrieben habe, nachdem ich die erforderlichen Bibliotheken über MacPorts installiert habe, erhalte ich diesen Fehler:
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.)
Anscheinend clock_gettime ist in Mac OS X nicht implementiert. Gibt es eine alternative Möglichkeit, die Epoche Zeit in Nanosekunden? Leider gettimeofday ist in Mikrosekunden.
Meine Dokumentation sagt “Alle Implementierungen unterstützen die systemweite Echtzeituhr, die durch CLOCK_REALTIME identifiziert wird.” Hast du #include <time.h>?
– pmg
2. März 2011 um 12:18 Uhr
Das hat nicht geholfen. clock_gettime ist in Mac OS X nicht implementiert.
– Delan Azabani
2. März 2011 um 12:23 Uhr
Ich weiss. Es ist in meiner Linker-Befehlszeile. Ich komme überhaupt nicht bis zur Verknüpfungsphase. Mac OS X hat das nicht clock_gettimewährend Linux dies tut.
Beachten Sie, dass macOS Sierra 10.12 (September 2016, XCode 8) und höher unterstützt wird clock_gettime() direkt – wie in dieser Antwort von James Wald erwähnt.
– Jonathan Leffler
26. Oktober 2016 um 4:32 Uhr
jbenet
Nachdem ich stundenlang verschiedene Antworten, Blogs und Header durchgesehen hatte, fand ich einen tragbaren Weg, um die aktuelle Uhrzeit abzurufen:
#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
ist host_get_clock_service teuer? Würde es sich auszahlen, es für den Prozess zwischenzuspeichern? ist es wiederverwendbar? Thread sicher? Vielen Dank – 🙂
– Peterk
15. Oktober 2011 um 1:56 Uhr
benötigt außerdem include: #ifdef __MACH__ #include #include #endif
– Nikolai Wjahi
31. Januar 2012 um 22:24 Uhr
@NikolayVyahhi Ja! Ich habe sie im Kern. Da Sie sie jedoch nicht gefunden haben, ist es vielleicht am besten, sie der Antwort hinzuzufügen.
– jbenet
1. Februar 2012 um 19:09 Uhr
Hat vielleicht jemand das obige zeitlich gemessen __MACH__ Code? Mit einem unabhängigen Mikrosekunden-Timer (gut getestet) habe ich den Eindruck, dass zwei Aufrufe des obigen Codes ~ 25 Mikrosekunden kosten.
– P. Marecki
12. Juli 2012 um 14:14 Uhr
Weiß jemand die Antwort auf die Frage von @peterk . In meinen Tests scheint es, als würde das Zwischenspeichern die Leistung verdoppeln, aber muss ich es pro Thread zwischenspeichern, oder kann ich einen erstellen und ihn für alle meine Threads freigeben?
– robbie_c
17. März 2014 um 18:18 Uhr
Sergej D
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 ihre Rückkehr dies vermuten lässt. Unten ist ein Test für 2 Lösungen, die von jbenet und Dmitri B vorgeschlagen wurden, plus meine Meinung dazu. Sie können den Code ohne Änderungen ausführen.
Die dritte Lösung zählt in Nanosekunden und gibt Ihnen relativ schnell absolute Unix-Zeit (~ 90 ns). Also, wenn jemand es nützlich findet – bitte lassen Sie es uns alle hier wissen :-). Ich bleibe bei der von Dmitri B (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 machen, 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;
}
Tatsächlich scheint es für macOS nicht vor Sierra 10.12 implementiert zu sein. Vielleicht möchten Sie sich das ansehen Blog-Eintrag. Die Hauptidee ist im folgenden Code-Snippet enthalten:
Ich möchte jedoch keine monotone Zeit, ich möchte die Echtzeit seit der Epoche in Nanosekunden.
– Delan Azabani
2. März 2011 um 12:35 Uhr
@Delan, ich verstehe nicht, warum Sie das wollen würden, 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 zu timen. Dann reicht es aus, sich die Zeit davor und danach zu nehmen, wie es in diesem Blog gemacht wird. Aber man könnte das immer simulieren, indem man nimmt gettimeofday und mach_absolute_time am Anfang Ihres Programms und addieren Sie dann Dinge.
– Jens Gustedt
2. März 2011 um 12:58 Uhr
Verwechseln Sie niemals Monotonie und Echtzeit. Die Echtzeit kann springen, wenn ein NTP-Daemon die Systemuhr korrigiert. Das sind wirklich zwei völlig verschiedene Dinge.
#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
Hier ist eine etwas frühere Version des Beispielcodes von dieser Seite, die alles mit Mach-Aufrufen macht (die aktuelle Version verwendet AbsoluteToNanoseconds von CoreServices). Im aktuellen OS X (dh auf Snow Leopard auf x86_64) sind die absoluten Zeitwerte tatsächlich in Nanosekunden und erfordern daher überhaupt keine Konvertierung. Wenn Sie also gut sind und portablen Code schreiben, werden Sie konvertieren, aber wenn Sie nur schnell etwas für sich selbst tun, müssen Sie sich nicht darum kümmern.
FWIW, mach_absolute_time ist Ja wirklich 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;
}
Jonathan Leffler
Beachten Sie, dass macOS Sierra 10.12 jetzt clock_gettime() unterstützt:
Sie benötigen XCode 8 oder höher, um diese Funktion nutzen zu können. Code, der zur Verwendung dieser Funktion kompiliert wurde, kann nicht auf Versionen von Mac OS X (10.11 oder früher) ausgeführt werden.
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
Es wäre besser, wenn Sie die zwischenspeichern würden mach_timebase_info aufrufen (vielleicht mit einer statischen Variable, um es sauber zu halten). mach_timebase_info() ist ein Syscall und dauert auf meinem Rechner ~180ns. Im Gegensatz zu den ~22ns für mach_absolute_time()was im Grunde nur ein Sampling ist rdtsc.
– Aqtau
15. September 2014 um 8:16 Uhr
14164500cookie-checkclock_gettime-Alternative in Mac OS Xyes
Meine Dokumentation sagt “Alle Implementierungen unterstützen die systemweite Echtzeituhr, die durch CLOCK_REALTIME identifiziert wird.” Hast du
#include <time.h>
?– pmg
2. März 2011 um 12:18 Uhr
Das hat nicht geholfen.
clock_gettime
ist in Mac OS X nicht implementiert.– Delan Azabani
2. März 2011 um 12:23 Uhr
Ich weiss. Es ist in meiner Linker-Befehlszeile. Ich komme überhaupt nicht bis zur Verknüpfungsphase. Mac OS X hat das nicht
clock_gettime
während Linux dies tut.– Delan Azabani
2. März 2011 um 12:26 Uhr
Ich habe dazu einen kurzen Wrapper geschrieben: gist.github.com/alfwatt/3588c5aa1f7a1ef7a3bb
– alfwatt
4. August 2015 um 21:11 Uhr
Beachten Sie, dass macOS Sierra 10.12 (September 2016, XCode 8) und höher unterstützt wird
clock_gettime()
direkt – wie in dieser Antwort von James Wald erwähnt.– Jonathan Leffler
26. Oktober 2016 um 4:32 Uhr