atraso do comando sleep grosseiramente impreciso (VM)
Eu preciso usar sleepem um script de shell, então tentei em um terminal, mas os atrasos que ele produz são inconsistentes e muito imprecisos. Por exemplo, sleep 3produz um atraso próximo a 20 segundos. Esses atrasos também podem flutuar quando o mesmo tempo é especificado. Em geral, o atraso parece aumentar exponencialmente com valores mais altos.
Tentei em um Ubuntu e um Debian VM com resultados igualmente ruins. Não acho que o componente VM esteja em jogo (executar um timeout 10em uma VM do Windows está bom).
Ao cronometrar cada comando, o relógio do sistema pensa que está funcionando bem, mas na realidade não está. Veja alguns exemplos abaixo.
O tempo entre parênteses é o tempo real decorrido (aproximado):
$ 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
O padrão é obviamente em segundos, mas adicionar um sao tempo não faz nenhuma diferença.
Nada mais está sendo executado na máquina host que possa consumir disco ou CPU.
Reinicializar a VM parece melhorar a situação nas primeiras tentativas, mas, depois disso, a precisão fica cada vez pior.
Alguma ideia de qual pode ser o problema?
EDITAR :
declare -p PS1retornos em execuçãodeclare -- PS1="\${debian_chroot:+(\$debian_chroot)}\\u@\\h:\\w\\\$ "command -V sleepretornos em execuçãosleep is hashed (/usr/bin/sleep)declare -p PATHretornos em execuçãodeclare -x PATH="/home/debwp/mycmds:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games"Resultados da postagem de 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 ~$entrar
dateno terminal a uma taxa de ~ uma vez por segundo resulta em$ 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
Respostas
O comportamento certamente está relacionado ao seu hipervisor.
time(7) diz:
O tempo real é definido como o tempo medido a partir de algum ponto fixo, seja de um ponto padrão no passado (veja a descrição da Época e do tempo do calendário abaixo), ou de algum ponto (por exemplo, o início) na vida de um processo ( Tempo decorrido).
O tempo do processo é definido como a quantidade de tempo da CPU usada por um processo. Às vezes, isso é dividido em componentes do usuário e do sistema. O tempo de CPU do usuário é o tempo gasto na execução do código no modo de usuário. O tempo de CPU do sistema é o tempo gasto pelo kernel executando no modo de sistema em nome do processo (por exemplo, executando chamadas de sistema). O comando time (1) pode ser usado para determinar a quantidade de tempo de CPU consumido durante a execução de um programa.
Com base nisso, podemos concluir que quando escrevemos:
$ time sleep 1
real 0m1.002s
user 0m0.002s
sys 0m0.000s
realé o tempo real, ou seja, o tempo real (às vezes chamado de tempo do relógio de parede) gasto no processo. useré o tempo de CPU (ciclos de CPU * frequência) gasto na execução do código no modo de usuário e sysé o tempo de CPU (ciclos de CPU * frequência) gasto pelo kernel executando no modo de sistema em nome do processo.
Para parafrasear seu problema:
Por que o
realtempo informado por não time(1)corresponde ao meu relógio?
Quando você executa um sistema operacional em bare metal, normalmente tem um oscilador de cristal alimentado por bateria que funciona em uma frequência constante. Este relógio de hardware controlará o tempo desde a época. O número de oscilações por segundo pode ser ajustado para corrigir o desvio (consulte hwclock(8)).
time(7) também diz:
A precisão de várias chamadas de sistema que definem tempos limite (por exemplo, selecione (2), sigtimedwait (2)) e medem o tempo de CPU (por exemplo, getrusage (2)) é limitada pela resolução do relógio do software, um relógio mantido pelo kernel que mede o tempo em instantes. O tamanho de um instante é determinado pelo valor da constante do kernel HZ.
O relógio do hardware é usado para inicializar o relógio do sistema (que, de outra forma, só saberia a hora desde a inicialização). Suspeito que seu hipervisor (virtualbox) usa algum hwclock para inicializar o tempo. Depois disso, o relógio do software assume o controle.
rtc(4) diz:
[hardware clocks] não deve ser confundido com o relógio do sistema, que é um relógio de software mantido pelo kernel e usado para implementar gettimeofday (2) e time (2), bem como definir carimbos de data / hora em arquivos e assim por diante.
O que acabamos de aprender aqui é que time(2)(que são as chamadas de biblioteca usadas pelo utilitário time(1)) na verdade obtém informações do relógio do sistema, não do relógio do hardware.
O relógio do software é mantido pelo kernel, que mede o tempo jiffies. Esta é uma unidade de tempo determinada por uma constante de kernel. Pelo que entendi, um certo número de ciclos de CPU aumentará um jiffie. Portanto, se o SO pensa que a CPU está rodando a 2,0 GHz, mas na verdade a CPU está rodando a 1,0 GHz, então um jiffie levaria 2ms quando comparado a um clock de parede em vez dos 1ms esperados.
Ao executar com hardware físico, dizemos à CPU o quão rápido desejamos que execute (mais lento para economia de energia, mais rápido para desempenho), então assumimos que o hardware faz o que prometeu porque o hardware físico faz isso. O truque é que, quando o "hardware" é virtual, o hipervisor decide como controlar a CPU virtual, não as leis da física.
Um hipervisor em execução no espaço do usuário (como uma caixa virtual) ficará à mercê do kernel do host para fornecer os ciclos de que precisa. Se o sistema host estiver executando 1000 máquinas virtuais, você pode imaginar que cada VM guest obterá apenas uma parte dos ciclos de CPU que esperava, fazendo com que os relógios estimados do sistema aumentem a uma taxa mais lenta. Mesmo se um hipervisor obtiver todos os recursos de que precisa, ele também pode optar por restringir os recursos conforme achar adequado, deixando o sistema operacional convidado para executar mais lentamente do que o esperado, sem entender por quê.
Encontrei esta resposta em Clock drift em um convidado VirtualBox :
No Virtualbox Manager, alterar o valor de Paravirtualização (Configurações do sistema -> guia Aceleração) de Defaultpara Minimalcorrigiu o problema.