Moin erstmal,
Ich bin ja schon eine Weile hier angemeldet, und habe mir auch schon die eine oder andere "Anregung" hier geholt.
Die meisten meiner kleinen Probleme haben sich bisher durch aufmerksames Lesen von Foren-Beiträgen gelöst.
Nun stehe ich allerdings vor einem Problem, bei dem ich nicht weiter komme.
Zur Erläuterung:
Sinn der Sache ist es auf Core 2 Prozessoren die aktuelle Taktfrequenz zu berechnen, ohne eine nennenswerte CPU-Last zu erzeugen. Verwendet wird hier Winring0 eine OpenSys Library.
Wie vielleicht bekannt ist konnte auf "älteren" Prozessoren die Taktfrequenz alleine über den Realtime Counter, sowie über den Performance Counter bestimmt werden.
Neuere Prozessoren, so auch der Core 2, haben einen konstanten TSC (Constant_TSC), d.h. unabhängig von der aktuellen Taktfrequenz wird der Realtime Counter mit der nominellen Taktfrequenz betrieben.
Ich habe mich in den letzten Tagen eingehend mit Intel Datenblättern und verschiedenen Counterwerten beschäftigt und bin zu dem Code der hier einfügt ist gekommen.
Verwendet werden hier zusätzlich IA32_APERF_MSR und IA32_MPERF_MSR.
IA32_APERF_MSR gibt die Anzahl der Taktzyklen wieder die sich der Prozessor im C0 State befand, bezogen auf die aktuelle Taktfrequenz.
IA32_MPERF_MSR gibt die Anzahl der Taktzyklen wieder die sich der Prozessor im C0 State befand, bezogen auf die nominelle Taktfrequenz.
Nun zum Problem: T_Delta wird in meinem Code als DWord deklariert, richtig wäre eigentlich Int64. Wenn ich T_Delta jedoch als Int64 deklariere treten bei der Berechnung der Taktfrequenz negative Werte auf.
Scheinbar gibt es Probleme damit das Int64 ein signed Wert ist, die Ausgabe des Realtime Counters jedoch ein unsigned Wert.
Hat jemand eine Idee wie dieses Problem zu lösen ist ?
Ich hänge sicherheitshalber noch einmal das gesamte Projekt an.
Delphi-Quellcode:
procedure TForm1.Timer1Timer(Sender: TObject);
var
EAX, EDX : DWord; //Variablen für Register Übergabe
Frequency : Int64; //Performance Counter Frequency
P_Count : Int64; //Performance Counter aktueller Wert
A_Count : Int64; //IA32_APERF_MSR Aktueller Wert
M_Count : Int64; //IA32_MPERF_MSR Aktueller Wert
T_Count : Int64; //Realtime Counter Aktueller Wert
P_Delta : Int64; //Performance Counter Delta Wert
A_Delta : Int64; //IA32_APERF_MSR Delta Wert
M_Delta : Int64; //IA32_MPERF_MSR Delta Wert
T_Delta : DWord; //Sollte eigentlich auch Int64 sein !!!
PC,PT : Cardinal;
Nominal : Integer;
Aktuell : Integer;
begin
// Routine läuft nur auf Core1
SetThreadAffinityMaskByID(GetCurrentThreadID, 1);
// Sichern der alten Prioritäten
PC := GetPriorityClass(GetCurrentProcess);
PT := GetThreadPriority(GetCurrentThread);
// Höchste Priorität
SetPriorityClass(GetCurrentProcess, REALTIME_PRIORITY_CLASS);
SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_TIME_CRITICAL);
// Performance Counter und Frequenz abfragen und merken
QueryPerformanceFrequency(Frequency);
QueryPerformanceCounter(P_Count);
// Realtime Counter abfragen und merken
Rdtsc(EAX,EDX);
T_Count := EAX + EDX shl 16;
// IA32_APERF_MSR abfragen und merken
Rdmsr(IA32_APERF_MSR,EAX,EDX);
A_Count := EAX + EDX shl 16;
// IA32_MPERF_MSR abfragen und merken
Rdmsr(IA32_MPERF_MSR,EAX,EDX);
M_Count := EAX + EDX shl 16;
//Warten ohne CPU-Last, die genauigkeit steigt mit steigender Wartezeit
Sleep(250);
// Performance Counter und Delta berechnen
QueryPerformanceCounter(P_Delta);
P_Delta := P_Delta-P_Count;
// Realtime Counter abfragen und Delta berechnen
Rdtsc(EAX,EDX);
T_Delta := (EAX + EDX shl 16) - T_Count;
// IA32_APERF_MSR abfragen und Delta berechnen
Rdmsr(IA32_APERF_MSR,EAX,EDX);
A_Delta := (EAX + EDX shl 16) - A_Count;
// IA32_MPERF_MSR abfragen und Delta berechnen
Rdmsr(IA32_MPERF_MSR,EAX,EDX);
M_Delta := (EAX + EDX shl 16) - M_Count;
// Berechnung der nominellen Taktfrequenz (Constant_TSC)
Nominal := Round(T_Delta/(P_Delta/Frequency)/1000000);
// Berechnung der aktuellen Taktfrequenz
Aktuell := Round(Nominal*(A_Delta/M_Delta)+0.5);
// Alte Prioritäten wiederherstellen
SetThreadPriority(GetCurrentThread, PT);
SetPriorityClass(GetCurrentProcess, PC);
Memo1.Lines.Add('Nomineller Prozessortakt : '+ IntToStr(Nominal));
Memo1.Lines.Add('Aktueller Prozessortakt : '+ IntToStr(Aktuell));
Memo1.Lines.Add('');
end;
MfG
El.Blindo