在Mac OS X中使用clock_gettime选项。

时间:2022-09-06 14:13:41

When compiling a program I wrote on Mac OS X after installing the necessary libraries through MacPorts, I get this error:

我在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.)

It appears that clock_gettime is not implemented in Mac OS X. Is there an alternative means of getting the epoch time in nanoseconds? Unfortunately gettimeofday is in microseconds.

似乎在Mac OS x中没有实现clock_gettime,是否有一种方法可以在纳秒内获得纪元时间?不幸的是,gettimeofday的时间是微秒。

13 个解决方案

#1


28  

In effect, it seems not to be implemented for macOS before Sierra 10.12. You may want to look at this blog entry, but this doesn't seem to be available anymore. The main idea is in the following code snippet:

实际上,在Sierra 10.12之前,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;
}

#2


124  

After hours of perusing different answers, blogs, and headers, I found a portable way to get the current time:

经过几个小时的不同的回答、博客和标题之后,我找到了一种可以移动的方式来获取当前的时间:

#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

or check out this gist: https://gist.github.com/1087739

或者看看这个要点:https://gist.github.com/1087739。

Hope this saves someone time. Cheers!

希望这能节省时间。干杯!

#3


31  

None of the solutions above answers the question. Either they don't give you absolute Unix time, or their accuracy is 1 microsecond. The most popular solution by jbenet is slow (~6000ns) and does not count in nanoseconds even though its return suggests so. Below is a test for 2 solutions suggested by jbenet and Dmitri B, plus my take on this. You can run the code without changes.

以上的解决方案都不能回答这个问题。要么他们没有给你绝对的Unix时间,要么他们的精度是1微秒。jbenet最流行的解决方案是缓慢的(~6000ns),即使它的返回表明它是纳秒,也不会被计算在内。下面是jbenet和Dmitri B提出的两个解决方案的测试,再加上我对此的看法。您可以在不更改的情况下运行代码。

The 3rd solution does count in nanoseconds and gives you absolute Unix time reasonably fast (~90ns). So if someone find it useful - please let us all know here :-). I will stick to the one from Dmitri B (solution #1 in the code) - it fits my needs better.

第三个解决方案在纳秒内计数,并且给您绝对的Unix时间相当快(~90ns)。因此,如果有人发现它有用,请让我们都知道:-)。我将坚持从Dmitri B(代码中的解决方案#1)-它适合我的需要更好。

I needed commercial quality alternative to clock_gettime() to make pthread_…timed.. calls, and found this discussion very helpful. Thanks guys.

我需要一个商业质量的替代品来代替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(&micro, 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(&micro, 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;
}

#4


30  

#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

#5


19  

Everything you need is described in Technical Q&A QA1398: Technical Q&A QA1398: Mach Absolute Time Units, basically the function you want is mach_absolute_time.

你所需要的一切都在技术问答《QA1398:技术问答》中描述:Mach绝对时间单元,基本上你想要的功能是mach_absolute_time。

Here's a slightly earlier version of the sample code from that page that does everything using Mach calls (the current version uses AbsoluteToNanoseconds from CoreServices). In current OS X (i.e., on Snow Leopard on x86_64) the absolute time values are actually in nanoseconds and so don't actually require any conversion at all. So, if you're good and writing portable code, you'll convert, but if you're just doing something quick and dirty for yourself, you needn't bother.

这里有一个稍早的版本的示例代码,它使用Mach调用来完成所有操作(当前版本使用的是CoreServices的绝对命令)。在当前OS X中(即:在x86_64上的雪豹上,绝对时间值实际上是在纳秒内,所以实际上不需要任何转换。所以,如果你擅长编写可移植的代码,你就会转换,但是如果你只是为自己做一些快速而肮脏的事情,你就不必麻烦了。

FWIW, mach_absolute_time is really fast.

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;
}

#6


11  

Note that macOS Sierra 10.12 now supports clock_gettime():

注意,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);
}

It does provide nanoseconds; however, the resolution is 1000, so it is (in)effectively limited to microseconds:

它提供纳秒;然而,分辨率是1000,所以它实际上是限制在微秒内:

CLOCK_REALTIME: res.tv_sec=0 res.tv_nsec=1000
CLOCK_REALTIME: time.tv_sec=1475279260 time.tv_nsec=525627000

You will need XCode 8 or later to be able to use this feature. Code compiled to use this feature will not run on versions of Mac OS X (10.11 or earlier).

