1、編寫linux下應用程序的時候,有時候會用到高精度相對時間的概念,好比間隔100ms。那麼應該使用哪一個時間函數更準確呢?
一、time
該函數返回的是自1970年以來的秒數,顯然精度不夠,不能使用
二、gettimeofday
該函數返回的是自1970年以來的秒數和微秒數,精度顯然是夠了。我想有不少程序員也是用的這個函數來計算相對時間的,若是說系統時間由於ntp等緣由發生時間跳變,那麼用這個函數來計算相對時間是否是就會出問題了。因此說這個函數也不能使用
三、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.linux
CLOCK_MONOTONIC_RAW that will not be modified at all, and will have a linear correlation with the hardware counters.
四、syscall(SYS_clock_gettime, CLOCK_MONOTONIC_RAW, &monotonic_time)
該函數提供了真正意義上的單調遞增時間(見三)程序員
點擊(此處)摺疊或打開函數
notrace static noinline int do_monotonic(struct timespec *ts)
spa
{
.net
unsigned long seq, ns, secs;
orm
do {
get
seq = read_seqbegin(>od->lock);
it
secs = gtod->wall_time_sec;
io
ns = gtod->wall_time_nsec + vgetns();
ast
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 guaranteed to be nonnegative.
*/
while (ns >= NSEC_PER_SEC) {
ns -= NSEC_PER_SEC;
++secs;
}
ts->tv_sec = secs;
ts->tv_nsec = ns;
return 0;
}
點擊(此處)摺疊或打開
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);
}
monotonic time: 該時間自系統開機後就一直單調地增長(ntp adjtimex會影響其單調性),它不像xtime能夠因用戶的調整時間而產生跳變,不過該時間不計算系統休眠的時間,也就是說,系統休眠時(total_sleep_time),monotoic時間不會遞增。
raw monotonic time: 該時間與monotonic時間相似,也是單調遞增的時間,惟一的不一樣是,raw monotonic time不會受到NTP時間調整的影響,它表明着系統獨立時鐘硬件對時間的統計。
boot time: 與monotonic時間相同,不過會累加上系統休眠的時間(total_sleep_time),它表明着系統上電後的總時間。5、總結 在linux下獲取高精度單調遞增的時間,只能使用syscall(SYS_clock_gettime, CLOCK_MONOTONIC_RAW, &monotonic_time)獲取!