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říkazuwhich 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.