clock_gettime替代Mac OS X中的
编译我在Mac OS X上编写的程序后,通过MacPorts安装必要的库,我得到这个错误:
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.)
看来, clock_gettime
没有在Mac OS X中实现。是否有其他方法获得在几 纳秒的纪元时间 ? 不幸的是, gettimeofday
只有gettimeofday
微秒 。
实际上,这似乎没有为MacOs实施。 你可能想看看这个博客条目 ,但这似乎不可用了。 主要思想是在下面的代码片段中:
#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; }
经过几个小时的阅读不同的答案,博客和标题,我发现一个便携的方式来获得当前的时间:
#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
或者查看这个要点: https : //gist.github.com/1087739
希望这可以节省一些时间。 干杯!
#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
上面的解决scheme都没有回答这个问题。 要么他们不给你绝对的Unix时间,要么他们的精度是1微秒。 由jbenet最stream行的解决scheme是慢(〜6000ns),并不算纳秒,即使它的回报表明如此。 下面是由jbenet和德米特里Bbuild议的两个解决scheme的testing,再加上我的这个。 您可以在不更改的情况下运行代码。
第三种解决scheme的计算时间为纳秒,并且给你绝对的Unix时间相当快(〜90ns)。 所以如果有人觉得有用 – 请让我们都知道在这里:-)。 我会坚持从德米特里B(代码中的解决scheme#1) – 这更符合我的需要。
我需要clock_gettime()的商业质量替代方法来使pthread_ … timed ..调用,并发现这个讨论非常有帮助。 多谢你们。
/* 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; }
技术问答QA1398:技术问答QA1398:马赫绝对时间单位 ,基本上你想要的function是mach_absolute_time
。
这是来自该页面的示例代码的稍微早一些版本,它使用Mach调用(当前版本使用CoreServices的AbsoluteToNanoseconds
)。 在当前的OS X中(即在x86_64上的Snow Leopard上),绝对时间值实际上是纳秒,所以根本不需要任何转换。 所以,如果你很好,编写可移植的代码,你会转换,但如果你只是为自己做一些快速和肮脏的事情,你不需要麻烦。
FWIW, mach_absolute_time
真的很快。
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; }
请注意,macOS Sierra 10.12现在支持clock_gettime():
#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); }
它确实提供了纳秒; 然而,分辨率是1000,所以它被(有效)限制在微秒级别:
CLOCK_REALTIME: res.tv_sec=0 res.tv_nsec=1000 CLOCK_REALTIME: time.tv_sec=1475279260 time.tv_nsec=525627000
您将需要XCode 8或更高版本才能使用此function。 编译为使用此function的代码不能在Mac OS X(10.11或更早版本)的版本上运行。
感谢您的post
我认为你可以添加以下几行
#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
让我知道你得到什么延迟和粒度
Maristic在这里迄今为止是最好的答案。 让我简化并添加一个评论。 #include
和Init()
:
#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; }
用于:
uint64_t t1, t2; Init(); t1 = mach_absolute_time(); /* profiled code here */ t2 = mach_absolute_time(); double duration_ns = (double)(t2 - t1) * conversion_factor;
这种定时器的延迟为65ns +/- 2ns
(2GHz CPU)。 如果您需要单次执行的“时间进度”,请使用此选项。 否则,使用gettimeofday()
(这是便携式(POSIX)),并且具有100ns +/- 0.5ns
的延迟(尽pipe只有1us
粒度),将代码循环10000
次并进行configuration文件。
我用clock_get_time尝试了版本,并caching了host_get_clock_service调用。 它比gettimeofday慢,每个调用需要几微秒。 而更糟糕的是,返回值有1000步,也就是微秒粒度。
我build议使用gettimeofday,并乘以1000的tv_usec。
基于开源的mach_absolute_time.c,我们可以看到extern mach_port_t clock_port;
告诉我们有一个马赫的港口已经初始化为单调的时间。 这个时钟端口可以直接访问,而不必诉诸于mach_absolute_time
然后转换回 struct timespec
。 绕过对mach_absolute_time
的调用应该可以提高性能。
我用基于extern clock_port
和类似线程的代码创build了一个小Github回购(PosixMachTiming) 。 PosixMachTiming模拟CLOCK_REALTIME
和CLOCK_MONOTONIC
clock_gettime
。 它也模拟函数clock_nanosleep
的绝对单调时间。 请试试看看性能如何。 也许你可能想创build比较testing或模拟其他POSIX时钟/function?
至less早在山狮, mach_absolute_time()
返回纳秒,而不是绝对时间(这是总线周期数)。
在我的MacBook Pro(2 GHz Core i7)上的以下代码显示,调用mach_absolute_time()
的时间在10次运行(最小35,最大45)内平均为39 ns,这基本上是两次调用返回mach_absolute_time (),约1个调用:
#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; }
我发现了另一种便携式解决
声明一些头文件(甚至在你的源文件中):
/* If compiled on DARWIN/Apple platforms. */ #ifdef DARWIN #define CLOCK_REALTIME 0x2d4e1588 #define CLOCK_MONOTONIC 0x0 #endif /* DARWIN */
并添加function实现:
#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 */
不要忘记包含<time.h>
。
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);
对于MacOS,您可以在其开发者页面上find一个很好的信息。