Search code examples
timersleepgettimetime-measurement

Fixed time error between two continuous time points


The following codes periodically sleep to expected time point(ts), and get the system time(tm2) immediately. Why is there a fixed time error (~52us) between ts and tm2, since two time points adjoin.

The running environment is a realtime-patched linux, and if I change the size of the periodic time interval, the fixed time error barely changes.

#include <time.h> 
#include <string.h> 
#include <stdio.h> 
#include <stdlib.h> 
  
#define US 100         /* sleep US micro-seconds */
#define LOOP 20 
  
double delayed[LOOP]; 
  
int main(void) 
{ 
    int loop = 0; 
    struct timespec tm1, tm2, tm2_old; 
    struct timespec ts; 
  
    clock_gettime(CLOCK_MONOTONIC, &tm1); 
    ts.tv_sec   = tm1.tv_sec; 
    ts.tv_nsec  = tm1.tv_nsec; 
  
    while(1){ 
        ts.tv_nsec  = ts.tv_nsec + US * 1000L; 
        ts.tv_sec   = ts.tv_sec + (ts.tv_nsec)/1000000000L; 
        ts.tv_nsec  = (ts.tv_nsec)%1000000000; 
  
        clock_gettime(CLOCK_MONOTONIC, &tm1); 
        clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL); 
        clock_gettime(CLOCK_MONOTONIC, &tm2); 
  
        delayed[loop] = (tm2.tv_sec-ts.tv_sec)*1000000.0 + \ 
                (tm2.tv_nsec - ts.tv_nsec)/1000.0; 
        ++loop; 
        if(loop >= LOOP) break; 
    } 
    for(int ii=0; ii<LOOP; ++ii){ 
        printf("delayed %4.2f\n", delayed[ii]); 
    } 
}

running results:

 delayed 55.62 
 delayed 53.02 
 delayed 52.47 
 delayed 52.30 
 delayed 52.25 
 delayed 52.32 
 delayed 52.30 
 delayed 52.45 
 delayed 52.28 
 delayed 52.29 
 delayed 52.16 
 delayed 52.16 
 delayed 52.19 
 delayed 52.28 
 delayed 52.26 
 delayed 52.23 
 delayed 52.24 
 delayed 52.26 
 delayed 52.32 
 delayed 52.15

Solution

  • timerslack is introduced in Linux kernel 4.6 to group timer expirations for the CPU power consumption.

    The "current" timer slack is used by the kernel to group timer expirations for the calling thread that are close to one another; as a consequence, timer expirations for the thread may be up to the specified number of nanoseconds late (but will never expire early). Grouping timer expirations can help reduce system power consumption by minimizing CPU wake-ups.

    Cited from Prctl Linux manual

    Users can change the timerslack value by edit the file /proc/{self}/timerslack_ns .