为什么我在使用 linux hrtimer 进行一秒回调时会出现时间漂移?

Why am I getting time drift when using linux hrtimer for one second callbacks?

在嵌入式 linux 内核模块中,我正在尝试实施每秒发生的测量操作,并且我正在使用 hrtimer 来提供计时。下面的函数是设置定时器时注册的回调。值得关注的是为 hrtimer 的下一个回调触发器添加时间的正确方法。我使用 'hrtimer_add_expires_ns' 的理解是,这会将 xx ns 添加到上次为计时器设置的时间 "expire"。

static enum hrtimer_restart delay_callback (struct hrtimer* MeasDelay)
{
    hrtimer_add_expires_ns (MeasDelay, MS2NS(1000));

    printk (KERN_ALERT "Delay Callback (%d).\n", DelayCount);

    if (0 == DelayCount)
    {
        /* Reset delay counter */
        DelayCount = MEASDELAYSECS;

        /* Setup stuff to do when counter reaches zero */

    }
    else
    { 
        /* Drop the counter */
        DelayCount--;
    }

    return HRTIMER_RESTART;
}

当 运行 此代码并查看 /var/log/syslog 时,我发现日志中存储的消息的 "drift" 时间不断增加:

Feb 15 13:48:15 blah: [ 4731.033628] Delay Callback (5).  
Feb 15 13:48:16 blah: [ 4732.034576] Delay Callback (4).  
Feb 15 13:48:17 blah: [ 4733.035861] Delay Callback (3).  
Feb 15 13:48:18 blah: [ 4734.036855] Delay Callback (2).  
Feb 15 13:48:19 blah: [ 4735.038025] Delay Callback (1).  
Feb 15 13:48:20 blah: [ 4736.039170] Delay Callback (0).  
Feb 15 13:48:21 blah: [ 4737.040332] Delay Callback (5).  
Feb 15 13:48:22 blah: [ 4738.041493] Delay Callback (4).  
Feb 15 13:48:23 blah: [ 4739.042621] Delay Callback (3).  
Feb 15 13:48:24 blah: [ 4740.043792] Delay Callback (2).  
Feb 15 13:48:25 blah: [ 4741.044949] Delay Callback (1).  
Feb 15 13:48:26 blah: [ 4742.046109] Delay Callback (0).  
Feb 15 13:48:27 blah: [ 4743.047264] Delay Callback (5).  
Feb 15 13:48:28 blah: [ 4744.048436] Delay Callback (4).  
Feb 15 13:48:29 blah: [ 4745.049567] Delay Callback (3).  
Feb 15 13:48:30 blah: [ 4746.050725] Delay Callback (2).  
Feb 15 13:48:31 blah: [ 4747.051852] Delay Callback (1).  
Feb 15 13:48:32 blah: [ 4748.054040] Delay Callback (0).  

每个回调执行时间戳略多于预期的 1 秒。我确实知道时间戳是存储消息的时间,但我希望时间会 "dither" 而不是不断前进......如果计时器正在做我期望的事情,那就是在上次过期时间(不是 "now")。

换句话说,我希望记录的时间戳总是尝试从初始计时器启动时间开始为一秒的倍数(编辑时间戳以显示计时器在 xxxx 启动时我的预期。 040000):

Feb 15 13:48:21 blah: [ 4737.040073] Delay Callback (5).  
Feb 15 13:48:22 blah: [ 4738.040100] Delay Callback (4).  
Feb 15 13:48:23 blah: [ 4739.040098] Delay Callback (3).  
Feb 15 13:48:24 blah: [ 4740.040050] Delay Callback (2).  
Feb 15 13:48:25 blah: [ 4741.040110] Delay Callback (1).  
Feb 15 13:48:26 blah: [ 4742.040101] Delay Callback (0).  
Feb 15 13:48:27 blah: [ 4743.041234] Delay Callback (5).  
Feb 15 13:48:28 blah: [ 4744.040030] Delay Callback (4).  
Feb 15 13:48:29 blah: [ 4745.040075] Delay Callback (3).  
Feb 15 13:48:30 blah: [ 4746.040099] Delay Callback (2).  
Feb 15 13:48:31 blah: [ 4747.040057] Delay Callback (1).  
Feb 15 13:48:32 blah: [ 4748.040040] Delay Callback (0).  

感谢您帮助我们更好地理解 linux hrtimers 的使用。

HR 计时器和 printk 使用 不同的时间源,因此它们测量的间隔不需要相等。

printk 使用低分辨率(但很快)时间源,基于 jiffies。 HR 定时器,顾名思义,使用更高分辨率的时间源(如果可用)。

您可以检查计时器的字段 ._softexpires.node.expires 是否以 fixed 步长递增。正是这些字段负责触发计时器。