Cette source est l'un des points de départ que j'ai créé pour lire les informations bas niveau du processeur. La source a été testée et validé sur un certains nombres de processeur, au minimum je garanti sur Core 2 + Phenom.
Ce projet étant assez vieux, je ne suis pas sur qu'elle soit compatible avec d'autres processeurs : en effet, j'utilise la table MSR pour lire le coefficient processeur, et ainsi détecter la fréquence réelle (pour rappel les processeurs sont apte à descendre leur coefficient pour consommer moins lorsqu'ils ne sont pas en fonctionnement intense. Ces informations sont stockés dans la MSR).
Les informations dans la MSR peuvent varier d'une famille de processeur à une autre, il faut donc se renseigner au cas par cas suivant votre processeur.
Si vous enlevez le coefficient MSR, normalement la lecture sera bonne pour tous les processeurs x86, mais vos n'aurez alors que la fréquence maximale théorique. Par ailleurs, vous n'aurez pas besoin de WinRing0 si vous enlevez MSR (mais alors vous n'aurez pas la vraie fréquence, seulement la maximale).
Le système utilise rdtsc(
http://fr.wikipedia.org/wiki/RDTSC) qui est un compteur interne du processeur (disponible en ASM), et WinRing0 qui est une DLL de descente en Ring0 pour windows (
http://en.wikipedia.org/wiki/Ring_%28computer_security%29), cette DLL n'est aujourd'hui plus trouvable sur le net (semble-t-il), j'en fournit donc une copie sous /Release.
Source / Exemple :
//Instruction de lecture Assembleur bas niveau pour le compilateur GCC MinGW
#define rdtsc(low,high) \
asm volatile( \
"xorl %%eax, %%eax\n\t" \
"cpuid\n\t" \
"rdtsc\n\t" \
: "=a" (low), "=d" (high) \
: \
: "%ebx", "%ecx");
//Lecture du compteur processeur :
//Renvoi la fréquence du processeur
double LireFrequenceCpu(int cpuNumber){
LARGE_INTEGER freq1, freq2;
double frequence;
DWORD tick1, tick2;
// Lit la frequence du chronomêtre Windows
// Avant
rdtsc(freq1.LowPart, freq1.HighPart);
//On place le chrono à 1ms
//timeBeginPeriod(1);
//tick1 = GetTickCount();
tick1 = timeGetTime();
//Pause de 1s pour pouvoir lire la fréquence...
for (int i=0; i<100; i++)
Sleep(10);
// Apres
rdtsc(freq2.LowPart, freq2.HighPart);
//tick2 = GetTickCount();
tick2 = timeGetTime();
//On replace le timer à sa position d'origine
//timeEndPeriod(1);
frequence = ((double)(freq2.QuadPart-freq1.QuadPart));
frequence /= (double) ((tick2 - tick1));
return (frequence*1000);
}
//Utilisation finale (avec MSR)
cout << "Nombre de core : ";
int nombreCore;
cin>>nombreCore;
DWORD eax, edx;
timeBeginPeriod(1);
LireFrequenceCpu(1); //La première lecture est toujours mauvaise...
for(int i=0; i<nombreCore; i++)
{
cout << "Core " << i << " :";
cout << endl << endl;
SetThreadAffinityMask(GetCurrentThread(), 1 >> i);
Rdmsr(0x198, &eax, &edx);
int currentCoeff = ((eax>>8)&0xFF);
int maxCoeff = ((edx>>8)&0xFF);
cout << "Frequence lu : " << FormatFrequence(LireFrequenceCpu(1 >> i)) << " MHz" << endl;
double frequence = FormatFrequence((LireFrequenceCpu(1 >> i)/maxCoeff)*currentCoeff);
cout << "Frequence actuelle : " << frequence << " MHz" << endl;
cout << "FSB : " << (frequence/currentCoeff) << " MHz" << endl << endl;
cout << hex << "eax : " << eax << " edx : " << edx << dec << endl;
cout << "Coefficient actuel : " << currentCoeff << endl;
cout << "Coefficient max : " << maxCoeff << endl << endl << endl;
}
timeEndPeriod(1);
Conclusion :
La compilation se fait sous Windows, avec MinGw 32bits, test réalisés sous Windows XP à l'époque, et encore fonctionnelle sous Windows 7. Je met le code source (puisque ce n'est pas indiqué dedans) sous licence LGPL donc faites en ce que bon vous semble !
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.