Linux系统下的单调时间函数

欢迎转载,转载请注明出处:http://forever.blog.chinaunix.net

一、编写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)获取!

时间: 2024-12-23 14:24:58

Linux系统下的单调时间函数的相关文章

linux系统下如何使用assert函数

  linux系统下使用assert函数的方法. 步骤如下: assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,原型定义: #include <assert.h> void assert( int expression ); assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息, 然后通过调用 abort 来终止程序运行. 请看下面的程序清单badptr.c: #inc

Linux系统下使用ntpdate同步时间

ntpd.ntpdate的区别 使用之前得弄清楚一个问题,ntpd与ntpdate在更新时间时有什么区别.ntpd不仅仅是时间同步服务器,他还可以做客户端与标准时间服务器进行同步时间,而且是平滑同步,并非ntpdate立即同步,在生产环境中慎用ntpdate,也正如此两者不可同时运行. 时钟的跃变,对于某些程序会导致很严重的问题.许多应用程序依赖连续的时钟--毕竟,这是一项常见的假定,即,取得的时间是线性的,一些操作,例如数据库事务,通常会地依赖这样的事实:时间不会往回跳跃.不幸的是,ntpda

Linux系统下优秀的代理服务器软件:Squid

作为一种免费的网络操作系统,Linux越来越受到广大网络爱好者的欢迎,目前Internet上运行的主机有相当一部分采用的就是Linux,而且中国已经把Linux作为政府上网的指定网络操作系统.种种迹象表明,Linux正在逐渐走向成熟. 为了解决Internet发展迅速和IP地址资源紧张的矛盾,代理服务器的使用越来越广泛.Squid是一种在Linux系统下使用的比较优秀的代理服务器软件. 代理服务 代理服务是指由一台拥有标准IP地址的机器代替若干没有标准IP地址的机器和 Internet上的其它主

Linux系统下NTP协议的超级配置攻略

  在Linux系统中,为了避免主机时间因为在长时间运行下所导致的时间偏差,进行时间同步(synchronize)的工作是非常必要的.Linux系统下,一般使用ntp服务来同步不同机器的时间.NTP 是网络时间协议(Network Time Protocol)的简称,干嘛用的呢?就是通过网络协议使计算机之间的时间同步化. 安装NTP包 检查是否安装了ntp相关包.如果没有安装ntp相关包,使用rpm或yum安装,安装也非常简单方便. 复制代码 代码如下: [root@localhost ~]#

Linux 系统下查看硬件信息命令大全

Linux 系统下查看硬件信息命令大全 有许多命令可以用来查看 Linux 系统上的硬件信息.有些命令只能够打印出像 CPU 和内存这一特定的硬件组件信息,另外一些命令可以查看多种硬件组件的信息. 这个教程可以带大家快速了解一下查看各种硬件设备的信息和配置详情的最常用的命令. lscpu lscpu命令能够查看 CPU 和处理单元的信息.该命令没有任何其他选项或者别的功能. lscpu 运行该命令会看到下面输出: lspci lspci是另一个命令行工具,可以用来列出所有的 PCI 总线,还有与

Linux系统下完成Windows的开发环境替换

当下有很多的人都在Windows下进行开发工作,在Windows下搭建相关的开发环境并且使用各种开发工具进行工作.其实更多的专业开发人员会选择Linux操作系统作为他们大的系统环境.理由很简单,Linux运行起来更快,更灵活,更加安全. Windows下的开发环境以及软件 Visual Studio 2010 Visual Studio 是微软公司推出的开发环境.是目前最流行的 Windows 平台应用程序开发环境.Visual Studio 可以用来创建 Windows 平台下的 Window

Linux系统下fd分配的方法

最近几天在公司里写网络通讯的代码比较多,自然就会涉及到IO事件监测方法的问题.我惊奇的发现select轮训的方法在那里居然还大行其道.我告诉他们现在无论在Linux系统下,还是windows系统下,select都应该被废弃不用了,其原因是在两个平台上select的系统调用都有一个可以说是致命的坑. 在windows上面单个fd_set中容纳的socket handle个数不能超过FD_SETSIZE(在win32 winsock2.h里其定义为64,以VS2010版本为准),并且fd_set结构

如何在Linux系统下运行微信Web开发者工具

微信Web开发者工具只有window版本和mac版本,如果想要在Linux系统下运行微信Web开发者工具,需要花费很大周折. 注:带 * 的步骤或文件为不确定是否管用的步骤或文件. 本人系统为Linux Mint 18.1版本. 1.下载nwjs 下载nwjs(http://nwjs.io/)的SDK. 2.将微信web开发者工具拷贝到nwjs 将在window系统下安装的微信web开发者工具文件夹中的package.nw.icon.ico.* 微信web开发者工具.exe拷贝到nwjs sdk

入侵检测系统-急!linux系统下的基于特征串匹配攻击检测系统的问题

问题描述 急!linux系统下的基于特征串匹配攻击检测系统的问题 为什么运行了以后没反应就直接结束了啊?下面附代码 #include #include #include #include #include #include #include #include typedef struct Packetinfo{ u_char src_ip[4]; u_char dest_ip[4]; char *packetcontent; int contentlen; }PACKETINFO; typede