Récupérer la fréquence du processeur


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

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.