Einzelnen Beitrag anzeigen

El.Blindo

Registriert seit: 24. Okt 2006
18 Beiträge
 
#1

Taktfrequenz berechnen, Realtime Counter, Überlauf ?

  Alt 27. Jan 2008, 15:25
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
Angehängte Dateien
Dateityp: zip perfmsr_541.zip (43,8 KB, 17x aufgerufen)
  Mit Zitat antworten Zitat