文档章节

Linux系统下的单调时间函数

invictus_lee
 invictus_lee
发布于 2014/10/22 10:49
字数 1036
阅读 277
收藏 0

一、编写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.
    4、syscall(SYS_clock_gettime, CLOCK_MONOTONIC_RAW, &monotonic_time)
        该函数提供了真正意义上的单调递增时间(见三)


二、glibc 中clock_gettime(CLOCK_MONOTONIC)的原理
    查看glibc的代码可以看到这个数值是由内核计算的。

    __vdso_clock_gettime-------->do_monotonic
    这个函数的实现如下:
    

点击(此处)折叠或打开

  1. notrace static noinline int do_monotonic(struct timespec *ts)

  2. {

  3.         unsigned long seq, ns, secs;

  4.         do {

  5.                 seq = read_seqbegin(&gtod->lock);

  6.                 secs = gtod->wall_time_sec;

  7.                 ns = gtod->wall_time_nsec + vgetns();

  8.                 secs += gtod->wall_to_monotonic.tv_sec;

  9.                 ns += gtod->wall_to_monotonic.tv_nsec;

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


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

  12.          * are all guaranteed to be nonnegative.

  13.          */

  14.         while (ns >= NSEC_PER_SEC) {

  15.                 ns -= NSEC_PER_SEC;

  16.                 ++secs;

  17.         } 

  18.         ts->tv_sec = secs;

  19.         ts->tv_nsec = ns; 


  20.         return 0;

  21. }

这个代码读取墙上时间,然后加上相对于单调时间的便宜,从而得到单调时间,但是这里并没有考虑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的实现
    

点击(此处)折叠或打开

  1. struct k_clock clock_monotonic_raw = {

  2.                 .clock_getres = hrtimer_get_res,

  3.                 .clock_get = posix_get_monotonic_raw,

  4.         };



  5. posix_timers_register_clock(CLOCK_MONOTONIC_RAW, &clock_monotonic_raw);




  6. /*

  7.  * Get monotonic-raw time for posix timers

  8.  */

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

  10. {

  11.         getrawmonotonic(tp);

  12.         return 0;

  13. }



  14. /**

  15.  * getrawmonotonic - Returns the raw monotonic time in a timespec

  16.  * @ts : pointer to the timespec to be set

  17.  *

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

  19.  */

  20. void getrawmonotonic(struct timespec *ts)

  21. {

  22.         unsigned long seq;

  23.         s64 nsecs;


  24.         do {

  25.                 seq = read_seqbegin(&xtime_lock);

  26.                 nsecs = timekeeping_get_ns_raw();

  27.                 *ts = raw_time;


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


  29.         timespec_add_ns(ts, nsecs);

  30. }

  31. EXPORT_SYMBOL(getrawmonotonic);



  32. static inline s64 timekeeping_get_ns_raw(void)

  33. {

  34.         cycle_t cycle_now, cycle_delta;

  35.         struct clocksource *clock;


  36.         /* read clocksource: */

  37.         clock = timekeeper.clock;

  38.         cycle_now = clock->read(clock);


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

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


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

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

  43. }


四、关于wall time和monotonic time
    
wall time:xtime,取决于用于对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://blog.chinaunix.net/uid-20662820-id-3880162.html

invictus_lee

invictus_lee

粉丝 1
博文 141
码字总数 21423
作品 2
徐汇
程序员
私信 提问
GLFW 2.7.5 发布,OpenGL 应用框架

GLFW 2.7.5 发布了,该版本修复了特定 Mac OS X 版本下的编译错误,支持 Cocoa 的单调时间输入。 GLFW是一个OpenGL的应用框架,支持Linux和Windows。GLFW 主要用来处理特定操作系统下的特定任...

红薯
2012/04/16
686
4
CFS调度算法的思想和细节

今天在邮件列表里面有位朋友问了一个问题,问题表述如下: 在唤醒进程的时候,发现在check_preempt_wakeup()中.会将 cfs_rq->next设置为唤醒的进程,cfs_rq->last设置为当前的运行进程.然后将要...

晨曦之光
2012/04/10
2.1K
0
linux shell脚本编程学习总结

0.linux shell脚本编程 对于一些简单的操作,我们可以直接通过在linux 命令行执行就可以了,比如列出文件命令ls -l,但是有时候我们需要完成的任务需要连续执行多条linux命令,而且他们之间具...

i_am_alone
2018/08/11
0
0
linux设备驱动时间、延迟及延缓操作

hz:上述间隔由hz的值设定,hz是一个与体系结构相关的常数 计数器:发生中断一次,计数器加一,这个计数器的值(只有)在系统引导时被初始化为0 jiffies变量:unsigned long 型变量,要么与jif...

慎思
2012/08/10
357
0
Linux系统时间和硬件时间设置

在Linux中有硬件时钟与系统时钟两种时钟。硬件时钟是指主机板上的时钟设备,也就是通常可在BIOS画面设定的时钟。系统时钟则是指kernel中的时钟。所有Linux相关指令与函数都是读取系统时钟的设...

舆图易稿
2014/03/28
0
0

没有更多内容

加载失败,请刷新页面

加载更多

详解tomcat的连接数与线程池

前言 在使用tomcat时,经常会遇到连接数、线程数之类的配置问题,要真正理解这些概念,必须先了解Tomcat的连接器(Connector)。 在前面的文章 详解Tomcat配置文件server.xml 中写到过:Con...

xiaomin0322
19分钟前
3
0
分布式锁的由来、特点、及Redis分布式锁的实现详解

什么是分布式锁 要介绍分布式锁,首先要提到与分布式锁相对应的是线程锁、进程锁。 1.线程锁 主要用来给方法、代码块加锁。当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代...

一只会编程的狼
23分钟前
5
0
docker+tomcat+负载均衡

1、首先安装docker docker安装 2、docker安装tomcat docker安装tomcat(支持多个) 3、docker按照nginx docker按照nginx 可能在最后你放我项目地址后,会发现nginx样式丢失先现象,不用慌,按...

你好夜故事
27分钟前
4
0
【巨杉数据库SequoiaDB】巨杉⼯具系列之一 | ⼤对象存储⼯具sdblobtool

近期,巨杉数据库正式推出了完整的SequoiaDB 工具包,作为辅助工具,更好地帮助大家使用和运维管理分布式数据库。为此,巨杉技术社区还将持续推出工具系列文章,帮助大家了解巨杉数据库丰富的...

巨杉数据库
27分钟前
3
0
软件开发相关规范

1,语义化版本 2.0.0

四季变幻
35分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部