Како користити команду за време на Линуку

Želite li da saznate koliko traje neki proces i mnogo više od toga? Linux komanda `time` vraća statistiku o vremenu, pružajući vam sjajan uvid u resurse koje koriste vaši programi.

Vreme ima mnogo rođaka

Postoji veliki broj Linux distribucija i različitih operativnih sistema sličnih Unix-u. Svaki od njih ima podrazumevanu komandnu liniju (shell). Najčešća podrazumevana komandna linija u modernim Linux distribucijama je bash shell. Međutim, postoje i mnoge druge, kao što su Z shell (zsh) i Korn shell (ksh).

Sve ove komandne linije uključuju sopstvenu komandu `time`, bilo kao ugrađenu komandu ili kao rezervisanu reč. Kada unesete `time` u terminal, komandna linija će izvršiti svoju internu komandu umesto da koristi GNU binarni program `time`, koji je deo vaše Linux distribucije.

Mi želimo da koristimo GNU verziju komande `time` jer ima više opcija i fleksibilnija je.

Koja će se komanda `time` izvršiti?

Možete proveriti koja će se verzija izvršiti pomoću komande `type`. `type` će vas obavestiti da li će komandna linija sama obraditi vašu instrukciju, sa svojim internim rutinama, ili će je proslediti GNU binarnom sistemu.

U prozoru terminala otkucajte `type`, razmak, a zatim reč `time` i pritisnite Enter.

type time

Možemo videti da je u bash shell-u `time` rezervisana reč. To znači da će Bash podrazumevano koristiti svoje interne rutine.

type time

U Z shell-u (zsh) `time` je takođe rezervisana reč, tako da će se interne shell rutine koristiti podrazumevano.

type time

U Korn shell-u `time` je ključna reč. Umesto GNU komande `time`, koristiće se interna rutina.

Pokretanje GNU `time` komande

Ako komandna linija na vašem Linux sistemu ima internu rutinu za `time`, moraćete da budete eksplicitni ako želite da koristite GNU `time` binarnu datoteku. Morate ili:

  • Navesti celu putanju do binarne datoteke, kao što je `/usr/bin/time`. Pokrenite komandu `which time` da pronađete ovu putanju.
  • Koristiti komandu `command time`.
  • Koristiti obrnutu kosu crtu kao `\time`.

Komanda `which time` nam daje putanju do binarne datoteke.

Ovo možemo testirati korišćenjem `/usr/bin/time` kao komande za pokretanje GNU binarne datoteke. To radi. Dobijamo odgovor od komande `time` koja nam govori da nismo dali nikakve parametre komandne linije za izvršenje.

Unos `command time` takođe funkcioniše, i dobijamo iste informacije o korišćenju od `time`. Komanda `command` govori komandnoj liniji da ignoriše sledeću komandu tako da se ona obrađuje izvan komandne linije.

Korišćenje znaka `\` ispred naziva komande je isto kao i korišćenje komande `command` ispred naziva komande.

Najjednostavniji način da se uverite da koristite GNU `time` binarnu datoteku je da koristite opciju obrnute kose crte.

\time
time

`time` poziva shell verziju `time`. `\time` koristi `time` binarnu datoteku.

Korišćenje komande `time`

Hajde da odredimo vreme izvršavanja za neke programe. Koristimo dva programa koja se zovu `loop1` i `loop2`. Oni su napravljeni od `loop1.c` i `loop2.c`. Oni ne rade ništa korisno, osim što pokazuju efekte jedne vrste neefikasnosti u kodiranju.

Ovo je `loop1.c`. Dužina stringa se dobija jednom, izvan dve ugnežđene petlje.

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

int main (int argc, char* argv[])
{
 int i, j, len, count=0;
 char szString[]="how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek";

 // get length of string once, outside of loops
 len = strlen( szString );  

 for (j=0; j<10000; j++)
 {
  for (i=0; i<1000; i++)
  {
   count++;
  }
 }
 printf("Count = %dn", count);
 return 0;
}

Ovo je `loop2.c`. Dužina stringa se dobija više puta, unutar spoljašnje petlje. Ova neefikasnost bi trebalo da se pokaže u merenju vremena.

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

int main (int argc, char* argv[])
{
 int i, j, count=0;
 char szString[]="how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek-how-to-geek";

 for (j=0; j<10000; j++)
 {
  for (i=0; i<1000; i++)
  {
   strlen( szString );
   count++;
  }
 }
 printf("Count = %dn", count);
 return 0;
}

Hajde da pokrenemo program `loop1` i koristimo `time` da izmerimo njegove performanse.

\time ./loop1

Sada uradimo isto za `loop2`.

\time ./loop2

To nam je dalo dva seta rezultata, ali oni su u prilično nezgodnom formatu. Možemo nešto da uradimo po tom pitanju kasnije, ali hajde da izdvojimo nekoliko delova informacija iz rezultata.

Kada se programi pokreću, postoje dva načina izvršavanja između kojih se prebacuju. Oni se zovu korisnički režim i režim kernela.

Ukratko rečeno, proces u korisničkom režimu ne može direktno da pristupi hardveru ili memoriji van svoje sopstvene alokacije. Da bi dobio pristup takvim resursima, proces mora da uputi zahteve kernelu. Ako kernel odobri zahtev, proces ulazi u izvršenje u režimu kernela sve dok zahtev nije zadovoljen. Proces se zatim vraća na izvršavanje u korisničkom režimu.

Rezultati za `loop1` nam govore da je `loop1` proveo 0,09 sekundi u korisničkom režimu. Ili je proveo nula vremena u režimu kernela, ili je vreme u režimu kernela premala vrednost da bi se registrovala kada se zaokruži naniže. Ukupno proteklo vreme je 0,1 sekundu. `loop1` je dodeljeno u proseku 89% CPU vremena tokom trajanja svog ukupnog proteklog vremena.

Neefikasnom programu `loop2` je trebalo tri puta duže da se izvrši. Njegovo ukupno proteklo vreme je 0,3 sekunde. Trajanje vremena obrade u korisničkom režimu je 0,29 sekundi. Ništa se ne registruje za režim kernela. `loop2` je dobio u proseku 96% CPU vremena za vreme svog rada.

Formatiranje izlaza

Možete da prilagodite izlaz iz `time` koristeći niz formata. Niz formata može da sadrži tekst i specifikacije formata. Lista specifikacija formata može se pronaći na man stranici za `time`. Svaka od specifikacija formata predstavlja deo informacije.

Kada se string odštampa, specifikacije formata se zamenjuju stvarnim vrednostima koje predstavljaju. Na primer, specifikacija formata za procenat CPU-a je slovo P. Da biste naznačili `time` da specifikacija formata nije samo obično slovo, dodajte mu znak procenta, kao `%P`. Hajde da ga upotrebimo u primeru.

Opcija `-f` (string formata) se koristi da naznači komandi `time` da je ono što sledi niz formata.

Naš niz formata će odštampati znakove „Program:“ i naziv programa (i sve parametre komandne linije koje prosledite programu). Specifikator `%C` formata je skraćenica za „Ime i argumente komandne linije komande koja se vremenski meri“. `\n` dovodi do premeštanja izlaza u sledeći red.

Postoji mnogo specifikacija formata i one su osetljive na velika i mala slova, tako da se uverite da ih unosite ispravno kada ovo radite sami.

Zatim ćemo odštampati znakove „Ukupno vreme:“ praćene vrednošću ukupnog proteklog vremena za ovo pokretanje programa (predstavljeno sa `%E`).

Koristimo `\n` da unesemo još jedan novi red. Zatim ćemo odštampati znakove „Korisnički režim (s)“, nakon čega sledi vrednost CPU vremena provedenog u korisničkom režimu, označeno sa `%U`.

Koristimo `\n` da unesemo još jedan novi red. Ovog puta se pripremamo za vrednost vremena kernela. Štampamo znakove „Kernel Mode(s)“, nakon čega sledi specifikacija formata za CPU vreme provedeno u režimu kernela, a to je `%S`.

Konačno, odštampaćemo znakove „\nCPU: “ da bismo dobili novi red i naslov za ovu vrednost podataka. Specifikator formata `%P` će dati prosečan procenat CPU vremena koje koristi vremenski ograničen proces.

Ceo niz formata je uokviren navodnicima. Mogli smo da uključimo i neke `\t` znakove da bismo postavili tabulatore u izlaz da smo bili zabrinuti oko poravnanja vrednosti.

\time -f "Program: %C\nTotal time: %E\nUser Mode (s) %U\nKernel Mode (s) %S\nCPU: %P" ./loop1

Slanje izlaza u datoteku

Da biste vodili evidenciju o vremenima testova koje ste sproveli, možete povremeno da pošaljete izlaz u datoteku. Da biste to uradili, koristite opciju `-o` (izlaz). Izlaz iz vašeg programa će i dalje biti prikazan u prozoru terminala. To je samo izlaz iz komande `time` koji se preusmerava u datoteku.

Možemo ponovo da pokrenemo test i sačuvamo izlaz u datoteci `test_results.txt` na sledeći način:

\time -o test_results.txt -f "Program: %C\nTotal time: %E\nUser Mode (s) %U\nKernel Mode (s) %S\nCPU: %P" ./loop1
cat test_results.txt

Izlaz programa `loop1` se prikazuje u prozoru terminala, a rezultati od `time` idu u datoteku `test_results.txt`.

Ako želite da snimite sledeći set rezultata u istoj datoteci, morate da koristite opciju `-a` (dodati) na sledeći način:

\time -o test_results.txt -a -f "Program: %C\nTotal time: %E\nUser Mode (s) %U\nKernel Mode (s) %S\nCPU: %P" ./loop2
cat test_results.txt

Sada bi trebalo da bude jasno zašto smo koristili specifikaciju formata `%C` da bismo uključili ime programa u izlaz iz niza formata.

I isteklo nam je vreme

Verovatno od najveće koristi programerima i programerima za fino podešavanje svog koda, komanda `time` je takođe korisna za svakoga ko želi da otkrije nešto više o tome šta se dešava ispod haube svaki put kada pokrenete program.