Vorrei visualizzare il tempo di completamento di uno script.
Quello che faccio attualmente è –
#!/bin/bash date ## echo the date at start # the script contents date ## echo the date at end
Questo mostra solo lora di inizio e fine dello script. Sarebbe possibile visualizzare un output a grana fine come tempo processore / ora io, ecc.?
Commenti
- stackoverflow.com/questions/385408/ …
- Penso che lattuale risposta accettata non sia davvero sufficiente a causa delle fluttuazioni temporali.
- @CiroSantilli 烏坎 事件 2016 六四 事件 法轮功 Penso che il thread proposto non sia ancora sufficiente per eliminare leffetto degli eventi temporali.
- Correlato anche: stackoverflow.com/questions/5152858/… o in qualche modo unix.stackexchange.com/questions/334145 / …
- Cè un comando che puoi eseguire e poi cronometra automaticamente tutti i comandi unix, hai dimenticato come abilitare?
Risposta
Jus t utilizzare time
quando chiami lo script:
time yourscript.sh
Commenti
- Viene restituito tre volte:
real
,user
esys
. Per il significato di questi, vedere qui . - e ” real ” è probabilmente ciò che le persone vogliono sapere: ” Il tempo reale è lora dellorologio da parete: il tempo dallinizio alla fine della chiamata ”
- Cè un modo per catturare lo stdout in un file? Ad esempio, qualcosa come
time $( ... ) >> out.txt
- Puoi anche eseguire questa operazione su sequenze di comandi sulla riga di comando, ad esempio:
time (command1 && command2)
- Oppure potrebbe, nel suo script, fare semplicemente: echo $ SECONDS assumendo che sia bash ….
Risposta
Se time
non è “unopzione,
start=`date +%s` stuff end=`date +%s` runtime=$((end-start))
Commenti
- Tieni presente che funziona solo se ‘ non necessita di una precisione inferiore al secondo. Per alcuni usi potrebbe essere accettabile , per altri no. Per una precisione leggermente migliore (‘ stai ancora invocando
date
due volte, ad esempio, quindi potresti a meglio ottenere una precisione in millisecondi nella pratica, e probabilmente meno), prova a utilizzaredate +%s.%N
. (%N
è nanosecondi dallintero secondo .) - @ChrisH Oh. Bene sottolinearlo; lespansione aritmetica di bash è di soli numeri interi. Vedo due obvi ous opzioni; o elimina il periodo nella stringa del formato della data (e considera il valore risultante come nanosecondi dallepoca), quindi utilizza
date +%s%N
o utilizza qualcosa di più capace comebc
per calcolare il tempo di esecuzione effettivo dai due valori come suggerisce jwchew. Tuttavia, ritengo che questo approccio sia un modo non ottimale per farlo;time
è notevolmente migliore se disponibile, per i motivi sopra descritti. - Installa
bc
e poi procedi in questo modo:runtime=$( echo "$end - $start" | bc -l )
- Se lo script richiede diversi minuti, utilizza:
echo "Duration: $((($(date +%s)-$start)/60)) minutes
- Oltre a @ rubo77 commento, se lo script richiede diverse ore, utilizza
hours=$((runtime / 3600)); minutes=$(( (runtime % 3600) / 60 )); seconds=$(( (runtime % 3600) % 60 )); echo "Runtime: $hours:$minutes:$seconds (hh:mm:ss)"
Answer
Basta chiamare times
senza argomenti alluscita dallo script.
Con ksh
o zsh
, puoi anche utilizzare time
. Con zsh
, time
ti fornirà anche lora dellorologio da parete oltre a utente e sistema tempo CPU.
Per preservare lo stato di uscita del tuo script, puoi farlo:
ret=$?; times; exit "$ret"
Oppure tu può anche aggiungere una trap su EXIT
:
trap times EXIT
In questo modo, gli orari verranno chiamati ogni volta che la shell esce e lo stato di uscita verrà preservato.
$ 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
Tieni presente inoltre che tutti i bash
, ksh
e zsh
hanno una $SECONDS
variabile speciale che viene incrementata automaticamente ogni secondo. In entrambi zsh
e ksh93
, quella variabile può anche essere resa in virgola mobile (con typeset -F SECONDS
) per ottenere una maggiore precisione. Questo è solo il tempo dellorologio da parete, non il tempo della CPU.
Commenti
- Quella variabile $ SECONDS è molto utile, grazie!
- Il tuo approccio elimina leffetto degli eventi temporali? – – Penso che il tuo approccio sia vicino allapproccio
time
presentato in precedenza.- – Penso che lapprocciotimeit
presentato nel codice MATLAB possa essere utile qui. - Ciao, @St é phane Chazelas. Ho trovato che
times
non ‘ fornisce lora del muro, giusto? ad esempio,bash -c 'trap times EXIT;sleep 2'
- @Binarus, sì, quella funzione proviene da ksh. Contrariamente a ksh93 / zsh, oltre a bash che non supporta il punto mobile, ‘ è anche rotto in quanto dopo aver impostato SECONDS su 0, cambierà in 1 da 0 a 1 secondo più tardi ( poiché considera solo il risultato di
time()
che ha solo un secondo granularità completo). - @Binarus, non quello ‘ s tra 0 e 1. Se si imposta SECONDS su 0 alle 12: 00: 00.000, cambierà in 1 un secondo dopo. Ma se lo imposti a 12: 00: 00.999, cambierà in 1 un millisecondo dopo. Ma sì, sono daccordo che probabilmente ‘ non importa molto in pratica se ‘ non ha una precisione inferiore al secondo.
Risposta
Sono “arrivato un po in ritardo sul carrozzone, ma volevo pubblicare la mia soluzione (per una precisione inferiore al secondo ) nel caso in cui altri si imbattano in questo thread durante la ricerca. Loutput è nel formato di giorni, ore, minuti e infine secondi:
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
Spero che qualcuno là fuori lo trova utile!
Commenti
- Immagino che non ci sia altro (solo bash) modo tranne usare ‘ bc ‘ per fare i calcoli. BTW script davvero buono;)
- Attenti a FreeBSD ‘ s
date
non supporta la precisione inferiore al secondo e aggiunge semplicemente “N
” al timestamp. - Script molto carino, ma la mia bash non ‘ t gestire la parte inferiore al secondo. Ho anche imparato che / 1 in bc lo elimina in modo efficace, quindi ho aggiunto @ / 1 @ al calcolo $ ds e ora mostra cose molto carine!
- bc supporta modulo:
dt2=$(echo "$dt%86400" | bc)
. Sto solo dicendo … A proposito, preferisco il modulodt2=$(bc <<< "${dt}%86400")
ma ‘ è del tutto personale. - Non ‘ Non so ancora nulla di
bc
, ma la divisione per86400
mi rende diffidente nei confronti del motivo seguente: ci sono giorni che non hanno 86400 secondi, ad esempio giorni in cui lora passa dallora legale allora normale e viceversa, o giorni con secondi intercalari. Se tali giorni fanno parte dellintervallo di tempo che desideri calcolare, ovvero sono compresi trares1
eres2
(compresi questi valori), il tuo script probabilmente fallirà.
Risposta
Il mio metodo per bash
:
# Reset BASH time counter SECONDS=0 # # do stuff # ELAPSED="Elapsed: $(($SECONDS / 3600))hrs $((($SECONDS / 60) % 60))min $(($SECONDS % 60))sec"
Commenti
- Questo mostra il tempo trascorso, ma non ‘ t mostra ” output a grana fine come il tempo del processore, il tempo di I / O ” come richiesto nella domanda.
- Coloro che cercano una risposta alla domanda posta probabilmente troveranno utile questa soluzione. Il tuo commento sarebbe meglio indirizzato alla domanda dei PO.
Risposta
Personalmente, mi piace racchiudere tutto il mio codice di script in alcune funzioni “principali” in questo modo:
main () { echo running ... } # stuff ... # calling the function at the very end of the script time main
Nota quanto sia facile utilizzare il comando time
in questo scenario. Ovviamente non stai misurando il tempo preciso, incluso il tempo di analisi dello script, ma lo trovo abbastanza accurato nella maggior parte delle situazioni.
Commenti
- Ottima soluzione, non ‘ non richiede strumenti aggiuntivi ed è autonomo.
Risposta
#!/bin/bash start=$(date +%s.%N) # HERE BE CODE end=$(date +%s.%N) runtime=$(python -c "print(${end} - ${start})") echo "Runtime was $runtime"
Sì, questo chiama Python, ma se riesci a conviverci, allora questa è una soluzione piuttosto carina e concisa.
Commenti
- Fai attenzione che lesecuzione del comando
python
in una subshell e la lettura del suo output richiederà diversi milioni di nanosecondi sulla maggior parte dei sistemi attuali. Lo stesso vale per lesecuzionedate
. - ” Diversi milioni di nanosecondi ” sono diversi millisecondi Le persone che temporizzano gli script bash di solito non sono molto preoccupati per questo (a meno che non eseguano diversi miliardi di script per megasecondo).
- Notare anche che, anche se il il calcolo viene eseguito allinterno di un processo python, i valori sono stati interamente raccolti prima che fosse invocato python. Il tempo di esecuzione dello script verrà misurato correttamente, senza ” milioni di nanosecondi ” overhead.
-
time main
sopra è molto più pulito …sì, possiamo convivere con un sacco di degrado, ma ‘ è molto meglio senza, quindi lascia che ‘ rimanga ingegneri! -
$(echo $end - $start | bc)
farà la stessa cosa senza Python
Risposta
Questa domanda è piuttosto vecchia ma nel tentativo di trovare il mio modo preferito di farlo questo thread è arrivato in alto … e “sono sorpreso che nessuno labbia menzionato:
perf stat -r 10 -B sleep 1
“perf” è uno strumento di analisi delle prestazioni incluso nel kernel sotto “tools / perf” e spesso disponibile per linstallazione come pacchetto separato (“perf” in CentOS e “linux-tools” su Debian / Ubuntu). Il Linux Kernal perf Wiki ha molte più informazioni al riguardo.
Lesecuzione di “perf stat” fornisce un bel po di dettagli, incluso il tempo medio di esecuzione proprio alla fine:
1.002248382 seconds time elapsed ( +- 0.01% )
Commenti
- Che cosè
perf
? - @B Layer – modificato la mia risposta t o fornire una breve descrizione di ‘ perf ‘.
-
perf stat
ora si lamenta di ” Potresti non essere autorizzato a raccogliere statistiche. ” a meno che tu non esegua alcuni comandi consudo
, il che lo rende inutile in tutti gli scenari in cui non ‘ possiedi completamente la macchina di destinazione. - Incredibile, grazie! Soluzione molto più dettagliata rispetto a
time
suggerita da altri. In particolare,time
non è applicabile alla misurazione di soluzioni di concorrenza tra codici (in quanto ‘ t tempo di stampa in millisecondi e inferiore) , mentre la tua soluzione sì.
Answer
Una piccola funzione di shell che può essere aggiunta prima comandi per misurare il loro tempo:
tm() { local start=$(date +%s) $@ local exit_code=$? echo >&2 "took ~$(($(date +%s)-${start})) seconds. exited with ${exit_code}" return $exit_code }
Quindi usalo nel tuo script o sulla riga di comando in questo modo:
tm the_original_command with all its parameters
Commenti
- Varrebbe la pena aggiungere millisecondi, ho provato ilke
s=$(date +%s000)
, non sono sicuro se funziona. - @loretoparisi per millisecondi, potresti provare
date +%s%N
. Vedi serverfault.com/questions/151109/… - È fantastico, ma più sicuro utilizza
"$@"
Risposta
#!/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..."
Commenti
- In che modo è davvero diverso dalle altre risposte già fornite che utilizzano
date
prima e dopo lo script e visualizza la differenza tra loro?
Answer
-
Solo utilizza
time [any command]
. Es:time sleep 1
dormirà per un tempo reale (ad esempio: come cronometrato da un cronometro) da ~ 1.000 a ~ 1.020 sec, come mostrato qui:$ time sleep 1 real 0m1.011s user 0m0.004s sys 0m0.000s
Che bella cosa. Puoi inserire qualsiasi comando dopo di esso e restituisce il risultato in una bella forma leggibile dalluomo. Mi piace molto usarlo per le build temporali. Es:
# time your "make" build time make # time your "Bazel" build time bazel build //path/to/some:target
… o per operazioni git che potenzialmente possono essere davvero lungo, così posso sviluppare aspettative mentali realistiche:
# 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
-
Per tempi più personalizzati è necessario dove potresti dover manipolare loutput o convertirlo in altre forme, in bash , utilizza la variabile interna
$SECONDS
. Ecco “una demo, inclusa la conversione di questi secondi in altre unità, come i minuti in virgola mobile:Tieni presente che
dt_min
viene arrotondato da0.01666666666...
(1 secondo = quel numero di minuti) a0.017
in questo caso, poiché “sto utilizzando la funzioneprintf
per arrotondare. La partesleep 1;
di seguito è dove “chiameresti il tuo script per lesecuzione e il tempo, ma io sto solo dormendo per 1 secondo invece per il bene di questa demo.Comando:
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"
Risultato:
dt_sec = 1; dt_min = 0.017
Correlati:
- Ulteriori informazioni circa
bc
eprintf
nella mia risposta qui: https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in-bash/58479867#58479867 - Non ricordo più dove ho imparato a conoscere il comando
time
, ma potrebbe essere stato da @Trudbert “la risposta proprio qui .
Risposta
Utilizzando solo bash è anche possibile misurare e calcolare la durata temporale per una parte dello script della shell (o il tempo trascorso per lintero script):
start=$SECONDS ... # do time consuming stuff end=$SECONDS
ora puoi semplicemente stampare la differenza:
echo "duration: $((end-start)) seconds."
se hai bisogno solo di una durata incrementale fai:
echo "duration: $((SECONDS-start)) seconds elapsed.."
Puoi anche memorizzare la durata in una variabile:
let diff=end-start
Commenti
- ^ QUESTA è la risposta, gente. O più semplicemente: $ SECONDS alla fine. ‘ è una variabile Bash INTEGRATA. Tutte le altre risposte stanno solo facendo un lavoro extra per reinventare questa ruota …
- Questa è solo una ripetizione della risposta precedente di Marks unix.stackexchange .com / a / 340156/155362 .
Risposta
Funzione di temporizzazione basata su SECONDS
, limitato solo alla granularità di secondo livello, non “utilizza alcun comando esterno:
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" }
Ad esempio:
time_it sleep 5
restituisce
2019-03-30_17:24:37 Starting sleep 5 2019-03-30_17:24:42 Finished sleep 5; elapsed = 5 seconds
Risposta
Utilizzare bash time builtin?
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.
Esempio:
TIMEFORMAT="The command took %Rs" time { sleep 0.1 }
Risultato:
The command took 0.108s
Risposta
Ecco “una variazione di Alex “s. Mi interessano solo i minuti e i secondi, ma volevo anche che fosse formattato in modo diverso. Così ho fatto questo:
start=$(date +%s) end=$(date +%s) runtime=$(python -c "print "%u:%02u" % ((${end} - ${start})/60, (${end} - ${start})%60)")
Commenti
- Perché il voto negativo? Ho un bug?
- Anche luso di
python
per quel calcolo sembra un bug, mi dispiace amico. Perché le persone non possono ‘ semplicemente chiamaretime
è al di là di me.
Rispondi
#!/bin/bash begin=$(date +"%s") Script termin=$(date +"%s") difftimelps=$(($termin-$begin)) echo "$(($difftimelps / 60)) minutes and $(($difftimelps % 60)) seconds elapsed for Script Execution."
Risposta
La soluzione accettata utilizzando time
scrive in stderr
.
La soluzione che utilizza times
scrive in stdout
.
Le soluzioni che utilizzano $SECONDS
mancano di una precisione inferiore al secondo.
Le altre soluzioni prevedono la chiamata di programmi esterni come date
o perf
che non è efficiente.
Se stai bene con uno di questi, usalo.
Ma se hai bisogno di una soluzione efficiente per ottenere i tempi con una precisione al millisecondo e necessitano nelle variabili in modo che loutput originale rimane indisturbato puoi combinare la sostituzione del processo con alcuni reindirizzamenti intorno a time
, che è molto più veloce della chiamata programmi esterni e consente reindirizzamenti attorno allo script wrapper di temporizzazione come nel comando / script originale.
# 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
Seleziona una delle seguenti varianti analizzando loutput di time
appropriato alle tue esigenze:
Variante più breve dove stdout
di $Cmd
è scritto in stderr
e nulla da stdout
:
read Elapsed User System < <({ time $Cmd 2>&3; } 3>&2 2>&1 >&3)
Variante più lunga che mantiene originali stdout
e stderr
separati luno dallaltro:
{ read Elapsed User System < <({ time $Cmd 2>&4; } 4>&2 2>&1 >&3); } 3>&1
La variante più complicata include la chiusura dei descrittori di file aggiuntivi in modo tale che $Cmd
venga chiamato come se non avesse questo wrapper temporale attorno ad esso e lvm
comandi come vgs
non si lamentano dei descrittori di file trapelati:
{ read Elapsed User System < <({ time $Cmd 2>&4 4>&-; } 4>&2 2>&1 >&3 3>&-); } 3>&1
Tu può persino simulare unaggiunta in virgola mobile in bash
senza chiamare bc
, il che sarebbe molto più lento:
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
Possibili output con i due esempi di $Cmd
su una CPU lenta:
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
Oppure:
stdout stderr CPU 0.008 s, Elapsed 0.109 s