Wie kann man die Ausführungszeit eines Skripts effektiv ermitteln?

Ich möchte die Fertigstellungszeit eines Skripts anzeigen.

Was ich derzeit mache, ist –

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

Dies zeigt nur den Zeitpunkt des Starts und des Endes des Skripts Es ist möglich, eine feinkörnige Ausgabe wie Prozessorzeit / Io-Zeit usw. anzuzeigen.

Kommentare

Antwort

Jus Verwenden Sie time nicht, wenn Sie das Skript aufrufen:

time yourscript.sh 

Kommentare

  • Dies wird dreimal ausgegeben: real, user und sys. Die Bedeutung dieser finden Sie unter hier .
  • und “ real “ ist wahrscheinlich das, was die Leute wissen wollen – “ Real ist die Wanduhrzeit – Zeit vom Beginn bis zum Ende des Anrufs “
  • Gibt es eine Möglichkeit, das Standardout in einer Datei zu erfassen? Beispiel: time $( ... ) >> out.txt
  • Sie können dies auch für Befehlssequenzen in der Befehlszeile tun, z. B.: time (command1 && command2)
  • Oder er könnte in seinem Skript einfach Folgendes tun: $ SECONDS wiedergeben, vorausgesetzt, es ist Bash ….

Antwort

Wenn time keine Option ist,

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

Kommentare

  • Beachten Sie, dass dies nur funktioniert, wenn Sie ‚ keine Genauigkeit von weniger als einer Sekunde benötigen. Für einige Anwendungen ist dies möglicherweise akzeptabel Für andere nicht. Für eine etwas bessere Genauigkeit (Sie ‚ rufen date beispielsweise zweimal auf, also möglicherweise bei Versuchen Sie am besten, date +%s.%N zu verwenden (%N ist Nanosekunden seit der gesamten Sekunde) .)
  • @ChrisH Oh. Gut darauf hinzuweisen; Bash-Arithmetik-Erweiterung ist nur eine ganze Zahl. Ich sehe zwei obvi Optionen; Lassen Sie entweder den Punkt in der Zeichenfolge im Datumsformat fallen (und behandeln Sie den resultierenden Wert als Nanosekunden seit der Epoche), verwenden Sie also date +%s%N oder verwenden Sie etwas Stärkeres wie bc, um die tatsächliche Laufzeit aus den beiden Werten zu berechnen, wie von jwchew vorgeschlagen. Dennoch halte ich diesen Ansatz für eine suboptimale Methode. time ist aus den oben genannten Gründen erheblich besser, wenn verfügbar.
  • Installieren Sie einfach bc und führen Sie folgende Schritte aus: runtime=$( echo "$end - $start" | bc -l )
  • Wenn Ihr Skript mehrere Minuten dauert, verwenden Sie: echo "Duration: $((($(date +%s)-$start)/60)) minutes
  • Weiter zu @ rubo77 Kommentar: Wenn Ihr Skript mehrere Stunden dauert, verwenden Sie hours=$((runtime / 3600)); minutes=$(( (runtime % 3600) / 60 )); seconds=$(( (runtime % 3600) % 60 )); echo "Runtime: $hours:$minutes:$seconds (hh:mm:ss)"

Antwort

Rufen Sie beim Beenden Ihres Skripts einfach times ohne Argumente auf.

Mit ksh oder zsh, Sie können stattdessen auch time verwenden. Mit zsh gibt time neben user und auch die Wanduhrzeit an System CPU-Zeit.

Um den Exit-Status Ihres Skripts beizubehalten, können Sie Folgendes festlegen:

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

Oder Sie kann auch eine Falle für EXIT hinzufügen:

trap times EXIT 

Auf diese Weise werden Zeiten aufgerufen, wenn die Shell beendet wird und Der Exit-Status bleibt erhalten.

$ 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 

Beachten Sie auch, dass alle bash, ksh und zsh haben eine spezielle Variable $SECONDS, die automatisch jede Sekunde erhöht wird. Sowohl in zsh als auch in ksh93 kann diese Variable auch als Gleitkomma festgelegt werden (mit typeset -F SECONDS ) um mehr Präzision zu bekommen. Dies ist nur die Wanduhrzeit, nicht die CPU-Zeit.

Kommentare

  • Diese Variable $ SECONDS ist sehr nützlich, danke!
  • Beseitigt Ihr Ansatz die Auswirkung zeitlicher Ereignisse? – – Ich denke, Ihr Ansatz ist in der Nähe des zuvor vorgestellten Ansatzes time.- – Ich denke, der im MATLAB-Code vorgestellte Ansatz timeit kann hier nützlich sein.
  • Hallo, @St é Phane Chazelas. Ich habe festgestellt, dass times ‚ keine Wandzeit angibt, oder? Beispiel: bash -c 'trap times EXIT;sleep 2'
  • @Binarus, ja, diese Funktion stammt von ksh. Im Gegensatz zu ksh93 / zsh ist neben bash, das kein Gleitkomma unterstützt, ‚ auch ein Fehler aufgetreten, nachdem Sie SECONDS auf 0 gesetzt haben, wird es von 0 auf 1 Sekunde später auf 1 geändert ( da nur das Ergebnis von time() berücksichtigt wird, das nur die volle zweite Granularität aufweist).
  • @Binarus, nicht das ‚ s zwischen 0 und 1. Wenn Sie SECONDS um 12: 00: 00.000 auf 0 setzen, wird es eine Sekunde später auf 1 geändert. Wenn Sie es jedoch auf 12: 00: 00.999 einstellen, wird es eine Millisekunde später auf 1 geändert. Aber ja, ich bin damit einverstanden, dass ‚ in der Praxis wahrscheinlich nicht viel ausmacht, wenn Sie ‚ ohnehin keine Genauigkeit von weniger als einer Sekunde haben.

Antwort

Ich bin etwas spät dran, wollte aber meine Lösung veröffentlichen (aus Gründen der Genauigkeit von weniger als einer Sekunde) ) für den Fall, dass andere beim Suchen auf diesen Thread stoßen. Die Ausgabe erfolgt im Format von Tagen, Stunden, Minuten und schließlich Sekunden:

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 

Hoffe auf jemanden da draußen findet das nützlich!

Kommentare

  • Ich denke, es gibt keinen anderen (nur bash) Weg als die Verwendung von ‚ bc ‚, um die Berechnungen durchzuführen. Übrigens wirklich gutes Skript;)
  • Beachten Sie, dass FreeBSD ‚ s date unterstützt keine Genauigkeit von weniger als einer Sekunde und hängt nur das Literal „N“ an den Zeitstempel an.
  • Sehr schönes Skript, aber meine Bash funktioniert nicht ‚ behandelt den Teil der zweiten Sekunde nicht. Ich habe auch gelernt, dass / 1 in bc das effektiv entfernt, also habe ich @ / 1 @ zur $ ds-Berechnung hinzugefügt und es zeigt jetzt sehr schöne Dinge an!
  • bc unterstützt modulo: dt2=$(echo "$dt%86400" | bc). Ich sage nur … Übrigens, ich bevorzuge die Form dt2=$(bc <<< "${dt}%86400"), aber diese ‚ ist ganz persönlich.
  • Ich ‚ Ich weiß noch nichts über bc, aber die Division durch 86400 macht mich misstrauisch gegenüber dem folgender Grund: Es gibt Tage ohne 86400 Sekunden, z. B. Tage, an denen die Zeit von der Sommerzeit auf die normale Zeit und umgekehrt umgeschaltet wird, oder Tage mit Schaltsekunden. Wenn solche Tage Teil der Zeitspanne sind, die Sie berechnen möchten, dh zwischen res1 und res2 (einschließlich dieser Werte), Ihrem Skript wird wahrscheinlich fehlschlagen.

Antwort

Meine Methode für bash :

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

Kommentare

  • Dies zeigt die verstrichene Zeit an, aber nicht ‚ “ feinkörnige Ausgabe wie Prozessorzeit, E / A-Zeit “ wie in der Frage angefordert.
  • Diejenigen, die nach einer Antwort auf die gestellte Frage suchen, werden diese Lösung wahrscheinlich nützlich finden. Ihr Kommentar ist besser auf die Frage des OP gerichtet.

Antwort

Persönlich möchte ich alle meine Fragen einpacken Skriptcode in einer „Haupt“ -Funktion wie der folgenden:

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

Beachten Sie, wie einfach die Verwendung des Befehls time ist In diesem Szenario. Offensichtlich messen Sie nicht die genaue Zeit einschließlich der Skript-Analysezeit, aber ich finde sie in den meisten Situationen genau genug.

Kommentare

  • Großartige Lösung, ‚ erfordert keine zusätzlichen Tools und ist in sich geschlossen.

Antwort

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

Ja, dies ruft Python auf, aber wenn Sie damit leben können, ist dies eine nette, knappe Lösung.

Kommentare

  • Beachten Sie, dass das Ausführen des Befehls python in einer Subshell und das Lesen der Ausgabe auf den meisten aktuellen Systemen mehrere Millionen Nanosekunden dauert. Gleiches gilt für das Ausführen von date.
  • “ Mehrere Millionen Nanosekunden “ sind mehrere Millisekunden Leute, die Bash-Skripte zeitlich festlegen, sind normalerweise nicht sehr besorgt darüber (es sei denn, sie führen mehrere Milliarden Skripte pro Megasekunde aus).
  • Beachten Sie auch, dass, selbst wenn die Die Berechnung erfolgt innerhalb eines Python-Prozesses. Die Werte wurden vollständig erfasst, bevor Python aufgerufen wurde. Die Ausführungszeit des Skripts wird korrekt gemessen, ohne dass der “ Millionen von Nanosekunden “ Overhead.
  • time main oben ist so viel sauberer …Ja, wir können mit viel Verschlechterung leben, aber es ist ‚ viel besser, ohne dass ‚ Ingenieure bleiben!
  • $(echo $end - $start | bc) macht dasselbe ohne Python

Antwort

Diese Frage ist ziemlich alt, aber als ich versuchte, meine Lieblingsmethode zu finden, kam dieser Thread hoch … und ich bin überrascht, dass niemand sie erwähnt hat:

perf stat -r 10 -B sleep 1 

„perf“ ist ein Tool zur Leistungsanalyse, das im Kernel unter „tools / perf“ enthalten ist und häufig als separates Paket installiert werden kann („perf“ in CentOS und „linux-tools“ unter Debian / Ubuntu). Das Linux Kernal perf Wiki enthält viel mehr Informationen dazu.

Das Ausführen von „perf stat“ enthält einige Details, einschließlich der durchschnittlichen Ausführungszeit ganz am Ende:

1.002248382 seconds time elapsed ( +- 0.01% ) 

Kommentare

  • Was ist perf?
  • @B Layer – hat meine Antwort bearbeitet t o Geben Sie eine kurze Beschreibung von ‚ perf ‚.
  • perf stat beschwert sich jetzt über “ Möglicherweise haben Sie keine Berechtigung zum Sammeln von Statistiken. “ es sei denn, Sie führen einige Befehle mit , was es in allen Szenarien nutzlos macht, in denen Sie ‚ Ihre Zielmaschine nicht vollständig besitzen.
  • Erstaunlich, danke! Viel feinkörnigere Lösung als time andere vorschlagen. Insbesondere ist time nicht auf Messcode-Wettbewerbslösungen anwendbar (da ‚ keine Druckzeit in Millisekunden und weniger benötigt wird). , wohingegen Ihre Lösung dies tut.

Antwort

Eine kleine Shell-Funktion, die zuvor hinzugefügt werden kann Befehle zum Messen ihrer Zeit:

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

Verwenden Sie sie dann in Ihrem Skript oder in Ihrer Befehlszeile wie folgt:

tm the_original_command with all its parameters 

Kommentare

  • Es wäre sinnvoll, Millisekunden hinzuzufügen, versucht ilke s=$(date +%s000), nicht sicher Wenn es funktioniert.
  • @loretoparisi für Millisekunden, können Sie date +%s%N versuchen. Siehe serverfault.com/questions/151109/…
  • Dies ist großartig, außer sicherer Verwenden Sie "$@"

Antwort

#!/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..." 

Kommentare

  • Wie unterscheidet sich das wirklich von den anderen bereits gegebenen Antworten, die vorher und nachher date verwenden? das Skript und geben Sie den Unterschied zwischen ihnen aus?

Antwort

  1. Nur benutze time [any command] . Beispiel: time sleep 1 schläft für eine Echtzeit (dh wie von einer Stoppuhr gesteuert) von ~ 1.000 bis ~ 1.020 Sekunden, wie hier gezeigt:

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

    Was für eine schöne Sache. Sie können einen beliebigen Befehl danach setzen und das Ergebnis wird in einer schönen, für Menschen lesbaren Form ausgegeben. Ich benutze es wirklich gerne für Timing-Builds. Beispiel:

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

    … oder für Git-Operationen, die möglicherweise wirklich sein können lang, damit ich realistische mentale Erwartungen entwickeln kann:

      # 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. Für individuellere Timing-Anforderungen müssen Sie möglicherweise die Ausgabe in bash bearbeiten oder in andere Formen konvertieren Verwenden Sie die interne Variable $SECONDS. Hier ist eine Demo, einschließlich der Konvertierung dieser Sekunden in andere Einheiten, z. B. Gleitkomma-Minuten:

    Beachten Sie, dass dt_min von 0.01666666666... (1 Sekunde = so viele Minuten) auf 0.017 gerundet wird in diesem Fall, da ich die Funktion printf zum Runden verwende. Im folgenden sleep 1; -Teil würden Sie Ihr Skript zum Ausführen und zur Zeit aufrufen, aber ich schlafe stattdessen nur 1 Sekunde, um diese Demo zu erstellen.

    Befehl:

      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"  

    Ausgabe:

      dt_sec = 1; dt_min = 0.017  

Verwandte Themen:

  1. Lesen Sie mehr über bc und printf in meiner Antwort hier: https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in-bash/58479867#58479867
  2. Ich kann mich nicht mehr erinnern, wo ich zum ersten Mal von dem Befehl time erfahren habe, aber möglicherweise von @Trudberts Antwort hier .

Antwort

Nur mit bash Es ist auch möglich, die Zeitdauer für einen Teil des Shell-Skripts zu messen und zu berechnen (oder die verstrichene Zeit für das gesamte Skript):

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

Sie können jetzt entweder einfach die Differenz drucken:

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

Wenn Sie nur eine inkrementelle Dauer benötigen, gehen Sie wie folgt vor:

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

Sie können die Dauer auch in einer Variablen speichern:

let diff=end-start 

Kommentare

  • ^ DAS ist die Antwort Leute. Oder einfacher: $ SECONDS am Ende. Es ‚ ist eine eingebaute Bash-Variable. Alle anderen Antworten machen nur zusätzliche Arbeit, um dieses Rad neu zu erfinden …
  • Dies ist nur eine Wiederholung der früheren Antwort von Marks unix.stackexchange .com / a / 340156/155362 .

Antwort

Timing-Funktion basierend auf SECONDS, nur auf Granularität der zweiten Ebene beschränkt, verwendet keine externen Befehle:

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" } 

Zum Beispiel:

time_it sleep 5 

gibt

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

Antwort

Bash-Zeit verwenden?

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. 

Beispiel:

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

Ausgabe:

The command took 0.108s 

Antwort

Hier ist eine Variation von Alex „s Antwort. Ich kümmere mich nur um Minuten und Sekunden, aber ich wollte auch, dass es anders formatiert wird. Also habe ich Folgendes getan:

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

Kommentare

  • Warum die Abwertung? Habe ich einen Fehler?
  • Die Verwendung von python für diese Berechnung scheint mir ebenfalls ein Fehler zu sein, sorry man. Warum Leute ‚ nicht einfach time anrufen können, ist mir ein Rätsel.

Antwort

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

Antwort

Die akzeptierte Lösung Mit time wird in stderr geschrieben.
Die Lösung mit times schreibt in stdout.
Bei den Lösungen mit $SECONDS fehlt eine Genauigkeit von weniger als einer Sekunde.
Bei den anderen Lösungen werden externe Programme wie aufgerufen date oder perf, was nicht effizient ist.
Wenn Sie mit einer dieser Optionen einverstanden sind, verwenden Sie sie.

Wenn Sie jedoch eine effiziente Lösung benötigen, um die Zeiten abzurufen mit Millisekundengenauigkeit und benötigen sie in Variablen , so dass die Die ursprüngliche Ausgabe bleibt ungestört. Sie können die Prozessersetzung mit einigen Umleitungen um time kombinieren, was viel schneller als das Aufrufen ist externe Programme und ermöglicht Umleitungen um das Timing-Wrapper-Skript wie im ursprünglichen Befehl / Skript.

# 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 

Wählen Sie eine der folgenden Varianten aus, um die Ausgabe von time passend zu Ihren Anforderungen:
Kürzeste Variante, in der stdout von $Cmd in stderr und nichts zu stdout:

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

Längere Variante, die beibehalten wird Original stdout und stderr voneinander getrennt:

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

Die komplizierteste Variante umfasst das Schließen der zusätzlichen Dateideskriptoren, sodass $Cmd aufgerufen wird, als ob ohne diesen Timing-Wrapper und lvm Befehle wie vgs beschweren sich nicht über durchgesickerte Dateideskriptoren:

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

Sie kann sogar eine Gleitkommaaddition in bash vortäuschen, ohne bc aufzurufen, was viel langsamer wäre:

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 

Mögliche Ausgaben mit den beiden Beispielen von $Cmd auf einer langsamen CPU:

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 

Oder:

stdout stderr CPU 0.008 s, Elapsed 0.109 s 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.