您将需要XCode 8或稍后才能使用这个特性。使用该特性编译的代码不会在Mac OS X(10.11或更早的版本)上运行。

#7


8  

Thanks for your posts

谢谢你的帖子

I think you can add the following lines

我认为你可以添加以下几行。

#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

Let me know what you get for latency and granularity

让我知道您在延迟和粒度上得到了什么。

#8


4  

Maristic has the best answer here to date. Let me simplify and add a remark. #include and Init():

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;
}

Use as:

使用:

  uint64_t t1, t2;

  Init();

  t1 = mach_absolute_time();
  /* profiled code here */
  t2 = mach_absolute_time();

  double duration_ns = (double)(t2 - t1) * conversion_factor;  

Such timer has latency of 65ns +/- 2ns (2GHz CPU). Use this if you need "time evolution" of single execution. Otherwise loop your code 10000 times and profile even with gettimeofday(), which is portable (POSIX), and has the latency of 100ns +/- 0.5ns (though only 1us granularity).

这样的计时器有65ns +/- 2ns (2GHz CPU)的延迟。如果您需要单执行的“时间演进”,请使用它。否则,即使gettimeofday()是可移植的(POSIX),它也会对代码进行10000次和概要的循环,并具有100ns +/- 0.5ns的延迟(尽管只有1个粒度)。

#9


3  

I tried the version with clock_get_time, and did cache the host_get_clock_service call. It's way slower than gettimeofday, it takes several microseconds per invocation. And, what's worse, the return value has steps of 1000, i.e. it's still microsecond granularity.

我使用clock_get_time尝试了这个版本,并缓存了host_get_clock_service调用。它比gettimeofday慢得多,每次调用需要几微秒。更糟糕的是,返回值的步骤是1000,也就是说,它仍然是微秒粒度。

I'd advice to use gettimeofday, and multiply tv_usec by 1000.

我建议使用gettimeofday,并将tv_usec乘以1000。

#10


2  

Based on the open source mach_absolute_time.c we can see that the line extern mach_port_t clock_port; tells us there's a mach port already initialized for monotonic time. This clock port can be accessed directly without having to resort to calling mach_absolute_time then converting back to a struct timespec. Bypassing a call to mach_absolute_time should improve performance.

基于开源mach_absolute_time。我们可以看到这条线是:mach_port_t clock_port;告诉我们有一个mach端口已经初始化为单调的时间。这个时钟端口可以直接访问,而不必调用mach_absolute_time然后转换回struct timespec。通过调用mach_absolute_time可以提高性能。

I created a small Github repo (PosixMachTiming) with the code based on the extern clock_port and a similar thread. PosixMachTiming emulates clock_gettime for CLOCK_REALTIME and CLOCK_MONOTONIC. It also emulates the function clock_nanosleep for absolute monotonic time. Please give it a try and see how the performance compares. Maybe you might want to create comparative tests or emulate other POSIX clocks/functions?

我创建了一个小Github repo (PosixMachTiming),它的代码基于外部的clock_port和一个类似的线程。PosixMachTiming为CLOCK_REALTIME和clock_单调复制了clock_gettime。它还模拟了在完全单调的时间内的函数clock_nanosleep。请试一试,看看性能如何比较。也许您可能想要创建比较测试或模拟其他POSIX时钟/函数?

#11


1  

As of at least as far back as Mountain Lion, mach_absolute_time() returns nanoseconds and not absolute time (which was the number of bus cycles).

至少就像Mountain Lion一样,mach_absolute_time()返回的是纳秒,而不是绝对时间(这是总线周期的数量)。

The following code on my MacBook Pro (2 GHz Core i7) showed that the time to call mach_absolute_time() averaged 39 ns over 10 runs (min 35, max 45), which is basically the time between the return of the two calls to mach_absolute_time(), about 1 invocation:

我的MacBook Pro (2 GHz Core i7)上的以下代码显示,调用mach_absolute_time()的时间平均为39 ns / 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;
}

#12


0  

I found another portable solution.

我找到了另一个便携的解决方案。

Declare in some header file (or even in your source one):

在一些头文件中声明(甚至在源文件中):

/* If compiled on DARWIN/Apple platforms. */
#ifdef DARWIN
#define    CLOCK_REALTIME    0x2d4e1588
#define    CLOCK_MONOTONIC   0x0
#endif /* DARWIN */

And the add the function implementation:

并添加功能实现:

#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 */

Don't forget to include <time.h>.

