Jak používat příkaz time na Linuxu

Zajímá vás, jak dlouho běží procesy a chtěli byste získat více informací? Příkaz time v Linuxu vám poskytne časové statistiky, díky nimž budete mít dokonalý přehled o zdrojích, které vaše programy využívají.

Rozmanitost příkazů time

V mnoha linuxových distribucích a operačních systémech podobných Unixu se nachází výchozí příkazový interpret. Typickým výchozím interpretem v moderních linuxových systémech je bash shell. Existují ale i další, jako například Z shell (zsh) nebo Korn shell (ksh).

Všechny tyto shelly obsahují vlastní verzi příkazu time, a to buď jako integrovaný příkaz, nebo jako rezervované slovo. Když v terminálu napíšete time, shell použije svůj interní příkaz namísto GNU verze time, která je součástí distribuce Linuxu.

My však chceme pracovat s GNU verzí, protože má více možností a je flexibilnější.

Jak zjistit, která verze time se spustí?

Použitím příkazu type můžete ověřit, která verze se spustí. type vám prozradí, zda shell dokáže váš příkaz obsloužit interními postupy, nebo jej předá externímu GNU binárnímu souboru.

V terminálu zadejte příkaz type time a stiskněte Enter.

type time

Vidíme, že v bash shellu je time rezervovaným slovem. To znamená, že bash implicitně použije své vnitřní rutiny.

type time

V Z shellu (zsh) je time také rezervovaným slovem, a proto se standardně použijí interní rutiny shellu.

type time

V Korn shellu je time klíčové slovo. Namísto GNU time se použije interní rutina.

Spuštění GNU verze time

Pokud shell ve vašem Linuxu obsahuje interní rutinu pro time, musíte explicitně určit, že chcete použít binární verzi GNU. Můžete:

  • Zadat celou cestu k binárnímu souboru, například /usr/bin/time. Cestu zjistíte pomocí příkazu which time.
  • Použít command time.
  • Použít zpětné lomítko jako \time.

Příkaz which time nám ukáže cestu k binárnímu souboru.

Ověříme to spuštěním příkazu /usr/bin/time. Vidíme, že funguje. Z příkazu time dostáváme odpověď, že jsme nezadali žádné parametry příkazové řádky.

Stejný výsledek získáme i pomocí command time. Příkaz command shellu říká, aby následující příkaz ignoroval a zpracoval ho mimo shell.

Použití zpětného lomítka \ před příkazem je stejné jako použití příkazu command před příkazem.

Nejjednodušší způsob, jak zajistit použití GNU verze time je použít zpětné lomítko.

time
\time

time zavolá shellovou verzi time. \time použije binární verzi.

Praktické využití příkazu time

Podívejme se, jak načasovat běh programů. Použijeme programy loop1 a loop2. Jsou odvozeny z loop1.c a loop2.c. Samotné programy nedělají nic užitečného, pouze demonstrují důsledky jednoho typu neefektivního kódování.

Zde je kód loop1.c. Délka řetězce je zjišťována vně dvou vnořených smyček.

#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

A toto je kód loop2.c. Délka řetězce je zjišťována opakovaně v každém cyklu vnější smyčky. Tato neefektivita by se měla projevit v časování.

#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

Nyní spustíme program loop1 a pomocí time změříme jeho výkon.

time ./loop1

A teď to samé pro loop2.

time ./loop2

Dostali jsme dva výstupy, ale ve špatném formátu. Můžeme to později upravit, ale nyní se podívejme na některé informace, které jsme získali.

Během spuštění programu dochází ke střídání mezi dvěma režimy provádění: uživatelským režimem a režimem jádra.

Ve zkratce, proces v uživatelském režimu nemůže přímo přistupovat k hardwaru ani k paměti mimo svou alokaci. Pro získání přístupu k těmto zdrojům musí proces odeslat požadavek do jádra. Pokud jádro požadavek schválí, proces přejde do režimu jádra, dokud není požadavek splněn. Poté se proces přepne zpět do uživatelského režimu.

Výsledky pro loop1 nám říkají, že loop1 strávil 0,09 sekundy v uživatelském režimu. V režimu jádra strávil buď nulový čas, nebo tak krátkou dobu, že se při zaokrouhlení neprojevila. Celkový uplynulý čas byl 0,1 sekundy. loop1 v průměru využíval 89 % času CPU během celkového uplynulého času.

Spuštění neefektivního programu loop2 trvalo třikrát déle. Celkový uplynulý čas je 0,3 sekundy. Čas v uživatelském režimu je 0,29 sekundy. Režim jádra nezaznamenal žádný čas. loop2 v průměru využíval 96 % času CPU během svého běhu.

Formátování výstupu

Výstup z time můžete formátovat pomocí formátovacího řetězce. Ten může obsahovat text a specifikátory formátu. Seznam specifikátorů formátu najdete v manuálové stránce k příkazu time. Každý specifikátor formátu představuje specifickou informaci.

Při vypisování řetězce jsou specifikátory formátu nahrazeny skutečnými hodnotami. Například specifikátor formátu pro procento využití CPU je P. Chcete-li příkazu time sdělit, že se nejedná o obyčejné písmeno, přidejte před něj znak procenta, tedy %P. Ukážeme si to na příkladu.

Volba -f (formátovací řetězec) se používá k určení, že následující argument je formátovací řetězec.

Náš formátovací řetězec vypíše text „Program: “ a název programu (i s parametry příkazové řádky). Specifikátor formátu %C znamená „Název a argumenty příkazové řádky časovaného příkazu“. \n způsobí přesunutí výstupu na další řádek.

Existuje mnoho specifikátorů formátu a je důležité rozlišovat velká a malá písmena. Dávejte pozor, aby jste je zadávali správně.

Dále vypíšeme text „Celkový čas: „, následovaný hodnotou celkového uplynulého času běhu programu (%E).

Pomocí \n vložíme nový řádek. Potom vypíšeme text „Uživatelský režim (s) „, následovaný hodnotou času CPU stráveného v uživatelském režimu (%U).

Opět použijeme \n pro nový řádek. Tentokrát se připravujeme na hodnotu času jádra. Vypíšeme „Režim jádra (s) „, následovaný specifikátorem pro čas CPU strávený v režimu jádra (%S).

Nakonec vypíšeme „nCPU: “ a vložíme nový řádek. Specifikátor %P udává průměrné procento času CPU využité časovaným procesem.

Celý formátovací řetězec je uzavřený v uvozovkách. Můžeme zahrnout i znaky \t pro vložení tabulátorů do výstupu.

time -f "Program: %C\nCelkový čas: %E\nUživatelský režim (s) %U\nRežim jádra (s) %S\nCPU: %P" ./loop1

Ukládání výstupu do souboru

Pro uchování časových dat můžete výstup z time uložit do souboru. K tomu použijte volbu -o (výstup). Výstup z vašeho programu se bude stále zobrazovat v terminálu, do souboru se přesměruje jen výstup z time.

Můžeme znovu spustit test a uložit výstup do souboru test_results.txt takto:

time -o test_results.txt -f "Program: %C\nCelkový čas: %E\nUživatelský režim (s) %U\nRežim jádra (s) %S\nCPU: %P" ./loop1
cat test_results.txt

Výstup programu loop1 se zobrazí v terminálu a výstup z time se uloží do souboru test_results.txt.

Pro uložení dalšího testu do stejného souboru použijte volbu -a (připojit):

time -o test_results.txt -a -f "Program: %C\nCelkový čas: %E\nUživatelský režim (s) %U\nRežim jádra (s) %S\nCPU: %P" ./loop2
cat test_results.txt

Nyní je zřejmé, proč jsme použili specifikátor %C, abychom zahrnuli název programu do výstupu z formátovacího řetězce.

Závěrem

Příkaz time je nejužitečnější pro programátory a vývojáře při ladění jejich kódu. Může být však užitečný i pro kohokoli, kdo se chce dozvědět něco více o tom, co se děje při spuštění programu.