Obter tempo de execução do programa no shell

407

Quero executar algo em um shell linux sob algumas condições diferentes e poder gerar o tempo de execução de cada execução.

Eu sei que eu poderia escrever um script perl ou python que faria isso, mas existe uma maneira de fazê-lo no shell? (que é o bash)

ʞɔıu
fonte
2
Caso do Windows: stackoverflow.com/questions/673523/…
n611x007
é possível obter o exemplo Ticksdo windows?
freeforall tousez

Respostas:

534

Use o built-in time palavra chave :

$ tempo de ajuda

time: time [-p] PIPELINE
    Execute o PIPELINE e imprima um resumo do tempo real, tempo de CPU do usuário,
    e tempo de CPU do sistema gasto executando PIPELINE quando ele termina.
    O status de retorno é o status de retorno de PIPELINE. A opção `-p '
    imprime o resumo do tempo em um formato ligeiramente diferente. Isso usa
    o valor da variável TIMEFORMAT como o formato de saída.

Exemplo:

$ time sleep 2
0m2.009s reais
usuário 0m0.000s
sys 0m0.004s
Robert Gamble
fonte
1
Como isso é usado em um comando como time -p i=x; while read line; do x=x; done < /path/to/file.txt? Ele retorna imediatamente 0,00, a menos que eu não coloque nada antes do loop while .. o que dá?
Nat1:
esta é uma versão ruim do 'tempo', bash embutido. Onde está o comando externo 'time'?
Znik
6
@Znik, tente / usr / bin / time #
21415 Mark Rajcok
10
@natli: Enquanto timeo tempo pode um gasoduto inteira como está (em virtude de ser um Bash palavra-chave ), você precisará usar um comando do grupo ( { ...; ...; }) para tempo vários comandos:time -p { i=x; while read line; do x=x; done < /path/to/file.txt; }
mklement0
2
Para ver todas as versões do tempo que você tem instalados no seu sistema, você pode usartype -a time
spinup
120

Você pode obter informações muito mais detalhadas do que o bash interno time(que Robert Gamble menciona) usando o tempo (1) . Normalmente é isso /usr/bin/time.

Nota do editor: para garantir que você esteja chamando o utilitário externo time em vez da time palavra-chave do seu shell , chame-o como /usr/bin/time.
timeé um utilitário exigido pelo POSIX , mas a única opção necessária para o suporte é -p.
Plataformas específicas implementam extensões específicas e fora do padrão: -vtrabalha com o utilitário GNUtime , como demonstrado abaixo (a questão está marcada); a implementação do BSD / macOS usa -lpara produzir resultados semelhantes - consulte man 1 time.

Exemplo de saída detalhada:


$ /usr/bin/time -v sleep 1
       Command being timed: "sleep 1"
       User time (seconds): 0.00
       System time (seconds): 0.00
       Percent of CPU this job got: 1%
       Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.05
       Average shared text size (kbytes): 0
       Average unshared data size (kbytes): 0
       Average stack size (kbytes): 0
       Average total size (kbytes): 0
       Maximum resident set size (kbytes): 0
       Average resident set size (kbytes): 0
       Major (requiring I/O) page faults: 0
       Minor (reclaiming a frame) page faults: 210
       Voluntary context switches: 2
       Involuntary context switches: 1
       Swaps: 0
       File system inputs: 0
       File system outputs: 0
       Socket messages sent: 0
       Socket messages received: 0
       Signals delivered: 0
       Page size (bytes): 4096
       Exit status: 0

grepsedawk
fonte
2
você não saberia de que pacote debian isso viria? parece não estar instalado por padrão #
22408
1
Eu estava referenciando seu post Robert. A menos que você queira dizer que o comando que você sugere não é o bash embutido?
22868 grepsedawk
24
Surpreendentemente, ele é instalado a partir de um pacote chamado "time".
Paul Tomblin
2
A saída do / usr / bin / time é parecida com "0.00user 0.00system 0: 02.00 CPU 0% decorrida (0avgtext + 0avgdata 0maxresident) k 0inputs + 0outputs (0major + 172minor) pagefaults 0swaps"
Paul Tomblin
4
@ Nick: "sudo apt-get install time".
Robert Gamble
79
#!/bin/bash
START=$(date +%s)
# do something
# start your script work here
ls -R /etc > /tmp/x
rm -f /tmp/x
# your logic ends here
END=$(date +%s)
DIFF=$(( $END - $START ))
echo "It took $DIFF seconds"
David
fonte
14
Existe uma maneira muito mais simples. O Bash calcula automaticamente a variável especial $ SECONDS e o recálculo com base no comando de data externa é desnecessário. A variável $ SECONDS mantém quantos segundos o script bash está em execução quando é iniciado. Essa variável possui alguma propriedade especial. Veja a página de manual: D
Znik
Eu tentei o acima e o método no comentário. No 1º recebo um erro 'variável ilegal' e a 2ª I get 'variável não identificado'
DrBwts
45

Para uma medição delta linha a linha, tente o gnomon .

Um utilitário de linha de comando, um pouco como o ts de moreutils, para acrescentar informações de registro de data e hora à saída padrão de outro comando. Útil para processos de longa execução, nos quais você deseja um registro histórico do que está demorando tanto.

Você também pode usar as opções --highe / ou --mediumpara especificar um limite de duração em segundos, durante o qual o gnomon destacará o carimbo de data / hora em vermelho ou amarelo. E você pode fazer algumas outras coisas também.

exemplo

Adriano Resende
fonte
3
Ótima dica, mas só para esclarecer: isso é útil para tempos de linha por linha , mas a sobrecarga de fazer esses tempos de granulação fina aumenta significativamente o tempo geral .
mklement0
2
Impressionante utilidade .. Obrigado por compartilhar
Kishan B 02/02
19

Se você quiser mais precisão, use %Ncom date(e use bcpara o diff, porque $(())apenas lida com números inteiros).

Veja como fazê-lo:

start=$(date +%s.%N)
# do some stuff here
dur=$(echo "$(date +%s.%N) - $start" | bc)

printf "Execution time: %.6f seconds" $dur

Exemplo:

start=$(date +%s.%N); \
  sleep 0.1s; \
  dur=$(echo "$(date +%s.%N) - $start" | bc); \
  printf "Execution time: %.6f seconds\n" $dur

Resultado:

Execution time: 0.104623 seconds
Benoit Duffez
fonte
15

Se você pretende usar os horários posteriormente para calcular, aprenda como usar a -fopção de /usr/bin/timepara gerar código que economiza tempo. Aqui está um código que usei recentemente para obter e classificar os tempos de execução de toda uma classe de programas de alunos:

fmt="run { date = '$(date)', user = '$who', test = '$test', host = '$(hostname)', times = { user = %U, system = %S, elapsed = %e } }"
/usr/bin/time -f "$fmt" -o $timefile command args...

Mais tarde concatenei todos os $timefilearquivos e canalizei a saída em um intérprete Lua . Você pode fazer o mesmo com Python ou bash ou qualquer que seja sua sintaxe favorita. Eu amo essa técnica.

Norman Ramsey
fonte
Nota: O caminho completo /usr/bin/timeé necessário porque, embora which timelhe diga o contrário, se você simplesmente executar time, ele executará a versão do seu shell timeque não aceita argumentos.
Kevin Dice
Eu iria com env time:-)
Ciro Santilli
13

Se você precisar apenas de precisão para o segundo, poderá usar a $SECONDSvariável embutida , que conta o número de segundos que o shell está executando.

while true; do
    start=$SECONDS
    some_long_running_command
    duration=$(( SECONDS - start ))
    echo "This run took $duration seconds"
    if some_condition; then break; fi
done
Glenn Jackman
fonte
10

Você pode usar timee subshell () :

time (
  for (( i=1; i<10000; i++ )); do
    echo 1 >/dev/null
  done
)

Ou no mesmo shell {}:

time {
  for (( i=1; i<10000; i++ )); do
    echo 1 >/dev/null
  done
}
Eduardo Cuomo
fonte
Você postou dois trechos de código idênticos. Você deve ter pensado em ter algo diferente lá.
Stason
3
@StasBekman não é verdade, primeiro usando (& )(novo contexto, subshell ) e outro com {& }(mesmo shell, mesmo contexto)
Eduardo Cuomo
Aha! Eu estava olhando muito duro para os dois e não vi a diferença. Obrigado por esclarecer que {} vs ().
Stason 17/08/19
2

O caminho é

$ > g++ -lpthread perform.c -o per
$ > time ./per

saída é >>

real    0m0.014s
user    0m0.010s
sys     0m0.002s
Robel Sharma
fonte
Não há necessidade de usar -lphtreadou -otags. Só precisa usar o timecomando, que a resposta aceita explica melhor.
Dennis
7
Foi um exemplo. Esse é o meu perform.c com encadeamento, então eu preciso -lpthread e, para uma identidade simples, é -o per.
Robel Sharma
0

Um método possivelmente simples (que pode não atender às necessidades de diferentes usuários) é o uso do shell PROMPT.it é uma solução simples que pode ser útil em alguns casos. Você pode usar o recurso de prompt do bash como no exemplo abaixo:

exportar PS1 = '[\ t \ u @ \ h] \ $' 

O comando acima resultará na alteração do prompt do shell para:

[HH: MM: nome de usuário SS @ nome do host] $ 

Cada vez que você executa um comando (ou pressiona enter) retornando ao prompt do shell, o prompt exibirá a hora atual.

notas:
1) lembre-se de que, se você esperou algum tempo antes de digitar seu próximo comando, esse tempo precisa ser considerado, ou seja, a hora exibida no prompt do shell é o carimbo de data e hora em que o prompt do shell foi exibido, não quando você digita o comando. alguns usuários optam por pressionar a tecla Enter para obter um novo prompt com um novo registro de data e hora antes de estarem prontos para o próximo comando.
2) Existem outras opções e modificadores disponíveis que podem ser usados ​​para alterar o prompt do bash, consulte (man bash) para obter mais detalhes.

tstorym
fonte
Não é o momento em que o programa é executado, mas a duração da execução do programa.
Geno Chen