sunplusedu的个人空间 https://blog.eetop.cn/sunplusedu [收藏] [复制] [分享] [RSS]

空间首页 动态 记录 日志 相册 主题 分享 留言板 个人资料

日志

总结:Linux系统下的单调时间函数

已有 2167 次阅读| 2013-9-4 14:53

          来自凌阳教育嵌入式培训 网

    一、编写linux下应用程序的时候,有时候会用到高精度相对时间的概念,比如间隔100ms。那么应该使用哪个时间函数更准确呢?

    1、time

    该函数返回的是自1970年以来的秒数,显然精度不够,不能使用

    2、gettimeofday

    该函数返回的是自1970年以来的秒数和微秒数,精度显然是够了。我想有很多程序员也是用的这个函数来计算相对时间的,如果说系统时间因为ntp等原因发生时间跳变,那么用这个函数来计算相对时间是不是就会出问题了。所以说这个函数也不能使用

    3、clock_gettime

    该函数提供了4种类型CLOCK_REALTIME、CLOCK_MONOTONIC、CLOCK_PROCESS_CPUTIMEID、CLOCK_THREAD_CPUTIME_ID。从字面意思可以判断出来,CLOCK_MONOTONIC提供了单调递增的时间戳,该函数返回值为自系统启动后秒数和纳秒数,但是该函数没有考虑ntp的情况,所以并不是绝对意义上的单调递增(见二)。

    CLOCK_REALTIME is affected by settime()/settimeofday() calls and can also be frequency corrected by NTP via adjtimex().

    CLOCK_MONOTONIC is not affected by settime()/settimeofday(), but is frequency adjusted by NTP via adjtimex().With Linux,NTP normally uses settimeofday() for large corrections (over half a second). The adjtimex() inteface allows for small clock frequency changes (slewing). This can be done in a few different ways, see the man page for adjtimex.

    CLOCK_MONOTONIC_RAW that will not be modified at all, and will have a linear correlation with the hardware counters.

    4syscall(SYS_clock_gettime, CLOCK_MONOTONIC_RAW, &monotonic_time)

    该函数提供了真正意义上的单调递增时间(见三)

    二、glibc clock_gettime(CLOCK_MONOTONIC)的原理

    查看glibc的代码可以看到这个数值是由内核计算的。

    __vdso_clock_gettime-------->do_monotonic

    这个函数的实现如下:

    点击(此处)折叠或打开

    notrace static noinline int do_monotonic(struct timespec *ts)

    {

    unsigned long seq, ns, secs;

    do {

    seq = read_seqbegin(&gtod->lock);

    secs = gtod->wall_time_sec;

    ns = gtod->wall_time_nsec + vgetns();

    secs += gtod->wall_to_monotonic.tv_sec;

    ns += gtod->wall_to_monotonic.tv_nsec;

    } while (unlikely(read_seqretry(&gtod->lock, seq)));

    /* wall_time_nsec, vgetns(), and wall_to_monotonic.tv_nsec

    * are all guaranteed to be nonnegative.

    */

    while (ns >= NSEC_PER_SEC) {

    ns -= NSEC_PER_SEC;

    ++secs;

    }

    ts->tv_sec = secs;

    ts->tv_nsec = ns;

    return 0;

    }

    这个代码读取墙上时间,然后加上相对于单调时间的便宜,从而得到单调时间,但是这里并没有考虑ntp通过adjtimex()调整小的时间偏差的情况,所以这个仍然不是绝对的单调递增。

    三、内核clock_gettime系统调用

    在kernel/posix-timers.c中内核实现了clock_gettime的系统调用,包括CLOCK_REALTIME、CLOCK_MONOTONIC、CLOCK_MONOTONIC_RAW、CLOCK_REALTIME_COARSE、CLOCK_MONOTONIC_COARSE、CLOCK_BOOTTIME等类型,这里我们看一下CLOCK_MONOTONIC_RAW的实现

    点击(此处)折叠或打开

    struct k_clock clock_monotonic_raw = {

    .clock_getres = hrtimer_get_res,

    .clock_get = posix_get_monotonic_raw,

    };

    posix_timers_register_clock(CLOCK_MONOTONIC_RAW, &clock_monotonic_raw);

    /*

    * Get monotonic-raw time for posix timers

    */

    static int posix_get_monotonic_raw(clockid_t which_clock, struct timespec *tp)

    {

    getrawmonotonic(tp);

    return 0;

    }

    /**

    * getrawmonotonic - Returns the raw monotonic time in a timespec

    * @ts: pointer to the timespec to be set

    *

    * Returns the raw monotonic time (completely un-modified by ntp)

    */

    void getrawmonotonic(struct timespec *ts)

    {

    unsigned long seq;

    s64 nsecs;

    do {

    seq = read_seqbegin(&xtime_lock);

    nsecs = timekeeping_get_ns_raw();

    *ts = raw_time;

    } while (read_seqretry(&xtime_lock, seq));

    timespec_add_ns(ts, nsecs);

    }

    EXPORT_SYMBOL(getrawmonotonic);

    static inline s64 timekeeping_get_ns_raw(void)

    {

    cycle_t cycle_now, cycle_delta;

    struct clocksource *clock;

    /* read clocksource: */

    clock = timekeeper.clock;

    cycle_now = clock->read(clock);

    /* calculate the delta since the last update_wall_time: */

    cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;

    /* return delta convert to nanoseconds using ntp adjusted mult. */

    return clocksource_cyc2ns(cycle_delta, clock->mult, clock->shift);

    }

    四、关于wall timemonotonic time

    wall timextime取决于用于对xtime计时的clocksource它的精度甚至可以达到纳秒级别内核大部分时间都是使用xtime来获得当前时间信息xtime记录的是自1970年当前时刻所经历的纳秒数。

    monotonic time: 该时间自系统开机后就一直单调地增加(ntp adjtimex会影响其单调性),它不像xtime可以因用户的调整时间而产生跳变,不过该时间不计算系统休眠的时间,也就是说,系统休眠时(total_sleep_time),monotoic时间不会递增。

    raw monotonic time: 该时间与monotonic时间类似,也是单调递增的时间,唯一的不同是,raw monotonic time不会受到NTP时间调整的影响,它代表着系统独立时钟硬件对时间的统计。

    boot time:  与monotonic时间相同,不过会累加上系统休眠的时间(total_sleep_time),它代表着系统上电后的总时间。

    五、总结

    在linux下获取高精度单调递增的时间,只能使用syscall(SYS_clock_gettime, CLOCK_MONOTONIC_RAW, &monotonic_time)获取!

    转自:http://emb.sunplusedu.com/answer/2013/0904/2142.html


点赞

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 注册

  • 关注TA
  • 加好友
  • 联系TA
  • 0

    周排名
  • 0

    月排名
  • 0

    总排名
  • 0

    关注
  • 1

    粉丝
  • 0

    好友
  • 0

    获赞
  • 2

    评论
  • 1927

    访问数
关闭

站长推荐 上一条 /1 下一条

小黑屋| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-5-14 01:14 , Processed in 0.014948 second(s), 6 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
返回顶部