![]() |
Taktfrequenz berechnen, Realtime Counter, Überlauf ?
Liste der Anhänge anzeigen (Anzahl: 1)
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:
MfG
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; El.Blindo |
Re: Taktfrequenz berechnen, Realtime Counter, Überlauf ?
Zitat:
[add] statt Addition
Delphi-Quellcode:
eine nette Verknüpfung
EAX + EDX shl 16
Delphi-Quellcode:
ist etwas schneller/optimaler
EAX or EDX shl 16;
|
Re: Taktfrequenz berechnen, Realtime Counter, Überlauf ?
Danke für den Tip mit dem OR.
Allerdings bin ich jetzt noch mehr verwirrt. Naja, ist schon Spät. Ich werde morgen mal ein paar Ausgaben mehr ins Memo bauen, dann sieht man was ich meine. Erstaunlicherweise erzeugt der Realtime Counter negative Werte, confused. |
Re: Taktfrequenz berechnen, Realtime Counter, Überlauf ?
Liste der Anhänge anzeigen (Anzahl: 1)
!!! an alle Tester: bei mir hat diese Ring0.dll einen netten BlueScreen ausgelöst
also sollte ihr vorher besser mal alles Speichern > AMD Duron (wollt nur mal sehn was der hier anzeigt :stupid: ) also wenn es nur an dem "signed" liegt, dann einfach statt Int64 dieses knuffige UInt64 verwenden. UInt64 ist praktisch ein 64-Bit-DWord und kennt somit kein Negativ :zwinker: Bist du mit dem shl 16 eigentlich sicher? (ist mir garnicht aufgefallen, aber wenn das stimmt, dann nimm doch besser + ) außerdem solltest du für das SHL den Datentyp vorher vergrößern, da sonst die höheren "16" Bits ins nirgendwo gescoben werden, da zu diesem Zeitpunkt EDX noch ein DWord ist ... wärend der Berechnung ist/bleibt er noch DWord und wird erst bei der Zuweisung an den (U)Int64 in diesesn Typen umgewandelt ... also SHL wird noch auf ein DWord angewendet. |
Re: Taktfrequenz berechnen, Realtime Counter, Überlauf ?
Delphi-Quellcode:
richtiger wäre
T_Count := EAX + EDX shl 16;
Delphi-Quellcode:
Gruß hagenUInt64Rec(T_Count).Lo := EAX; UInt64Rec(T_Count).Hi := EDX; // oder T_Count := EAX + EDX shl 32; // falls Delphi EDX automatisch auf 64Bit Datentyp erweitert, ansonsten EDX vorher in einen temporären UInt64 kopieren |
Re: Taktfrequenz berechnen, Realtime Counter, Überlauf ?
Sorry Doppelpost
|
Re: Taktfrequenz berechnen, Realtime Counter, Überlauf ?
Erstmal, Sorry für den Bluescreen. Ist halt für Core Prozessoren.
Wobei, verstehen kann ich auch das nicht. Das Programm prüft erst ob die CPUID unterstützt wird, wenn nicht bricht es ab. Wenn CPUID unterstützt wird, dann wird auf den Vendor geprüft, ist dieser nicht GENUEINTEL wird das Programm abgebrochen. Beim AMD Duron sollte dort eigentlich AUTENTICAMD stehen. Vielleicht liegt es am statischen Einbinden der DLL, wobei, das sollte eigentlich auch nix machen, das vor der Überprüfung auf den Prozzessor keine DLL Aufrufe erfolgen. Wie dem auch sei, ich habe, um der Sache auf den Grund zu kommen: 1. Eure Tips beachtet, shl 32 müsste übrigens richtig sein, was bin ich für ein Depp. 2. Ich habe die Ausgaben im Memo erweitert. 3. Nun funktioniert es. Ich habe nun folgendes gemacht:
Delphi-Quellcode:
Die Ausgabe sieht nun so aus:type UInt64 = packed record Lo, Hi : DWord; end; . . . // Realtime Counter abfragen und merken Rdtsc(EAX,EDX); UInt64(T_Count).Lo := EAX; UInt64(T_Count).Hi := EDX; // IA32_APERF_MSR abfragen und merken Rdmsr(IA32_APERF_MSR,EAX,EDX); UInt64(A_Count).Lo := EAX; UInt64(A_Count).Hi := EDX; // IA32_MPERF_MSR abfragen und merken Rdmsr(IA32_MPERF_MSR,EAX,EDX); UInt64(M_Count).Lo := EAX; UInt64(M_Count).Hi := EDX; //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); UInt64(T_Delta).Lo := EAX; UInt64(T_Delta).Hi := EDX; T_Delta := T_Delta-T_Count; // IA32_APERF_MSR abfragen und Delta berechnen Rdmsr(IA32_APERF_MSR,EAX,EDX); UInt64(A_Delta).Lo := EAX; UInt64(A_Delta).Hi := EDX; A_Delta := A_Delta - A_Count; // IA32_MPERF_MSR abfragen und Delta berechnen Rdmsr(IA32_MPERF_MSR,EAX,EDX); UInt64(M_Delta).Lo := EAX; UInt64(M_Delta).Hi := EDX; M_Delta := M_Delta - M_Count; . . . T_Delta : 499578708 T_Count : 443978902840440 M_Delta : 7999140 M_Count : 75242284529760 A_Delta : 3998292 A_Count : 47422740994605 P_Delta : 894070 P_Count : 794571775763 Nomineller Prozessortakt : 2000 Aktueller Prozessortakt : 1000 T_Delta : 499655388 T_Count : 443980903020900 M_Delta : 7133940 M_Count : 75242391276468 A_Delta : 3565674 A_Count : 47422794368151 P_Delta : 894208 P_Count : 794575355381 Nomineller Prozessortakt : 2000 Aktueller Prozessortakt : 1000 T_Delta : 499559364 T_Count : 443982903294864 M_Delta : 22331856 M_Count : 75242513536524 A_Delta : 11165232 A_Count : 47422855498137 P_Delta : 894036 P_Count : 794578935166 Nomineller Prozessortakt : 2000 Aktueller Prozessortakt : 1000 Danke für die Hilfe. |
Re: Taktfrequenz berechnen, Realtime Counter, Überlauf ?
Besteht vielleicht die Möglichkeit, das gesamte Projekt noch einmal mit dem korrigierten Code zu posten ?
Danke im Voraus... |
Re: Taktfrequenz berechnen, Realtime Counter, Überlauf ?
schau mal in deine SysUtils ... in neueren Delphis dürfte UInt64Rec schon definiert sein.
wär allerdings auch praktisch gewsen, wenn die WinRing0-Dinger dieses schon als UInt64 exportieren würden :stupid: ja und wegen dem BS ... hab auch nicht mit sowas gerechnet, aber bis auf 'nen fast fertigen Download ist nichts verloren gegengen (nja, der Firefox hat leider Probleme mit dem DL-Fortsetzten) ... nja und ich war da noch der Meinung hier sei 'nen BilligIntel drin (nja, aber wenn ich so überlege ... dessen Vorgänger war ein Pentium 1, also so weit lag ich ja nich daneben :roll: ) Zitat:
'ne gegnerische One-Core-CPU @devidespe wenn's dir egal ist wie das 32-Bitproblem (shl 16) und die UIntInt64 gelöst wurden, dann brauchst nur sein Projekt nehmen und das Eine durch meine .PAS ersetzten oder du nimmst sein Projekt und erstzt einige Ausschnitte dieser .PAS mit den Codestücken aus seinem letztem Post. |
Re: Taktfrequenz berechnen, Realtime Counter, Überlauf ?
Liste der Anhänge anzeigen (Anzahl: 1)
@devidespe
Bitte |
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:47 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz