![]() |
CPU Speed Assembler & Delphi - Was passiert da?
Hiermit ermittle ich die CPU Geschwindigkeit. Eine nicht ganz unbekannte Assembler Routine in DElphi eingebunden .... ich gebe aber ehrlich zu: Ich verstehe den CODE nich zu 100%!!
Delphi-Quellcode:
function CPU_SPEED_FLOAT: Extended;
const DelayTime = 500; // measure time in ms var TimerHi, TimerLo: DWord; PriorityClass, Priority: Integer; begin try PriorityClass := GetPriorityClass(GetCurrentProcess); Priority := GetThreadPriority(GetCurrentThread); SetPriorityClass(GetCurrentProcess, REALTIME_PRIORITY_CLASS); SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_TIME_CRITICAL); try Sleep(10); asm dw 310Fh // rdtsc mov TimerLo, eax mov TimerHi, edx end; Sleep(DelayTime); asm dw 310Fh // rdtsc sub eax, TimerLo sbb edx, TimerHi mov TimerLo, eax mov TimerHi, edx end; finally SetThreadPriority(GetCurrentThread, Priority); SetPriorityClass(GetCurrentProcess, PriorityClass); end; Result := TimerLo / (1000.0 * DelayTime); except Result := 0; end; end; Warum setze bzw. operiere ich mit "TimerHi"? ... Kann jemand mir den CODE auskommentieren bzw. erklären, was ich mit den Registern wirklich mache und warum ich "TimerHi" in der Ausgabe nicht nutze? Wenn die Tutorial und Programmier-Cracks wie Luckie & Co einen Augenblick Zeit haben, würde ich mich freuen ... mag es nicht, Code zu verwenden, den ich nicht zu 100% verstehe. |
Re: CPU Speed Assembler & Delphi - Was passiert da?
Ich bin jetzt kein Programmiercrack, wie Luckie und Co, aber ich antworte trotzdem mal. Der Luckie is nämlich schon müde ;).
Bevor es los geht: Wie ist Hertz definiert? Nun, ![]() Außerdem einen kurzen Exkurs zum RDTSC (ReaD TSC) Befehl. Der Befehl wurde mit der Pentium Prozessorklasse eingeführt. Prinzipiel kann man mit ihm den Time Stamp Counter auslesen. Der Time Stamp Counter ist dabei ein 64bit großer Zähler, der mit jedem Zyklus um eins inkrementiert wird. Ich denke Du wirst jetzt schon erahnen worauf der Code hinaus läuft ...
Delphi-Quellcode:
Und ja ... da wars. Bei weiteren Fragen, einfach stellen.
function CPU_SPEED_FLOAT: Extended;
const DelayTime = 500; // measure time in ms var TimerHi, TimerLo: DWord; PriorityClass, Priority: Integer; begin try // Zuerst einmal sichern wir die alten Prioritäten für unseren Prozess bzw. Thread, damit wir unsere Änderungen rückgängig machen können ... PriorityClass := GetPriorityClass(GetCurrentProcess); Priority := GetThreadPriority(GetCurrentThread); // ... und dann sagen wir Windows das wir derart wichtig sind, daß wir möglichst vor allen anderen Threads und Anwendungen ausgeführt werden wollen. SetPriorityClass(GetCurrentProcess, REALTIME_PRIORITY_CLASS); SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_TIME_CRITICAL); try Sleep(10); // Wir holen uns als erstes den aktuellen Zykluszähler. Da der Zähler ein 64bit Wert ist, wir aber nur 32bit Register haben, muss der Zähler // auf 2 Register verteilt werden. In EAX landen die Low Order Bits und in EDX die High Order Bits. asm dw 310Fh // rdtsc // Da wir die später nochmal brauchen werden, müssen die aber noch gesichert werden: Die Low Bits in TimerLo und die High Bits in TimerHi. mov TimerLo, eax mov TimerHi, edx end; // Und dann warten wir einen definierten Zeitraum ... Sleep(DelayTime); // Um danach den Zähler nochmal auszulesen ... asm dw 310Fh // rdtsc // ... und die Differenz aus den neuen Werten und den gespeicherten zu berechnen ... sub eax, TimerLo sbb edx, TimerHi // ... die wir dann auch direkt in unsere Timer* Variablen packen. mov TimerLo, eax mov TimerHi, edx end; finally // Da wir nicht ewig mit Echtzeit Priorität laufen dürfen, weil der User sonst böse Mails schreibt, werden die Prioritäten wieder zurückgesetzt. SetThreadPriority(GetCurrentThread, Priority); SetPriorityClass(GetCurrentProcess, PriorityClass); end; // Hier gibts einen Bug. Zur Berechnung wird nur TimerLo herangezogen, was falsch ist. Man müsste auf TimerHi und TimerLo wieder einen // 64bit Wert bauen um mit dem zu rechnen. Ab einer bestimmten Geschwindigkeit wird der Code also nicht mehr korrekt funktionieren. // Aber egal ... da Hertz die Anzahl der Zyklen in Sekunden angibt und wir wissen, wieviele Zyklen im von uns gestoppten Zeitraum // durchlaufen wurden, rechnen wir das ganze um (in Megahertz übrigens ;)). Result := TimerLo / (1000.0 * DelayTime); except Result := 0; end; end; |
Re: CPU Speed Assembler & Delphi - Was passiert da?
Mit anderen Worten, müsste ich das Result so ausgeben??
Delphi-Quellcode:
Result := (TimerLo + TimerHi / (1000.0 * DelayTime);
|
Re: CPU Speed Assembler & Delphi - Was passiert da?
Zitat:
Hier mal eine fehlerbereinigte Version:
Delphi-Quellcode:
Die Funktion empfiehlt sich übrigens nicht zum messen. Stromsparfunktionen etc. verfälschen das Ergebnis. Wenn Du die wirkliche Frequenz haben willst, solltest Du WMI bemühen ;).
function GetProcessorSpeed(TimeToWait : Cardinal) : Cardinal;
var TickCountFirst, TickCountSecond : Cardinal; CycleCountFirst, CycleCountSecond : ULARGE_INTEGER; begin TickCountFirst := GetTickCount; // Erster Meßpunkt asm dw 310Fh // rdtsc mov CycleCountFirst.LowPart, eax mov CycleCountFirst.HighPart, edx end; sleep(TimeToWait); TickCountSecond := GetTickCount; // Zweiter Meßpunkt asm dw 310Fh // rdtsc mov CycleCountSecond.LowPart, eax mov CycleCountSecond.HighPart, edx end; result := (CycleCountSecond.QuadPart - CycleCountFirst.QuadPart) div ((TickCountSecond - TickCountFirst) * 1000); end; |
Re: CPU Speed Assembler & Delphi - Was passiert da?
W M I ... wieder die böse Abkürzung ... :wall: .
Dank Dir für die Antwort zu so später Stunde :-D |
Re: CPU Speed Assembler & Delphi - Was passiert da?
Zitat:
Zitat:
|
Re: CPU Speed Assembler & Delphi - Was passiert da?
wozu WMI ... WMI ließt auch nur dieses hier aus:
![]() dann ist Sleep nicht grade genau, drum lesen viele zusätzlich noch mit den QueryPerformanceCounter die tatsächliche Pause-Zeit aus ![]() außerdem zeigt dein Code bei mehr als einer CPU eventuell was Falsches an: ![]() PS: ![]() ja, ich nutze immernoch Cool&Quite :angel2: PSS: auch wenn's nichts Schlimmes ist, warum geben fast alle immernoch RDTSC als Bytecode an? der Delphicompiler kennt diesen ASM-Befehl schon seit seeeeeeeehr vielen Jahren :nerd: |
Re: CPU Speed Assembler & Delphi - Was passiert da?
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:13 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