Comment obtenir efficacement le temps dexécution dun script?

Je voudrais afficher lheure de fin dun script.

Ce que je fais actuellement est –

#!/bin/bash date ## echo the date at start # the script contents date ## echo the date at end 

Ceci montre simplement lheure de début et de fin du script. Serait-ce possible dafficher une sortie à grain fin comme le temps processeur / temps io, etc?

Commentaires

Réponse

Jus t utilisez time lorsque vous appelez le script:

time yourscript.sh 

Commentaires

  • Affiche trois fois: real, user et sys. Pour connaître leur signification, consultez ici .
  • et  » real  » est probablement ce que les gens veulent savoir –  » Real est lheure de lhorloge murale – heure du début à la fin de lappel  »
  • Existe-t-il un moyen de capturer la sortie standard dans un fichier? Par exemple, quelque chose comme time $( ... ) >> out.txt
  • Vous pouvez également faire cela pour des séquences de commandes sur la ligne de commande, par exemple: time (command1 && command2)
  • Ou il pourrait, dans son script, simplement faire: echo $ SECONDS en supposant que cest bash ….

Réponse

Si time nest « pas une option,

start=`date +%s` stuff end=`date +%s` runtime=$((end-start)) 

Commentaires

  • Notez que cela ne fonctionne que si vous navez ‘ pas besoin dune précision inférieure à la seconde. Pour certaines utilisations, cela peut être acceptable , pour les autres non. Pour une précision légèrement meilleure (vous ‘ invoquez toujours date deux fois, par exemple, donc vous pouvez à mieux obtenir une précision à la milliseconde en pratique, et probablement moins), essayez dutiliser date +%s.%N. (%N est en nanosecondes depuis toute la seconde .)
  • @ChrisH Oh. Cest bien de le signaler; le développement arithmétique de bash est uniquement composé dentiers. Je vois deux obvi ous options; soit abandonnez le point dans la chaîne de format de date (et traitez la valeur résultante comme des nanosecondes depuis lépoque), utilisez donc date +%s%N, ou utilisez quelque chose de plus capable comme bc pour calculer le temps dexécution réel à partir des deux valeurs comme le suggère jwchew. Pourtant, je pense que cette approche est une manière sous-optimale de le faire; time est considérablement meilleur sil est disponible, pour les raisons exposées ci-dessus.
  • Installez simplement bc et procédez comme suit: runtime=$( echo "$end - $start" | bc -l )
  • Si votre script prend plusieurs minutes, utilisez: echo "Duration: $((($(date +%s)-$start)/60)) minutes
  • Suite à @ rubo77 commentaire, si votre script prend plusieurs heures, utilisez hours=$((runtime / 3600)); minutes=$(( (runtime % 3600) / 60 )); seconds=$(( (runtime % 3600) % 60 )); echo "Runtime: $hours:$minutes:$seconds (hh:mm:ss)"

Answer

Appelez simplement times sans argument en quittant votre script.

Avec ksh ou zsh, vous pouvez également utiliser time à la place. Avec zsh, time vous donnera également lheure de lhorloge murale en plus de l utilisateur et système temps CPU.

Pour conserver létat de sortie de votre script, vous pouvez le faire:

ret=$?; times; exit "$ret" 

Ou vous peut également ajouter un piège sur EXIT:

trap times EXIT 

De cette façon, les heures seront appelées chaque fois que le shell sort et létat de sortie sera conservé.

$ bash -c "trap times EXIT; : {1..1000000}" 0m0.932s 0m0.028s 0m0.000s 0m0.000s $ zsh -c "trap time EXIT; : {1..1000000}" shell 0.67s user 0.01s system 100% cpu 0.677 total children 0.00s user 0.00s system 0% cpu 0.677 total 

Notez également que tous les éléments bash, ksh et zsh ont une variable spéciale $SECONDS qui est automatiquement incrémentée toutes les secondes. À la fois dans zsh et ksh93, cette variable peut également être en virgule flottante (avec typeset -F SECONDS ) pour obtenir plus de précision. Ce nest que lheure de lhorloge murale, pas le temps CPU.

