jmfmarques
Messages postés7666Date d'inscriptionsamedi 5 novembre 2005StatutMembreDernière intervention22 août 2014
-
20 mai 2007 à 16:03
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019
-
20 mai 2007 à 21:59
Bon...
Je viens de le dire ailleurs, alors pourquoi pas ici également ...
J'y suis d'autant plus encouragé que, cette semaine encore, quelqu'un s'est "frotté" à ce genre de chose...
De quoi s'agit-il ?
De la Fonction Timer de VB et de l'utilisation de la fonction GetTickCount de l'API de Windows...
Je sais... je sais... (on va me parler une fois de plus de la faculté qu'a la 2ème de compter en millisecondes alors que la 1ère ne le peut pas (dixit l'aide en ligne mais non exact... et j'ai déjà eu l'occasion de le dire à propos de l'estimation de la longueur d'un click "long"...) ...
La preuve ?
Private Declare Function GetTickCount& Lib "kernel32" ()
Private Sub Command1_Click()
Dim starting As Long, starting1 As Long
starting = Timer * 1000
starting1 = GetTickCount()
For i = 1 To 1000000
DoEvents
Next
MsgBox "with timer : " & CLng((Timer * 1000) - starting) & " milliseconds " & _
"and with Gettickcount = " & CLng(GetTickCount() - starting1) & " milliseconds"
End Sub
La différence de 1 milliseconde entre une méthode et l'autre (qu'il vous sera possible de constater dans certains cas) ne résulte que du fait du traitement de l'une avant l'autre !
Je ne veux pas faire un "snipet" pour si peu... juste le dire...
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 20 mai 2007 à 20:15
GetTickCount fonctionne comme le Timer, même résolution de synchro de l'horloge donc AUCUNE précision à la milliseconde. C'est d'ailleurs bien précisé dans MSDN.
La seule haute précision est QueryPerformanceCounter.
cs_casy
Messages postés7741Date d'inscriptionmercredi 1 septembre 2004StatutMembreDernière intervention24 septembre 201440 20 mai 2007 à 16:59
Il faut tout de même preciser (chose qui n'est pas forcément très clair dans le msdn) c'est que la fonction Timer est basé sur l'horloge RTC, celle qui est implanté au niveau du bios et qui donne l'heure au niveau système.
Tout ce qui touche sous Windows de près ou de loin à une datation calendaire (comme ici Timer qui renvoie le nombre de secondes depuis minuit) est basé sur cette horloge, horloge qui a une résolution de 20ms (précisément18.2ms). Donc pour toutes ces fonctions tout résultat ou partie de résultat inférieur à 20ms doit etre pris avec extreme prudence car pas forcement significatif.
A contrario GetTickCount, n'est pas basé sur l'horloge RTC, mais sur une des horloges, timers et autres compteurs systèmes qui eux sont en lien direct avec l'oscilateur qui cadence le processeur. Il en va ainsi une bien meilleure precision. D'ailleurs GetTickCount n'est rien d'autre qu'un compteur.
Donc pour tout ce qui se trouve en dessous de 20 ms, il est illusoire de faire confiance à la fonction Timer, même si en apparence ça semble fonctionner.
PS : J'ai eu l'occasion de me confronter à ce problème dans le cadre d'une expertise de code pour laquelle j'aimis pas loin d'un mois complet à cerner et comprendre le problème. D'autant plus qu'il y avait dans ce même code un second bug lié au (très) faux amis qui est le controle Timer du style "Pourquoi, pour un timer à 150ms avec un code relativement conséquent, environ 15ms d'execution, au bout de 1.5 sec, il n'y avait eu que 9 execution au lieu de 10". Il m'a fallu monter des carte d'entrée/sortie, et branché des osciloscope pour arriver à comprendre. Aucune doc n'existe sur le net pour ce problème.
---- Sevyc64 (alias Casy) ----<hr size="2" width="100%" /># LE PARTAGE EST NOTRE FORCE #
Gobillot
Messages postés3140Date d'inscriptionvendredi 14 mai 2004StatutMembreDernière intervention11 mars 201934 20 mai 2007 à 17:23
Salut,
hum ! testons donc et voyons les différences:
1) les deux sont parfaitement synchronisés,
la différence affichée est toujours la même à +/- 1ms près
2) résolution maxi atteinte:
par Timer --> 15,625 ms
par Gettickcount --> 16 ms
Daniel
Vous n’avez pas trouvé la réponse que vous recherchez ?
jmfmarques
Messages postés7666Date d'inscriptionsamedi 5 novembre 2005StatutMembreDernière intervention22 août 201427 20 mai 2007 à 17:39
Hé oui ! (bonjour Daniel)
Mais on va tester autrement, pour en avoir le coeur net...
Avec Sleep.
On peut bien évidemment considérer que Sleep lui même n'est pas fiable, mais cette infiabilité n'a pas d'importance, dès lors que l'on va "sleeper" (hé ! hé!) pendant la même durée pour les deux mesures !
et là encore, ma foi, les résultats sont semblables ...
Allons-y donc :
Private Declare Function GetTickCount& Lib "kernel32" ()
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Sub Command1_Click()
Dim j As Integer
For j = 600 To 0 Step -10
testons j
DoEvents
Next
End Sub
Private Sub testons(combien As Integer)
Dim starting As Long, starting1 As Long
starting = Timer * 1000
starting1 = GetTickCount()
Sleep combien Me.Print "temps d'attente " & combien & " >> avec timer : " & CLng((Timer * 1000) - starting) & " milliseconds " & _
"et avec Gettickcount = " & CLng(GetTickCount() - starting1) & " milliseconds"
End Sub
Private Sub Form_Activate()
Me.Move 0, 0, Screen.Width, Screen.Height
Me.AutoRedraw = True
End Sub
jmfmarques
Messages postés7666Date d'inscriptionsamedi 5 novembre 2005StatutMembreDernière intervention22 août 201427 20 mai 2007 à 18:05
Bon...
Plus de réactions ( bouh.... je vais pleurer, alors....)
On va clore le sujet, alors, mais pas sans avoir dit ce qui suit :
La fonction GetTickCount n'apporte (contrairement à ce que l'on a l'habitude de penser) qu'une faible précision .
Il en va hélàs de même avec la fonction TimeGetTime de la Librairie Winmm (bouh....)
La preuve ?
La voilà :
Private Declare Function GetTickCount& Lib "kernel32" ()
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare Function timeGetTime Lib "winmm.dll" () As Long
Private Sub Command1_Click()
Dim j As Integer
For j = 300 To 0 Step -5
testons j
DoEvents
Next
End Sub
Private Sub testons(combien As Integer)
Dim starting As Long, starting1 As Long
starting = Timer * 1000
starting1 = GetTickCount()
starting2 = timeGetTime()
Sleep combien Me.Print "temps d'attente " & combien & " >> avec timer : " & CLng((Timer * 1000) - starting) & " ms " & _
"et avec Gettickcount = " & CLng(GetTickCount() - starting1) & " ms" & _
"et avec TimeGetTime = " & CLng(timeGetTime() - starting2) & " ms"
End Sub
Private Sub Form_Activate()
Me.Move 0, 0, Screen.Width, Screen.Height
Me.AutoRedraw = True
End Sub
Gobillot
Messages postés3140Date d'inscriptionvendredi 14 mai 2004StatutMembreDernière intervention11 mars 201934 20 mai 2007 à 18:21
pour ma part je suis convaincu,
je retrouve toujours la même chose avec différentes méthodes
résolution 15,625ms avec Timer et 16ms avec GettickCount
comme Timer est en Single et GettickCount est en entier, la différence n'est pas parlante
donc je considère que les deux sont identiques avec avantage pour Timer d'être en natif et évite d'utiliser une Api extérieure.
merci jmf
Gobillot
Messages postés3140Date d'inscriptionvendredi 14 mai 2004StatutMembreDernière intervention11 mars 201934 20 mai 2007 à 19:09
je rajoute que le contrôle Timer se déclenche au bout d'un temps multiple de la résolution (15,625ms chez moi)
le pire cas c'est interval = 16, déclenchement à 15,625 ou 31,25 du simple au double quoi !
si je met interval = 125 j'aurais souvent 125 (8 fois 15,625) et parfois 140,625 (9 fois 15,625)
pas très fiable donc mais rien à voir avec la fonction Timer
cs_casy
Messages postés7741Date d'inscriptionmercredi 1 septembre 2004StatutMembreDernière intervention24 septembre 201440 20 mai 2007 à 19:27
Salut Daniel, suite à mon expertise je vais t'en dire plus sur le controle timer.
De ce que j'ai pu observer, lorsque on programme un Controle Timer pour (admettons, pour l'exemple) 125 ms, les déclenchements auront lieu tous les 125+temps d'execution de la routine Timer.
Donc avec une routine Timer assez costaud, par exemple 37ms, les déclenchements auront lieu toutes les 162ms (125+37).
C'est le premier effet K**Cool du timer
Mais si c'était si simple ça sera trop facile.
Deuxième effet que j'ai pu constaté ce que malgrés ce déclenchement toute les 162ms, de temps en temps (à priori assez régulièrement sans que j'ai réellement pu le quantifié) le timer va se resynchronisé sur un multiple de 125. donc régulièrement on pourra avoir un temps intermédiare de moins de 125 ms (peut-etre 50 ou 80 ms) au lieu des 162 ms déduites du premier point.
C'est pour cela que sur la longueur le Controle Timer semble relativement régulier et le phénomène passe totalement inapperçu. Mais lorsque, comme ça a été mon cas, d'ou l'expertise, au bout d'un certain temps donné tu dois avoir un nombre X de déclenchement et que tu te retrouve avec un nombre X-1 ou X-2 ça marche plus (du fait de la resynchronisation, l'écart n'est jamais bien grand).
Voila le double effet K**Cool de notre Faux Ami, le controle Timer
---- Sevyc64 (alias Casy) ----<hr size="2" width="100%" /># LE PARTAGE EST NOTRE FORCE #
Gobillot
Messages postés3140Date d'inscriptionvendredi 14 mai 2004StatutMembreDernière intervention11 mars 201934 20 mai 2007 à 19:43
c'est ce que voulais savoir, est-ce le temps d'exécution du contrôle timer joue même s'il est inférieur à l'interval ?
effectivement oui, si je rajoute un Sleep 10, je vois un nombre de 140,625 bien supérieur (au lieu de 125)
avec un Sleep 50, c'est une catastrophe, j'obtiens 171,875 (soit 11 fois 15,625) et aussi 187,5 (12 fois 15,625)
j'ai jamais vu de temps inférieur à l'interval (sauf pour les arrondis 16 au lieu de 15,625)
je ne crois pas qu'il y est de resynchronisation, ce qui perdu est perdu, essayes donc avec un Timer de 16, le temps moyen sera de 1,5 fois 15,625 (moyenne entre 1 fois et 2 fois)
attention ce temps 15,625 n'est pas le même suivant les OS:
In Windows 98 the 18.2 Hz DOS timer was used, with update interval of
about 54.9 ms; but the value transferred from the OS was rounded to a
multiple of 10, and so went up in steps of 50 or 60.
In Windows XP the update rate is 64 Hz, interval 15.625 ms; and that is
rounded only to integer, so rising in steps of 15 or 16. But
applications can alter the update rate.
Gobillot
Messages postés3140Date d'inscriptionvendredi 14 mai 2004StatutMembreDernière intervention11 mars 201934 20 mai 2007 à 20:09
ah ce timer qui donne pas des temps précis !
pour en être sûr je reprends mon préféré QueryPerf ...
sans Sleep (aucun jeu de mot) c'est moins grave ça tourne entre 124 et 125
avec Sleep 50 j'ai 187,50 plus ou moins des poussières
et une fois j'ai eu 203,... (13 fois la résolution)
bon ça se confirme, il n'y a pas rattrapage.
' voilà la base de mon code pour tester
Private Sub Timer1_Timer()
jmfmarques
Messages postés7666Date d'inscriptionsamedi 5 novembre 2005StatutMembreDernière intervention22 août 201427 20 mai 2007 à 20:55
Bonsoir Brunews,
Je suis tout-à-fait d'accord avec ce que tu exposes là.
Encore faut-il que la machine le "supporte"...
Pour ceux que ces choses intéressent de plus près (mais là également : à condition que la machine le "supporte"):
cs_casy
Messages postés7741Date d'inscriptionmercredi 1 septembre 2004StatutMembreDernière intervention24 septembre 201440 20 mai 2007 à 21:25
QueryPerformanceCounter marchent sur certains celeron, pentium4, 5, amd, ... et pas d'autres, même des plus récents. JE pense que ça ne doit pas dépendre uniquement du processeur
J'ai voulue faire un test sur le portable tout neuf d'une connaissance, il y a quelque mois, avec QueryPerformanceCounter pour plus de precision, ben la fonction n'est pas implantée. Je ne saurais pas dire exactement sur quel proco, mais le pc etait tout neuf, portable pro moyen/haut de gamme d'il y a 6/8 mois environ.
---- Sevyc64 (alias Casy) ----<hr size="2" width="100%" /># LE PARTAGE EST NOTRE FORCE #
jmfmarques
Messages postés7666Date d'inscriptionsamedi 5 novembre 2005StatutMembreDernière intervention22 août 201427 20 mai 2007 à 21:52
Hé bé !....
la présente discussion "juste pour un dimanche"...n'avait pas d'autre but que celui d'appeler l'attention sur certains aspects.
Mais aussi de se décontracter un peu.
Ne trahissons pas cet esprit-là, hein ?
Une satisfaction pour chacun d'entre nous : nous nous sommes à la fois divertis un peu et nous sommes, par la même occasion, rémémorés ensemble certains aspects de Windows et de VB.
Je remercie tous ceux qui ont participé à cette discussion. Aucune intervention n'a été ni inutile, ni futile.
Merci à tous.
Bonne nuit.
cs_casy
Messages postés7741Date d'inscriptionmercredi 1 septembre 2004StatutMembreDernière intervention24 septembre 201440 20 mai 2007 à 21:54
Perso ce n'est pas la première fois que je rencontre le cas, mais je pensais moi aussi que depuis quelques années, toutes les machines en étaient systématiquement équipées.
Je l'ai aussi rencontré sur des Pentium III, certes sur des machines d'assembleurs asiatiques. Plus étrange, je l'ai rencontré sur un Pentium IV avec Win NT4.0, la fonction n'était pas reconnue, laosr que le même PC avec Win2000, c'était OK et un pc strictement identique avec WinNT4.0 c'était OK (juste un suffixe différent dans le num de série de la carte mère, CM Dell, les 2 pc ont été achetés en lot).
C'est pour cela, que je pense que ça ne vient pas uniquement du proco.
---- Sevyc64 (alias Casy) ----<hr size="2" width="100%" /># LE PARTAGE EST NOTRE FORCE #