Uzyskaj czas wykonania programu w powłoce

407

Chcę wykonać coś w powłoce linuksowej w kilku różnych warunkach i móc wyprowadzić czas wykonania każdego wykonania.

Wiem, że mógłbym napisać skrypt Perla lub Pythona, który by to zrobił, ale czy istnieje sposób, aby to zrobić w powłoce? (która okazuje się bash)

.ıu
źródło
2
Obudowa
czy można uzyskać Tickspodobną obudowę systemu Windows?
freeforall tousez
unix.stackexchange.com/questions/52313/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Odpowiedzi:

534

Użyj wbudowanego timesłowa kluczowego:

$ czas pomocy

time: time [-p] PIPELINE
    Uruchom PIPELINE i wydrukuj podsumowanie czasu rzeczywistego, czasu procesora użytkownika,
    oraz czas procesora systemu spędzony na wykonywaniu PIPELINE po jego zakończeniu.
    Status zwrotu to status zwrotu PIPELINE. Opcja `-p '
    drukuje podsumowanie czasowe w nieco innym formacie. To używa
    wartość zmiennej TIMEFORMAT jako formatu wyjściowego.

Przykład:

$ time sleep 2
prawdziwe 0m2.009s
użytkownik 0m0.000s
sys 0m0,004s
Robert Gamble
źródło
1
Jak to jest używane w poleceniu time -p i=x; while read line; do x=x; done < /path/to/file.txt? Natychmiast zwraca 0,00, chyba że nie wstawię niczego przed pętlą while. Co daje?
natli
jest to kiepska wersja „czasu”, wbudowana bash. gdzie jest zewnętrzne polecenie „czas”?
Znik
6
@Znik, spróbuj / usr / bin / time
Mark Rajcok
10
@natli: Chociaż timemożna odmierzać czas trwania całego potoku w stanie, w jakim się znajduje (ze względu na to, że jest słowem kluczowym Bash ), musisz użyć polecenia group ( { ...; ...; }), aby time -p { i=x; while read line; do x=x; done < /path/to/file.txt; }
zmierzyć
2
Aby zobaczyć wszystkie wersje czasu, które zainstalowałeś w swoim systemie, możesz użyćtype -a time
spinup
120

Możesz uzyskać znacznie bardziej szczegółowe informacje niż wbudowane bash time(o czym wspomina Robert Gamble), używając czasu (1) . Zwykle tak jest /usr/bin/time.

Uwaga edytora: Aby upewnić się, że wywołujesz zewnętrzne narzędzie time zamiast time słowa kluczowego powłoki , wywołaj je jako /usr/bin/time.
timejest narzędziem wymaganym przez POSIX , ale jedyną opcją wymaganą do obsługi jest -p.
Konkretnych platform realizacji konkretnych niestandardowe rozszerzenia: -vprace z GNU „s timeużyteczności, jak pokazano poniżej (pytanie jest oznaczone); implementacja BSD / macOS używa -ldo generowania podobnych wyników - patrz man 1 time.

Przykład pełnego wyjścia:


$ /usr/bin/time -v sleep 1
       Command being timed: "sleep 1"
       User time (seconds): 0.00
       System time (seconds): 0.00
       Percent of CPU this job got: 1%
       Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.05
       Average shared text size (kbytes): 0
       Average unshared data size (kbytes): 0
       Average stack size (kbytes): 0
       Average total size (kbytes): 0
       Maximum resident set size (kbytes): 0
       Average resident set size (kbytes): 0
       Major (requiring I/O) page faults: 0
       Minor (reclaiming a frame) page faults: 210
       Voluntary context switches: 2
       Involuntary context switches: 1
       Swaps: 0
       File system inputs: 0
       File system outputs: 0
       Socket messages sent: 0
       Socket messages received: 0
       Signals delivered: 0
       Page size (bytes): 4096
       Exit status: 0

grepsedawk
źródło
2
nie zdarzyłbyś się, z jakiego pakietu debian pochodziłby? nie wydaje się być instalowany domyślnie
ʞɔıu
1
Odniosłem się do twojego postu Robert. Chyba że masz na myśli polecenie, które sugerujesz, nie jest wbudowane w bash?
grepsedawk
24
O dziwo, jest instalowany z pakietu o nazwie „czas”.
Paul Tomblin,
2
Dane wyjściowe z / usr / bin / time wyglądają jak "0,00user 0,00system 0: 02.00 upłynął 0% CPU (0avgtext + 0avgdata 0maxresident) k 0 wejść + 0 wyjść (0major + 172minor) błędy strony 0swaps"
Paul Tomblin
4
@Nick: „sudo apt-get install time”.
Robert Gamble,
79
#!/bin/bash
START=$(date +%s)
# do something
# start your script work here
ls -R /etc > /tmp/x
rm -f /tmp/x
# your logic ends here
END=$(date +%s)
DIFF=$(( $END - $START ))
echo "It took $DIFF seconds"
David
źródło
14
Jest o wiele prostszy sposób. Bash automatycznie oblicza specjalną zmienną $ SECONDS, następnie niepotrzebne jest ponowne obliczanie na podstawie polecenia daty zewnętrznej. Zmienna $ SECONDS przechowuje liczbę sekund uruchomionego skryptu bash. Ta zmienna ma jakąś specjalną właściwość. Zobacz stronę
podręcznika
Próbowałem zarówno powyższej, jak i metody w komentarzu. W pierwszym dostaję błąd „nielegalnej zmiennej”, a w drugim dostaję „niezidentyfikowaną zmienną”
DrBwts
45

Do pomiaru delta linia po linii spróbuj gnomon .

Narzędzie wiersza poleceń, trochę jak ts moreutils, do dołączania informacji o znaczniku czasu do standardowego wyjścia innego polecenia. Przydatny w długotrwałych procesach, w których potrzebujesz historycznego zapisu tego, co trwa tak długo.

Możesz także użyć opcji --highi / lub, --mediumaby określić próg długości w sekundach, powyżej którego gnomon podświetli znacznik czasu na czerwono lub żółto. Możesz także zrobić kilka innych rzeczy.

przykład

Adriano Resende
źródło
3
Świetna wskazówka, ale dla jasności: jest to przydatne w przypadku taktowania linia po linii , ale narzut związany z przyjmowaniem tak drobnoziarnistych taktów znacznie zwiększa ogólny czas.
mklement0
2
Niesamowite narzędzie .. Dzięki za udostępnienie
Kishan B
19

Jeśli chcesz uzyskać większą precyzję, użyj %Nz date(i użyj bcdla diff, ponieważ $(())obsługuje tylko liczby całkowite).

Oto jak to zrobić:

start=$(date +%s.%N)
# do some stuff here
dur=$(echo "$(date +%s.%N) - $start" | bc)

printf "Execution time: %.6f seconds" $dur

Przykład:

start=$(date +%s.%N); \
  sleep 0.1s; \
  dur=$(echo "$(date +%s.%N) - $start" | bc); \
  printf "Execution time: %.6f seconds\n" $dur

Wynik:

Execution time: 0.104623 seconds
Benoit Duffez
źródło
15

Jeśli zamierzasz wykorzystać czasy później do obliczeń, dowiedz się, jak korzystać z -fopcji /usr/bin/timegenerowania kodu, który oszczędza czas. Oto kod, którego ostatnio użyłem, aby uzyskać i posortować czasy wykonania całej klasy programów dla studentów:

fmt="run { date = '$(date)', user = '$who', test = '$test', host = '$(hostname)', times = { user = %U, system = %S, elapsed = %e } }"
/usr/bin/time -f "$fmt" -o $timefile command args...

Później połączyłem wszystkie $timefilepliki i potokowałem dane wyjściowe do interpretera Lua . Możesz zrobić to samo z Pythonem, bash lub dowolną ulubioną składnią. Uwielbiam tę technikę.

Norman Ramsey
źródło
Uwaga: Pełna ścieżka /usr/bin/timejest konieczna, ponieważ chociaż which timepowie ci inaczej, jeśli po prostu uruchomisz time, uruchomi ona wersję powłoki, timektóra nie przyjmuje żadnych argumentów.
Kevin Dice,
env time
Poszedłbym
13

Jeśli potrzebujesz dokładności co do sekundy, możesz użyć wbudowanej $SECONDSzmiennej, która zlicza liczbę sekund, które uruchomiła powłoka.

while true; do
    start=$SECONDS
    some_long_running_command
    duration=$(( SECONDS - start ))
    echo "This run took $duration seconds"
    if some_condition; then break; fi
done
Glenn Jackman
źródło
10

Możesz użyć timei podpowłoki () :

time (
  for (( i=1; i<10000; i++ )); do
    echo 1 >/dev/null
  done
)

Lub w tej samej powłoce {}:

time {
  for (( i=1; i<10000; i++ )); do
    echo 1 >/dev/null
  done
}
Eduardo Cuomo
źródło
Opublikowałeś dwa identyczne fragmenty kodu. Musiałeś mieć tam coś innego.
Stason
3
@StasBekman nie jest prawdą, najpierw używa (& )(nowy kontekst, podpowłoka ), a inne z {& }(ta sama powłoka, ten sam kontekst)
Eduardo Cuomo
Aha! Patrzyłem na nich bardzo mocno i nie zauważyłem różnicy. Dziękujemy za wyjaśnienie, że {} vs ().
Stason
2

Tak jest

$ > g++ -lpthread perform.c -o per
$ > time ./per

wyjście to >>

real    0m0.014s
user    0m0.010s
sys     0m0.002s
Robel Sharma
źródło
Nie trzeba używać -lphtreadani -otagować. Wystarczy użyć timepolecenia, które zaakceptowana odpowiedź wyjaśnia lepiej.
Dennis
7
To był przykład. Oto moja wydajność. C ma wątki, więc potrzebuję -lpthread, a dla prostej tożsamości jest to -o per.
Robel Sharma
0

jedną z możliwie prostych metod (która może nie spełniać różnych potrzeb użytkowników) jest użycie powłoki PROMPT. jest to proste rozwiązanie, które może być przydatne w niektórych przypadkach. Możesz użyć funkcji monitowania bash, jak w poniższym przykładzie:

eksport PS1 = „[\ t \ u @ \ h] \ $” 

Powyższe polecenie spowoduje zmianę monitu powłoki na:

[GG: MM: nazwa użytkownika SS @ nazwa hosta] $ 

Za każdym razem, gdy uruchomisz polecenie (lub naciśniesz Enter), wracając do monitu powłoki, w monicie wyświetli się bieżąca godzina.

uwagi:
1) strzeż się, że jeśli poczekałeś chwilę przed wpisaniem następnego polecenia, to należy wziąć to pod uwagę, tj. czas wyświetlany w wierszu polecenia powłoki jest znacznikiem czasu, gdy polecenie wiersza było wyświetlane, a nie po wprowadzeniu polecenia. niektórzy użytkownicy wybierają klawisz Enter, aby otrzymać nowy monit z nowym znacznikiem czasu, zanim będą gotowi na następne polecenie.
2) Istnieją inne dostępne opcje i modyfikatory, których można użyć do zmiany monitu bash, patrz (man bash), aby uzyskać więcej szczegółów.

tstorym
źródło
Nie punkt, w którym program się uruchamia, ale czas jego trwania.
Geno Chen