[Timer学习]wall time和monotonic time
来源:互联网 发布:网络棋牌论坛推广途径 编辑:程序博客网 时间:2024/05/17 03:00
article 1
在一些系统调用中需要指定时间是用CLOCK_MONOTONIC还是CLOCK_REALTIME,以前总是搞不太清楚它们之间的差别,现在终于有所理解了。
CLOCK_MONOTONIC是monotonic time,而CLOCK_REALTIME是wall time。
monotonic time字面意思是单调时间,实际上它指的是系统启动以后流逝的时间,这是由变量jiffies来记录的。系统每次启动时jiffies初始化为0,每来一个timer interrupt,jiffies加1,也就是说它代表系统启动后流逝的tick数。jiffies一定是单调递增的,因为时间不够逆嘛!
wall time字面意思是挂钟时间,实际上就是指的是现实的时间,这是由变量xtime来记录的。系统每次启动时将CMOS上的RTC时间读入xtime,这个值是"自1970-01-01起经历的秒数、本秒中经历的纳秒数",每来一个timer interrupt,也需要去更新xtime。
以前我一直想不明白,既然每个timer interrupt,jiffies和xtime都要更新,那么不都是单调递增的吗?那它们之间使用时有什么区别呢?昨天看到一篇文章,终于明白了,wall time不一定是单调递增的。因为wall time是指现实中的实际时间,如果系统要与网络中某个节点时间同步、或者由系统管理员觉得这个wall time与现实时间不一致,有可能任意的改变这个wall time。最简单的例子是,我们用户可以去任意修改系统时间,这个被修改的时间应该就是wall time,即xtime,它甚至可以被写入RTC而永久保存。一些应用软件可能就是用到了这个wall time,比如以前用vmware workstation,一启动提示试用期已过,但是只要把系统时间调整一下提前一年,再启动就不会有提示了,这很可能就是因为它启动时用gettimeofday去读wall time,然后判断是否过期,只要将wall time改一下,就可以欺骗过去了。
///////////////////////////////////
articale 2
Clock_realtime
CLOCK_MONOTONIC
函数的原型如下:
int clock_gettime(clockid_t clk_id, struct timespect *tp);
clockid_tclk_id用于指定计时时钟的类型,对于我们Programmr以下三种比较常用:
struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
- 代码
- #include <iostream>
- #include <time.h>
- using namespace std;
- timespec diff(timespec start, timespec end);
- int main()
- {
- timespec time1, time2;
- int temp;
- clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1);
- for (int i = 0; i< 242000000; i++)
- temp+=temp;
- clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time2);
- cout<<diff(time1,time2).tv_sec<<":"<<diff(time1,time2).tv_nsec<<endl;
- return 0;
- }
- timespec diff(timespec start, timespec end)
- {
- timespec temp;
- if ((end.tv_nsec-start.tv_nsec)<0) {
- temp.tv_sec = end.tv_sec-start.tv_sec-1;
- temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
- } else {
- temp.tv_sec = end.tv_sec-start.tv_sec;
- temp.tv_nsec = end.tv_nsec-start.tv_nsec;
- }
- return temp;
- }
//////////////////////////
article 3一、编写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
这个函数的实现如下:
点击(此处)折叠或打开
- notrace static noinlineint do_monotonic(struct timespec*ts)
- {
- unsigned long seq, ns, secs;
- do{
- seq = read_seqbegin(>od->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(>od->lock, seq)));
- /* wall_time_nsec, vgetns(),and wall_to_monotonic.tv_nsec
- * are all guaranteedto be nonnegative.
- */
- while(ns>= NSEC_PER_SEC){
- ns -= NSEC_PER_SEC;
- ++secs;
- }
- ts->tv_sec= secs;
- ts->tv_nsec= ns;
- return 0;
- }
三、内核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-rawtime 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: pointerto the timespec to beset
- *
- * 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 convertto nanoseconds using ntp adjusted mult.*/
- return clocksource_cyc2ns(cycle_delta, clock->mult, clock->shift);
- }
四、关于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)获取!
- [Timer学习]wall time和monotonic time
- Wall time(real time), Process time和Monotonic time.
- 用户CPU时间, 系统CPU时间,CPU时间,Wall time, Process time和Monotonic time.
- Wall Time
- linux time和timer
- wall clock time(response time)
- CPU time与WALL time
- CPU time与WALL time
- Wall clock time
- 什么是wall clock time
- VB函数Time和Timer的区别
- linux中的wall clock time
- java timer show the time
- Time 与Timer 函数解释
- Timer schedule 与Time cancel
- boost asio timer,linux time and timer
- time
- time
- 更改myeclipse默认工作空间
- HDU 1051 Wooden Sticks 排序+最长递增
- Android自定义View------指南针
- 免费软件如何赚钱?
- 解决QT中Warning中Wreorder
- [Timer学习]wall time和monotonic time
- 题目1460:Oil Deposit(Flood Fill)
- Socket编程原理
- HDU 2109 Fighting for HDU 排序
- android View Stub
- CString Format函数 VS2013
- UICollectionView 集合视图
- 利用Xstream注解实现xml和java bean之间的转换
- java学习笔记(1)