<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    Linux系統下的單調時間函數

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    歡迎轉載,轉載請注明出處: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)獲取!

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全