Ao escrever esta resposta para outra pergunta e resposta aqui , percebi que o tempo na solução zsh que usa select()
para dormir por um determinado número de centissegundos estava errado em uma quantidade maior do que eu esperava.
Parece que está select()
no meu sistema, cujo tempo limite parece ter um desvio consistente, como se seus segundos valessem 1.001 segundos normais.
$ strace -qqTe /select zsh -c 'zmodload zsh/zselect; zselect -t 6000'
pselect6(0, 0x7ffcee6a9f60, 0x7ffcee6a9fe0, 0x7ffcee6aa060, {tv_sec=60, tv_nsec=0}, NULL) = 0 (Timeout) <60.058930>
$ strace -qqTe /select zsh -c 'zmodload zsh/zselect; zselect -t 600'
pselect6(0, 0x7ffcf2042b70, 0x7ffcf2042bf0, 0x7ffcf2042c70, {tv_sec=6, tv_nsec=0}, NULL) = 0 (Timeout) <6.006212>
$ uname -rs
Linux 6.7.12-amd64
Veja como leva 6,006 segundos com um tempo limite de 6 segundos e 60,06 para um tempo limite de 60 segundos.
Observo o mesmo em hardware diferente e no Ubuntu 22.04 com Linux 6.5.0.
O mesmo com perl
em vez de zsh
:
$ strace -qqTe /select perl -e 'select undef,undef,undef,60'
pselect6(0, NULL, NULL, NULL, {tv_sec=60, tv_nsec=0}, NULL) = 0 (Timeout) <60.060218>
E o mesmo com poll() em vez de select():
$ strace -qqTe /poll perl -MIO::Poll -e 'IO::Poll->new()->poll(6)'
poll([], 0, 6000) = 0 (Timeout) <6.006215>
$ strace -qqTe /poll perl -MIO::Poll -e 'IO::Poll->new()->poll(60)'
poll([], 0, 60000) = 0 (Timeout) <60.060214>
Isso não parece se aplicar a clock_nanosleep()
or alarm()
.
Esse é um problema conhecido? Isso é possivelmente intencional?
Isto é intencional, embora não esteja documentado como parte da interface do kernel .
select
os tempos limite têm alguma folga, atualmente¹ 0,1% do tempo limite para tarefas regulares, com um limite de 100 ms (0,5% para tarefas “legais”):A folga é usada no agendamento do timeout ; ele define quanta margem de manobra o kernel tem para mover a ativação de volta por motivos de energia ou desempenho.
Essa folga não é exatamente o atraso máximo que você verá no
select
, já que o tempo é gasto antes de o cronômetro ser definido e depois que a tarefa é ativada; mas deve estar próximo do limite superior:Se uma tarefa tiver uma folga do temporizador maior ( ) do que a folga
/proc/pid/timerslack_ns
calculada , isso será usado :select
A única maneira de reduzir a folga é tornar a tarefa em tempo real:
¹ Desde 6.2.28, em 2008…