Jak efektivně získat čas provedení skriptu?

Chtěl bych zobrazit čas dokončení skriptu.

To, co v současné době dělám, je –

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

Toto jen ukazuje čas začátku a konce skriptu. je možné zobrazit jemně zrnitý výstup, jako je čas procesoru / čas io atd.?

Komentáře

Odpověď

Jus Při volání skriptu nepoužívejte time:

time yourscript.sh 

Komentáře

  • Toto se zobrazí třikrát: real, user a sys. Jejich význam najdete zde .
  • a “ real “ je pravděpodobně to, co lidé chtějí vědět – “ reálný je čas nástěnných hodin – čas od začátku do konce hovoru “
  • Existuje způsob, jak zachytit standardní výstup do souboru? Například něco jako time $( ... ) >> out.txt
  • Můžete to udělat i se sekvencemi příkazů na příkazovém řádku, např .: time (command1 && command2)
  • Nebo by mohl ve svém skriptu jednoduše udělat: echo $ SECONDS za předpokladu, že je to bash ….

Odpověď

Pokud time není k dispozici,

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

Komentáře

  • Upozorňujeme, že to funguje, pouze pokud nepotřebujete ‚ přesnost za sekundu. Pro některá použití, která mohou být přijatelná , pro ostatní ne. Pro mírně lepší přesnost (‚ stále vyvoláváte date například dvakrát, takže můžete na nejlépe získat v praxi milisekundovou přesnost a pravděpodobně i méně), zkuste použít date +%s.%N. (%N je nanosekunda od celé sekundy .)
  • @ChrisH Ach. Dobré, poukazuji na to; bash aritmetická expanze je pouze celé číslo. Vidím dvě obvi další možnosti; buď vypusťte období v řetězci formátu data (a výslednou hodnotu považujte od epochy za nanosekundy), použijte tedy date +%s%N nebo použijte něco schopnějšího, jako je bc pro výpočet skutečného běhu ze dvou hodnot, jak navrhuje jwchew. Přesto mám pocit, že tento přístup je neoptimální způsob, jak toho dosáhnout; time je podstatně lepší, pokud je k dispozici, z důvodů uvedených výše.
  • Stačí nainstalovat bc a provést toto: runtime=$( echo "$end - $start" | bc -l )
  • Pokud váš skript trvá několik minut, použijte: echo "Duration: $((($(date +%s)-$start)/60)) minutes
  • Dále k @ rubo77 komentář, pokud váš skript trvá několik hodin, použijte hours=$((runtime / 3600)); minutes=$(( (runtime % 3600) / 60 )); seconds=$(( (runtime % 3600) % 60 )); echo "Runtime: $hours:$minutes:$seconds (hh:mm:ss)"

odpověď

Po ukončení skriptu stačí zavolat times bez argumentů.

S ksh nebo zsh, místo toho můžete použít time. S zsh vám time kromě uživatelů a poskytne také nástěnné hodiny. systémový čas CPU.

Chcete-li zachovat stav ukončení skriptu, můžete to udělat:

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

Nebo vy můžete také přidat trap na EXIT:

trap times EXIT 

Tímto způsobem budou časy volány vždy, když shell opustí a stav ukončení bude zachován.

$ 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 

Upozorňujeme, že všechny bash, ksh a zsh mají $SECONDS speciální proměnnou, která se každou sekundu automaticky zvyšuje. V zsh i ksh93 lze z této proměnné udělat také plovoucí desetinnou čárku (s typeset -F SECONDS ) pro větší přesnost. Toto je pouze čas nástěnných hodin, ne čas CPU.

Komentáře

  • Tato proměnná $ SECONDS je velmi užitečná, díky!
  • Vylučuje váš přístup účinek časových událostí? – – Myslím, že váš přístup je blízko time přístupu uvedeného výše.- – Myslím, že přístup timeit uvedený v kódu MATLAB může být užitečný zde.
  • Ahoj, @St é Phane Chazelas. Zjistil jsem, že times nedává ‚ čas na zeď, že? například bash -c 'trap times EXIT;sleep 2'
  • @Binarus, ano, tato funkce pochází z ksh. Na rozdíl od ksh93 / zsh, kromě bash nepodporujících plovoucí desetinnou čárku, je to také ‚ s rozbité v tom, že když nastavíte SECONDS na 0, změní se na 1 z 0 na 1 sekundu později ( protože bere v úvahu pouze výsledek time() který má pouze úplnou druhou zrnitost).
  • @Binarus, ne to ‚ s mezi 0 a 1. Pokud nastavíte SECONDS na 0 ve 12:00: 00 000, změní se na 1 o jednu sekundu později. Pokud jej ale nastavíte na 12: 00: 00,999, změní se na 1 o milisekundu později. Ale ano, souhlasím, že pravděpodobně v praxi moc nezáleží na tom, jestli ‚ stejně nemáte subsekundovou přesnost.

Odpověď

Jsem trochu pozdě do rozjetého vlaku, ale chtěl jsem zveřejnit své řešení (pro subsekundovou přesnost ) pro případ, že by ostatní narazili na toto vlákno při hledání. Výstup je ve formátu dnů, hodin, minut a nakonec sekund:

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 

