UKOnline

Type de temps

Comme soulevé en début de chapitre, il existe différents types de temps d'exécution. Lorsqu'un programme est en cours d'exécution, il consomme du temps sur le processeur. Néanmoins, comme plusieurs choses peuvent se dérouler en même temps sur un ordinateur, le processeur est partagé entre les différentes tâches, qui reçoivent chacune des intervalles de temps processeur et sont en attente le reste du temps.

On peut donc déjà faire la différence entre le temps processeur, temps durant lequel le programme est effectivement en cours d'exécution sur le processeur et le temps utilisateur, temps qui s'écoule entre le moment où le programme a été lancé et celui où il a fini son exécution.

Un autre type de temps qui existe est le temps de réponse. Il correspond au temps qu'il faut attendre avant que le programme fournisse un premier « signe de vie » après avoir été lancé. Ce dernier est plus complexe à mesurer et est souvent utilisé pour les applications interactives avec interface graphique, mesurant combien de temps l'utilisateur doit attendre avant de pouvoir commencer à interagir avec le programme.

Temps processeur

Il est possible, sous certaines conditions, d'avoir accès à une horloge qui est en lien avec le temps processeur utilisé par le programme en cours d'exécution. Pour cela, il faut utiliser la fonction clock_gettime du module time, en lui précisant l'horloge à utiliser.

Par exemple, et sur les systèmes Unix uniquement, l'horloge représentée par la constante time.CLOCK_PROCESS_CPUTIME_ID fournit un temps processeur de haute résolution, en lien avec le programme en cours d'exécution. Voici un exemple d'utilisation de cette horloge pour mesurer un temps d'exécution :

Cet exemple mesure le temps d'exécution de time.sleep(1.5), instruction qui met le programme en pause pendant 1,5 s. Le temps utilisateur, mesuré avec la fonction time devrait donc être proche de 1,5 s, tandis que le temps processeur devrait être proche de $0$, le programme n'ayant été qu'en attente. Le résultat de l'exécution confirme cela :

1.5 s
9.30000000000028e-05 s

En fonction de votre système d'exploitation et de votre machine, d'autres horloges peuvent être disponibles. Aussi, il faut savoir que, pour avoir le temps processeur, on aurait pu directement utiliser la fonction process_time. L'exemple précédent aurait pu s'écrire comme suit :

Le résultat de l'exécution donne bel et bien un temps proche de $0$ :

8.099999999999774e-05 s

Compteur de performance

Parfois, lorsqu'il s'agit de mesurer des temps très courts, la fonction time n'est pas suffisamment précise. Une première solution consiste à utiliser une horloge plus précise, comme celle représentée par la constante time.CLOCK_HIGHRES et disponible sous Solaris. On peut également utiliser la fonction perf_counter qui renvoie la valeur d'un compteur de performance, à savoir le temps mesuré par une horloge (la précision qu'il est possible d'obtenir avec une telle horloge dépend du hardware de la machine et peut aller jusqu'à des nanosecondes) avec la plus haute précision possible.

Cette fonction permet de mesurer un temps utilisateur avec une grande précision, pour autant que votre système d'exploitation et votre ordinateur disposent des outils permettant une telle mesure. Elle est donc potentiellement utile pour mesurer des temps très courts. Mesurons, par exemple, le temps mis pour affecter une valeur à la variable start, à savoir l'instant de départ du chronomètre :

Sur la machine utilisée, le résultat de l'exécution montre une plus grande précision dans le deuxième cas :

0.0019073486328125 ms
0.0006050000000007438 ms

Paramétrer le compteur de timeit

Par défaut, la fonction timeit utilise la fonction perf_counter pour les mesures de temps qu'elle réalise. Elle permet donc de mesurer le temps utilisateur écoulé, avec la plus grande précision possible. Il est également possible de ne compter que le temps effectivement utilisé par le processeur, avec la fonction process_time vue plus haut.

Lorsque l'on travaille avec timeit en ligne de commande, il suffit d'utiliser l'option -p pour ce faire :

> python3 -m timeit -n 100 -p -s 'from prog import fib' 'fib(25)'
100 loops, best of 5: 38.5 msec per loop

Lorsque l'on travaille avec le module timeit en code Python, on peut modifier le compteur utilisé avec le paramètre optionnel timer. L'exemple suivant effectue trois mesures de temps différentes. La première mesure utilise le compteur de performance, la deuxième le temps processeur et la troisième utilise la fonction time vue à la section 3.1 :

Selon que votre ordinateur est moderne ou plus ancien, selon que son processeur soit occupé à exécuter autre chose que le programme à mesurer ou non, les valeurs renvoyées par ces trois méthodes seront plus ou moins proches. Dans notre cas, elles sont plutôt proches :

3.750158489
3.726765
3.7059531211853027