Linux / Commande time : mesurer la durée, le CPU et les ressources

time mesure la durée d’une tâche et le temps de processeur qu’elle consomme. Dans Bash, le mot-clé time peut mesurer directement une commande interne, une fonction ou un pipeline ; l’exécutable GNU Time, souvent installé comme /usr/bin/time, ajoute des statistiques de ressources et un rapport séparé avec -o.

Identifier le time utilisé avant de choisir ses options

Le mot-clé de Bash fait partie de la syntaxe du shell. GNU Time est un programme distinct qui peut manquer sur une installation minimale. Les options -v et -f de GNU Time ne sont donc pas des options du mot-clé Bash.

type -a time
type -P time

Dans Bash, la première réponse peut indiquer un mot réservé, et la seconde recherche un fichier externe. Le guide de type explique ces différences. Les exemples suivants supposent Bash hors mode POSIX ; ce mode possède des règles particulières de reconnaissance de time lorsque le mot suivant commence par un tiret.

Avant d’utiliser les exemples GNU, vérifiez que le chemin correspond bien à GNU Time :

/usr/bin/time --version

Si ce fichier n’existe pas, installez GNU Time au moyen du gestionnaire de paquets de votre distribution ou adaptez le chemin à l’exécutable vérifié. Un autre programme de même nom peut proposer des options et unités différentes. Les exemples Bash restent utilisables sans GNU Time.

Lire real, user et sys sans confondre attente et calcul

time sleep 1

À la fin de la commande, Bash affiche normalement ses statistiques sur la sortie d’erreur. Le format exact dépend de TIMEFORMAT ; les valeurs peuvent varier avec la charge et la précision de mesure.

Valeur Signification
real Durée écoulée entre le début et la fin de la tâche mesurée, y compris les attentes et délais d’ordonnancement.
user Temps CPU consommé en mode utilisateur par le travail mesuré.
sys Temps CPU consommé en mode noyau pour ce travail.

sleep 1 attend au lieu d’occuper continuellement un processeur : sa durée écoulée doit être proche de l’attente demandée, avec une consommation CPU généralement faible. N’attendez pas des valeurs exactement identiques à chaque essai.

Si plusieurs processeurs travaillent en parallèle, la somme des temps CPU peut dépasser la durée écoulée. À l’inverse, une tâche limitée par des entrées-sorties peut passer beaucoup de temps à attendre sans consommer autant de CPU. Les trois nombres ne représentent donc pas trois parties qui devraient s’additionner pour produire real.

Voici un calcul fini utilisant les opérations arithmétiques de Bash :

time (
  total=0
  for ((i=1; i<=20000; i++)); do
    ((total+=i))
  done
  printf 'Somme : %s\n' "$total"
)

Le résultat fonctionnel attendu est Somme : 200010000. Les temps ne sont pas une constante de l’exemple : cette boucle illustre une tâche de calcul, mais ne constitue pas un benchmark général du système.

Définir le périmètre : pipeline et groupe de commandes

Le mot-clé Bash mesure le pipeline suivant

time printf 'b\na\n' | sort

La sortie attendue contient a, puis b, sur deux lignes. La mesure porte sur le pipeline complet, pas seulement sur printf. La documentation Bash des pipelines et du mot-clé time précise ce périmètre.

Avec /usr/bin/time programme | autre, le shell construit un pipeline dont le premier élément lance GNU Time : le programme mesuré est celui qui lui est passé, pas automatiquement l’autre élément. Pour inclure tout un pipeline dans GNU Time, vous pouvez le confier à un nouveau Bash :

/usr/bin/time -v bash --noprofile --norc -c 'set -o pipefail; printf "b\na\n" | sort'

Cette mesure inclut le lancement du Bash supplémentaire. Elle n’est donc pas strictement équivalente au même pipeline déjà exécuté dans votre shell courant. Les fonctions locales de ce dernier ne sont pas automatiquement disponibles dans le nouveau processus.

Regrouper plusieurs étapes et garder un statut utile

time {
  printf '%s\n' 'Début'
  sleep 0.2
  printf '%s\n' 'Fin'
}

Les accolades regroupent les étapes dans le shell courant. Des parenthèses créent au contraire un sous-shell, comme dans l’exemple du calcul : les changements de variables et de répertoire de ce groupe ne restent pas dans le shell parent.

La mesure n’annule pas les règles de statut du pipeline. Sans pipefail, le statut vient normalement du dernier élément ; avec cette option, une erreur antérieure peut faire échouer l’ensemble. Ce bloc l’illustre sans modifier durablement vos options :

(
  set -o pipefail
  time false | true
  printf 'Statut du pipeline : %s\n' "$?"
)

La ligne attendue indique 1. Sans pipefail, ce pipeline se terminerait normalement avec le statut nul de true. Vérifiez le statut immédiatement après la tâche mesurée, avant qu’une autre commande ne remplace $?.

Adapter le format Bash sans changer durablement la session

-p demande le format de présentation de type POSIX avec les libellés real, user et sys :

time -p sleep 1

Pour choisir les champs et une ponctuation décimale prévisible dans un essai Bash :

(
  export LC_ALL=C
  TIMEFORMAT='real=%3R user=%3U sys=%3S cpu=%P%%'
  time sleep 1
)

Les durées sont ici exprimées en secondes avec trois chiffres après le point. %R représente la durée écoulée, %U le temps CPU utilisateur, %S le temps CPU noyau, %P le rapport CPU calculé à partir de ces temps et %% un signe pour cent littéral.

Les parenthèses limitent TIMEFORMAT et la locale à cet essai. Une valeur vide de TIMEFORMAT désactive l’affichage du rapport Bash, ce qui peut expliquer une absence apparente de mesure. La référence des variables Bash détaille ce format.

