Obtenga el tiempo de ejecución del programa en el shell

407

Quiero ejecutar algo en un shell de Linux en algunas condiciones diferentes y poder generar el tiempo de ejecución de cada ejecución.

Sé que podría escribir un script de Perl o Python que haría esto, pero ¿hay alguna manera de hacerlo en el shell? (que resulta ser bash)

ʞɔıu
fuente
2
Caso de Windows: stackoverflow.com/questions/673523/…
n611x007
¿Es posible obtener Tickscomo el caso de Windows?
freeforall tousez
unix.stackexchange.com/questions/52313/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respuestas:

534

Use la timepalabra clave incorporada :

$ tiempo de ayuda

tiempo: tiempo [-p] TUBERÍA
    Ejecute PIPELINE e imprima un resumen del tiempo real, el tiempo de CPU del usuario,
    y el tiempo de CPU del sistema dedicado a ejecutar PIPELINE cuando finaliza.
    El estado de retorno es el estado de retorno de PIPELINE. La opción '-p'
    imprime el resumen de tiempos en un formato ligeramente diferente. Esto usa
    El valor de la variable TIMEFORMAT como formato de salida.

Ejemplo:

$ time sleep 2
0m2.009s reales
usuario 0m0.000s
sys 0m0.004s
Robert Gamble
fuente
1
¿Cómo se usa esto en un comando time -p i=x; while read line; do x=x; done < /path/to/file.txt? Inmediatamente devuelve 0.00 a menos que no ponga nada antes del ciclo while ... ¿qué da?
natli
Esta es una versión pobre de 'tiempo', bash incorporado. ¿Dónde está el comando 'tiempo' externo?
Znik
66
@Znik, prueba / usr / bin / time
Mark Rajcok
10
@natli: Si bien timepuede cronometrar una tubería completa tal como está (en virtud de ser una palabra clave Bash ), debe usar un comando de grupo ( { ...; ...; }) para time -p { i=x; while read line; do x=x; done < /path/to/file.txt; }
cronometrar
2
Para ver todas las versiones de tiempo que ha instalado en su sistema, puede usartype -a time
spinup
120

Puede obtener información mucho más detallada que el bash incorporado time(que Robert Gamble menciona) usando el tiempo (1) . Normalmente esto es /usr/bin/time.

Nota del editor: para asegurarse de que está invocando la utilidad externa en time lugar de la time palabra clave de su shell , invoque como /usr/bin/time.
timees una utilidad obligatoria de POSIX , pero la única opción que debe admitir es -p.
Las plataformas específicas implementan extensiones específicas no estándar: -vfunciona con la utilidad de GNUtime , como se demuestra a continuación (la pregunta está etiquetada); la implementación de BSD / macOS utiliza -lpara producir resultados similares - ver man 1 time.

Ejemplo de salida detallada:


$ /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
fuente
2
¿no sabrías de qué paquete debian vendría? no parece estar instalado de forma predeterminada
Decıu
1
Estaba haciendo referencia a tu publicación Robert. ¿A menos que se refiera al comando que sugiere no es el bash incorporado?
grepsedawk
24
Sorprendentemente, se instala desde un paquete llamado "tiempo".
Paul Tomblin
2
El resultado de / usr / bin / time se ve como "0.00usuario 0.00sistema 0: 02.00elapsado 0% CPU (0avgtext + 0avgdata 0maxresident) k 0inputs + 0outputs (0major + 172minor) pagefaults 0swaps"
Paul Tomblin
44
@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
fuente
14
Hay una manera mucho más simple. Bash calcula automáticamente la variable especial $ SECONDS, luego no es necesario volver a calcular según el comando de fecha externo. La variable $ SECONDS mantiene cuántos segundos se ejecuta el script bash cuando se inicia. Esta variable tiene alguna propiedad especial. Ver página de manual: D
Znik
He intentado tanto lo anterior como el método en el comentario. En el primero recibo un error de 'variable ilegal' y el segundo recibo 'variable no identificada'
DrBwts
45

Para una medición delta línea por línea, pruebe gnomon .

Una utilidad de línea de comandos, un poco como ts de moreutils, para anteponer información de marca de tiempo a la salida estándar de otro comando. Útil para procesos de larga duración en los que desea un registro histórico de lo que lleva tanto tiempo.

También puede usar las opciones --highy / o --mediumpara especificar un umbral de longitud en segundos, durante el cual gnomon resaltará la marca de tiempo en rojo o amarillo. Y también puedes hacer algunas otras cosas.

ejemplo

Adriano Resende
fuente
3
Gran consejo, pero para ser claros: esto es útil para los tiempos de línea por línea , pero la sobrecarga de tomar esos tiempos de grano fino aumenta significativamente el tiempo general .
mklement0
2
Utilidad impresionante .. Gracias por compartir
Kishan B
19

Si desea más precisión, use %Ncon date(y use bcpara el diff, porque $(())solo maneja enteros).

Aquí se explica cómo hacerlo:

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

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

Ejemplo:

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
fuente
15

Si tiene la intención de usar los tiempos posteriores para calcular, aprenda a usar la -fopción de /usr/bin/timegenerar código que ahorre tiempo. Aquí hay un código que utilicé recientemente para obtener y ordenar los tiempos de ejecución de toda una clase de programas de estudiantes:

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...

Luego concatenaba todos los $timefilearchivos y canalizaba la salida en un intérprete de Lua . Puede hacer lo mismo con Python o bash o cualquiera que sea su sintaxis favorita. Amo esta técnica

Norman Ramsey
fuente
Nota: La ruta completa /usr/bin/timees necesaria porque aunque which timele dirá lo contrario, si simplemente ejecuta time, ejecutará la versión de su shell de la timecual no acepta ningún argumento.
Kevin Dice
Yo iría con env time:-)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
13

Si solo necesita precisión para el segundo, puede usar la $SECONDSvariable integrada , que cuenta el número de segundos que el shell ha estado ejecutándose.

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
fuente
10

Puede usar timey subshell () :

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

O en el mismo caparazón {}:

time {
  for (( i=1; i<10000; i++ )); do
    echo 1 >/dev/null
  done
}
Eduardo Cuomo
fuente
Has publicado dos fragmentos de código idénticos. Debes haber querido tener algo diferente allí.
stason
3
@StasBekman no es cierto, primero usando (& )(nuevo contexto, subshell ) y otro con {& }(mismo shell, mismo contexto)
Eduardo Cuomo
¡Ajá! Estaba mirando muy duro a los dos y no vi la diferencia. Gracias por aclarar que {} vs ().
stason
2

El camino es

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

la salida es >>

real    0m0.014s
user    0m0.010s
sys     0m0.002s
Robel Sharma
fuente
No es necesario usar -lphtreadni -oetiquetas. Solo necesito usar el timecomando, que la respuesta aceptada explica mejor.
Dennis
77
Fue un ejemplo. Ese es mi desempeño.c tiene subprocesos, así que necesito -lpthread y para una identidad simple es -o per.
Robel Sharma
0

Un método posiblemente simple (que puede no satisfacer las necesidades de los diferentes usuarios) es el uso de shell PROMPT. Es una solución simple que puede ser útil en algunos casos. Puede usar la función de solicitud de bash como en el ejemplo a continuación:

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

El comando anterior dará como resultado el cambio del indicador de shell a:

[HH: MM: nombre de usuario SS @ nombre de host] $ 

Cada vez que ejecuta un comando (o presiona enter) que regresa al indicador del shell, el indicador mostrará la hora actual.

notas:
1) tenga en cuenta que si esperó algún tiempo antes de escribir su próximo comando, entonces esta vez debe tenerse en cuenta, es decir, la hora que se muestra en el indicador del shell es la marca de tiempo cuando se muestra el indicador del shell, no cuando ingresa el comando. algunos usuarios eligen presionar la tecla Intro para obtener un nuevo aviso con una nueva marca de tiempo antes de que estén listos para el siguiente comando.
2) Hay otras opciones y modificadores disponibles que se pueden usar para cambiar el indicador de bash, consulte (man bash) para obtener más detalles.

tstorym
fuente
No es el punto cuando el programa se ejecuta, sino la duración de la ejecución del programa.
Geno Chen