Quer saber por quanto tempo um processo é executado e muito mais? O time
comando Linux retorna estatísticas de tempo, dando a você uma visão interessante sobre os recursos usados por seus programas.
Índice
tempo tem muitos parentes
Existem muitas distribuições de Linux e diferentes sistemas operacionais do tipo Unix. Cada um deles possui um shell de comando padrão. O shell padrão mais comum nas distribuições Linux modernas é o shell bash. Mas existem muitos outros, como o shell Z (zsh) e o shell Korn (ksh).
Todas estas conchas incorporar seu próprio time
comando, como um built-in comando ou como uma palavra reservada . Quando você digita time
em uma janela de terminal, o shell executa seu comando interno em vez de usar o time
binário GNU que é fornecido como parte de sua distribuição Linux.
Queremos usar a versão GNU do time
porque tem mais opções e é mais flexível.
Que horas vai ser executado?
Você pode verificar qual versão será executada usando o type
comando. type
permitirá que você saiba se o próprio shell irá lidar com sua instrução, com suas rotinas internas, ou passá-la para o binário GNU.
em uma janela de terminal, digite a palavra type
, um espaço e, em seguida, a palavra time
e pressione Enter.
digite tempo
Podemos ver que no shell bash time
é uma palavra reservada. Isso significa que o Bash usará suas time
rotinas internas por padrão.
digite tempo
No shell Z (zsh) time
é uma palavra reservada, então as rotinas internas do shell serão usadas por padrão.
digite tempo
No shell Korn, time
existe uma palavra-chave. Uma rotina interna será usada em vez do time
comando GNU .
Executando o comando GNU time
Se o shell em seu sistema Linux tiver uma time
rotina interna, você precisará ser explícito se quiser usar o time
binário GNU . Você deve:
- Fornece o caminho completo para o binário, como
/usr/bin/time
. Execute owhich time
comando para encontrar este caminho. - Use
command time
. - Use uma barra invertida como
\time
.
O which time
comando nos fornece o caminho para o binário.
Podemos testar isso usando /usr/bin/time
um comando para iniciar o binário GNU. Isso funciona. Recebemos uma resposta do time
comando informando que não fornecemos nenhum parâmetro de linha de comando para que ele funcione.
A digitação command time
também funciona e obtemos as mesmas informações de uso de time
. O command
comando diz ao shell para ignorar o próximo comando para que seja processado fora do shell.
Usar um \
caractere antes do nome do comando é o mesmo que usar command
antes do nome do comando.
A maneira mais simples de garantir que você está usando o time
binário GNU é usar a opção de barra invertida.
Tempo
\Tempo
time
invoca a versão shell do tempo. \time
usa o time
binário .
Usando o comando de tempo
Vamos cronometrar alguns programas. Estamos usando dois programas chamados loop1
e loop2
. Eles foram criados a partir de loop1.ce loop2.c. Eles não fazem nada de útil além de demonstrar os efeitos de um tipo de ineficiência de codificação.
Este é o loop1.c. O comprimento de uma string é necessário dentro dos dois loops aninhados. O comprimento é obtido antecipadamente, fora dos dois loops aninhados.
#include "stdio.h" #include "string.h" #include "stdlib.h" int main (int argc, char * argv []) { int i, j, len, count = 0; char szString [] = "how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek"; // obtém o comprimento da string uma vez, fora dos loops len = strlen (szString); para (j = 0; j <500000; j ++) { para (i = 0; i <len; i ++) { if (szString [i] == '-') contagem ++; } } printf ("Contados% d hifens \ n", contagem); saída (0); } // fim do principal
Este é o loop2.c. O comprimento da corda é obtido vez após vez para cada ciclo do loop externo. Essa ineficiência deve aparecer nos tempos.
#include "stdio.h" #include "string.h" #include "stdlib.h" int main (int argc, char * argv []) { int i, j, contagem = 0; char szString [] = "how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek"; para (j = 0; j <500000; j ++) { // obtendo o comprimento da string a cada // tempo os loops disparam para (i = 0; i <strlen (szString); i ++) { if (szString [i] == '-') contagem ++; } } printf ("Contados% d hifens \ n", contagem); saída (0); } // fim do principal
Vamos iniciar o loop1
programa e usá-lo time
para medir seu desempenho.
\ time ./loop1
Agora vamos fazer o mesmo para loop2
.
\ time ./loop2
Isso nos deu dois conjuntos de resultados, mas eles estão em um formato muito feio. Podemos fazer algo sobre isso mais tarde, mas vamos escolher algumas informações dos resultados.
Quando os programas são executados, há dois modos de execução entre os quais eles são alternados. Eles são chamados de modo de usuário e modo de kernel .
Resumidamente, um processo no modo de usuário não pode acessar diretamente o hardware ou a memória de referência fora de sua própria alocação. Para obter acesso a tais recursos, o processo deve fazer solicitações ao kernel. Se o kernel aprovar a solicitação, o processo entra em execução no modo kernel até que o requisito seja satisfeito. O processo é então alternado de volta para execução no modo de usuário.
Os resultados para loop1
nos loop1
mostram que gastou 0,09 segundos no modo de usuário. Ele gastou tempo zero no modo kernel ou o tempo no modo kernel é um valor muito baixo para registrar depois de arredondado para baixo. O tempo total decorrido foi de 0,1 segundos. loop1
obteve uma média de 89% do tempo de CPU sobre a duração de seu tempo total decorrido.
O loop2
programa ineficiente demorou três vezes mais para ser executado. Seu tempo total decorrido é de 0,3 segundos. A duração do tempo de processamento no modo de usuário é de 0,29 segundos. Nada está se registrando no modo kernel. loop2
obteve uma média de 96% do tempo de CPU para a duração de sua execução.
Formatando a saída
Você pode personalizar a saída time
usando uma string de formato. A string de formato pode conter especificadores de texto e formato. A lista de especificadores de formato pode ser encontrada na página de manual de time
. Cada um dos especificadores de formato representa uma informação.
Quando a string é impressa, os especificadores de formato são substituídos pelos valores reais que representam. Por exemplo, o especificador de formato para a porcentagem de CPU é a letra P
. Para indicar time
que um especificador de formato não é apenas uma letra regular, adicione um sinal de porcentagem a ela, como %P
. Vamos usá-lo em um exemplo.
A opção -f
(string de formato) é usada para dizer time
que o que se segue é uma string de formato.
Nossa string de formato irá imprimir os caracteres “Programa:” e o nome do programa (e quaisquer parâmetros de linha de comando que você passar para o programa). O %C
especificador de formato significa “Nome e argumentos de linha de comando do comando sendo cronometrado”. O \n
faz com que a saída mova para a próxima linha.
Existem muitos especificadores de formato e eles diferenciam maiúsculas de minúsculas, portanto, certifique-se de inseri-los corretamente ao fazer isso.
A seguir imprimiremos os caracteres “Tempo total:” seguidos do valor do tempo total decorrido para esta execução do programa (representado por %E
).
Costumamos \n
dar outra nova linha. Em seguida, imprimiremos os caracteres “Modo (s) de usuário“, seguidos do valor do tempo de CPU gasto no modo de usuário, representado pelo %U
.
Costumamos \n
dar outra nova linha. Desta vez, estamos nos preparando para o valor de tempo do kernel. Imprimimos os caracteres “Kernel Mode (s)“, seguidos do especificador de formato para o tempo de CPU gasto no modo kernel, que é %S
.
Finalmente, vamos imprimir os caracteres “ \n
CPU:” para nos dar uma nova linha e o título para este valor de dados. O %P
especificador de formato fornecerá a porcentagem média de tempo de CPU usado pelo processo cronometrado.
Toda a string de formato é colocada entre aspas. Poderíamos ter incluído alguns \t
caracteres para colocar tabulações na saída se estivéssemos preocupados com o alinhamento dos valores.
\ time -f "Programa:% C \ nTempo total:% E \ nModo (s) do usuário% U \ nModo (s) do kernel% S \ nCPU:% P" ./loop1
Enviando a saída para um arquivo
Para manter um registro das temporizações dos testes realizados, você pode enviar a saída de time
para um arquivo. Para fazer isso, use a -o
opção (saída). A saída do seu programa ainda será exibida na janela do terminal. É apenas a saída time
que é redirecionada para o arquivo.
Podemos executar novamente o teste e salvar a saída no test_results.txt
arquivo da seguinte maneira:
\ time -o test_results.txt -f "Programa:% C \ nTempo total:% E \ nModo (s) de usuário% U \ nModo (s) kernel% S \ nCPU:% P" ./loop1
cat test_results.txt
A loop1
saída do programa é exibida na janela do terminal e os resultados time
vão para o test_results.txt
arquivo.
Se você deseja capturar o próximo conjunto de resultados no mesmo arquivo, deve usar a -a
opção (anexar) da seguinte forma:
\ time -o test_results.txt -a -f "Programa:% C \ nTempo total:% E \ nModo (s) do usuário% U \ nModo (s) kernel% S \ nCPU:% P" ./loop2
cat test_results.txt
Agora deve estar claro por que usamos o %C
especificador de formato para incluir o nome do programa na saída da string de formato.
E estamos sem tempo
Provavelmente mais útil para programadores e desenvolvedores para ajustar seu código, o time
comando também é útil para quem deseja descobrir um pouco mais sobre o que acontece nos bastidores cada vez que você inicia um programa.