固定两个连续时间点之间的时间误差

Fixed time error between two continuous time points

以下代码周期性休眠到预期时间点(ts),并立即获取系统时间(tm2)。为什么tstm2之间有一个固定的时间误差(~52us),因为两个时间点相邻。

运行环境是一个实时补丁linux,如果我改变周期时间间隔的大小,固定时间误差几乎没有变化。

#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]); 
    } 
}

运行 结果:

 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

timerslack 是在 Linux 内核 4.6 中引入的,用于对 CPU 功耗的定时器到期进行分组。

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.

引用自Prctl Linux manual

用户可以通过编辑文件 /proc/{self}/timerslack_ns 来更改 timerslack 值。