Como medir o tempo médio de execução de um script?


23

Eu tenho dois scripts que calculam cada fatorial de um número. Eu gostaria de saber qual é mais rápido. O timecomando fornece milissegundos e o resultado é diferente de tempos em tempos:

piousbox@piousbox-laptop:~/projects/trash$ time ruby fac2.rb
30414093201713378043612608166064768844377641568960512000000000000

real    0m0.089s
user    0m0.052s
sys 0m0.028s
piousbox@piousbox-laptop:~/projects/trash$ time ruby fac1.rb
30414093201713378043612608166064768844377641568960512000000000000

real    0m0.091s
user    0m0.048s
sys 0m0.036s
piousbox@piousbox-laptop:~/projects/trash$ time ruby fac1.rb
30414093201713378043612608166064768844377641568960512000000000000

real    0m0.088s
user    0m0.048s
sys 0m0.040s
piousbox@piousbox-laptop:~/projects/trash$ time ruby fac2.rb
30414093201713378043612608166064768844377641568960512000000000000

real    0m0.088s
user    0m0.048s
sys 0m0.028s
piousbox@piousbox-laptop:~/projects/trash$ time ruby fac1.rb
30414093201713378043612608166064768844377641568960512000000000000

real    0m0.087s
user    0m0.064s
sys 0m0.028s
piousbox@piousbox-laptop:~/projects/trash$ time ruby fac2.rb
30414093201713378043612608166064768844377641568960512000000000000

real    0m0.089s
user    0m0.068s
sys 0m0.016s
piousbox@piousbox-laptop:~/projects/trash$ 

Como levo o tempo médio necessário para executar o script? Eu poderia analisar e calcular a média da saída de 100 time, mas imagino que exista uma solução melhor?


Respostas:


4

Não, sua ideia de calcular a média está correta.

A execução do script depende de muitos fatores e, no entanto, deve ser dividida entre o tempo de configuração (carregamento do interpretador na memória, configuração e, possivelmente, compilação de código em código de código ou máquina) e o tempo de execução real.

Para focar melhor no tempo de execução interno, faça o loop no próprio script (ou seja, em vez de calcular um fatorial, você o calcula 100 vezes em uma execução do script. O script será configurado uma vez e a rotina interna executará 100 vezes).

Para se concentrar no tempo total, você executa o script cem vezes e calcula a média dos resultados. Idealmente, você deve separar essas execuções o suficiente para que o sistema retorne sempre em um "estado de referência" (ou em um estado não relacionado a scripts). Por exemplo, o próprio intérprete será armazenado em cache na memória, para que a primeira execução do script seja sensivelmente mais lenta que as subsequentes.

Para ter uma ideia melhor do algoritmo, acho que a melhor maneira é algo assim (em uma máquina ociosa):

  • agrupar o algoritmo em uma única função.
  • no aplicativo de controle:
    • chame a função uma vez
    • obtenha o tempo do sistema ("relógio de parede") e adicione 10 (ou um N razoável) segundos
    • entre no loop e comece a contar as iterações
    • após cada chamada para a função, aumente o contador
    • se a hora do sistema estiver abaixo da hora economizada, faça outro loop
    • obter N exato, possivelmente ponto flutuante, da hora atual do relógio de parede
    • exibir o contador dividido por N: esse é o número de iterações / segundo.

O aplicativo é executado apenas uma vez, toda a configuração e preparação é feita pela primeira iteração temporizada, portanto, isso deve minimizar as despesas gerais (exceto talvez a chamada de tempo).

Se a função receber uma entrada, convém fornecer uma sequência aleatória de entradas usando um PRNG semeado com um valor fixo, para garantir que ambas as versões da função sendo testada recebam os mesmos valores. Isso evita que uma função tenha um desempenho aparentemente melhor devido a "números da sorte" (por exemplo, lembro-me de uma variação do algoritmo Hillsort que teve um desempenho mensurável melhor se o número de itens a serem classificados estivesse no formato 2 k -1 com pequenos k s).


Certo, obrigado. Notei que as chamadas subseqüentes estavam ficando mais curtas. Eu corro o loop dentro dos scripts agora e descobri que um algoritmo é definitivamente mais rápido que o outro.
precisa saber é o seguinte

39

Você pode executar iterações do programa em um loop; e divida o tempo total pelo número de iterações:

time for i in {1..10}; do sleep 1; done
real    0m10.052s
user    0m0.005s
sys 0m0.018s

2
Super simples, adorei. Eu também nunca vi {1..10}antes e estou confuso que funcione, não consigo encontrá-lo no manual do bash. O mais triste é que você não conhece a propagação dos seus resultados (tempo mínimo e máximo).
W00t 12/10

@ w00t:man -P 'less +/Brace\ Expansion' bash
user2683246

Obrigado @ user2683246! Eu também o encontrei em gnu.org/software/bash/manual/bash.html#Brace-Expansion - bom uso de menos btw. Agora eu também estou curioso sobre quando este apareceu na festa ...
w00t

11
Ah, versão 3, 10 anos depois que comecei a usar o bash :) tldp.org/LDP/abs/html/bashver3.html
w00t

2
Se isso não funcionar para os googlers que chegam, pode ser porque você não está concorrendo bash. Tente executar /bin/bashantes disso.
Cory Klein

14

existe uma ferramenta chamada multitime que faz exatamente isso: executar um comando várias vezes, medindo quanto tempo leva (real / usuário / sistema com tempo médio, mínimo / máximo e mediano calculado automaticamente)

Por exemplo, para medir um script semelhante 100 vezes:

multitime -q -n 100 "fact1.sh"
===> multitime results
1: -q fact1.sh
            Mean        Std.Dev.    Min         Median      Max
real        0.122       0.032       0.086       0.116       0.171       
user        0.148       0.044       0.096       0.137       0.223       
sys         0.023       0.019       0.000       0.014       0.061 

12

Isso é antigo, mas surgiu tão alto no google quando eu estava procurando por um comando que usei anteriormente, mas não consegui encontrar. De qualquer forma, minha maneira preferida de fazer isso é:

perf stat -r 10 -B sleep 1

Isso fornece muitos detalhes, incluindo o tempo médio de execução no final:

1.002248382 seconds time elapsed                   ( +-  0.01% )


1

Hyperfine é outra opção.

Uso da amostra:

hyperfine --warmup 3 'ruby fac1.rb'

11
hyperfine é muito melhor do que as outras alternativas que é ridículo. Detecção de execuções necessárias, aquecimento, saída bonita, relatórios de remarcação, escritos em ferrugem etc.
Klas Mellbourn 30/11
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.