TIMER, SLEEP, CHRONOMÉTRAGE, VITESSE DU PROCESSEUR, A LA MICROSECONDE PRÈS !

BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019 - 22 août 2005 à 14:23
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 - 27 mai 2011 à 10:08
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/33376-timer-sleep-chronometrage-vitesse-du-processeur-a-la-microseconde-pres

cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
27 mai 2011 à 10:08
Suite à une question par MP de zapanyeti (En gros, un Sleep un peu précis en full VB6, mais des problèmes de dépassement de capacité) ->
Son code utilisait QueryPerformance* en leurs passant des LARGE_INTEGER et en travaillant sur les 32 bits de poids faible.
Une astuce (Je la connais de Renfield) consiste plutôt à utiliser le type Currency qui est sur 64 bits (Avec 4 digits derrière la virgule, mais ça n'a pas d'importance dans ce cas vu les opération effectuées).

Voici donc un code inspiré du sien qui nécessite une form avec un bouton btnWait.
Les attentes sont affichées dans la fenêtre d'exécution. Le résultat est assez précis.
==================================================
Option Explicit

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As Currency) As Long
Private Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As Currency) As Long

Private curFreq As Currency
Private stopLoop As Boolean

Public Sub WaitMicroSeconde(Duree As Long)
Dim curStart As Currency
Dim curEnd As Currency
Dim WaitTop As Currency

QueryPerformanceCounter curStart
WaitTop = (Duree * curFreq) / 1000000 + curStart
Do
QueryPerformanceCounter curEnd
Loop Until curEnd >= WaitTop
End Sub

Private Sub btnWait_Click()
Dim i As Integer
Dim curStart As Currency
Dim curEnd As Currency

btnWait.Enabled = False

For i = 0 To 200
If stopLoop Then Exit Sub
QueryPerformanceCounter curStart
WaitMicroSeconde 2000
QueryPerformanceCounter curEnd
Debug.Print "Waited " & (curEnd - curStart) / curFreq * 1000000 & " micro secondes"
Sleep 1
DoEvents
Next i

btnWait.Enabled = True

End Sub

Private Sub Form_Load()
QueryPerformanceFrequency curFreq
stopLoop = False
End Sub

Private Sub Form_Unload(Cancel As Integer)
stopLoop = True
End Sub
==================================================

Ce code devrait être franchement moins sujet aux dépassement de capacité quoiqu'ils peuvent encore se produire notamment lors du calcul de WaitTop. L'échec en cas de dépassement de capacité est désactivable dans les propriétés du projet, onglet "compilation", bouton "Optimisations avancées".
butcherofsiberia Messages postés 1 Date d'inscription vendredi 9 février 2007 Statut Membre Dernière intervention 9 février 2007
9 févr. 2007 à 11:16
Y'a pas mieux que ca :

LARGE_INTEGER t1, t2
LARGE_INTEGER param;
QueryPerformanceCounter(&t1);
QueryPerformanceCounter(&t2);
QueryPerformanceFrequency( ¶m );
double ts = ((double)(t2.QuadPart-t1.QuadPart))/((double)(param.QuadPart)); //le temps en seconde
double ts = (((double)(t2.QuadPart-t1.QuadPart))/((double)(param.QuadPart)))*1000.0; //le temps en ms

vous obtiendrez qqch du genre : ts = 0.00039096927800171260 ms (c'est le tps d'execution du code que je vous donne) !!!

Le nanoseconde, c'est deja trop long !!! (ca dechire !!!)

bos.
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
2 août 2006 à 10:56
Bonjour,

Désolé je connais très mal le C++.

Déjà, la routine que tu souhaites utiliser ne s'appel pas Sleep (Elle est renommer dans la déclaration en VB6).

Son nom est EXtmr_Sleep.

Donc je dirais :

inp32 = (inpfuncPtr) GetProcAddress(hLib, "EXtmr_Sleep");

Quoi qu'il arrive, en C++, tu devrait pouvoir faire l'équivalent de ma dll en quelques dizaines de lignes, en te servant des API QueryPerformanceCounter et QueryPerformanceFrequency.
bwoufy86 Messages postés 4 Date d'inscription vendredi 3 janvier 2003 Statut Membre Dernière intervention 31 juillet 2006
31 juil. 2006 à 20:47
super cette dll, j'ai hate de l'essayer pour un de mes projet.
Mais le hic c'est que je compte programmer en C++ Builder et j'arrive a charger la dll mais pas a appeler Sleep.
Il me dit acces violation.

quelqu'un pourrai peut etre m'aider ?
je donne mon morceau de code au cas ou !


typedef long _stdcall (*inpfuncPtr) (String lpEx, long nTime = 0);




void TForm1::gererAttente()
{
HINSTANCE hLib;
inpfuncPtr inp32;
short x;
int i;
long z;

/* Load the library */
hLib = LoadLibrary("EX_Time.dll");

if (hLib == NULL) {
Application->MessageBox("LoadLibrary Failed", "Look", MB_OK);
}
else
{
inp32 = (inpfuncPtr) GetProcAddress(hLib, "Sleep");

z = (inp32)(" ",100000);
FreeLibrary(hLib);
}

}

Il me dit ACCESS Violation at adress 0000000.....

Merci d avance !
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
21 oct. 2005 à 18:39
A priori, c'est fait...
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
17 oct. 2005 à 09:40
Content que tu es trouvé une solution ! Pour la mise à jour, ça ce rapproche, si si ! (Vive les réseaux des écoles d'ingé...)
tokomosso Messages postés 2 Date d'inscription mercredi 4 août 2004 Statut Membre Dernière intervention 15 octobre 2005
15 oct. 2005 à 16:52
Hi RT15 !
J'ai utilisé QueryPerformanceCounter
et QueryPerformanceFrequency dans un module VB6
le résultat est excellent : +/- 20µs !
Donc pas de problème.
J'ai procédé à la vérification à l'oscillo des largeurs d'impulsion que je génère : de 5 à 10 ms.
Donc pas besoin de Dll mais je garde la tienne...
A+
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
12 oct. 2005 à 19:20
Pardon, l'Overclocking, c'est le cramage de proce. Intel fait de l'Underclocking. J'ai recompilé la dll. Elle marche nickel, et mes jeux tournant à 100 Hz ne consomment pratiquement plus de CPU !!! J'ai ajouté quelques fonctions (renvoie du registre TSC, calcul de la fréquence actuelle d'un centrino, qui peut descendre vraiment bas!...)

Les API, c'était plutôt QueryPerformanceCounter et QueryPerformanceFrequency.

J'ai plus qu'à mettre à jour sur ce site, et c'est là qu'il y a problème...
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
30 sept. 2005 à 12:55
Merci TOKOMOSSO, les fleurs ça fait toujours plaisir.

Mais j'ai eu des problème avec ma dll. J'ai a présent un portable, et il semblerait que la fréquence de son processeur centrino varie (On appel ça l'overclocking) !

Conséquement, la fréquence d'incrémentation du TSC varie avec le temps !

Cela n'a apparement pas d'influences sur mon timer: La fréquence est maximale lors d'une utilisation de la CPU à 100%.

Cependant, la fonction qui renvoie le temps écoulé fonctionne très mal si la CPU n'as pas beaucoup de boulot.

Mais je travail à améliorer les choses, en vue d'un mise à niveau de la dll.

Je compte nottement utiliser les API QueryPerformFrequency et QueryPerformCounter (y me semble qu'elle s'appellent comme ça).

De cette manière, le calcul de la vitesse du processeur sera inutile !

Par contre, je n'ai toujours pas trouvé un moyen de réduire la consommation de ressource (Mes chronométrage de Sleep(1) donne vraiment des résultats décevants.

Je vous promet une mise à jour pour bientôt, avec des routines de temps qui fonctionnent sur centrino, et un timer qui essaira de consommer moins de ressources pour des fréquences forcément inférieures au 1 kHZ, et 100% pour les fréquences supérieures. Le tout sans calcul de la vitesse processeur, mais avec moins de précision et de régularité.
tokomosso Messages postés 2 Date d'inscription mercredi 4 août 2004 Statut Membre Dernière intervention 15 octobre 2005
30 sept. 2005 à 00:59
Bravo RT15 pour ta dll delphi !
Maintenant, il m'est très facile de créer des impulsions stables et de largeur rigoureuse.
j'ai essayé le RDTSC (asm et vc++) mais la compatibilité est
hasardeuse avec VB6.
Bravo et merci
A+
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
31 août 2005 à 11:02
Arf, fallait commencer par ton lien !

Là je n'est vraiment plus rien à dire...

Bravo !

Et merci pour les infos sur RDTSC et RDPMPC !
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
25 août 2005 à 12:33
ah oui et pour exe, c'est sur que le code doit être mis en DLL pour utilisation par langage interprété.
http://www.vbfrance.com/code.aspx?id=18494
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
25 août 2005 à 12:28
RDPMC n'a pas a être utilisé hors du ring0 donc réservé au kernel mode, sous Windows c'est dans un driver. RDTSC je le répète est TOUJOURS accessible sous Windows, on n'a pas à prendre en compte le cas d'un tout fou qui ferait un driver pour le bloquer car on le ferait illico référencer comme virus et le problème serait rapidement réglé.
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
25 août 2005 à 12:07
Pas mal pour le coup de la petite startup !

En tout cas, ceux qui programme sous VB peuvent pas utiliser un exe.

Plus sérieusement, même un otiste comme moi, en ring 0, je pourrai bloquer le TSC en ring 3.

Mais je sais pas du tout comment me mettre en ring 0...

J'ai préférer me couvrir d'un éventuel bug, comme l'auteur du livre, j'imagine...

Je crois que RDPMC est moins utiliser que RDTSC, mais qu'il est plus précis. Le problème est qu'il est encore moins accessible que RDTSC. Mais je ne fais que répéter ce que j'ai compris du bouquin...
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
25 août 2005 à 11:30
CPU SPEED MGHZ (WIN32, ASM)
http://www.cppfrance.com/code.aspx?id=23837

RDTSC est garanti par Intel sur tous les processeurs depuis le Pentium, autant dire aucun risque qu'il n'y soit pas. Il est toujours accessible en ring3 (à l'inverse de RDPMC par exemple) sous Windows.
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
25 août 2005 à 10:56
Salut BruNews,

Mon intention était surtout de mettre a la disposition des programmeurs sous VB des routines originales, et qui peuvent être, je crois, très utiles.

Les faire en C aurait été probablement préférable (VC proche de VB).

Mais en l'occurence, je ne connais que le Delphi et il semble que dans le cas présent, il ai très bien fait son job.

Le code en assembleur n'est pas de moi, et celui qui l'a écrit conseille apparement le Delphi plutôt que VC++ et C++ Builder.

N'aillant pas fait de C, je ne me lancerai pas dans une guerre Delphi vs C++.

Saros,

J'ai récement utilisé des API qui m'ont donné entière satisfaction. Cependant le registre RDTSC fait, je crois, partie des instructions systèmes.

Les instructions systèmes ne sont pas garantit d'exister sur un processeur.

Cela rend la programmation système très difficile.

Cependant, RDTSC est très utilisée, et on ait donc pratiquement sûr de tomber sur un processeur qui l'ait.

Une autre explication est les API sont peut être écrites en C sans assemblage en ligne...
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
23 août 2005 à 19:12
Bien entendu, un compilo C est fait pour transcrire illico en asm afin de produire un code exécutable natif, il n'a pas à rechercher tous les mots clé pour appels vers une quelconque virtual machine. Il est donc tout naturel qu'on puisse direct lui mettre de l'asm.
On a 2 méthodes:
- soit avec prise en charge compilo, on entre des instructions asm au milieu de lignes C auquel cas le compilo ajoutera la sauvegarde et restauration des registres (n'y aura pas besoin dans cet exemple bidon):
int __stdcall monAlea(int x)
{
int alea;
__asm {
rdtsc
mov alea, eax
}
return (x + alea);
}
- soit on écrit une fonction en pur asm en préfixant la func du "bas les pattes compilo":
__declspec(naked) int __stdcall monAlea(int x)
{
__asm {
rdtsc
add eax, dword ptr[esp+4] ; ajoute x sur accumulateur
ret 4 ; repart sur EIP et dépile 4 octets de x
}
}

Si on cherche optimisation maxi, je conseille la version 'naked'.

Je pense qu'on déborde du cadre vbfrance, on s'arrêtera donc ici.
Saros Messages postés 921 Date d'inscription vendredi 20 décembre 2002 Statut Membre Dernière intervention 23 septembre 2010
23 août 2005 à 18:32
C'est le travail du compilo C que de faire du assembleur inline ?
En tout cas ça m'étonne pas que ce soit pas dispo en Basic, c'est un langage substanciellement pour débutant... et l'asm pour débuter c'est pas le top ^^

Comment ça se fait que les fonctions de l'API windows ne fonctionne pas aussi bien (du moins il en parait) que les fonctions de ta DLL ?
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
23 août 2005 à 16:58
dépend du compilo, pour VC:
__asm {
; asm ici
}
Saros Messages postés 921 Date d'inscription vendredi 20 décembre 2002 Statut Membre Dernière intervention 23 septembre 2010
23 août 2005 à 16:45
Assembleur en ligne ? C'est la commande asm( ... ) en C ?
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
22 août 2005 à 14:23
Salut,

il est peut-être mignon ton Delphi mais n'abusons tout de même pas, exporter ces qlqs fonctions en 17 Ko n'a rien d'exceptionnel, tu le sors en moins de la moitié avec VC++. Le meilleur assembleur inline restera par force un compilo C car c'est son travail, pour cela qu'on l'appelle un assembleur de haut niveau.
Le meilleur est à mon sens celui qui n'insère absolument rien d'autre que l'ASM qu'on y a entré à la main. Je vois RtlUnwind (et d'autres comme GetCommandLineA etc...) comme import sur Kernel32 dans ta dll, il m'étonnerait pourtant très fort que tu l'aies appelé explicitement dans ton code.
Rejoignez-nous