script example ejemplos definicion performance bash

performance - example - Herramientas de perfilado de rendimiento para shell scripts



shell script example (5)

Estoy intentando acelerar una colección de scripts que invocan subshells y hacen todo tipo de cosas. Me pregunto si hay herramientas disponibles para cronometrar la ejecución de un script de shell y sus shells anidados e informar sobre qué partes del script son las más caras.

Por ejemplo, si tuviera un script como el siguiente.

#!/bin/bash echo "hello" echo $(date) echo "goodbye"

Me gustaría saber cuánto duró cada una de las tres líneas. time solo me dará tiempo total para el guión. bash -x es interesante pero no incluye marcas de tiempo u otra información de tiempo.


Mi enfoque preferido es a continuación. La razón es que también es compatible con OSX (que no tiene fecha de alta precisión) y se ejecuta incluso si no tiene bc instalado.

#!/bin/bash _profiler_check_precision() { if [ -z "$PROFILE_HIGH_PRECISION" ]; then #debug "Precision of timer is unknown" if which bc > /dev/null 2>&1 && date ''+%s.%N'' | grep -vq ''/.N$''; then export PROFILE_HIGH_PRECISION=y else export PROFILE_HIGH_PRECISION=n fi fi } _profiler_ts() { _profiler_check_precision if [ "y" = "$PROFILE_HIGH_PRECISION" ]; then date ''+%s.%N'' else date ''+%s'' fi } profile_mark() { _PROF_START="$(_profiler_ts)" } profile_elapsed() { _profiler_check_precision local NOW="$(_profile_ts)" local ELAPSED= if [ "y" = "$PROFILE_HIGH_PRECISION" ]; then ELAPSED="$(echo "scale=10; $NOW - $_PROF_START" | bc | sed ''s//(/.[0-9]/{0,3/}/)[0-9]*$//1/'')" else ELAPSED=$((NOW - _PROF_START)) fi echo "$ELAPSED" } do_something() { local _PROF_START profile_mark() sleep 10 echo "Took $(profile_elapsed()) seconds" }


No tengo conocimiento de ninguna herramienta de creación de perfiles de shell.

Históricamente, uno simplemente vuelve a escribir scripts de shell demasiado lentos en Perl, Python, Ruby o incluso C.

Una idea menos drástica sería usar un shell más rápido que bash. Dash y ash están disponibles para todos los sistemas de estilo Unix y, por lo general, son bastante más pequeños y más rápidos.


Parece que quieres sincronizar cada eco. Si eco es todo lo que estás haciendo, es fácil.

alias echo=''time echo''

Si está ejecutando otro comando, esto obviamente no será suficiente.


Podría canalizar la salida de ejecutar debajo de -x a algo que marca la hora de cada línea cuando se recibe. Por ejemplo, tai64n de daemontools de djb. En un ejemplo básico,

sh -x slow.sh 2>&1 | tai64n | tai64nlocal

Esto combina stdout y stderr pero le da a todo un sello de tiempo. Tendría que analizar la salida para encontrar líneas costosas y correlacionar eso con su fuente.

También podría encontrar útil usar strace . Por ejemplo,

strace -f -ttt -T -o /tmp/analysis.txt slow.sh

Esto producirá un informe muy detallado, con mucha información de tiempo en /tmp/analysis.txt , pero a nivel de llamadas por sistema, que puede ser demasiado detallado.


Puedes configurar PS4 para que muestre la hora y el número de línea. Hacer esto no requiere instalar ninguna utilidad y funciona sin redireccionar stderr a stdout.

Para este script:

#!/bin/bash -x # Note the -x flag above, it is required for this to work PS4=''+ $(date "+%s.%N ($LINENO) ")'' for i in {0..2} do echo $i done sleep 1 echo done

La salida se ve como:

+ PS4=''+ $(date "+%s.%N ($LINENO) ")'' + 1291311776.108610290 (3) for i in ''{0..2}'' + 1291311776.120680354 (5) echo 0 0 + 1291311776.133917546 (3) for i in ''{0..2}'' + 1291311776.146386339 (5) echo 1 1 + 1291311776.158646585 (3) for i in ''{0..2}'' + 1291311776.171003138 (5) echo 2 2 + 1291311776.183450114 (7) sleep 1 + 1291311777.203053652 (8) echo done done

Esto supone la fecha de GNU, pero puede cambiar la especificación de salida a cualquier cosa que desee o que coincida con la versión de la fecha que utiliza.

Nota: Si tiene un script existente con el que desea hacer esto sin modificarlo, puede hacerlo:

PS4=''+ $(date "+%s.%N ($LINENO) ")'' bash -x scriptname

En el próximo Bash 5, podrá guardar la date bifurcación (pero obtendrá microsegundos en lugar de nanosegundos):

PS4=''+ $EPOCHREALTIME ($LINENO) ''