Alternativa de referência 'tempo' universal não-bash? [fechadas]

9

Para comparar tempos de execução de scripts entre diferentes shells, algumas respostas do SE sugerem o uso do comando bash do time , assim:

time bash -c 'foo.sh'
time dash -c 'foo.sh'

... etc , para cada shell para testar. Tais benchmarks não eliminam o tempo que cada shell carrega e inicializa o próprio . Por exemplo, suponha que os dois comandos acima tenham sido armazenados em um dispositivo lento com a velocidade de leitura de um disquete inicial , (124KB / s), dash (a ~ 150K executável) carregaria cerca de 7x mais rápido que bash ( ~ 1M ) , o tempo de carregamento do shell distorceria os números time - os tempos de pré-carregamento desses shells sendo irrelevantes para medir os tempos de execução de foo.sh sob cada shell após os shells serem carregados. / p>

Qual é o melhor utilitário portátil e geral para executar o tempo de script que pode ser executado em dentro de cada shell? Então, o código acima seria algo como:

bash -c 'general_timer_util foo.sh'
dash -c 'general_timer_util foo.sh'

NB: não há comandos shell embutidos time , pois nenhum é portátil ou geral.

Melhor ainda se o utilitário também puder avaliar o tempo gasto pelos comandos e pipelines internos de um shell, sem que o usuário tenha que primeiro envolvê-los em um script. Sintaxe artificial como essa ajudaria:

general_timer_util "while read x ; do echo x ; done < foo"

Algumas shells ' time podem gerenciar isso. Por exemplo, bash -c "time while false ; do : ; done" funciona.

    
por agc 01.01.2017 / 18:56

5 respostas

9

Você deve notar que time é especificado por POSIX , e AFAICT a única opção que POSIX menciona ( -p ) é suportada corretamente por vários shells:

$ bash -c 'time -p echo'

real 0.00
user 0.00
sys 0.00
$ dash -c 'time -p echo'

real 0.01
user 0.00
sys 0.00
$ busybox sh -c 'time -p echo'

real 0.00
user 0.00
sys 0.00
$ ksh -c 'time -p echo'       

real 0.00
user 0.00
sys 0.00
    
por 01.01.2017 / 19:18
6

O utilitário time é normalmente incorporado ao shell, como você observou, o que o torna inútil como um temporizador "neutro".

No entanto, o utilitário geralmente também está disponível como um utilitário externo, /usr/bin/time , que pode ser usado para realizar os experimentos de temporização que você propõe.

$ bash -c '/usr/bin/time foo.sh'
    
por 01.01.2017 / 19:14
6

Eu uso o comando GNU date , que suporta um temporizador de alta resolução:

START=$(date +%s.%N)
# do something #######################

"$@" &> /dev/null

#######################################
END=$(date +%s.%N)
DIFF=$( echo "scale=3; (${END} - ${START})*1000/1" | bc )
echo "${DIFF}"

E então eu chamo o script assim:

/usr/local/bin/timing dig +short unix.stackexchange.com
141.835

A unidade de saída está em milissegundos.

    
por 01.01.2017 / 19:18
4

Aqui está uma solução que:

  1. eliminate[s] the time taken for each shell to load and initialize itself

  2. can be run from within each shell

  3. Usos

    no shell built-in time commands, since none are portable or general

  4. Funciona em todos os shells compatíveis com POSIX.
  5. Funciona em todos os sistemas compatíveis com POSIX e XSI com um compilador C , ou onde você pode compilar um executável C antecipadamente.
  6. Usa a mesma implementação de tempo em todos os shells.

Existem duas partes: um pequeno programa em C que encerra gettimeofday , que é obsoleto, mas ainda mais portátil que clock_gettime e um script de shell curto que usa esse programa para obter um relógio com precisão de microssegundo lendo ambos os lados da origem de um script. O programa C é a única maneira portátil e mínima de sobrecarga para obter uma precisão de menos de um segundo em um timestamp.

Aqui está o programa C epoch.c :

#include <sys/time.h>
#include <stdio.h>
int main(int argc, char **argv) {
    struct timeval time;
    gettimeofday(&time, NULL);
    printf("%li.%06i", time.tv_sec, time.tv_usec);
}

E o script de shell timer :

#!/bin/echo Run this in the shell you want to test

START=$(./epoch)
. "$1"
END=$(./epoch)
echo "$END - $START" | bc

Esta é a linguagem de comandos shell padrão e .opengroup.org / onlinepubs / 9699919799 / utilities / bc.html "> bc e deve funcionar como um script em qualquer shell compatível com POSIX.

Você pode usar isso como:

$ bash timer ./test.sh
.002052
$ dash timer ./test.sh
.000895
$ zsh timer ./test.sh
.000662

Não mede o tempo do sistema ou do usuário, apenas o tempo decorrido não monotônico do relógio de parede. Se o relógio do sistema mudar durante a execução do script, isso fornecerá resultados incorretos. Se o sistema estiver sob carga, o resultado não será confiável. Eu não acho que nada melhor possa ser portátil entre os shells.

Um script de timer modificado pode usar eval para executar comandos fora do um script.

    
por 01.01.2017 / 23:46
4

Solução revisada várias vezes usando /proc/uptime e dc / bc / awk em grandes partes graças à entrada de agc :

#!/bin/sh

read -r before _ < /proc/uptime

sleep 2s # do something...

read -r after _ < /proc/uptime

duration=$(dc -e "${after} ${before} - n")
# Alternative using bc:
#   duration=$(echo "${after} - ${before}" | bc)
# Alternative using awk:
#   duration=$(echo "${after} ${before}" | awk '{print $1 - $2}')

echo "It took $duration seconds."

Presume-se que /proc/uptime exista e tenha uma certa forma.

    
por 01.01.2017 / 19:10