Une classe simple en c++ pour mesurer le temps d'execution d'une portion de code sur une machine non dediee aux tests (windo

Soyez le premier à donner votre avis sur cette source.

Vue 22 015 fois - Téléchargée 9 330 fois

Description

On a parfois besoin de mesurer le temps d'exécution CPU d'une portion de code (lors de l'optimisation de l'efficacité d'une procédure par exemple), et pas toujours les moyens de consacrer une machine exclusivement aux tests.
L'utilisation de procédures comme clock(), GetTime(), QueryPerformanceCounter() ou d'autres permet de calculer le temps "réel" qui s'est écoulé entre deux points du code. Lorsqu'on ne peut pas dédier une machine aux tests, l'inconvénient de ces méthodes est de prendre en compte le temps des autres applications qui tournent sur le système en concurrence avec celle testée. Ce cas de figure est par exemple rencontré sur une machine sur laquelle on ne possède pas les droits suffisants pour désactiver une défragmentation, une analyse antivirus... automatique. Le temps consommé par ces applications n'est alors pas décompté par les méthodes sus-citées, ce qui fausse totalement les mesures.
Cette classe fournit un moyen simple de mesurer le temps processeur du processus courant uniquement entre un point de l'exécution et un autre grâce à l'utilisation de la fonction le l'API de Windows GetProcessTimes. L'utilisation de cette procédure permet de ne pas avoir recours à une gestion avancée du multi-tâche pour contrôler la préemption de notre processus.
Elle dispose en outre d'une mémoire comparable à celle d'un chronomètre classique afin de pouvoir ajouter une mesure à d'autres.
Elle présente les avantages suivants :
- ne mesurer que le temps du processus (si d'autres applications sont en cours d'exécution sur le système, la mesure n'est pas faussée)
- très simple (à mon avis) d'utilisation

Source / Exemple :


//---------------------------------------------------------------------------
// Classe Chronomètre : permet de mesurer le temps CPU du processus courant
// Le temps considéré est le UserTime du processus, soit le temps pendant
// lequel le système exécute du code appartenant au processus uniquement.
//---------------------------------------------------------------------------
#ifndef chronoH
#define chronoH
#include <windows.h>
//---------------------------------------------------------------------------
class Chrono
{
  // Handle du processus courant
  HANDLE ihP;
  // Temps CPU lors du déclenchement
  unsigned int startTime;

public :
  // mémoire du chrono
  unsigned int m;

  // Constructeur
  Chrono() {reset();}
  // mise à zéro de la mémoire
  void reset() {m=0;}
  // Lance le chronomètre
  void iGo()
    {
    FILETIME ilpCreationTime;
    FILETIME ilpExitTime;
    FILETIME ilpKernelTime;
    FILETIME ilpUserTime;
    SYSTEMTIME stUser;
    ihP=GetCurrentProcess();
    GetProcessTimes(ihP,&ilpCreationTime,&ilpExitTime,&ilpKernelTime,&ilpUserTime);
    FileTimeToSystemTime(&ilpUserTime,&stUser);
    startTime=(stUser.wMilliseconds +1000*(stUser.wSecond
	     +60*(stUser.wMinute+60*(stUser.wHour+24*(stUser.wDay-1)))));
  }
  // Renvoie le temps CPU du processus, en millisecondes, 
  // écoulé depuis le lancement du chrono
  unsigned int iStop()
    {
    FILETIME ilpCreationTime;
    FILETIME ilpExitTime;
    FILETIME ilpKernelTime;
    FILETIME ilpUserTime;
    SYSTEMTIME stUser;
    GetProcessTimes(ihP,&ilpCreationTime,&ilpExitTime,&ilpKernelTime,&ilpUserTime);
    FileTimeToSystemTime(&ilpUserTime,&stUser);
    return stUser.wMilliseconds +1000*(stUser.wSecond
	+60*(stUser.wMinute+60*(stUser.wHour+24*(stUser.wDay-1))))
	-startTime;
    }
  // Ajoute le temps CPU du processus, en millisecondes, 
  // écoulé depuis le lancement du chrono à la mémoire
  void iStopAndAdd()
    {
    m+=iStop();
    }
};
//---------------------------------------------------------------------------
#endif

Conclusion :


Pour utiliser la classe, il suffit de :
- ajouter l'include (#include "Chrono.h" après avoir copié le fichier dans le répertoire source)
- définir un objet Chrono (par exemple, tps) pour chaque temps que vous voulez mesurer
- déclencher le chronomètre juste avant la portion de code à chronométrer (tps.iGo())
- si vous voulez ajouter le temps à la mémoire, faire tps.iStopAndAdd(), le temps écoulé sera ajouté à tps.m
si vous voulez seulement récupérer les temps écoulé depuis le déclenchement, faire temps=tps.iStop()
Le zip contient un exemple d'utilisation (demo.cpp), peut-être plus clair que ces explications...

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

Messages postés
17
Date d'inscription
dimanche 12 décembre 2004
Statut
Membre
Dernière intervention
10 mai 2007

Bonjour Shuttleur,

je ne connais pas l'explication a priori. Cependant, cela pourrait être une de ces raisons (simples hypothèses) :
- le déroulement des fonctions que vous appelez est sensible au temps (une fonction prépare le terrain pour une deuxième ; si celle-ci ne s'exécute pas immédiatement (en cas de basculement vers un autre thread...), des opérations supplémentaires sont nécessaires pour l'exécution de la seconde. J'opterais pour cette hypothèse dans le cas de la manipulation d'objets OLE ; je n'ai aucune idée de comment les interactions sont gérées mais cela me semble plausible : durant la période ou le thread chronométré est suspendu, d'autres processus ou threads peuvent modifier l'état d'un objet OLE. A la reprise du thread, l'objet est signalé comme modifié, et la récupération du nouvel état de l'objet doit être effectuée par notre thread (d'où la consommation CPU). Lorsqu'aucun sleep n'est appelé, l'ensemble des fonctions est exécuté intégralement dans "intervalle inter-tick" (puisque le temps mesuré est nul), et aucun thread extérieur ne peut modifier l'objet partagé.

- lors de l'appel à Sleep (ou lors du réveil du thread), il semblerait qu'il puisse y avoir un petit délai dû au fait que le temps de "sommeil" ne soit pas proportionnel au "clock tick rate" (http://msdn.microsoft.com/en-us/library/ms686298(VS.85).aspx). Ceci pourrait peut-être expliquer une augmentation du temps mesuré de quelques millisecondes par appel à sleep, au cas où ces cas soient gérés approximativement par le système (serait surprenant ?).
Messages postés
33
Date d'inscription
mercredi 12 septembre 2007
Statut
Membre
Dernière intervention
30 juin 2008

Salut Bweps

Je n'ai pas trop compris pourquoi il y a eu si peu d'engouement pour votre source, je la trouve très pratique.

Dans la pratique, j'ai des résultats étonnants : j'obtiens 0 ms pour l'exécution de plusieurs fonctions (dont des appels à une interface OLE), et si j'insère dans cette liste de fonctions exécutées un Sleep(500), j'obtiens des valeurs entre 70 et 90 ms.

J'ai essayé d'utiliser SetThreadAffinityMask(GetCurrentThread(),1) qui est nécessaire pour que certains chronomètres de ce site fonctionnent bien (bride l'appli à un coeur) mais rien ne change.

J'utilise simplement : tps->iGo() et j'affiche tps->iStop()

Sinon, le chronomètre renvoie une valeur plausible à un seul endroit de mon code.

Auriez vous une explication ?
(Vista + Core2Duo)
Messages postés
1
Date d'inscription
lundi 17 décembre 2007
Statut
Membre
Dernière intervention
25 janvier 2008

rien à dire sur tout ce qui dit bweps, c'est le meilleur, c'est mon petit frère...
Messages postés
17
Date d'inscription
dimanche 12 décembre 2004
Statut
Membre
Dernière intervention
10 mai 2007

Bonjour,
a priori vous pouvez utiliser la même méthode dans n'importe quel langage sous Windows, à partir du moment où celui-ci vous permet d'appeler des fonctions de l'API Windows (GetCurrentProcess et GetProcessTimes ici).
Bon courage.
Messages postés
1
Date d'inscription
jeudi 13 avril 2006
Statut
Membre
Dernière intervention
3 avril 2007

Bonjour , je trouve trés interessant ce que vous avez fait ,moi je cherche à clalculer le temps d'éxecution d'un fonction en temps réel sans en prendre en compte de ce qu'elle fait windows en c#
est ce que vous croyer que je peux utiliser votre téchnique.
Cordialement
Afficher les 21 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.