Eu quero iniciar um processo e medir o tempo da CPU (user + sys) de que precisa até que termine.
Eu sei que posso usar a chamada de sistema wait4
, que retorna uma estrutura com o usuário e a hora do sistema (eu uso a soma de ambas as vezes).
Eu também posso usar o cpuacct
cgroup subsystem , colocar o processo em um novo cgroup e leia o arquivo cpuacct.usage
(que contém o tempo combinado do usuário e do sistema).
Eu sei que o primeiro tem problemas quando o processo gera subprocessos (às vezes seu tempo não é contado). No entanto, pensei que, para um caso de processo único, as duas medições deveriam ser quase iguais. Eu esperava que o valor cpuacct fosse um pouco menor, porque eu só posso colocar o processo no cgroup depois que ele foi criado (mas eu faço isso imediatamente após o fork, então a diferença deve ser mínima).
Agora, para processos que demoram alguns segundos, vejo os resultados esperados.
Exemplos:
wait4: 8.292518s
cpuacct: 8.299105444s
wait4: 13.788861s
cpuacct: 13.796484557s
wait4: 24.229514s
cpuacct: 24.234132965s
wait4: 84.101255s
cpuacct: 84.104336222s
No entanto, para processos que demoram mais tempo, recebo um resultado diferente:
wait4: 155.309706s
cpuacct: 155.306291274s
wait4: 505.547594s
cpuacct: 505.526723631s
wait4: 897.180069s
cpuacct: 897.131232685s
Agora, o valor de cpuacct é um pouco menor, o que eu nunca esperaria que acontecesse. Alguém tem uma ideia de por que isso acontece?
Eu não me preocupo com a precisão de 0,1s, e nunca experimentei uma diferença maior. Posso estar confiante de que a diferença será sempre tão pequena? Ou existem cenários possíveis em que a diferença será maior?
A documentação cpuacct
indica que o valor pode ser impreciso em 2 casos. No entanto, ambos os casos não se aplicam aqui, como estou em uma máquina de 64 bits, e posso esperar uma quantidade arbitrária de tempo após a conclusão do processo, a leitura de cpuacct.usage
permanecerá constante (por isso acredito firmemente que não é um desatualizado) valor).
Configuração precisa:
Meu processo de partida é um processo Python. Eu uso subprocess.Popen()
para gerar a tarefa e os.wait4()
para obter o tempo. Para usar os cgroups, passo uma função para o parâmetro preexec_fn
de Popen
que adiciona o novo processo ao cgroup (portanto, isso é feito entre as chamadas de sistema fork
e exec
). O processo iniciado é uma VM Java.
Eu não acho que isso seja relevante, mas eu queria fornecer essa informação apenas no caso.