Séparer le résultat, les diagnostics et la mesure

Préparez un nouveau fichier tache-demo.sh avec ce contenu complet. Il produit un résultat normal, un diagnostic et une courte attente, sans autre dépendance que Bash et sleep :

#!/usr/bin/env bash
printf '%s\n' 'Résultat de démonstration'
printf '%s\n' 'Diagnostic de démonstration' >&2
sleep 0.2

Un premier lancement permet de vérifier les deux messages :

bash tache-demo.sh

Pour capturer la mesure Bash et les diagnostics ensemble, tout en séparant la sortie normale, utilisez de nouveaux noms de fichiers :

(
  export LC_ALL=C
  TIMEFORMAT='real=%3R user=%3U sys=%3S'
  set -o noclobber
  { time bash tache-demo.sh > sortie-bash.txt; } 2> mesure-et-erreurs.txt
)

sortie-bash.txt doit contenir seulement le résultat. mesure-et-erreurs.txt contient le diagnostic de la tâche et le rapport temporel : la redirection du groupe les collecte tous deux. Une simple redirection placée sur la commande mesurée ne capture pas nécessairement le rapport du mot-clé Bash.

noclobber empêche les redirections d’écraser un fichier existant. Si un nom est déjà pris, choisissez-en un autre ; une erreur peut laisser un autre fichier partiel. Vérifiez le statut et les contenus au lieu de considérer la seule existence d’un fichier comme une mesure réussie.

Avec GNU Time installé au chemin indiqué, son option -o permet de conserver le rapport séparément des diagnostics de la tâche :

(
  set -o noclobber
  /usr/bin/time -v -a -o mesure-gnu.txt bash tache-demo.sh > sortie-gnu.txt 2> erreurs-gnu.txt
)

Le rapport de ressources est ajouté à mesure-gnu.txt, la sortie normale va dans sortie-gnu.txt et les diagnostics dans erreurs-gnu.txt. -a demande un ajout au rapport ; sans cette option, -o remplace son contenu, indépendamment du réglage Bash noclobber.

Un nouveau lancement nécessite ici de nouveaux noms pour les fichiers de sortie protégés. Le manuel d’invocation de GNU Time décrit les options et les avertissements émis quand la cible échoue.

Interpréter les statistiques supplémentaires de GNU Time

-v utilise un rapport détaillé. GNU Time accepte aussi -p pour son format de présentation portable. Pour ne demander que certains champs, -f choisit un autre format :

/usr/bin/time -f 'elapsed=%e user=%U sys=%S max_rss=%M exit=%x' bash tache-demo.sh

Dans ce format GNU, %e est la durée écoulée en secondes et %x le statut de la cible. Les formats GNU Time et TIMEFORMAT de Bash sont différents : ne remplacez pas arbitrairement %R par %e dans l’autre outil.

Indicateur GNU Ce qu’il aide à observer Limite
Durées écoulée, utilisateur et noyau Attente et consommation de CPU de la tâche mesurée. La portée du programme lancé et des ressources comptabilisées compte.
%M, mémoire résidente maximale Un pic de mémoire résidente rapporté par le système. Ce n’est ni la mémoire allouée cumulée ni automatiquement un pic simultané de tout un arbre de processus.
Défauts de page Activité de gestion de la mémoire et recours éventuel aux entrées-sorties. Un défaut de page n’est pas en soi une erreur de programme.
Entrées-sorties et changements de contexte Opérations et interruptions d’exécution comptabilisées par le système. Ne pas assimiler directement les compteurs à un débit en octets ; certaines informations peuvent manquer.

La référence mémoire de GNU Time décrit %M en kilooctets. Sur Linux, le champ ru_maxrss sous-jacent est exprimé en kibioctets, soit des unités de 1 024 octets ; pour les enfants, il correspond au plus grand enfant, pas à une somme simultanée de l’arbre. Le manuel Linux de getrusage précise cette limite et les champs effectivement renseignés.

Quand vous comparez plusieurs processus, contrôlez donc la méthode de collecte au lieu d’additionner des pics observés à des instants différents. Le système et l’outil peuvent aussi afficher zéro pour une ressource non disponible : cette valeur n’établit pas toujours une absence réelle d’activité.

Comparer deux exécutions de façon utile

Définissez d’abord le résultat attendu et le périmètre de la mesure : même entrée, même tâche et même destination de sortie. Une comparaison entre un programme déjà lancé et un nouveau shell ajoute une différence qui peut dominer une tâche très courte.

  • Répétez plusieurs essais et examinez la médiane ou la dispersion, plutôt qu’un meilleur temps isolé.
  • Distinguez un premier lancement des suivants : caches, compilation à la volée ou connexions réutilisées peuvent modifier le travail effectué.
  • Notez la version, le nombre de travailleurs, la charge concurrente et les ressources allouées lorsqu’ils influencent la comparaison.
  • Gardez une destination de sortie comparable : l’affichage dans un terminal peut coûter différemment d’une écriture dans un fichier.
  • Contrôlez le statut et le résultat fonctionnel ; une tâche plus rapide parce qu’elle s’est arrêtée trop tôt n’est pas une amélioration équivalente.

Pour vérifier simplement les répétitions sur la tâche de démonstration, sans changement persistant des réglages :

(
  export LC_ALL=C
  TIMEFORMAT='real=%3R user=%3U sys=%3S'
  for essai in 1 2 3; do
    printf 'Essai %s\n' "$essai" >&2
    time bash tache-demo.sh
  done
)

Chaque essai doit produire les deux messages de la tâche et une mesure. Les chiffres restent propres à votre environnement. Pour une analyse de performance réelle, conservez aussi les conditions de l’essai afin de savoir ce qui a changé entre les mesures.