Doufám, že někdo tam to považuje za užitečné!

Komentáře

  • Myslím, že kromě použití ‚ bc ‚ provádět výpočty. BTW opravdu dobrý skript;)
  • Pozor, FreeBSD ‚ s date nepodporuje přesnost vteřin a do časového razítka pouze připojí doslovný „N„.
  • Velmi pěkný scénář, ale můj bash ‚ nezpracovává subsekundovou část. Také jsem se dozvěděl, že / 1 v bc to efektivně odstraní, takže jsem přidal @ / 1 @ do výpočtu $ ds a nyní to vypadá velmi pěkně!
  • bc podporuje modulo: dt2=$(echo "$dt%86400" | bc). Jen říkám … BTW Dávám přednost formě dt2=$(bc <<< "${dt}%86400"), ale ‚ je zcela osobní.
  • Nemám ‚ zatím o bc nic nevím, ale dělení 86400 mi nedůvěřuje následující důvod: Existují dny, které nemají 86400 sekund, například dny, kdy je čas přepnut z DST na normální čas a naopak, nebo dny s přestupnými sekundami. Pokud jsou takové dny součástí časového rozsahu, který chcete vypočítat, tj. Jsou mezi res1 a res2 (včetně těchto hodnot), váš skript pravděpodobně selže.

Odpověď

Moje metoda pro bash :

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

Komentáře

  • To ukazuje uplynulý čas, ale ‚ nezobrazuje “ jemnozrnný výstup, jako je čas procesoru, čas I / O „, jak je požadováno v otázce.
  • Pro ty, kteří hledají odpověď na otázku, kterou pokládají, bude toto řešení pravděpodobně užitečné. Váš komentář by byl lépe adresován na otázku OP.

Odpověď

Osobně rád zabalím všechny své kód skriptu v některých „hlavních“ funkcích:

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

Všimněte si, jak snadné je použít příkaz time v tomto scénáři. Je zřejmé, že neměříte přesný čas včetně času analýzy skriptu, ale ve většině situací mi připadá dostatečně přesný.

Komentáře

  • Skvělé řešení, nevyžaduje ‚ další nástroje a je samostatná.

Odpovědět

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

Ano, toto se nazývá Python, ale pokud s tím dokážete žít, pak je to docela pěkné a stručné řešení.

Komentáře

  • Dejte si pozor, aby spuštění příkazu python v subshellu a čtení jeho výstupu trvalo na většině současných systémů několik milionů nanosekund. Totéž pro spuštění date.
  • “ Několik milionů nanosekund “ je několik milisekund . Lidé, kteří časují bash skripty, se tím obvykle příliš nezabývají (pokud nespustí několik miliard skriptů za megasekundu).
  • Všimněte si také, že i když výpočet se provádí uvnitř pythonovského procesu, hodnoty byly zcela shromážděny před vyvoláním pythonu. Doba spuštění skriptu bude měřena správně, bez “ milionů nanosekund “ režie.
  • time main výše je mnohem čistší …ano, můžeme žít se spoustou degradace, ale ‚ je to mnohem lepší, aniž bychom ‚ zůstali inženýři!
  • $(echo $end - $start | bc) udělá totéž bez pythonu

odpověď

Tato otázka je docela stará, ale při hledání mého oblíbeného způsobu, jak to udělat, se toto vlákno dostalo vysoko … a já jsem překvapen, že se o tom nikdo nezmínil:

perf stat -r 10 -B sleep 1 

„perf“ je nástroj pro analýzu výkonu, který je součástí jádra pod „tools / perf“ a je často k dispozici k instalaci jako samostatný balíček („perf“ v CentOS a „linux-tools“ v Debianu / Ubuntu). Linux Kernal perf Wiki obsahuje mnohem více informací.

Spuštění „perf stat“ poskytuje spoustu podrobností včetně průměrné doby provedení hned na konci:

1.002248382 seconds time elapsed ( +- 0.01% ) 

Komentáře

  • Co je perf?
  • @B Layer – upravil moji odpověď t o uveďte stručný popis ‚ perf ‚.
  • perf stat nyní si stěžuje na “ Pravděpodobně nemáte oprávnění ke shromažďování statistik. “ pokud nespustíte některé příkazy pomocí sudo, což je zbytečné ve všech scénářích, kdy nemáte ‚ úplně vlastní cílový stroj.
  • Úžasné, díky! Způsob jemnějšího řešení, než navrhují time. Zejména time nelze použít pro měření konkurenčních řešení kódu (protože ‚ t doba tisku v milisekundách a méně) , zatímco vaše řešení ano.

Odpověď

Malá funkce shellu, kterou lze přidat dříve příkazy k měření jejich času:

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

Potom jej použijte ve svém skriptu nebo na příkazovém řádku takto:

tm the_original_command with all its parameters 

