OSX上的单调时钟

Bre*_*ett 22 macos posix timing objective-c clock

CLOCK_MONOTONIC似乎不可用,所以clock_gettime已经用完了.

我在某些地方读过,mach_absolute_time()可能是正确的方法,但在阅读之后它是一个'cpu依赖值',它立即让我想知道它是否在下面使用rtdsc.因此,即使它是单调的,该值也可能随时间漂移.此外,线程关联性问题可能会导致调用函数产生有意义的不同结果(使其在所有内核中不是单调的).

当然,这只是猜测.有谁知道mach_absolute_time实际上是如何工作的?我实际上正在寻找clock_gettime的替代品(CL​​OCK_MONOTONIC ......或类似于OSX的东西.无论时钟源是什么,我都期望至少毫秒精度和毫秒精度.

我只想了解哪些时钟可用,哪些时钟是单调的,如果某些时钟漂移,有线程亲和性问题,所有Mac硬件都不支持,或者执行"超高"数量的cpu周期.

以下是我能够找到关于这个主题的链接(一些已经死链接,但在archive.org上找不到):

https://developer.apple.com/library/mac/#qa/qa1398/_index.html http://www.wand.net.nz/~smr26/wordpress/2009/01/19/monotonic-time-in -mac-os-x / http://www.meandmark.com/timing.pdf

谢谢!布雷特

zne*_*eak 25

Mach内核提供对系统时钟的访问,其中至少有一个(SYSTEM_CLOCK)由文档公布为单调递增.

#include <mach/clock.h>
#include <mach/mach.h>

clock_serv_t cclock;
mach_timespec_t mts;

host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
Run Code Online (Sandbox Code Playgroud)

mach_timespec_t具有纳秒精度.不过,我不确定准确性.

Mac OS X支持三种时钟:

  • SYSTEM_CLOCK 返回自启动时间以来的时间;
  • CALENDAR_CLOCK 返回自1970-01-01以来的UTC时间;
  • REALTIME_CLOCK已弃用,SYSTEM_CLOCK与其当前实现中的相同.

除非有人打电话,否则说明时钟的文件clock_get_time是单调递增的clock_set_time.调用clock_set_time鼓励,因为它可以打破时钟的单调性,事实上,目前的实现返回KERN_FAILURE而不做任何事情.


alf*_*att 9

在查找了几个不同的答案之后,我最终定义了一个在mach上模拟clock_gettime的标题:

#include <sys/types.h>
#include <sys/_types/_timespec.h>
#include <mach/mach.h>
#include <mach/clock.h>

#ifndef mach_time_h
#define mach_time_h

/* The opengroup spec isn't clear on the mapping from REALTIME to CALENDAR
 being appropriate or not.
 http://pubs.opengroup.org/onlinepubs/009695299/basedefs/time.h.html */

// XXX only supports a single timer
#define TIMER_ABSTIME -1
#define CLOCK_REALTIME CALENDAR_CLOCK
#define CLOCK_MONOTONIC SYSTEM_CLOCK

typedef int clockid_t;

/* the mach kernel uses struct mach_timespec, so struct timespec
    is loaded from <sys/_types/_timespec.h> for compatability */
// struct timespec { time_t tv_sec; long tv_nsec; };

int clock_gettime(clockid_t clk_id, struct timespec *tp);

#endif
Run Code Online (Sandbox Code Playgroud)

并在mach_gettime.c中

#include "mach_gettime.h"
#include <mach/mach_time.h>

#define MT_NANO (+1.0E-9)
#define MT_GIGA UINT64_C(1000000000)

// TODO create a list of timers,
static double mt_timebase = 0.0;
static uint64_t mt_timestart = 0;

// TODO be more careful in a multithreaded environement
int clock_gettime(clockid_t clk_id, struct timespec *tp)
{
    kern_return_t retval = KERN_SUCCESS;
    if( clk_id == TIMER_ABSTIME)
    {
        if (!mt_timestart) { // only one timer, initilized on the first call to the TIMER
            mach_timebase_info_data_t tb = { 0 };
            mach_timebase_info(&tb);
            mt_timebase = tb.numer;
            mt_timebase /= tb.denom;
            mt_timestart = mach_absolute_time();
        }

        double diff = (mach_absolute_time() - mt_timestart) * mt_timebase;
        tp->tv_sec = diff * MT_NANO;
        tp->tv_nsec = diff - (tp->tv_sec * MT_GIGA);
    }
    else // other clk_ids are mapped to the coresponding mach clock_service
    {
        clock_serv_t cclock;
        mach_timespec_t mts;

        host_get_clock_service(mach_host_self(), clk_id, &cclock);
        retval = clock_get_time(cclock, &mts);
        mach_port_deallocate(mach_task_self(), cclock);

        tp->tv_sec = mts.tv_sec;
        tp->tv_nsec = mts.tv_nsec;
    }

    return retval;
}
Run Code Online (Sandbox Code Playgroud)