Gostaria de saber por quanto tempo um processo está em execução e obter informações detalhadas sobre o uso de recursos? O comando ‘time’ no Linux é a ferramenta ideal para isso. Ele fornece estatísticas de tempo que oferecem uma visão clara de como seus programas estão utilizando os recursos do sistema.
A Diversidade de ‘time’ nos Ambientes Unix
O ecossistema Linux, juntamente com outros sistemas operacionais baseados em Unix, apresenta uma variedade de shells de comando. O shell bash é o mais comum nas distribuições Linux modernas, mas existem alternativas como o zsh e o ksh. É importante notar que cada um desses shells possui seu próprio comando ‘time’, que pode ser uma função interna ou uma palavra reservada.
Ao digitar ‘time’ em um terminal, o shell pode executar sua versão interna do comando, em vez de utilizar o binário GNU ‘time’ fornecido com a distribuição Linux. No entanto, para uma análise mais completa e flexível, a versão GNU é preferível por oferecer mais opções.
Determinando Qual Versão do ‘time’ Está Sendo Utilizada
O comando ‘type’ permite verificar qual versão do ‘time’ será executada. Ele informa se o shell tratará a instrução internamente ou se a encaminhará para o binário GNU.
Para descobrir, digite ‘type time’ no terminal.
type time
Em shells como bash, o ‘time’ é uma palavra reservada, indicando que o shell usará sua implementação interna por padrão.
type time
O mesmo ocorre no zsh, onde ‘time’ é uma palavra reservada, e as rotinas internas do shell serão usadas por padrão.
type time
No shell Korn, ‘time’ também é uma palavra-chave, o que significa que uma rotina interna será usada no lugar do comando GNU ‘time’.
Executando o Comando GNU ‘time’
Se o seu shell possui uma rotina interna para o comando ‘time’, será necessário especificar que deseja usar o binário GNU. Isso pode ser feito de três maneiras:
- Utilizando o caminho completo para o binário (ex: /usr/bin/time). Para descobrir o caminho, utilize o comando ‘which time’.
- Usando o comando ‘command time’.
- Precedendo o comando ‘time’ com uma barra invertida (ex: \time).
O comando ‘which time’ revela o caminho para o binário.
Testamos o binário GNU utilizando ‘/usr/bin/time’. A resposta indica que não foram fornecidos parâmetros na linha de comando. Similarmente, o comando ‘command time’ também funciona, retornando as mesmas informações de uso. O comando ‘command’ instrui o shell a ignorar a interpretação do próximo comando e processá-lo externamente.
Preceder o nome do comando com uma barra invertida tem o mesmo efeito que usar ‘command’. A forma mais direta de garantir o uso do binário GNU ‘time’ é utilizar essa barra invertida.
time
time
‘time’ invoca a versão do shell, enquanto ‘\time’ utiliza o binário do time.
Exemplos Práticos com o Comando ‘time’
Vamos usar o comando ‘time’ para medir a performance de dois programas, ‘loop1’ e ‘loop2’. Eles foram criados a partir de ‘loop1.c’ e ‘loop2.c’ e são projetados para demonstrar diferenças na eficiência de codificação.
O código de ‘loop1.c’ calcula o comprimento de uma string uma única vez, fora dos 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"; // get length of string once, outside of loops len = strlen( szString ); for (j=0; jJá o código de 'loop2.c' recalcula o comprimento da string em cada iteração do loop externo, demonstrando ineficiência:
#include "stdio.h" #include "string.h" #include "stdlib.h" int main (int argc, char* argv[]) { int i, j, count=0; char szString[]="how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek"; for (j=0; jVamos analisar o desempenho do 'loop1' usando 'time'.
time ./loop1
Agora vamos repetir o processo para o 'loop2'.
time ./loop2
Os resultados são exibidos de forma padrão. Ao analisá-los, é importante entender que os processos alternam entre dois modos de execução: modo usuário e modo kernel.
Em resumo, um processo no modo usuário não pode acessar diretamente o hardware ou memória fora de sua alocação. Para isso, ele deve fazer solicitações ao kernel. Após aprovação, o processo entra no modo kernel para executar a solicitação, retornando ao modo usuário em seguida.
No caso do 'loop1', o tempo gasto no modo usuário foi de 0,09 segundos, praticamente nenhum no modo kernel, e um tempo total de 0,1 segundos. Ele obteve em média 89% do tempo de CPU durante a execução.
O 'loop2', por outro lado, levou três vezes mais tempo para ser executado, com um tempo total de 0,3 segundos e 0,29 segundos no modo usuário. A média de uso da CPU foi de 96%.
Personalizando a Saída do Comando 'time'
A saída do 'time' pode ser personalizada através de strings de formato. Essas strings podem incluir texto e especificadores de formato, encontrados na página de manual do comando. Cada especificador representa uma informação específica.
Ao exibir a string, os especificadores são substituídos pelos valores correspondentes. Por exemplo, o especificador para a porcentagem de CPU é %P. O sinal de porcentagem indica ao 'time' que se trata de um especificador e não de um caractere comum.
A opção '-f' (formato) é usada para indicar ao 'time' que a string seguinte é um formato.
Nossa string de formato irá exibir "Programa:", seguido pelo nome do programa e seus parâmetros (%C). \n força a saída para a próxima linha.
Existem muitos especificadores de formato, que são sensíveis a maiúsculas e minúsculas, portanto, é necessário ter atenção ao usá-los.
Em seguida, exibiremos "Tempo total:", seguido pelo valor do tempo total de execução (%E).
Usaremos \n novamente, seguido por "Modo(s) de usuário" e o tempo de CPU gasto nesse modo (%U).
Novamente, \n para "Modo(s) Kernel" e o tempo de CPU gasto no modo kernel (%S).
Finalmente, "nCPU:" para exibir a porcentagem média de tempo de CPU usada (%P).
A string de formato é colocada entre aspas. Poderíamos também incluir caracteres \t para adicionar tabulações na saída.
time -f "Program: %CnTotal time: %EnUser Mode (s) %UnKernel Mode (s) %SnCPU: %P" ./loop1
Redirecionando a Saída para um Arquivo
Para manter um histórico dos resultados, a saída do 'time' pode ser redirecionada para um arquivo. Utilize a opção '-o' (saída). A saída do seu programa será exibida no terminal normalmente, mas a saída do 'time' será direcionada ao arquivo.
Podemos salvar a saída no arquivo 'test_results.txt' da seguinte forma:
time -o test_results.txt -f "Program: %CnTotal time: %EnUser Mode (s) %UnKernel Mode (s) %SnCPU: %P" ./loop1cat test_results.txt
A saída de 'loop1' continua sendo mostrada no terminal e os resultados do 'time' são gravados em 'test_results.txt'.
Se desejar adicionar novos resultados ao mesmo arquivo, use a opção '-a' (anexar):
time -o test_results.txt -a -f "Program: %CnTotal time: %EnUser Mode (s) %UnKernel Mode (s) %SnCPU: %P" ./loop2cat test_results.txt
O uso do especificador %C para incluir o nome do programa na saída da string de formato torna-se evidente.
Considerações Finais Sobre o Comando 'time'
O comando 'time' é uma ferramenta valiosa para programadores e desenvolvedores que buscam otimizar o desempenho de seu código, mas também para quem deseja entender melhor o que acontece nos bastidores ao executar um programa.