Komentáře

  • Bylo by vhodné přidat milisekundy, vyzkoušel jsem ilke s=$(date +%s000), nevím pokud to funguje.
  • @loretoparisi po dobu milisekund, můžete zkusit date +%s%N. Viz serverfault.com/questions/151109/…
  • To je skvělé, kromě bezpečnějších použijte "$@"

odpověď

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

Komentáře

  • Jak se to opravdu liší od ostatních již uvedených odpovědí, které používají date před a po skript a vygenerovat rozdíl mezi nimi?

odpověď

  1. Jen použijte time [any command] . Příklad: time sleep 1 bude spát v reálném čase (tj. Podle stopek) ~ 1 000 až ~ 1 020 s, jak je znázorněno zde:

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

    Jaká krásná věc. Po něm můžete vložit libovolný příkaz a výsledek se zobrazí v pěkné, čitelné podobě. Opravdu ho rád používám pro načasování sestavení. Příklad:

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

    … nebo pro operace git, které mohou být skutečně dlouho, takže mohu rozvíjet realistická mentální očekávání:

      # 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. Pro více přizpůsobené načasování kde možná budete muset manipulovat s výstupem nebo jej převést do jiných forem v bash , použijte interní $SECONDS proměnnou. Zde je ukázka, včetně převodu těchto sekund na jiné jednotky, například minuty s plovoucí desetinnou čárkou:

    Upozorňujeme, že dt_min se zaokrouhlí z 0.01666666666... (1 sekunda = tolik minut) na 0.017 v tomto případě, protože používám funkci printf k zaokrouhlování. Níže uvedená část sleep 1; je místo, kde zavoláte skript, který se má spustit a spustit, ale místo toho kvůli této ukázce jen spím 1 sekundu.

    Příkaz:

      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"  

    Výstup:

      dt_sec = 1; dt_min = 0.017  

Související:

  1. Přečíst více asi bc a printf v mé odpovědi zde: https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in-bash/58479867#58479867
  2. Už si nepamatuji, kde jsem se poprvé dozvěděl o příkazu time, ale mohl to být z odpověď @Trudberta právě zde .

Odpověď

Používání pouze bash je také možné měřit a vypočítat dobu trvání části shellového skriptu (nebo uplynulý čas pro celý skript):

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

nyní můžete rozdíl pouze vytisknout:

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

pokud potřebujete pouze přírůstkové trvání, proveďte:

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

Trvání můžete také uložit do proměnné:

let diff=end-start 

Komentáře

  • ^ TOTO je odpověď. Nebo jednodušeji: $ SECONDS na konci. Je ‚ s proměnnou BUILT-IN Bash. Všechny ostatní odpovědi právě dělají práci navíc, aby znovu vymysleli toto kolo …
  • Toto je jen opakování dřívější odpovědi Marks unix.stackexchange .com / a / 340156/155362 .

Odpověď

Časová funkce založená na SECONDS, omezeno pouze na granularitu druhé úrovně, nepoužívá žádné externí příkazy:

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

Například:

time_it sleep 5 

dává

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

odpověď

Použít integrovaný čas bash?

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. 

Příklad:

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

Výstup:

The command took 0.108s 

Odpověď

Zde je variace Alex „Odpověď. Zajímám se jen o minuty a sekundy, ale také jsem chtěl, aby byl formátován jinak. Udělal jsem to takto:

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

Komentáře

  • Proč downvote? Mám chybu?
  • Použití python pro tento výpočet pro mě vypadá jako chyba, omlouvám se. Proč lidé ‚ prostě nemohou volat time je mimo mě.

Odpověď

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

Odpověď

Přijaté řešení pomocí time zapíše stderr.
Řešení používající times zapíše do stdout.
V řešeních používajících $SECONDS chybí přesnost druhé sekundy.
Další řešení zahrnují volání externích programů, jako je date nebo perf, které nejsou efektivní.
Pokud vám některý z nich vyhovuje, použijte jej.

Ale pokud potřebujete efektivní řešení pro získání časů s milisekundovou přesností a potřebujete je do proměnných tak, aby původní výstup zůstává nerušený můžete kombinovat substituci procesu s některými přesměrováními kolem time, které je mnohem rychlejší než volání externích programů a umožňuje přesměrování kolem skriptu časování obálky jako v původním příkazu / skriptu.

# 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 

Vyberte jednu z následujících variant analyzujících výstup time odpovídající vašim potřebám:
Nejkratší varianta, do které je stdout z $Cmd zapsán stderr a nic stdout:

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

Delší varianta, která udržuje původní stdout a stderr od sebe oddělené:

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

Nejkomplikovanější varianta zahrnuje uzavření dalších deskriptorů souborů, takže $Cmd se volá, jako by bez tohoto časovacího obálky a lvm příkazy jako vgs si nestěžují na uniklé deskriptory souborů:

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

vy může dokonce předstírat sčítání s plovoucí desetinnou čárkou v bash bez volání bc, což by bylo mnohem pomalejší:

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 

Možné výstupy se dvěma příklady $Cmd na pomalé 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 

Nebo:

stdout stderr CPU 0.008 s, Elapsed 0.109 s 

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *