Kuinka saada komentosarjan suoritusaika tehokkaasti?

Haluan näyttää komentosarjan valmistumisajan.

Tällä hetkellä teen –

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

Tämä vain näyttää komentosarjan alkamis- ja lopetusajan. Onko se mahdollista näyttää hienorakeinen lähtö, kuten prosessorin aika / io-aika jne.?

Kommentit

Vastaa

Jus t käytä time, kun soitat komentosarjaa:

time yourscript.sh 

kommentit

  • Tämä tuottaa kolme kertaa: real, user ja sys. Katso näiden merkitykset täältä .
  • ja ” todellinen ” on todennäköisesti mitä ihmiset haluavat tietää – ” Todellinen on seinäkello – aika puhelun alusta loppuun ”
  • Onko olemassa tapaa siepata stdout tiedostoon? Esimerkiksi time $( ... ) >> out.txt
  • Voit tehdä tämän myös komentosarjojen kanssa komentorivillä, esim .: time (command1 && command2)
  • Tai hän voisi skriptissään vain tehdä: echo $ SECONDS olettaen, että se on bash ….

Vastaa

Jos time ei ole vaihtoehto,

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

Kommentit

  • Huomaa, että tämä toimii vain, jos et ’ tarvitse toissijaista tarkkuutta. Joillekin käyttötavoille, jotka voivat olla hyväksyttäviä , muille ei. Hieman paremman tarkkuuden saavuttamiseksi (’ kutsutaan edelleen date esimerkiksi kahdesti, joten saatat olla kohdassa paras millisekunnin tarkkuus käytännössä ja todennäköisesti vähemmän), yritä käyttää date +%s.%N. (%N on nanosekuntia, koska koko sekunti .)
  • @ChrisH Oh. Hyvä osoittaa se; bashin aritmeettinen laajennus on vain kokonaisluku. Näen kaksi obvi ous vaihtoehtoja; joko ojaa päivämäärä muotoilumerkkijonossa (ja käsittele tuloksena olevaa arvoa nanosekunteina aikakaudesta lähtien), joten käytä date +%s%N tai käytä jotain kykenevämpää kuten bc laskea todellinen ajonaika kahdesta arvosta, kuten jwchew ehdottaa. Silti minusta tämä lähestymistapa on epäoptimaalinen tapa tehdä se; time on huomattavasti parempi, jos saatavilla, yllä esitetyistä syistä.
  • Asenna vain bc ja tee tämä seuraavasti: runtime=$( echo "$end - $start" | bc -l )
  • Jos komentosarjasi kestää useita minuutteja, käytä: echo "Duration: $((($(date +%s)-$start)/60)) minutes
  • Seuraava osoitteeseen @ rubo77 kommentti, jos komentosarjasi kestää useita tunteja, käytä hours=$((runtime / 3600)); minutes=$(( (runtime % 3600) / 60 )); seconds=$(( (runtime % 3600) % 60 )); echo "Runtime: $hours:$minutes:$seconds (hh:mm:ss)"

vastausta

Soita vain times ilman argumentteja poistutessasi komentosarjastasi.

ksh tai zsh, voit käyttää sen sijaan myös time. zsh, time antaa sinulle myös seinäkellonajan käyttäjän ja lisäksi system suorittimen aika.

Voit säilyttää komentosarjan poistumistilan tekemällä sen:

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

Tai sinä voi myös lisätä ansaan EXIT:

trap times EXIT 

Tällä tavalla aikoja kutsutaan aina, kun kuori poistuu ja poistumistila säilyy.

$ 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 

Huomaa myös, että kaikki bash, ksh ja zsh on $SECONDS -muuttuja, joka kasvaa automaattisesti sekunnin välein. Sekä zsh että ksh93 muuttujasta voidaan tehdä myös liukuluku (typeset -F SECONDS ) tarkkuuden lisäämiseksi. Tämä on vain seinäkello, ei suorittimen aikaa.

Kommentit

  • Että $ SECONDS-muuttuja on erittäin hyödyllinen, kiitos! > Poistaako lähestymistapasi ajallisten tapahtumien vaikutukset? – – Mielestäni lähestymistapasi on lähellä aiemmin esitettyä time -tapaa.- – Mielestäni MATLAB-koodissa esitetystä timeit -lähestymistavasta voi olla hyötyä.
  • Hei, @St é Phane Chazelas. Huomasin, että times ei anna ’ t antaa seinälle aikaa, eikö? esimerkiksi bash -c 'trap times EXIT;sleep 2'
  • @Binarus, kyllä, tämä ominaisuus tulee ksh: stä. Päinvastoin kuin ksh93 / zsh, bashin lisäksi, joka ei tue liukulukua, se ’ rikkoutuu myös siinä, että kun asetat SECONDS-arvoksi 0, se muuttuu arvoksi 0 0 sekunniksi 1 sekunnin kuluttua ( koska se ottaa huomioon vain time() -tuloksen, jolla on vain täysi toinen tarkkuus).
  • @Binarus, ei sitä, että ’ s välillä 0 – 1. Jos asetat SECONDS-arvoksi 0 klo 12: 00: 00.000, se muuttuu yhdeksi sekunniksi myöhemmin. Mutta jos asetat sen 12: 00: 00.999, se muuttuu yhdeksi millisekunniksi myöhemmin. Mutta kyllä, olen samaa mieltä siitä, että sillä ei todennäköisesti ’ ole väliä väliä käytännössä, jos sinulla ’ ei ole muutaman sekunnin tarkkuutta.

vastaus

I ”vähän myöhässä bandwagoniin, mutta halusin lähettää ratkaisuni (sekunnin tarkkuudesta) ), jos toiset törmäävät tähän ketjuun etsimällä. Tulos on päivien, tuntien, minuuttien ja viimeisten sekuntien muoto:

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 

Toivottavasti joku siellä se pitää tätä hyödyllisenä!

Kommentit

  • Luulen, ettei ole muuta (vain bash) tapaa kuin käyttää ’ bc ’ tehdä laskelmat. BTW todella hyvä komentosarja;)
  • Varo, että FreeBSD ’ s date ei tue sekunnin tarkkuutta ja lisää vain kirjaimellisen ”N” aikaleimaan.
  • Erittäin mukava käsikirjoitus, mutta bash ei ole ’ t käsittele alaosaa. Olen myös oppinut, että / 1 bc: ssä nauhoittaa sen tehokkaasti, joten lisäsin @ / 1 @ $ ds -laskentaan, ja se näyttää nyt erittäin hienoja juttuja!
  • bc tukee moduloa: dt2=$(echo "$dt%86400" | bc). Sanon vain … BTW mieluummin muoto dt2=$(bc <<< "${dt}%86400"), mutta se, että ’ on täysin henkilökohtainen.
  • En ’ en tiedä vielä mitään bc, mutta jakaminen 86400 tekee minut epäluuloiseksi seuraava syy: On päiviä, joissa ei ole 86400 sekuntia, esimerkiksi päivät, jolloin aika vaihdetaan DST: stä normaaliaikaan ja päinvastoin, tai päivät, joissa sekuntia on harppaus. Jos tällaiset päivät ovat osa laskettavaa aikajaksoa, eli ne ovat res1res2 (nämä arvot mukaan lukien) välillä, komentosarjasi epäonnistuu todennäköisesti.

Vastaa

Menetelmäni kohteelle bash :

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

Kommentit

  • Tämä näyttää kuluneen ajan, mutta ei ’ t näytä ” hienorakeinen lähtö, kuten prosessorin aika, I / O-aika ” kuten kysymys kysytään.
  • Ne, jotka etsivät vastausta esitettyyn kysymykseen, pitävät tätä ratkaisua todennäköisesti hyödyllisenä. Kommenttisi olisi paremmin osoitettu OP-kysymykseen.

Vastaa

Henkilökohtaisesti haluan kääri kaikki komentokoodi joissakin ”main” -funktioissa, kuten:

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

Huomaa kuinka helppoa on käyttää time -komentoa tässä skenaariossa. Ilmeisesti et mittaa tarkkaa aikaa, mukaan lukien komentosarjan jäsentämisaika, mutta mielestäni se on riittävän tarkka useimmissa tilanteissa.

Kommentit

  • Loistava ratkaisu, ei vaadi ylimääräisiä työkaluja ja on itsenäinen.

Vastaa

ei vaadi ylimääräisiä työkaluja.

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

Kyllä, tämä kutsuu Pythonia, mutta jos pystyt elämään sen kanssa, tämä on varsin mukava, lyhyt ratkaisu.

Kommentit

  • Varo, että kyseisen python -komennon suorittaminen alikuoressa ja sen lähdön lukeminen vie useita miljoonia nanosekunteja useimmissa nykyisissä järjestelmissä. Sama käynnissä date.
  • ” Useat miljoonat nanosekunnit ” on useita millisekunteja Ihmiset, jotka ajoittavat bash-komentosarjoja, eivät yleensä ole siitä kovin huolissaan (paitsi jos he käyttävät useita miljardeja komentosarjoja megasekunnissa).
  • Huomaa myös, että vaikka Laskenta tehdään python-prosessissa, arvot kerättiin kokonaan ennen pythonin käynnistämistä. Komentosarjan suoritusaika mitataan oikein ilman ” miljoonia nanosekunteja ” yleiskustannuksia.
  • time main yllä on paljon puhtaampaa …kyllä, voimme elää paljon huonontumista, mutta se ’ on parempi tapa ilman, että ’ pysyvät insinööreinä!
  • $(echo $end - $start | bc) tekee saman asian ilman pythonia

Vastaa

Tämä kysymys on melko vanha, mutta yrittäessäni löytää suosikkini tapani tehdä tämä säie nousi korkealle … ja minä yllättyin, ettei kukaan maininnut sitä:

perf stat -r 10 -B sleep 1 

”perf” on suorituskyvyn analysointityökalu, joka sisältyy ytimen kohtaan ”tools / perf” ja on usein asennettavissa erillisenä pakettina (”perf” CentOS: ssa ja ”linux-tools” Debianissa / Ubuntussa). Linux Kernal perf Wikissä on paljon enemmän tietoa siitä.

”perf stat”: n suorittaminen antaa melko vähän yksityiskohtia, mukaan lukien keskimääräinen suoritusaika aivan lopussa:

1.002248382 seconds time elapsed ( +- 0.01% ) 

kommentit

  • Mikä on perf?
  • @B Layer – muokkasi vastaustani t o anna lyhyt kuvaus ’ perf ’.
  • perf stat valittaa nyt ” Sinulla ei ehkä ole lupaa kerätä tilastoja. ” ellet aja komentoja sudo, mikä tekee siitä hyödyttömän kaikissa tilanteissa, joissa et ’ omista täysin kohdekonetta.
  • Hämmästyttävä, kiitos! Paljon hienorakeisempaa ratkaisua kuin time muut ehdottavat. Erityisesti time ei sovellu koodikilpailuratkaisujen mittaamiseen (koska se ei tulosta ’ t millisekunteina tai vähemmän) , kun taas ratkaisusi tekee.

Vastaa

Pieni kuoritoiminto, joka voidaan lisätä ennen komennot aikansa mittaamiseksi:

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

Käytä sitten komentosarjassa tai komentorivillä näin:

tm the_original_command with all its parameters 

Kommentit

  • Kannattaa lisätä millisekunteja, yritti ilke s=$(date +%s000), en ole varma jos se toimii.
  • @loretoparisi millisekunnin ajan, voit kokeilla date +%s%N. Katso serverfault.com/questions/151109/…
  • Tämä on hieno, paitsi turvallisempi käytä "$@"

Vastaa

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

kommentit

  • Miten tämä todella eroaa muista jo annetuista vastauksista, joissa käytetään date ennen ja jälkeen komentosarja ja antaa niiden välinen ero?

Vastaa

  1. Vain käytä time [any command] . Esimerkki: time sleep 1 nukkuu reaaliajassa (ts. Sekuntikellon ajastamana) ~ 1000 – ~ 1,020 sekuntia, kuten tässä näytetään:

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

    Mikä kaunis asia. Voit laittaa minkä tahansa komennon sen jälkeen, ja se tuottaa tuloksen mukavassa, ihmisten luettavassa muodossa. Haluan todella käyttää sitä rakennusten ajoitukseen. Esimerkki:

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

    … tai git-operaatioille, jotka voivat olla todella pitkä, joten voin kehittää realistisia henkisiä odotuksia:

      # 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. Lisää räätälöityjä ajoitustarpeita varten missä sinun on ehkä käsiteltävä lähtöä tai muunnettava se muuhun muotoon, bash , käytä sisäistä muuttujaa $SECONDS. Tässä on esittely, mukaan lukien näiden sekuntien muuntaminen muiksi yksiköiksi, kuten liukuluku minuutteiksi:

    Huomaa, että dt_min pyöristetään arvosta 0.01666666666... (1 sekunti = niin monta minuuttia) arvoon 0.017 tässä tapauksessa koska ”käytän pyöristykseen printf -funktiota. Alla olevasta sleep 1; osasta kutsutaan komentosarjaasi ajamaan, mutta nukun vain yhden sekunnin ajan tämän esittelyn vuoksi.

    Komento:

      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"  

    Tulos:

      dt_sec = 1; dt_min = 0.017  

Liittyvä:

  1. Lue lisää noin bc ja printf vastauksestani: https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in-bash/58479867#58479867
  2. En muista, mistä ensin sain tietää time -komennosta, mutta se on saattanut olla @Trudbert vastaus täällä .

Vastaa

Käytä vain vain bash on myös mahdollista mitata ja laskea kuoriskriptin osan kesto (tai koko komentosarjan kulunut aika):

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

voit nyt joko tulostaa eron:

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

jos tarvitset vain inkrementaalista kestoa, tee:

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

Voit tallentaa keston myös muuttujaan:

let diff=end-start 

kommentit

  • ^ TÄMÄ on vastaus ihmisille. Tai yksinkertaisemmin: $ SECONDS lopussa. Se ’ on BUILT-IN Bash -muuttuja. Kaikki muut vastaukset tekevät vain ylimääräistä työtä keksimään tämä pyörä uudelleen.
  • Tämä on vain toistoa Marksin aikaisemmasta vastauksesta unix.stackexchange .com / a / 340156/155362 .

vastaus

Ajoitustoiminto perustuu id = ”9d6089280a”>

, rajoitettu vain toisen tason rakeisuuteen, ei käytä ulkoisia komentoja:

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

Esimerkki:

time_it sleep 5 

antaa

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

vastaus

Käytä sisäänrakennettua bash-aikaa?

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. 

Esimerkki:

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

Tulos:

The command took 0.108s 

Vastaa

Tässä Alexin muunnelma ”Vastaus. Minusta välittävät vain minuutit ja sekunnit, mutta halusin myös, että se muotoiltiin eri tavalla. Joten tein tämän:

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

Kommentit

  • Miksi downvote? Onko minulla vika?
  • python: n käyttäminen laskutoimituksessa näyttää minulta myös virhettä, anteeksi mies. Miksi ihmiset ’ eivät voi vain soittaa numeroon time, on minun ulkopuolella.

Vastaa

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

vastaus

Hyväksytty ratkaisu käyttämällä time kirjoittaa stderr.
Ratkaisu, joka käyttää times, kirjoittaa osoitteeseen stdout.
Ratkaisuista, jotka käyttävät $SECONDS, puuttuu toisen sekunnin tarkkuus.
Muihin ratkaisuihin kuuluu ulkoisten ohjelmien, kuten date tai perf, joka ei ole tehokasta.
Jos jokin näistä on kunnossa, käytä sitä.

Mutta jos tarvitset tehokkaan ratkaisun saadaksesi ajat millisekunnin tarkkuudella ja tarvitsevat ne muuttujiksi siten, että alkuperäinen lähtö pysyy häiriöttömänä voit yhdistää prosessin korvaamisen joihinkin uudelleenohjauksiin time ympärille, mikä on paljon nopeampi kuin soittaminen ulkoiset ohjelmat ja sallii uudelleenohjauksen ajoituksen käärintäkomentosarjan ympärille kuten alkuperäisessä komennossa / komentosarjassa.

# 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 

Valitse jokin seuraavista muunnoksista, jotka jäsennetään time sinulle sopiva:
Lyhin muunnos, johon stdout / $Cmd kirjoitetaan osoitteeseen stderr eikä mitään stdout:

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

Pidempi vaihtoehto, joka pitää alkuperäinen stdout ja stderr erillään toisistaan:

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

Monimutkaisin variantti sisältää ylimääräisten tiedostokuvaajien sulkemisen siten, että $Cmd kutsutaan ikään kuin ilman tätä ajoituspakettia sen ympärille ja lvm -komennot, kuten vgs, eivät valita vuotaneista tiedostokuvaajista:

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

Sinä voi jopa väärentää kelluvan pisteen lisäyksen hakemistossa bash soittamatta bc, mikä olisi paljon hitaampaa:

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 

Mahdolliset lähdöt kahdella esimerkillä $Cmd hitaalla suorittimella:

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 

Tai:

stdout stderr CPU 0.008 s, Elapsed 0.109 s 

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *