Récupérer la fréquence du processeur

Soyez le premier à donner votre avis sur cette source.

Vue 23 241 fois - Téléchargée 921 fois


Description

Cette source classique permet de récupérer une valeur approchée de la fréquence de son processeur. Comme je n'en ai pas vu pour C#/.NET, je l'ai adapté en C#. Cette implémentation alloue de la mémoire non managée pour y écrire un bout de code en assembleur, puis l'exécute en créant un thread dont le point d'entrée est l'adresse de la mémoire contenant le code asm.

Source / Exemple :


public struct CpuFreqParams
{
	//addresse de QueryPerformanceCounter
	public IntPtr lpQPCounterAddress;
	//temps à attendre pendant le test
	public long testSpan;
	//nombre de cycles passés pendant le test
	public long nCycles;
}

//code asm utilisé. un peu plus long que la plupart de codes de ce genre
//à cause de l'addition/soustraction d'entiers 64 bits (avec add/adc et sub/sbb)
//et de la structure utilisée pour les paramètres, pour être lancé comme thread
__declspec(naked) void __stdcall GetCPUFrequency( LPVOID lpParams )
{
	//Pile locale:
	//
	//UINT64 endCycle			(ebp-68 et ebp-64)
	//UINT64 startCycle			(ebp-60 et ebp-56)
	//UINT64 tickCurrent			(ebp-52 et ebp-48)
	//UINT64 tickEnd			(ebp-44 et ebp-40)
	//UINT64 tickStart			(ebp-36 et ebp-32)
	//DWORD lpQPCounterAddress		(ebp-28)
	//UINT64 testSpan			(ebp-20 et ebp-16)
	//UINT64 nCycles			(ebp-12 et ebp-8)
	__asm
	{
		push ebp
		mov ebp, esp
		;alloue la pile locale
		sub esp, 64
		;sauvegarde les registres et les flags
		push eax
		push ecx
		push edx
		push esi
		push edi
		pushfd
		;vérifie que lpParams n'est pas null
		cmp dword ptr [ebp+8], 0
		je clear
		;copie les paramètres dans la pile
		mov esi, dword ptr [ebp+8]
		lea edi, dword ptr [ebp-28]
		mov ecx, 24
		cld
		rep movsb
		;vérifie que lpQPCounterAddress n'est pas null
		cmp dword ptr [ebp-28], 0
		je clear
		;obtient le nombre de ticks avec QueryPerfCounter
		lea ecx, dword ptr [ebp-36]
		push ecx
		call dword ptr [ebp-28]
		;ajoute testSpan au nombre ticks pour avoir l'"heure" en ticks à attendre
		mov ecx, dword ptr [ebp-36]
		add ecx, dword ptr [ebp-20]
		mov dword ptr [ebp-44], ecx
		mov ecx, dword ptr [ebp-32]
		adc ecx, dword ptr [ebp-16]
		mov dword ptr [ebp-40], ecx
		;obtient le nombre de cycles du processeur
		rdtsc
		mov dword ptr [ebp-60], eax
		mov dword ptr [ebp-56], edx
		;boucle d'attente
L1:
		;obtient le nombre de ticks avec QueryPerfCounter
		lea ecx, dword ptr [ebp-52]
		push ecx
		call dword ptr [ebp-28]
		;regarde si on doit sortir de la boucle
		lea esi, dword ptr [ebp-44]
		lea edi, dword ptr [ebp-52]
		mov ecx, 2
		cld
		rep cmpsd
		jae L1
		;obtient le nombre final de cycles du processeur
		rdtsc 
		mov dword ptr [ebp-68], eax
		mov dword ptr [ebp-64], edx
		;obtient le nombre de cycles passés pendant le test
		mov ecx, dword ptr [ebp-68]
		sub ecx, dword ptr [ebp-60]
		mov dword ptr [ebp-12], ecx
		mov ecx, dword ptr [ebp-64]
		sbb ecx, dword ptr [ebp-56]
		mov dword ptr [ebp-8], ecx
		;copie la pile vers les paramètres
		lea esi, dword ptr [ebp-28]
		mov edi, dword ptr [ebp+8]
		mov ecx, 24
		cld
		rep movsb
clear:
		popfd
		pop edi
		pop esi
		pop edx
		pop ecx
		pop eax
		add esp, 64
		mov esp, ebp
		pop ebp
		ret
	}
}

Conclusion :


Ce code devrait marcher pour tous les processeurs à partir du Pentium, et sur toutes les versions de Windows à partir de 2000 (à cause de l'appel à VirtualProtect). Le test effectué est sur un AMD 2400+ (2.0 Ghz) sous Windows XP. Pour les systèmes multiprocesseurs/multicore/HyperThreading, le test peut échouer s'il est trop long (ex: 1 sec), une durée de 10 ms ou moins devrait réussir dans la plupart des cas.

Codes Sources

A voir également

Ajouter un commentaire Commentaires
Messages postés
103
Date d'inscription
lundi 8 juillet 2002
Statut
Membre
Dernière intervention
24 novembre 2005

Content de l'entendre :)

Sinon désolé pour les mises à jour multiples, et j'ai également oublié de retirer un fichier qui n'a rien à voir (FileDecrypt.cs).
Messages postés
16
Date d'inscription
dimanche 2 juillet 2006
Statut
Membre
Dernière intervention
15 juillet 2008

Au fait je suis sous vista, et je vient d'essayer avec l'ajout du nouveau code,
eh bien sa marche parfaitement:)
Messages postés
16
Date d'inscription
dimanche 2 juillet 2006
Statut
Membre
Dernière intervention
15 juillet 2008

Ok, donc j'attends que tu fasse la mise a jour

Merci!!!
Messages postés
103
Date d'inscription
lundi 8 juillet 2002
Statut
Membre
Dernière intervention
24 novembre 2005

Enfait je viens de me rendre compte que j'avais mis à jour mon code sans envoyer la version mise à jour sur ce site, ce que je vais faire de suite.
Messages postés
103
Date d'inscription
lundi 8 juillet 2002
Statut
Membre
Dernière intervention
24 novembre 2005

Salut,

Quelle version et édition de Windows utilises tu? (XP/Vista, 32/64 bit)
Si c'est Vista ou XP 64, l'erreur doit venir du fait que la mémoire allouée par AllocHGlobal ne possède pas le droit d'exécution.

Pour corriger cela, il fait ajouter un appel à VirtualProtect avant l'appel à CreateThread:

//ajoute le droit d'exécution à la page de mémoire allouée
int oldProtect;

VirtualProtect( hCode, new IntPtr( code.Length ), PAGE_EXECUTE_READWRITE, out oldProtect );

//crée un thread qui va exécuter la fonction ASM
hThread = CreateThread( IntPtr.Zero,
...

//constante et déclaration de VirtualProtect
private const int PAGE_EXECUTE_READWRITE = 0x40;

[DllImport("Kernel32.dll")]
private static extern void VirtualProtect( IntPtr adress, IntPtr size, int newProtect, out int oldProtect );
Afficher les 18 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.