IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Delphi Discussion :

Calcul du temps entre 2 taches


Sujet :

Langage Delphi

  1. #1
    Nouveau membre du Club
    Inscrit en
    Janvier 2007
    Messages
    71
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 71
    Points : 34
    Points
    34
    Par défaut Calcul du temps entre 2 taches
    Salut
    J’ai 1 edit et 2 boutons j’essaye de trouver le meilleur code pour que quand je clic sur le bouton 1 un chrono se déclenche et quand je clic sur le bouton 2 le chrono s’arrête et écris le temps qui a passé entre les 2 clics en Minute.
    Merci de plus

  2. #2
    Rédacteur/Modérateur
    Avatar de ero-sennin
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2005
    Messages
    2 965
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2005
    Messages : 2 965
    Points : 4 935
    Points
    4 935
    Par défaut
    Re,

    Pour faire ce que tu demandes, il te faut :

    - Deux boutons
    - Un Timer
    - Un Label
    - Un peu de recherche

    Essaie de faire un morceau de code et si tu as des soucis, met le sur le forum

  3. #3
    Nouveau membre du Club
    Inscrit en
    Janvier 2007
    Messages
    71
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 71
    Points : 34
    Points
    34
    Par défaut
    Peut tu m'éclairais un tous petit peu ?

  4. #4
    Rédacteur/Modérateur
    Avatar de ero-sennin
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2005
    Messages
    2 965
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2005
    Messages : 2 965
    Points : 4 935
    Points
    4 935
    Par défaut
    Tu as le Timer avec la propriété Interval qui va te permettre de jouer sur le temps ... 1000 équivaut à une seconde ...

    Ensuite, tu as un bouton qui va :
    - déclencher le Timer (Timer.Enable:=True)
    - mémoriser dans une variable globale le top départ de type TDateTime

    Tu as un bouton qui va
    - 'arrêter le Timer (Timer.Enable:=false)

    Dans l'événement OnTimer du timer, tu effectues ton calcul :
    - Top départ - Heure système que t'affiche dans le caption du label en formatant le résultat avec TimeToStr

    J'espère t'avoir mis sur la piste ...
    A+

  5. #5
    Nouveau membre du Club
    Inscrit en
    Janvier 2007
    Messages
    71
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 71
    Points : 34
    Points
    34
    Par défaut
    Merci je vais essayer !

  6. #6
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut Calcul du temps entre 2 taches
    Salut,

    Pour calculer le temps entre deux tâches ou le temps mis par une boucle vaut mieux éviter le Timer qui est est peu fiable (le timer est approxiamtif) préférer GetTickCount. Voiçi un exemple utilisé ici pour tester la rapidité d'une boucle (rapidité d'une routine) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    procedure TForm1.CopyAndFillLeftClick(Sender: TObject);
    var       s : string; Start : DWORD;
    begin     Start:=getTickCount; // < ici le top-départ du chrono
              for i:=1 to 1000000 do
              begin s:='ab'; CopyAndFill5(s, 200, 'o', true); end;
              edMis.text:='mis : '+intToStr(getTickCount - Start)+' millisecondes'; //< ici l'affichage du temps mis
    end;
    ... c'est beaucoup moins approximatif qu'avec un Timer sans être parfait car Wondows pique la main quand ça lui chante et autant de fois que ça lui chante pendant qu'on chronomètre ce qui fait qu'entre deux clicks successifs les résultats varient de quelques millisecondes et parfois davantage ... mais comme on sait que cela provient de Windows suffit de retenir la valeur la plus faible résultant de plusieurs clicks au lieu d'en faire la moyenne.

    A+

  7. #7
    Rédacteur/Modérateur
    Avatar de ero-sennin
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2005
    Messages
    2 965
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2005
    Messages : 2 965
    Points : 4 935
    Points
    4 935
    Par défaut
    Citation Envoyé par Gilbert Geyer Voir le message
    Salut,

    Pour calculer le temps entre deux tâches ou le temps mis par une boucle vaut mieux éviter le Timer qui est est peu fiable (le timer est approxiamtif) préférer GetTickCount. Voiçi un exemple utilisé ici pour tester la rapidité d'une boucle (rapidité d'une routine) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    procedure TForm1.CopyAndFillLeftClick(Sender: TObject);
    var       s : string; Start : DWORD;
    begin     Start:=getTickCount; // < ici le top-départ du chrono
              for i:=1 to 1000000 do
              begin s:='ab'; CopyAndFill5(s, 200, 'o', true); end;
              edMis.text:='mis : '+intToStr(getTickCount - Start)+' millisecondes'; //< ici l'affichage du temps mis
    end;
    ... c'est beaucoup moins approximatif qu'avec un Timer sans être parfait car Wondows pique la main quand ça lui chante et autant de fois que ça lui chante pendant qu'on chronomètre ce qui fait qu'entre deux clicks successifs les résultats varient de quelques millisecondes et parfois davantage ... mais comme on sait que cela provient de Windows suffit de retenir la valeur la plus faible résultant de plusieurs clicks au lieu d'en faire la moyenne.

    A+
    Salut Gilbert

    Je suis tout à fait d'accord avec toi J'avais l'intention d'y venir mais après la réussite du code avec le Timer! J'allais lui expliquer le cas que tu as décris! J'ai plus besoin de m'en soucier désormais

    @+

  8. #8
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    Salut

    pour moi, il n'y a pas besoin de timer...


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
     
    type
      TForm2 = class(TForm)
        Edit1: TEdit;
        Button1: TButton;
        Button2: TButton;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
      private
        FDebut, FFin: Cardinal;
        function CalculInterval(Debut, Fin: Cardinal): Cardinal;
      public
      end;
     
    var
      Form2: TForm2;
     
    implementation
     
    {$R *.dfm}
     
    procedure TForm2.Button1Click(Sender: TObject);
    begin
      FDebut := GetTickCount;
    end;
     
    procedure TForm2.Button2Click(Sender: TObject);
    begin
      FFin := GetTickCount;
      Edit1.Text := IntToStr(CalculInterval(FDebut, FFin));
    end;
     
    function TForm2.CalculInterval(Debut, Fin: Cardinal): Cardinal;
    var
      diff: Cardinal;
    begin
      diff := FFin - FDebut;
      Result := diff div 1000;
    end;
     
    end.

  9. #9
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Salut Ero-sennin

    Tu dis :
    Je suis tout à fait d'accord avec toi
    ... et moi je suis d'accord avec toi ... et avec Kaféine "pas besoin de timer..." avec GetTickCount.

    A+

  10. #10
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 173
    Points
    4 173
    Par défaut
    Juste une remarque : GetTickCount a une précision de 15ms environ.
    Si on mesure un temps avec GetTickCount, on doit faire deux mesures (date de début, date de fin), chacune avec une incertitude de 15ms.

    Au final, ça donne une incertitude de 30ms.

    Pour avoir une meilleure précision, il vaut mieux utiliser les compteurs de performances :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var t0, t1 : int64;
         freq : int64;
         duree : int64;
    begin
      QueryPerformanceCounter(t0); // Lecture de la date de début.
     
      ... // Mettre ici le code dont on veut mesurer la durée.
     
      QueryPerformanceCounter(t1); // Lecture de la date de fin.
      QueryPerformanceFrequency(Freq); // Lecture de la précision du compteur.
     
      duree := (t1 -t0) * 1000000 div freq; // temps écoulé en ms.
    end;
    QueryPerformanceCounter possède une précision de 100 nanosecondes...

  11. #11
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Salut,

    Franck SORIANO a écrit :
    1) duree := (t1 -t0) * 1000000 div freq; // temps écoulé en ms.
    2) QueryPerformanceCounter possède une précision de 100 nanosecondes...
    1) calcule durée : duree := (t1 -t0) * 1000 div freq; // temps écoulé en ms.
    2) précision de 100 nanosec : oui-mais uniquement lors de mesures en laboratoire où la mesure est faite dans des conditions où rien ne perturbe la mesure.
    Or sur nos bécanes Windows prend la main quand il veut et autant de fois qu'il veut pendant que l'on chronomètre ce qui fait qu'on mesure le temps piqué par Windows pour effectuer des tâches annexes et qui s'additionne au temps mis par le bout de code dont on veut mesurer la rapidité d'éxec.

    Lors de tests avec le code suivant utilisant cette fois-ci le compteur hautes performances :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    procedure TForm1.CopyAndFillLeftClick(Sender: TObject);
    var       s : string; 
    begin    QueryPerformanceCounter(t0); // Lecture de la date de début.
              // Remplissage avec des 'o' à Gauche
              for i:=1 to 1000000 do
              begin s:='ab'; CopyAndFill5(s, 200, 'o', true); end;
              QueryPerformanceFrequency(Freq); // Lecture de la précision du compteur.
              QueryPerformanceCounter(t1); // Lecture de la date de fin.
              duree := (t1 - t0)*1000 div freq; // temps écoulé en ms.
              edMis.text:='mis : '+intToStr(duree)+' ms';
    end;
    ... les temps mesurés lors d'une succession de 10 clicks sur le bouton de commande on donné :
    - durée max : 831 millisec
    - durée min : 823 millisec
    ... d'où une précision de 831 - 823 = 8 millisec : à comparer aux 100 nanosec.

    Faudrait trouver un moyen pour empêcher Windows de piquer la main pendant qu'on effectue un chronométrage pour pouvoir bénéficier réellement des performances du QueryPerformanceCounter.

    A+

  12. #12
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 173
    Points
    4 173
    Par défaut
    1) calcule durée : duree := (t1 -t0) * 1000 div freq; // temps écoulé en ms.
    Exact, j'ai fait un copier/coller depuis un bout de code que j'avais modifié avant pour avoir le temps en microseconde et pas en ms.

    2) précision de 100 nanosec : oui-mais uniquement lors de mesures en laboratoire où la mesure est faite dans des conditions où rien ne perturbe la mesure.
    Pas exactement. La précision de 100 nanosec c'est sur la mesure de la date au moment de la lecture, pas sur le temps mesuré.

    Or sur nos bécanes Windows prend la main quand il veut et autant de fois qu'il veut pendant que l'on chronomètre ce qui fait qu'on mesure le temps piqué par Windows pour effectuer des tâches annexes et qui s'additionne au temps mis par le bout de code dont on veut mesurer la rapidité d'éxec.
    C'est vrai, mais Windows ne prend pas la main de façon aussi aléatoire que ça : Comme tout OS multi-tâche, il va basculer sur une autre tâche au moment d'événements particuliers. Ces derniers sont de deux types :
    - Lorsqu'une tâche réalise une E/S, la tâche se bloque en attente de la fin de l'E/S, l'OS en profite pour reprendre la main et la donner à une autre tâche (d'ailleurs c'est assez marrant quand on génère des traces très détaillées dans une appli multi-tâche, on arrive à voir assez précisément à quel moment Windows commute d'une tâche à une autre).
    - Sur les IPC d'une façon générale.
    - Sur tempo lorsqu'une tâche tourne depuis trop longtemps.

    Donc paradoxalement, les mesures de durées avec les compteurs de performances sont plus précises lorsqu'on mesure des temps courts que des temps longs (d'ailleurs plus le test est long et plus tu as de chances qu'il soit perturbé par un événement extérieur).
    Diminue le nombre d'itérations dans ta boucle et je suis sûr que la précision de ta mesure sera bien meilleure que les 8ms. D'ailleurs avec les compteurs de performances, tu n'as pas besoin de faire de boucle du tout (sauf si l'opération est vraiment très très courte, mais dans ce cas tu as sûrement mieux à optimiser ailleurs)

    J'utilise fréquemment les compteurs de performances pour faire des mesures de perfs. Quand tu le fais directement sans aucune boucle, en lançant l'exécution plusieurs fois bien sûr, tu verras que les temps inférieur à 1 ms sont extrèmement stables et qu'on n'est pas loin de la précision de 200 ns sur la durée.
    Et dans les autres cas, même tes 8ms d'incertitude c'est mieux que 30 avec GetTickCount... GetTickCount n'est adapté que pour mesurer des temps assez longs.
    Les compteurs de performances sont un peu plus lents à lire mais fonctionnent même avec des temps très courts.

  13. #13
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Re-salut,

    Ok, vu.

    Tu dis
    Diminue le nombre d'itérations dans ta boucle et je suis sûr que la précision de ta mesure sera bien meilleure que les 8ms.
    ... ben oui en divisant le nombre de boucles par 10 on obtient forcément des temps et des écarts de mesures divisés par 10.

    Quand tu le fais directement sans aucune boucle ...
    ... dans ce cas ça m'affiche généralement 0 ms ... et j'augmente le nombre de boucles tant que la durée du test ne dépasse pas les 30 secondes car c'est pénible de poireauter devant un sablier surtout quand on se met à comparer les perfs de "n" routines qui font la même chose mais qui sont codées suivant des approches différentes.

    Et dans les autres cas, même tes 8ms d'incertitude c'est mieux que 30 avec GetTickCount...
    ... absolument d'accord, mais même 30 ms sur une durée d'environ 1000 ms (cas de l'emple cité dans mon msg précédent) ça ne conduit qu'à une erreur de 3% et comme j'utilise ce type de mesures pour comparer les performances de deux ou plusieurs routines qui font la même chose c'est bien suffisant pour éliminer les routines les plus lentes.

    Et puis comme je fais fréquemment des tests il se trouve en plus que, la flamme aidant, avec Start:=getTickCount; puis edMis.text:='mis : '+intToStr(getTickCount - Start)+' ms'; le code est bouclé avec seulement deux lignes, et même le choix de l'Edit "edMis" résulte de cette flemme car au moins avec un TEdit on peut faire un copier-coller pour transférer le résultat de la mesure ailleurs ... ergonomie bien ordonnée commence par soi-même. Non ?

    A+

  14. #14
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 173
    Points
    4 173
    Par défaut
    ... ben oui en divisant le nombre de boucles par 10 on obtient forcément des temps et des écarts de mesures divisés par 10.
    Je me suis mal exprimé, ça c'est mathématique, en fait je voulais parler de l'incertitude relative.

    ... dans ce cas ça m'affiche généralement 0 ms ...
    C'est le problème avec GetTickCount. Il faut avoir consience de la résolution de 15 ms du timer (malgré le fait que le résultat est en millisecondes) sinon on a vite fait d'en conclure que les perfs sont excelentes.

    Et puis comme je fais fréquemment des tests il se trouve en plus que, la flamme aidant, avec Start:=getTickCount; puis edMis.text:='mis : '+intToStr(getTickCount - Start)+' ms'; le code est bouclé avec seulement deux lignes, et même le choix de l'Edit "edMis" résulte de cette flemme car au moins avec un TEdit on peut faire un copier-coller pour transférer le résultat de la mesure ailleurs ... ergonomie bien ordonnée commence par soi-même. Non ?
    On est d'accord, on est tous de gros flémards. Je faisais la même chose jusqu'à ce que je découvre Event Tracing for Windows :

    http://fsoriano.developpez.com/articles/etw/delphi/

    Maintenant, j'instrumente directement l'application qui contient le code à optimiser. Au début du traitement j'ajoute la ligne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    GenericLogger.TraceBegin(EVENT_START, 'Début du traitement', currentTime);
    à la fin du traitement j'ajoute :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    GenericLogger.TraceEnd(EVENT_END, 'Fin du traitement', currentTime);
    Puis je démarre la trace et je lance l'appli. Et j'obtiens la durée du traitement directement dans la trace. Et comme je fais ça un peu partout dans l'appli, j'ai également le profil d'exécution de l'appli complète...

  15. #15
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Salut,

    Ok, vu. Event Tracing for Windows semble être super mais vu les pré-requis :
    ETW n'est disponible qu'à partir de Windows 2000.
    ... faudra que m'en passe car je suis toujours sous Win98 et comme j'ai appris que pour installer Win-XP il fallait tout désinstaller pour le réinstaller sous XP j'ai choisi d'éviter cette galère.

    A+

Discussions similaires

  1. Réponses: 3
    Dernier message: 09/09/2010, 17h47
  2. calcul de temps entre deux évenements
    Par bech59 dans le forum Excel
    Réponses: 2
    Dernier message: 06/07/2010, 11h09
  3. [Toutes versions] Calcul du temps entre 2 dates (ans, mois, jours)
    Par nico84 dans le forum Contribuez
    Réponses: 0
    Dernier message: 30/10/2009, 10h48
  4. Calcul de temp entre un timestamp et un varchar
    Par DelphiCool dans le forum Requêtes
    Réponses: 0
    Dernier message: 01/04/2009, 18h45
  5. Requête pour calculer le temps entre deux dates
    Par Badboy62cfp dans le forum Access
    Réponses: 2
    Dernier message: 19/05/2006, 13h50

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo