Jak używać polecenia czasu w systemie Linux

Photo of author

By maciekx

Chcesz wiedzieć, jak długo trwa proces i wiele więcej? Polecenie czasu w systemie Linux zwraca statystyki czasu, dając ciekawy wgląd w zasoby używane przez twoje programy.

Dlaczego warto znać czas?

Istnieje wiele dystrybucji Linuksa oraz różne systemy operacyjne podobne do Uniksa. Każdy z nich ma domyślną powłokę poleceń. Najpowszechniejszą domyślną powłoką w nowoczesnych dystrybucjach Linuksa jest powłoka bash. Istnieje jednak wiele innych, takich jak powłoka Z (zsh) i powłoka Korna (ksh).

Wszystkie te powłoki zawierają własne polecenia czasu, jako wbudowane polecenie lub jako słowo zastrzeżone. Kiedy wpiszesz „czas” w oknie terminala, powłoka wykona swoje wewnętrzne polecenie zamiast używać binarnego czasu GNU, który jest dostarczany w ramach twojej dystrybucji Linuksa.

Preferujemy użycie wersji GNU, ponieważ oferuje ona więcej opcji i jest bardziej elastyczna.

Jak sprawdzić, która wersja czasu działa?

Możesz sprawdzić, która wersja będzie działać, używając polecenia „type”. To polecenie poinformuje cię, czy powłoka sama obsłuży twoją instrukcję, czy też przekaże ją do pliku binarnego GNU.

W oknie terminala wpisz „type time” i naciśnij Enter.

type time

Widzimy, że „czas” w powłoce bash jest słowem zastrzeżonym, co oznacza, że Bash domyślnie użyje swoich wewnętrznych procedur czasu.

type time

W powłoce Z (zsh) „czas” jest również słowem zastrzeżonym, co oznacza, że wewnętrzne procedury powłoki będą używane domyślnie.

type time

W powłoce Korna „czas” jest również słowem zastrzeżonym. W tym przypadku używana jest procedura wewnętrzna zamiast polecenia czasu GNU.

Jak uruchomić polecenie GNU time?

Jeśli powłoka w systemie Linux ma wewnętrzną procedurę czasową, musisz wyraźnie określić, że chcesz używać binarnego czasu GNU. Możesz to zrobić na kilka sposobów:

  • Podaj pełną ścieżkę do pliku binarnego, na przykład /usr/bin/time. Uruchom polecenie „which time”, aby znaleźć tę ścieżkę.
  • Użyj polecenia „time” z odwrotnym ukośnikiem.

Polecenie „which time” daje nam ścieżkę do pliku binarnego.

Możemy to sprawdzić, używając /usr/bin/time jako polecenia do uruchomienia pliku binarnego GNU. To działa, a odpowiedź z polecenia „time” informuje nas, że nie podaliśmy żadnych parametrów wiersza poleceń, nad którymi mógłby działać.

Użycie polecenia „time” również działa, a czasami otrzymujemy te same informacje o użyciu. Polecenie „\time” mówi powłoce, aby zignorowała następne polecenie i przetworzyła je poza powłoką.

Najprostszym sposobem upewnienia się, że używasz binarnego czasu GNU, jest użycie opcji odwrotnego ukośnika.

time
\time

„time” wywołuje powłokową wersję czasu, podczas gdy „\time” używa wersji binarnej.

Jak korzystać z polecenia czasu?

Możesz użyć polecenia „time” do kilku programów. Użyjemy dwóch programów o nazwach loop1 i loop2, które zostały utworzone z plików loop1.c i loop2.c. Nie robią one nic pożytecznego poza demonstrowaniem skutków jednego rodzaju nieefektywności kodowania.

Oto kod dla loop1.c, w którym długość łańcucha jest określona w dwóch zagnieżdżonych pętlach, a długość jest ustalana z góry, poza pętlami.

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

int main (int argc, char* argv[])
{
    int i, j, len, count=0;
    char szString[]="newsblog.pl-newsblog.pl-newsblog.pl-newsblog.pl-newsblog.pl-newsblog.pl";

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

    for (j=0; j

Oto kod dla loop2.c, w którym długość łańcucha jest uzyskiwana na każdym cyklu pętli zewnętrznej. Ta nieefektywność powinna być widoczna w pomiarach czasowych.

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

int main (int argc, char* argv[])
{
    int i, j, count=0;
    char szString[]="newsblog.pl-newsblog.pl-newsblog.pl-newsblog.pl-newsblog.pl-newsblog.pl";

    for (j=0; j

Uruchommy program loop1 i użyjmy polecenia „time”, aby zmierzyć jego wydajność.

time ./loop1

Teraz zróbmy to samo dla loop2.

time ./loop2

Uzyskujemy dwa zestawy wyników, ale są one w nieczytelnym formacie. Możemy później poprawić formatowanie, ale na teraz przyjrzyjmy się wynikom.

Podczas uruchamiania programów istnieją dwa tryby wykonywania, między którymi odbywa się przełączanie: tryb użytkownika i tryb jądra.

Krótko mówiąc, proces w trybie użytkownika nie ma bezpośredniego dostępu do sprzętu lub pamięci poza własnym przydziałem. Aby uzyskać dostęp do takich zasobów, proces musi kierować żądania do jądra. Jeśli jądro zatwierdzi żądanie, proces przechodzi do wykonywania w trybie jądra, dopóki wymaganie nie zostanie spełnione, a następnie wraca do trybu użytkownika.

Wyniki loop1 pokazują, że program ten spędził 0,09 sekundy w trybie użytkownika, a czas w trybie jądra jest zbyt mały, aby można było go zarejestrować po zaokrągleniu. Całkowity czas wyniósł 0,1 sekundy, a loop1 otrzymał średnio 89% czasu procesora podczas swojego działania.

Nieefektywny program loop2 wykonał się trzy razy dłużej. Całkowity czas wyniósł 0,3 sekundy, a czas przetwarzania w trybie użytkownika wyniósł 0,29 sekundy. Nie zarejestrowano czasu w trybie jądra, a loop2 otrzymał średnio 96% czasu procesora podczas swojego działania.

Formatowanie danych wyjściowych

Możesz dostosować dane wyjściowe polecenia „time”, używając ciągu formatu. Ciąg ten może zawierać tekst i specyfikatory formatu. Listę specyfikatorów formatu można znaleźć w dokumentacji polecenia „time”. Każdy ze specyfikatorów formatu reprezentuje określoną informację.

Gdy ciąg jest drukowany, specyfikatory formatu są zastępowane rzeczywistymi wartościami, które reprezentują. Na przykład specyfikatorem formatu procentowego wykorzystania procesora jest litera P. Aby wskazać, że specyfikator formatu nie jest zwykłą literą, należy dodać przed nim znak procentu, na przykład %P. Użyjmy tego w praktyce.

Opcja -f (łańcuch formatujący) służy do określenia, że to, co następuje, jest łańcuchem formatu.

Nasz ciąg formatu wypisze znaki „Program:” oraz nazwę programu (oraz wszelkie parametry wiersza poleceń, które przekazujesz do programu). Specyfikator formatu %C oznacza „Nazwa i argumenty wiersza polecenia polecenia, którego czas jest mierzony”. N powoduje przejście do następnego wiersza.

Istnieje wiele specyfikatorów formatu, a ich wielkość liter ma znaczenie, dlatego upewnij się, że wprowadzasz je poprawnie.

Następnie wydrukujemy znaki „Całkowity czas:” oraz wartość całkowitego czasu, jaki upłynął dla tego uruchomienia programu (reprezentowany przez %E).

Używamy N do przejścia do nowej linii. Następnie wydrukujemy znaki „Tryb (y) użytkownika”, a po nich wartość czasu procesora spędzonego w trybie użytkownika, oznaczoną przez %U.

Używamy N do przejścia do nowej linii. Tym razem przygotowujemy się na wartość czasu jądra. Drukujemy znaki „Tryb (y) jądra”, po których następuje specyfikator formatu czasu procesora spędzonego w trybie jądra, czyli %S.

Na koniec wydrukujemy znaki „nCPU:”, aby uzyskać nowy wiersz i tytuł tej wartości danych. Specyfikator formatu %P podaje średni procent czasu procesora używanego przez proces czasowy.

Cały ciąg formatu jest zawinięty w cudzysłów. Możemy również dodać znaki tabulacji, aby dostosować wyrównanie wartości, jeśli zajdzie taka potrzeba.

time -f "Program: %CnTotal time: %EnUser Mode (s): %UnKernel Mode (s): %SnCPU: %P" ./loop1

Jak zapisać wyniki do pliku?

Aby zachować zapis czasów z przeprowadzonych testów, możesz przesyłać dane wyjściowe do pliku. Użyj opcji -o (wyjście), aby dane wyjściowe z czasu były przekierowane do pliku. Wyniki twojego programu będą nadal wyświetlane w oknie terminala.

Możemy ponownie uruchomić test i zapisać wynik do pliku test_results.txt w następujący sposób:

time -o test_results.txt -f "Program: %CnTotal time: %EnUser Mode (s): %UnKernel Mode (s): %SnCPU: %P" ./loop1
cat test_results.txt

Wyjście programu loop1 jest wyświetlane w oknie terminala, a wyniki z polecenia „time” trafiają do pliku test_results.txt.

Aby przechwycić następny zestaw wyników w tym samym pliku, musisz użyć opcji -a (append), w następujący sposób:

time -o test_results.txt -a -f "Program: %CnTotal time: %EnUser Mode (s): %UnKernel Mode (s): %SnCPU: %P" ./loop2
cat test_results.txt

Powinno być teraz jasne, dlaczego użyliśmy specyfikatora formatu %C, aby dołączyć nazwę programu do danych wyjściowych z ciągu formatu.

Podsumowanie

Polecenie „time” jest często używane przez programistów do optymalizacji ich kodu, ale jest również przydatne dla każdego, kto chce dowiedzieć się więcej o tym, co dzieje się pod maską za każdym razem, gdy uruchamiasz program.


newsblog.pl