Vous cherchez à évaluer la durée d’exécution d’un processus et bien plus encore ? La commande `time` sous Linux est votre alliée. Elle vous fournit des statistiques temporelles précieuses, révélant les ressources utilisées par vos applications.
`time`, une commande aux multiples visages
Linux foisonne de distributions, tout comme les systèmes d’exploitation de type Unix. Chacun possède son propre interpréteur de commandes (shell) par défaut. Si le shell `bash` est le plus répandu sur les distributions Linux récentes, d’autres existent, comme `zsh` ou `ksh`.
Ces shells embarquent tous leur propre version de la commande `time`, qu’elle soit intégrée ou un mot réservé. Ainsi, lorsque vous saisissez `time` dans votre terminal, le shell exécute sa propre version plutôt que l’exécutable `time` GNU, qui fait partie de votre distribution Linux.
Cependant, la version GNU de `time` nous intéresse davantage, car elle offre davantage d’options et de flexibilité.
Quelle version de `time` sera exécutée ?
Pour savoir quelle version de `time` sera exécutée, vous pouvez utiliser la commande `type`. Elle vous indiquera si le shell traitera directement votre instruction avec ses routines internes ou si elle sera transmise à l’exécutable GNU.
Dans votre terminal, tapez `type time` puis appuyez sur Entrée.
type time
Nous constatons que dans le shell `bash`, `time` est un mot réservé. Cela signifie que `bash` utilisera ses propres routines par défaut.
type time
De même, dans le shell `zsh`, `time` est un mot réservé. Les routines internes du shell seront donc sollicitées par défaut.
type time
Quant au shell `ksh`, `time` est un mot-clé, et une routine interne sera utilisée à la place de la commande `time` GNU.
Lancer la commande `time` GNU
Si votre shell utilise sa propre version de la commande `time`, vous devrez spécifier explicitement que vous souhaitez utiliser l’exécutable `time` GNU. Pour ce faire, vous pouvez :
- Indiquer le chemin complet vers l’exécutable, par exemple `/usr/bin/time`. Vous pouvez obtenir ce chemin grâce à la commande `which time`.
- Utiliser la commande `command time`.
- Faire précéder la commande `time` d’une barre oblique inversée, soit `\time`.
La commande `which time` nous indique le chemin vers l’exécutable.
Pour le vérifier, nous pouvons utiliser `/usr/bin/time` comme commande pour lancer l’exécutable GNU. Cela fonctionne. La commande nous indique qu’aucun paramètre n’a été fourni.
Saisir `command time` fonctionne également, et nous obtenons les mêmes informations. La commande `command` force le shell à ignorer l’alias ou la fonction de même nom, et à exécuter la commande externe.
L’utilisation d’une barre oblique inversée `\` devant le nom de la commande équivaut à utiliser `command` avant le nom de la commande.
La manière la plus simple de s’assurer que l’on utilise l’exécutable `time` GNU est d’utiliser la barre oblique inversée `\`.
time
\time
`time` invoque la version du shell, tandis que `\time` utilise l’exécutable.
Utilisation de la commande `time`
Chronomettrons quelques programmes. Nous utiliserons deux programmes appelés `loop1` et `loop2`, créés à partir de `loop1.c` et `loop2.c`. Ces programmes n’ont pas d’utilité particulière si ce n’est d’illustrer les effets d’une inefficacité de codage.
Voici le code de `loop1.c`. La longueur d’une chaîne est calculée une seule fois avant les deux boucles imbriquées.
#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; jVoici le code de `loop2.c`. La longueur de la chaîne est recalculée à chaque itération de la boucle externe, ce qui constitue une inefficacité que les temps d'exécution devraient mettre en évidence.
#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; jLançons le programme `loop1` et utilisons `time` pour mesurer ses performances.
time ./loop1Faisons de même pour `loop2`.
time ./loop2Nous avons deux ensembles de résultats, mais leur format est peu lisible. Nous pourrons améliorer cela par la suite, mais analysons tout de même les informations fournies.
Pendant l'exécution d'un programme, le système alterne entre deux modes : le mode utilisateur et le mode noyau.
En bref, un processus en mode utilisateur n'a pas d'accès direct au matériel ou à la mémoire qui n'est pas allouée spécifiquement. Pour accéder à ces ressources, le processus doit faire des requêtes au noyau. Si ce dernier approuve la requête, le processus passe en mode noyau jusqu'à ce que la demande soit satisfaite, puis il revient en mode utilisateur.
Les résultats pour `loop1` indiquent que ce programme a passé 0,09 seconde en mode utilisateur. Le temps passé en mode noyau est négligeable, voire inexistant. Le temps total écoulé est de 0,1 seconde. `loop1` a utilisé en moyenne 89 % du temps CPU durant son exécution.
Le programme `loop2`, quant à lui, a mis trois fois plus de temps à s'exécuter, soit 0,3 seconde. Le temps de traitement en mode utilisateur est de 0,29 seconde, et aucun temps n'est enregistré en mode noyau. `loop2` a utilisé en moyenne 96 % du temps CPU.
Mise en forme de la sortie
Il est possible de personnaliser la sortie de `time` à l'aide d'une chaîne de format. Cette chaîne peut contenir du texte et des spécificateurs de format. Vous trouverez la liste des spécificateurs de format dans la page de manuel de `time`. Chaque spécificateur représente une information.
Lors de l'affichage de la chaîne, les spécificateurs sont remplacés par les valeurs réelles qu'ils représentent. Par exemple, le spécificateur pour le pourcentage de CPU est la lettre `P`. Pour indiquer que `%P` n'est pas un simple caractère, il faut le faire précéder d'un signe pourcentage, comme suit `%P`. Prenons un exemple.
L'option `-f` (chaîne de format) indique à `time` que ce qui suit est une chaîne de format.
Notre chaîne de format va afficher le texte «Programme:», suivi du nom du programme et de ses paramètres. Le spécificateur de format `%C` signifie «Nom et arguments de la ligne de commande». Le `\n` insère un retour à la ligne.
Il existe de nombreux spécificateurs de format, qui sont sensibles à la casse. Soyez donc attentif à les saisir correctement.
Ensuite, nous allons afficher le texte «Temps total:» suivi de la valeur du temps total écoulé pendant l'exécution du programme (représenté par `%E`).
Nous utilisons `\n` pour ajouter un autre retour à la ligne. Puis, nous affichons le texte «Mode(s) utilisateur», suivi du temps CPU passé en mode utilisateur, représenté par `%U`.
Nous utilisons `\n` pour insérer une nouvelle ligne. Cette fois, nous nous intéressons au temps passé en mode noyau. Nous affichons donc «Mode(s) noyau», suivi du spécificateur `%S`, qui représente le temps CPU passé en mode noyau.
Enfin, nous affichons le texte «% CPU:», afin de donner un titre à cette valeur. Le spécificateur `%P` donne le pourcentage moyen de temps CPU utilisé par le processus chronométré.
La chaîne de format est placée entre guillemets. Nous aurions pu inclure des caractères `\t` pour insérer des tabulations dans la sortie afin d'aligner les valeurs.
time -f "Program: %CnTotal time: %EnUser Mode (s) %UnKernel Mode (s) %SnCPU: %P" ./loop1Enregistrer la sortie dans un fichier
Pour conserver une trace des mesures que vous avez effectuées, vous pouvez enregistrer la sortie de `time` dans un fichier. Pour cela, utilisez l'option `-o` (output). La sortie de votre programme continuera à s'afficher dans le terminal. Seule la sortie de `time` sera redirigée vers le fichier.
Nous pouvons exécuter à nouveau le test et enregistrer la sortie dans le fichier `test_results.txt` comme suit :
time -o test_results.txt -f "Program: %CnTotal time: %EnUser Mode (s) %UnKernel Mode (s) %SnCPU: %P" ./loop1cat test_results.txtLa sortie du programme `loop1` s'affiche dans le terminal, tandis que les résultats de `time` sont enregistrés dans le fichier `test_results.txt`.
Si vous souhaitez ajouter les résultats suivants dans le même fichier, utilisez l'option `-a` (append) comme suit :
time -o test_results.txt -a -f "Program: %CnTotal time: %EnUser Mode (s) %UnKernel Mode (s) %SnCPU: %P" ./loop2cat test_results.txtOn comprend maintenant l'intérêt d'avoir utilisé le spécificateur `%C` pour inclure le nom du programme dans la chaîne de format.
Le temps est écoulé
Particulièrement utile pour les programmeurs et les développeurs qui cherchent à optimiser leur code, la commande `time` est également intéressante pour tous ceux qui souhaitent en savoir plus sur ce qui se passe dans les coulisses lorsqu'ils lancent un programme.