часы 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 находится в микросекунд.
13 ответов:
по сути, он, кажется, не будет реализован для macOS до Sierra 10.12. Вы можете посмотреть на это запись в блог, но это, кажется, больше не доступно. Основная идея заключается в следующем фрагменте кода:
#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
надеюсь, это сэкономит кому-то время. Ура!
ни одно из решений выше отвечает на вопрос. Либо они не дают вам абсолютного времени Unix, либо их точность составляет 1 микросекунду. Самое популярное решение jbenet является медленным (~6000ns) и не учитывается в наносекундах, хотя его возврат предполагает это. Ниже приведен тест для 2 решений, предложенных jbenet и Дмитрием B, плюс мой взгляд на это. Вы можете запустить код без изменений.
3-е решение действительно считается в наносекундах и дает вам абсолютное время Unix разумно быстро (~90нс). Так что если кто-то найдет это полезным - пожалуйста, дайте нам знать и здесь :-). Я буду придерживаться одного из Дмитрия Б (Решение № 1 в коде) - он лучше соответствует моим потребностям.
Мне нужен коммерческий качественной альтернативой при успешном выполнении функции clock_gettime (), чтобы сделать pthread_...время.. звонит, и нашел это обсуждение очень полезным. Спасибо, ребята.
/* 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; }
#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
все, что вам нужно, описано в технические вопросы QA1398: технические вопросы QA1398: Маха абсолютных единицах времени, в основном функция, которую вы хотите
mach_absolute_time.вот немного более ранняя версия примера кода с этой страницы, которая делает все, используя вызовы Mach (текущая версия использует
AbsoluteToNanosecondsот CoreServices). В текущей OS X (т. е. на Snow Leopard на x86_64) абсолютные значения времени фактически находятся в наносекундах и поэтому фактически не требуют каких-либо преобразования на всех. Итак, если Вы хороши и пишете портативный код, вы будете конвертировать, но если вы просто делаете что-то быстрое и грязное для себя, вам не нужно беспокоиться.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 Сьерра-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, поэтому оно (in)эффективно ограничено микросекундами:
CLOCK_REALTIME: res.tv_sec=0 res.tv_nsec=1000 CLOCK_REALTIME: time.tv_sec=1475279260 time.tv_nsec=525627000вам понадобится XCode 8 или более поздней версии, чтобы иметь возможность использовать эту функцию. Код, скомпилированный для использования этой функции, не будет работать в версиях Mac OS X (10.11 или более ранних).
Спасибо за ваши посты
Я думаю, вы можете добавить следующие строки
#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(процессор 2 ГГц). Используйте это, если вам нужна "эволюция времени" одного выполнения. В противном случае цикл ваш код10000раз и профиль, даже сgettimeofday(), который является портативным (POSIX), и имеет задержку100ns +/- 0.5ns(правда, только1usгранулярности).
Я попробовал версию с clock_get_time, и сделал кэширование вызова host_get_clock_service. Это намного медленнее, чем gettimeofday, это занимает несколько микросекунд на вызов. И, что еще хуже, возвращаемое значение имеет шаги 1000, т. е. это все еще микросекундная гранулярность.
Я бы посоветовал использовать gettimeofday и умножить tv_usec на 1000.
на основе открытого исходного кода mach_absolute_time.c мы видим, что строка
extern mach_port_t clock_port;говорит нам, что порт mach уже инициализирован для монотонного времени. Этот порт часов можно получить напрямую, не прибегая к вызовуmach_absolute_timeпосле преобразования назад доstruct timespec. Обход вызова наmach_absolute_timeдолжны улучшить производительность.Я создал небольшой GitHub repo (PosixMachTiming) С кодом на основе extern
clock_portи похожие темы. PosixMachTiming эмулируетclock_gettimeнаCLOCK_REALTIMEиCLOCK_MONOTONIC. Он также эмулирует функциюclock_nanosleepдля абсолютного монотонного времени. Пожалуйста, дайте ему попробовать и посмотреть, как производительность сравнивает. Возможно, вы захотите создать сравнительные тесты или эмулировать другие часы/функции POSIX?
по крайней мере, с тех пор, как горный лев,
mach_absolute_time()возвращает наносекунд и не абсолютное время (которое было числом циклов шины).следующий код на моем MacBook Pro (2 ГГц Core i7) показал, что время для вызова
mach_absolute_time()усреднил 39 НС за 10 запусков (мин 35, Макс 45), что в основном время между возвратом двух вызовов 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 */и добавить реализацию функции:
#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 вы можете найти хорошую информацию на их странице разработчиков https://developer.apple.com/library/content/documentation/Darwin/Conceptual/KernelProgramming/services/services.html
Comments