不要忘记包含

#13


0  

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);

For MacOS you can find a good information on their developers page https://developer.apple.com/library/content/documentation/Darwin/Conceptual/KernelProgramming/services/services.html

对于MacOS,你可以在他们的开发者页面上找到一个好的信息。

#1


28  

In effect, it seems not to be implemented for macOS before Sierra 10.12. You may want to look at this blog entry, but this doesn't seem to be available anymore. The main idea is in the following code snippet:

实际上,在Sierra 10.12之前,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;
}

#2


124  

After hours of perusing different answers, blogs, and headers, I found a portable way to get the current time:

经过几个小时的不同的回答、博客和标题之后,我找到了一种可以移动的方式来获取当前的时间:

#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

or check out this gist: https://gist.github.com/1087739

或者看看这个要点:https://gist.github.com/1087739。

Hope this saves someone time. Cheers!

希望这能节省时间。干杯!

#3


31  

None of the solutions above answers the question. Either they don't give you absolute Unix time, or their accuracy is 1 microsecond. The most popular solution by jbenet is slow (~6000ns) and does not count in nanoseconds even though its return suggests so. Below is a test for 2 solutions suggested by jbenet and Dmitri B, plus my take on this. You can run the code without changes.

以上的解决方案都不能回答这个问题。要么他们没有给你绝对的Unix时间,要么他们的精度是1微秒。jbenet最流行的解决方案是缓慢的(~6000ns),即使它的返回表明它是纳秒,也不会被计算在内。下面是jbenet和Dmitri B提出的两个解决方案的测试,再加上我对此的看法。您可以在不更改的情况下运行代码。

The 3rd solution does count in nanoseconds and gives you absolute Unix time reasonably fast (~90ns). So if someone find it useful - please let us all know here :-). I will stick to the one from Dmitri B (solution #1 in the code) - it fits my needs better.

第三个解决方案在纳秒内计数,并且给您绝对的Unix时间相当快(~90ns)。因此,如果有人发现它有用,请让我们都知道:-)。我将坚持从Dmitri B(代码中的解决方案#1)-它适合我的需要更好。

I needed commercial quality alternative to clock_gettime() to make pthread_…timed.. calls, and found this discussion very helpful. Thanks guys.

我需要一个商业质量的替代品来代替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(&micro, 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(&micro, 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;
}

#4


30  

#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

#5


19  

Everything you need is described in Technical Q&A QA1398: Technical Q&A QA1398: Mach Absolute Time Units, basically the function you want is mach_absolute_time.

你所需要的一切都在技术问答《QA1398:技术问答》中描述:Mach绝对时间单元,基本上你想要的功能是mach_absolute_time。

Here's a slightly earlier version of the sample code from that page that does everything using Mach calls (the current version uses AbsoluteToNanoseconds from CoreServices). In current OS X (i.e., on Snow Leopard on x86_64) the absolute time values are actually in nanoseconds and so don't actually require any conversion at all. So, if you're good and writing portable code, you'll convert, but if you're just doing something quick and dirty for yourself, you needn't bother.

这里有一个稍早的版本的示例代码,它使用Mach调用来完成所有操作(当前版本使用的是CoreServices的绝对命令)。在当前OS X中(即:在x86_64上的雪豹上,绝对时间值实际上是在纳秒内,所以实际上不需要任何转换。所以,如果你擅长编写可移植的代码,你就会转换,但是如果你只是为自己做一些快速而肮脏的事情,你就不必麻烦了。

FWIW, mach_absolute_time is really fast.

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;
}

#6


11  

Note that macOS Sierra 10.12 now supports clock_gettime():

注意,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);
}

It does provide nanoseconds; however, the resolution is 1000, so it is (in)effectively limited to microseconds:

它提供纳秒;然而,分辨率是1000,所以它实际上是限制在微秒内:

CLOCK_REALTIME: res.tv_sec=0 res.tv_nsec=1000
CLOCK_REALTIME: time.tv_sec=1475279260 time.tv_nsec=525627000

You will need XCode 8 or later to be able to use this feature. Code compiled to use this feature will not run on versions of Mac OS X (10.11 or earlier).

您将需要XCode 8或稍后才能使用这个特性。使用该特性编译的代码不会在Mac OS X(10.11或更早的版本)上运行。

#7


8  

Thanks for your posts

谢谢你的帖子

I think you can add the following lines

我认为你可以添加以下几行。

#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

Let me know what you get for latency and granularity

让我知道您在延迟和粒度上得到了什么。

#8


4  

Maristic has the best answer here to date. Let me simplify and add a remark. #include and Init():

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;
}

Use as:

使用:

  uint64_t t1, t2;

  Init();

  t1 = mach_absolute_time();
  /* profiled code here */
  t2 = mach_absolute_time();

  double duration_ns = (double)(t2 - t1) * conversion_factor;  

Such timer has latency of 65ns +/- 2ns (2GHz CPU). Use this if you need "time evolution" of single execution. Otherwise loop your code 10000 times and profile even with gettimeofday(), which is portable (POSIX), and has the latency of 100ns +/- 0.5ns (though only 1us granularity).

这样的计时器有65ns +/- 2ns (2GHz CPU)的延迟。如果您需要单执行的“时间演进”,请使用它。否则,即使gettimeofday()是可移植的(POSIX),它也会对代码进行10000次和概要的循环,并具有100ns +/- 0.5ns的延迟(尽管只有1个粒度)。

#9


3  

I tried the version with clock_get_time, and did cache the host_get_clock_service call. It's way slower than gettimeofday, it takes several microseconds per invocation. And, what's worse, the return value has steps of 1000, i.e. it's still microsecond granularity.

我使用clock_get_time尝试了这个版本,并缓存了host_get_clock_service调用。它比gettimeofday慢得多,每次调用需要几微秒。更糟糕的是,返回值的步骤是1000,也就是说,它仍然是微秒粒度。

I'd advice to use gettimeofday, and multiply tv_usec by 1000.

我建议使用gettimeofday,并将tv_usec乘以1000。

#10


2  

Based on the open source mach_absolute_time.c we can see that the line extern mach_port_t clock_port; tells us there's a mach port already initialized for monotonic time. This clock port can be accessed directly without having to resort to calling mach_absolute_time then converting back to a struct timespec. Bypassing a call to mach_absolute_time should improve performance.

基于开源mach_absolute_time。我们可以看到这条线是:mach_port_t clock_port;告诉我们有一个mach端口已经初始化为单调的时间。这个时钟端口可以直接访问,而不必调用mach_absolute_time然后转换回struct timespec。通过调用mach_absolute_time可以提高性能。

I created a small Github repo (PosixMachTiming) with the code based on the extern clock_port and a similar thread. PosixMachTiming emulates clock_gettime for CLOCK_REALTIME and CLOCK_MONOTONIC. It also emulates the function clock_nanosleep for absolute monotonic time. Please give it a try and see how the performance compares. Maybe you might want to create comparative tests or emulate other POSIX clocks/functions?

我创建了一个小Github repo (PosixMachTiming),它的代码基于外部的clock_port和一个类似的线程。PosixMachTiming为CLOCK_REALTIME和clock_单调复制了clock_gettime。它还模拟了在完全单调的时间内的函数clock_nanosleep。请试一试,看看性能如何比较。也许您可能想要创建比较测试或模拟其他POSIX时钟/函数?

#11


1  

As of at least as far back as Mountain Lion, mach_absolute_time() returns nanoseconds and not absolute time (which was the number of bus cycles).

至少就像Mountain Lion一样,mach_absolute_time()返回的是纳秒,而不是绝对时间(这是总线周期的数量)。

The following code on my MacBook Pro (2 GHz Core i7) showed that the time to call mach_absolute_time() averaged 39 ns over 10 runs (min 35, max 45), which is basically the time between the return of the two calls to mach_absolute_time(), about 1 invocation:

我的MacBook Pro (2 GHz Core i7)上的以下代码显示,调用mach_absolute_time()的时间平均为39 ns / 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;
}

#12


0  

I found another portable solution.

我找到了另一个便携的解决方案。

Declare in some header file (or even in your source one):

在一些头文件中声明(甚至在源文件中):

/* If compiled on DARWIN/Apple platforms. */
#ifdef DARWIN
#define    CLOCK_REALTIME    0x2d4e1588
#define    CLOCK_MONOTONIC   0x0
#endif /* DARWIN */

And the add the function implementation:

并添加功能实现:

#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 */

Don't forget to include <time.h>.

不要忘记包含

#13


0  

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);

For MacOS you can find a good information on their developers page https://developer.apple.com/library/content/documentation/Darwin/Conceptual/KernelProgramming/services/services.html

对于MacOS,你可以在他们的开发者页面上找到一个好的信息。