Commentaires

  • Cette variable $ SECONDS est très utile, merci!
  • Votre approche élimine-t-elle leffet des événements temporels? – – Je pense que votre approche est proche de lapproche time présentée précédemment.- – Je pense que lapproche timeit présentée en code MATLAB peut être utile ici.
  • Bonjour, @St é phane Chazelas. Jai trouvé que times ‘ ne donne pas de temps sur le mur, nest-ce pas? par exemple, bash -c 'trap times EXIT;sleep 2'
  • @Binarus, oui, cette fonctionnalité vient de ksh. Contrairement à ksh93 / zsh, à côté de bash ne prenant pas en charge la virgule flottante, il ‘ est également interrompu en ce quaprès avoir défini SECONDS sur 0, il passera à 1 de 0 à 1 seconde plus tard ( car il ne considère que le résultat de time() qui na quune seconde granularité complète).
  • @Binarus, pas que ‘ s entre 0 et 1. Si vous réglez SECONDS sur 0 à 12: 00: 00.000, il passera à 1 une seconde plus tard. Mais si vous le définissez sur 12: 00: 00.999, il passera à 1 un milliseconde plus tard. Mais oui, je conviens que cela n’a probablement pas ‘ d’importance en pratique si vous n’avez pas ‘ une précision inférieure à la seconde de toute façon.

Réponse

Je « suis un peu en retard dans le train en marche, mais je voulais publier ma solution (pour une précision inférieure à la seconde ) au cas où dautres tomberaient sur ce fil de discussion lors dune recherche. La sortie est au format jours, heures, minutes et enfin secondes:

res1=$(date +%s.%N) # do stuff in here res2=$(date +%s.%N) dt=$(echo "$res2 - $res1" | bc) dd=$(echo "$dt/86400" | bc) dt2=$(echo "$dt-86400*$dd" | bc) dh=$(echo "$dt2/3600" | bc) dt3=$(echo "$dt2-3600*$dh" | bc) dm=$(echo "$dt3/60" | bc) ds=$(echo "$dt3-60*$dm" | bc) LC_NUMERIC=C printf "Total runtime: %d:%02d:%02d:%02.4f\n" $dd $dh $dm $ds 

Jespère que quelquun là-bas trouve cela utile!

Commentaires

  • Je suppose quil ny a pas dautre moyen (seulement bash) sauf en utilisant ‘ bc ‘ pour faire les calculs. BTW vraiment bon script;)
  • Attention à FreeBSD ‘ s date ne prend pas en charge la précision inférieure à la seconde et ajoutera simplement le littéral «N» à lhorodatage.
  • Très beau script, mais mon bash ne le fait pas ‘ t gérer la sous-seconde partie. Jai aussi appris que / 1 dans bc supprime effectivement cela, alors jai ajouté @ / 1 @ au calcul $ ds, et il affiche des trucs très bien maintenant!
  • bc prend en charge modulo: dt2=$(echo "$dt%86400" | bc). Dire simplement … BTW, je préfère la forme dt2=$(bc <<< "${dt}%86400") mais que ‘ est entièrement personnel.
  • Je ne ‘ Je ne sais encore rien sur bc, mais la division par 86400 me rend méfiant pour le raison suivante: il y a des jours qui nont pas 86400 secondes, par exemple des jours où lheure passe de lheure dété à lheure normale et vice versa, ou des jours avec des secondes intercalaires. Si ces jours font partie de la période que vous souhaitez calculer, cest-à-dire se situent entre res1 et res2 (y compris ces valeurs), votre script échouera probablement.

Réponse

Ma méthode pour bash :

# Reset BASH time counter SECONDS=0 # # do stuff # ELAPSED="Elapsed: $(($SECONDS / 3600))hrs $((($SECONDS / 60) % 60))min $(($SECONDS % 60))sec" 

Commentaires

  • Cela montre le temps écoulé, mais cela ne ‘ t afficher  » une sortie à grain fin comme le temps du processeur, le temps dE / S  » comme demandé dans la question.
  • Ceux qui recherchent une réponse à la question posée trouveront probablement cette solution utile. Votre commentaire serait mieux adressé à la question des OP.

Réponse

Personnellement, jaime envelopper tous mes code de script dans une fonction « main » comme ceci:

main () { echo running ... } # stuff ... # calling the function at the very end of the script time main 

Remarquez à quel point il est facile dutiliser la commande time dans ce scénario. Évidemment, vous ne mesurez pas le temps précis, y compris le temps d’analyse du script, mais je le trouve suffisamment précis dans la plupart des situations.

Commentaires

  • Excellente solution, ne ‘ t nécessite des outils supplémentaires et est autonome.

Réponse

#!/bin/bash start=$(date +%s.%N) # HERE BE CODE end=$(date +%s.%N) runtime=$(python -c "print(${end} - ${start})") echo "Runtime was $runtime" 

Oui, cela appelle Python, mais si vous pouvez vivre avec cela, alors cest une solution assez intéressante et concise.

Commentaires

  • Sachez que lexécution de cette commande python dans un sous-shell et la lecture de sa sortie prendront plusieurs millions de nanosecondes sur la plupart des systèmes actuels. Idem pour lexécution de date.
  •  » Plusieurs millions de nanosecondes  » font plusieurs millisecondes . Les gens qui chronométrent les scripts bash ne sont généralement pas très préoccupés par cela (sauf sils exécutent plusieurs milliards de scripts par mégaseconde).
  • Notez également que, même si le le calcul est fait dans un processus python, les valeurs ont été entièrement collectées avant lappel de python. Le temps dexécution du script sera mesuré correctement, sans les  » millions de nanosecondes  » surcoût.
  • time main ci-dessus est tellement plus propre …oui, nous pouvons vivre avec beaucoup de dégradation, mais cela ‘ est bien mieux sans alors laissez ‘ rester des ingénieurs!
  • $(echo $end - $start | bc) fera la même chose sans python

Réponse

Cette question est assez ancienne, mais en essayant de trouver ma façon préférée de le faire, ce fil est venu haut … et je « suis surpris que personne ne lait mentionné:

perf stat -r 10 -B sleep 1 

« perf » est un outil danalyse des performances inclus dans le noyau sous « tools / perf » et souvent disponible pour linstallation en tant que paquet séparé (« perf » dans CentOS et « linux-tools » sur Debian / Ubuntu). Le Linux Kernal perf Wiki a beaucoup plus dinformations à ce sujet.

Lexécution de « perf stat » donne pas mal de détails, y compris le temps dexécution moyen à la fin:

1.002248382 seconds time elapsed ( +- 0.01% ) 

Commentaires

  • Quest-ce que perf?
  • @B Layer – a modifié ma réponse t o donne une brève description de ‘ perf ‘.
  • perf stat se plaint maintenant de  » Vous navez peut-être pas lautorisation de collecter des statistiques.  » sauf si vous exécutez certaines commandes avec sudo, ce qui le rend inutile dans tous les scénarios où vous ne possédez ‘ pas complètement la machine cible.
  • Incroyable, merci! Solution bien plus fine que time dautres suggèrent. En particulier, time ne sapplique pas à la mesure des solutions de concurrence de code (car il ne permet pas ‘ t le temps dimpression en millisecondes et moins) , contrairement à votre solution.

Réponse

Une petite fonction shell qui peut être ajoutée avant commandes pour mesurer leur temps:

tm() { local start=$(date +%s) $@ local exit_code=$? echo >&2 "took ~$(($(date +%s)-${start})) seconds. exited with ${exit_code}" return $exit_code } 

Ensuite, utilisez-le dans votre script, ou sur votre ligne de commande comme ceci:

tm the_original_command with all its parameters 

Commentaires

  • Cela vaudrait la peine dajouter des millisecondes, a essayé ilke s=$(date +%s000), pas sûr si cela fonctionne.
  • @loretoparisi pendant des millisecondes, vous pouvez essayer date +%s%N. Voir serverfault.com/questions/151109/…
  • Cest génial, mais plus sûr utilisez "$@"

Answer

#!/bin/csh #PBS -q glean #PBS -l nodes=1:ppn=1 #PBS -l walltime=10:00:00 #PBS -o a.log #PBS -e a.err #PBS -V #PBS -M [email protected] #PBS -m abe #PBS -A k4zhang-group START=$(date +%s) for i in {1..1000000} do echo 1 done END=$(date +%s) DIFF=$(echo "$END - $START" | bc) echo "It takes DIFF=$DIFF seconds to complete this task..." 

Commentaires

  • En quoi est-ce vraiment différent des autres réponses déjà données qui utilisent date avant et après le script et afficher la différence entre eux?

Réponse

  1. Juste utilisez time [any command] . Ex: time sleep 1 dormira pendant un temps réel (cest-à-dire: comme chronométré par un chronomètre) de ~ 1.000 à ~ 1.020 sec, comme indiqué ici:

      $ time sleep 1 real 0m1.011s user 0m0.004s sys 0m0.000s  

    Quelle belle chose. Vous pouvez mettre nimporte quelle commande après, et il produit le résultat sous une forme agréable et lisible par lhomme. Jaime vraiment lutiliser pour chronométrer les builds. Ex:

      # time your "make" build time make # time your "Bazel" build time bazel build //path/to/some:target  

    … ou pour des opérations git qui peuvent potentiellement être long, pour que je puisse développer des attentes mentales réalistes:

      # time how long it takes to pull from a massive repo when # I"m working from home during COVID-19. NB: `git pull` # is sooooo much slower than just pulling the one branch # you need with `git pull origin <branch>`, so just fetch # or pull what you need! time git pull origin master  
  2. Pour des besoins de synchronisation plus personnalisés où vous devrez peut-être manipuler la sortie ou la convertir en dautres formes, en bash , utilisez la variable interne $SECONDS. Voici « une démo, comprenant la conversion de ces secondes en dautres unités, telles que les minutes en virgule flottante:

    Notez que dt_min est arrondi de 0.01666666666... (1 seconde = autant de minutes) à 0.017 dans ce cas puisque je « m utilise la fonction printf pour arrondir. La partie sleep 1; ci-dessous est lendroit où vous « appelleriez votre script pour quil sexécute et chronométrer, mais je dors juste 1 seconde pour le plaisir de cette démo.

    Commande:

      start=$SECONDS; sleep 1; end=$SECONDS; dt_sec=$(( end - start )); \ dt_min=$(printf %.3f $(echo "$dt_sec/60" | bc -l)); \ echo "dt_sec = $dt_sec; dt_min = $dt_min"  

    Sortie:

      dt_sec = 1; dt_min = 0.017  

Connexes:

  1. En savoir plus à propos de bc et printf dans ma réponse ici: https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in-bash/58479867#58479867
  2. Je ne me souviens plus de lendroit où jai découvert la commande time, mais cela peut provenir de Réponse de @Trudbert « ici .

Réponse

En utilisant uniquement bash il est également possible de mesurer et de calculer la durée dune partie du script shell (ou le temps écoulé pour tout le script):

start=$SECONDS ... # do time consuming stuff end=$SECONDS 

vous pouvez maintenant soit simplement imprimer la différence:

echo "duration: $((end-start)) seconds." 

si vous navez besoin que dune durée incrémentielle, faites:

echo "duration: $((SECONDS-start)) seconds elapsed.." 

Vous pouvez également stocker la durée dans une variable:

let diff=end-start 

Commentaires

  • ^ CECI est la réponse aux gens. Ou plus simplement: $ SECONDS à la fin. Il ‘ est une variable Bash INTÉGRÉE. Toutes les autres réponses font juste un travail supplémentaire pour réinventer cette roue …
  • Ceci est juste une répétition de la réponse précédente de Marks unix.stackexchange .com / a / 340156/155362 .

Answer

Fonction de chronométrage basée sur SECONDS, limité à la granularité de second niveau uniquement, nutilise aucune commande externe:

time_it() { local start=$SECONDS ts ec printf -v ts "%(%Y-%m-%d_%H:%M:%S)T" -1 printf "%s\n" "$ts Starting $*" "$@"; ec=$? printf -v ts "%(%Y-%m-%d_%H:%M:%S)T" -1 printf "%s\n" "$ts Finished $*; elapsed = $((SECONDS-start)) seconds" # make sure to return the exit code of the command so that the caller can use it return "$ec" } 

Par exemple:

time_it sleep 5 

donne

2019-03-30_17:24:37 Starting sleep 5 2019-03-30_17:24:42 Finished sleep 5; elapsed = 5 seconds 

Réponse

Utiliser le temps bash intégré?

time: time [-p] PIPELINE Execute PIPELINE and print a summary of the real time, user CPU time, and system CPU time spent executing PIPELINE when it terminates. The return status is the return status of PIPELINE. The `-p" option prints the timing summary in a slightly different format. This uses the value of the TIMEFORMAT variable as the output format. 

Exemple:

TIMEFORMAT="The command took %Rs" time { sleep 0.1 } 

Résultat:

The command took 0.108s 

Answer

Voici « une variante dAlex « La réponse. Je ne me soucie que des minutes et des secondes, mais je voulais aussi quelle soit formatée différemment. Jai donc fait ceci:

start=$(date +%s) end=$(date +%s) runtime=$(python -c "print "%u:%02u" % ((${end} - ${start})/60, (${end} - ${start})%60)") 

Commentaires

  • Pourquoi voter contre? Ai-je un bug?
  • Utiliser python pour ce calcul me semble non plus être un bogue, désolé mec. Pourquoi les gens peuvent ‘ appeler simplement time me dépasse.

Réponse

#!/bin/bash begin=$(date +"%s") Script termin=$(date +"%s") difftimelps=$(($termin-$begin)) echo "$(($difftimelps / 60)) minutes and $(($difftimelps % 60)) seconds elapsed for Script Execution." 

Réponse

La solution acceptée en utilisant time écrit dans stderr.
La solution utilisant times écrit dans stdout.
Les solutions utilisant $SECONDS manquent de précision inférieure à la seconde.
Les autres solutions impliquent lappel de programmes externes comme date ou perf ce qui nest pas efficace.
Si lun de ces éléments vous convient, utilisez-le.

Mais si vous avez besoin dune solution efficace pour obtenir les temps avec une précision de la milliseconde et en ont besoin en variables telles que la sortie dorigine reste intacte vous pouvez combiner la substitution de processus avec des redirections autour de time, ce qui est beaucoup plus rapide que dappeler programmes externes et autorise les redirections autour du script dencapsulation de synchronisation comme sur la commande / script dorigine.

# Preparations: Cmd=vgs # example of a program to be timed which is writing to stdout and stderr Cmd="eval { echo stdout; echo stderr >&2; sleep 0.1; }" # other example; replace with your own TIMEFORMAT="%3R %3U %3S" # make time output easy to parse 

Sélectionnez lune des variantes suivantes analysant la sortie de time adapté à vos besoins:
Variante la plus courte où stdout de $Cmd est écrit dans stderr et rien à stdout:

read Elapsed User System < <({ time $Cmd 2>&3; } 3>&2 2>&1 >&3) 

Variante plus longue qui conserve original stdout et stderr séparés lun de lautre:

{ read Elapsed User System < <({ time $Cmd 2>&4; } 4>&2 2>&1 >&3); } 3>&1 

La variante la plus compliquée comprend la fermeture des descripteurs de fichiers supplémentaires tels que $Cmd est appelé comme si sans ce wrapper de synchronisation et lvm Les commandes comme vgs ne se plaignent pas de la fuite de descripteurs de fichiers:

{ read Elapsed User System < <({ time $Cmd 2>&4 4>&-; } 4>&2 2>&1 >&3 3>&-); } 3>&1 

Vous peut même simuler une addition en virgule flottante dans bash sans appeler bc ce qui serait beaucoup plus lent:

CPU=`printf %04d $((10#${User/.}+10#${System/.}))` # replace with your own postprocessing echo CPU ${CPU::-3}.${CPU: -3} s, Elapsed $Elapsed s >&2 # redirected independent of $Cmd 

Sorties possibles avec les deux exemples de $Cmd sur un CPU lent:

File descriptor 3 (/dev/pts/1) leaked on vgs invocation. Parent PID 10756: bash File descriptor 4 (/dev/pts/1) leaked on vgs invocation. Parent PID 10756: bash VG #PV #LV #SN Attr VSize VFree b3 3 24 0 wz--n- 1.31t 1.19t CPU 0.052 s, Elapsed 0.056 s 

Ou:

stdout stderr CPU 0.008 s, Elapsed 0.109 s 

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *