睡眠命令延迟严重不准确 (VM)

睡眠命令延迟严重不准确 (VM)

我需要sleep在 shell 脚本中使用,所以我在终端中尝试了它,但是它产生的延迟不一致并且非常不准确。例如sleep 3产生接近 20 秒的延迟。当指定相同时间时,这些延迟也可能会波动。一般来说,延迟似乎随着值的增加而呈指数增长。

在 Ubuntu 和 Debian VM 上尝试过,但结果同样不佳。我认为 VM 组件没有发挥作用(timeout 10在 Windows VM 上运行就可以了)。

通过对每个命令进行计时,系统时钟认为它运行正常,但实际上并非如此。请参阅下面的几个示例。


括号中的时间是实际经过的时间(近似值):

$ time sleep 1        (7 secs)

real    0m1.040s
user    0m0.003s
sys     0m0.016s
$ time sleep 1        (5 secs)

real    0m1.028s      
user    0m0.009s
sys     0m0.013s
$ time sleep 1        (5 secs)

real    0m1.027s
user    0m0.013s
sys     0m0.007s
$ time sleep 1        (5 secs)

real    0m1.029s
user    0m0.007s
sys     0m0.016s
$ time sleep 3       (17 secs)

real    0m3.036s
user    0m0.000s
sys     0m0.021s
$ time sleep 5       (29.5 secs)

real    0m5.026s
user    0m0.007s
sys     0m0.013s

默认值显然以秒为单位,但添加s时间并没有任何区别。

主机上没有运行任何可能占用磁盘或 CPU 的其他内容。

重新启动虚拟机似乎可以改善前几次尝试的情况,但之后准确性会变得越来越差。

知道问题可能是什么吗?

编辑:

  • 运行declare -p PS1回报

    declare -- PS1="\${debian_chroot:+(\$debian_chroot)}\\u@\\h:\\w\\\$ "
    
  • 运行command -V sleep回报

    sleep is hashed (/usr/bin/sleep)
    
  • 运行declare -p PATH回报

    declare -x PATH="/home/debwp/mycmds:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games"
    
  • Paul_Pedant 帖子的结果:

    ~$ date '+%T.%N'; time sleep 5; date '+%T.%N'
    22:47:49.679497552
    ^[[A
    ^[[A
    ^[[A
    ^[[A
    
    real  0m5.033s
    user  0m0.005s
    sys   0m0.014s
    22:47:54.788302324
    ~$ date '+%T.%N'; time sleep 5; date '+%T.%N'
    22:47:54.830674809
    
    real  0m5.043s
    user  0m0.008s
    sys   0m0.012s
    22:47:59.934542825
    ~$ date '+%T.%N'; time sleep 5; date '+%T.%N'
    22:47:59.994006022
    
    real  0m5.057s
    user  0m0.004s
    sys   0m0.018s
    22:48:05.159303996
    ~$ date '+%T.%N'; time sleep 5; date '+%T.%N'
    22:48:05.241043114
    
    real  0m5.099s
    user  0m0.004s
    sys   0m0.021s
    22:48:10.383158635
    ~$ date '+%T.%N'; time sleep 5; date '+%T.%N'
    22:48:10.435520982
    
    real  0m5.028s
    user  0m0.004s
    sys   0m0.012s
    22:48:15.497877219
    ~$
    
  • date以每秒一次的速度在终端输入导致

    $ date
    Mon 31 Aug 20:42:25 CEST 2020
    $ date
    Mon 31 Aug 20:42:25 CEST 2020
    $ date
    Mon 31 Aug 20:42:25 CEST 2020
    $ date
    Mon 31 Aug 20:42:26 CEST 2020
    

答案1

该行为肯定与您的虚拟机管理程序有关。

time(7)说:

实时被定义为从某个固定点测量的时间,可以是从过去的标准点(参见下面的纪元和日历时间的描述),也可以是从进程生命周期中的某个点(例如,开始)(经过的时间)。

进程时间定义为进程使用的 CPU 时间量。有时将其分为用户和系统组件。用户CPU时间是在用户模式下执行代码所花费的时间。系统CPU时间是内核代表进程在系统模式下执行(例如,执行系统调用)所花费的时间。 time(1) 命令可用于确定程序执行期间消耗的 CPU 时间量。

基于此,我们可以得出这样的结论:

$ time sleep 1

real    0m1.002s
user    0m0.002s
sys     0m0.000s

real是真实时间,意味着该过程中花费的实际时间(有时称为挂钟时间)。 user是在用户模式下执行代码所花费的 CPU 时间(CPU 周期 * 频率),并且sys是内核代表进程在系统模式下执行所花费的 CPU 时间(CPU 周期 * 频率)。

解释一下你的问题:

为什么没有real报告时间time(1)匹配我的手表吗?

当您在裸机上运行操作系统时,您通常会有一个以恒定频率运行的电池供电的晶体振荡器。该硬件时钟将跟踪自纪元以来的时间。每秒振荡的次数可以调整以校正漂移(参见hwclock(8))。

time(7)还说:

设置超时(例如 select(2)、sigtimedwait(2))和测量 CPU 时间(例如 getrusage(2))的各种系统调用的精度受软件时钟分辨率的限制,软件时钟由内核维护,以 jiffy 为单位测量时间。jiffy 的大小由内核常量 HZ 的值决定。

硬件时钟用于初始化系统时钟(否则只能知道自启动以来的时间)。我怀疑您的虚拟机管理程序(virtualbox)使用一些 hwclock 来初始化时间。之后,软件时钟接管。

rtc(4)说:

[硬件时钟]不要与系统时钟混淆,系统时钟是由内核维护的软件时钟,用于实现 gettimeofday(2) 和 time(2),以及在文件上设置时间戳等。

我们在这里刚刚了解到的是time(2)(这是实用程序使用的库调用time(1))实际上从系统时钟获取信息,而不是硬件时钟。

软件时钟由内核维护,它测量时间jiffies。这是由内核常数确定的时间单位。据我了解,一定数量的CPU周期会增加一个jiffie。因此,如果操作系统认为 CPU 运行在 2.0 GHz,但 CPU 实际上运行在 1.0GHz,那么与挂钟相比,一个 jiffie 实际上需要 2ms,而不是预期的 1ms。

当使用物理硬件运行时,我们告诉CPU我们希望它运行多快(为了省电而减慢速度,为了提高性能而加快速度),然后我们假设硬件按照它所承诺的那样运行,因为物理硬件确实做到了这一点。诀窍在于,当“硬件”是虚拟的时,管理程序决定如何控制虚拟 CPU,而不是物理定律。

在用户空间(如虚拟机)中运行的虚拟机管理程序将受主机内核的支配,为其提供所需的周期。如果主机系统运行 1000 个虚拟机,您可以想象每个来宾 VM 只会获得其预期的 CPU 周期的一部分,从而导致猜测系统时钟以较慢的速率增加。即使虚拟机管理程序获得了所需的所有资源,它也可以选择在其认为合适的情况下限制资源,从而使来宾操作系统的运行速度比预期慢,而无需了解原因。

答案2

成立这个答案VirtualBox 来宾中的时钟漂移:

在 Virtualbox Manager 中,将半虚拟化值(系统设置 --> 加速选项卡)从 更改为Default更正Minimal了问题。

相关内容