OvaS
Administrator

Data inscrierii: 29/Aug/2007 Mesaje: 68 Localitate: Calarasi |
|
Utilizarea functiei RDTSC Afla de cat timp e pornit CPU-ul |
|
In acest tutorial va voi explica cum sa folositi functia RDTSC din ASM (assembly) pentru a afla de cat timp e pornit procesorul (si implicit calculatorul) explicat pe un exemplu facut in limbajul Pascal (folosind Delphi 7 ca si compiler)... In exemplu, ce este dupa // este comentariu, deci nu face parte din cod.
In mare, functioneaza asa: aflam cate clock-cycle-uri au fost efectuate pana in secunda X, apoi cate au fost pana in secunda X + 1, iar apoi vedem cate au fost efectuate intr-o singura secunda (X+1 - X). Acum ca stim cate clock-cycle-uri sunt efectuate in 1 secunde (desigur, obtinem un rezultat diferit de fiecare cand facem asta, deoarece nu efectueaza acelasi numar de clock-cycle-uri in fiecare secunda, insa o variatie mica) si ca sa aflam de cate secunde e pornit calculatorul vedem cate clock-cycle-uri au fost efectuate pana in timpul in care vrem sa aflam de cate secunde e pornit, iar numarul acela de clock-cycle-uri il impartim la numarul de clock-cycle-uri pe efectuate intr-o secunda (din operatia de mai devreme) si aflam de cate secunde e pornit calculatorul (desigur de fiecare data rezultatul nu va fi EXACT datorita variatiei de clock-cycle-uri pe secunda, insa veti vedea ca odata arata cu X secunde in plus, sau Y in minus, sau…etc)
In primul rand: ce este/ce face RDTSC? (Read Time Stamp Count)
Instructiunea RDTSC (in HEX $0F31) arata cate 'batai de ceas' (clock-cycles) au fost efectuate de catre CPU (procesor) de cand a fost pornit.
Rezultatul este un numar pe 64-biti, 'returnat' / afisat in EDX:EAX (EDX si EAX sunt registrii / variabile de procesor pe 32-biti, folosite pentru a stoca distincte informatii pe tot parcursul executiei unui program, iar combinarea lor in felul EDX:EAX 'formeaza' un numar pe 64-biti (maxim FFFFFFFF:FFFFFFFF adica FFFFFFFF shl 32 + FFFFFFFF, adica 18.446.744.073.709.551.615)
Se vor utiliza variabilele:
- Hi64 si Lo64 (declarate ca numar intreg pe 64-biti -- Int64) pentru a compune numarul de clock-cycle-uri efectuate de la pornirea calculatorului.
- CalcPerSec (declarat ca numar intreg pe 64-biti -- Int64)
- CalcPerSecLo1, CalcPerSecLo2, CalcPerSecHi1, CalcPerSecHi2 (declarate ca numere pe 32-biti -- DWORD >Double Word< ) pentru a obtine numarul de calcule/batai de ceas/clock-cycle-uri efectuate intr-o secunda.
- secunde (declarat ca numar intreg pe 64-biti – Int64) aici se va stoca rezultatul final
//Declararea variabilelor
var Hi64,Lo64:int64;
CalcPerSecLo1,CalcPerSecLo2,CalcPerSecHi1,CalcPerSecHi2: DWORD;
CalcPerSec,secunde:int64;
begin
asm // Folosit pentru a 'spune' compiler-ului ca urmeaza un cod in ASM
RDTSC // se apeleaza functia RDTSC pentru a afla cate clock-cycle-uri au fost efectuate de la pornirea procesorului pana in momentul ACESTA
MOV CalcPerSecHi1,EDX // in CalcPerSecHi1 se stocheaza primii 32 de biti din numarul de 64 biti returnat/calculat de catre RDTSC, care initial a fost stocat in EDX
MOV CalcPerSecLo1,EAX // in CalcPerSecLo1 se stocheaza urmatorii 32 de biti din numarul de 64-biti returnat/calculat de catre RDTSC, care initial a fost stocat in EAX
end;
sleep(1000); // comanda sleep(1000) opreste executia programului pentru 1000 milisecunde (1 sec) dupa care continua normal, insa in acest timp procesorul continua sa efectueze clock-cycle-uri
asm
RDTSC // se mai cheama odata functia RDTSC pentru a afla cate clock cycle-uri au fost efectuate de la pornirea procesorului pana in momentul de ACESTA, adica dupa o secunda de la ultima chemare a functii RDTSC, pentru ca mai tarziu sa vedem cate cloc-cycle-uri au fost efectuate intr-o secunda.
MOV CalcPerSecHi2,EDX
MOV CalcPerSecLo2,EAX
end;
Lo64:=CalcPerSecLo2; // stocam primii 32 de biti din numarul de clock-cycle-uri efectuate de la pornirea procesorului intr-un numar pe 64-biti (Lo64), pentru calculele cu numere pe 64-biti de mai jos
Hi64:=CalcPerSecHi2; // stocam urmatorii 32 de biti din numarul de clock-cycle-uri efectuate de la pornirea procesorului intr-un numar pe 64-biti (Hi64), pentru calculele cu numere pe 64-biti de mai jos
CalcPerSec:= (CalcPerSecHi2 shl 32+CalcPerSecLo2) - (CalcPerSecHi1 shl 32 + CalcPerSecLo1); // Calculam cate clock-cycle-uri/batai de ceas/calcule a efectuat intr-o secunda (
- (CalcPerSecHi2 shl 32 +CalcPerSecLo2) reprezinta numarul de clock-cycle-uri la secunda X+1
- (CalcPerSecHi1 shl 32 + CalcPerSecLo1) reprezinta numarul de clock-cycle-uri la secunda X, astfel aflam cate au fost facute in secunda X+1 - X (adica 1 secunde) )
// Reamintesc ca variabila CalcPerSec este declarata ca stocand un numar pe 64-biti, deoarece calculele astea (diferenta/scaderea efectuata) contine termeni care consta in numere pe 64-biti
secunde:= (Hi64 shl 32+Lo64) div CalcPerSec; // Impartim numarul de clock-cycle-uri efectuate pana in momentul de fata la cate clock-cycle-uri sunt efectuate pe secunda, astfel obtinand cate secunde au trecut de la pornirea calculatorului.
Codul de mai sus (fara comentarii) pentru Delphi:
Code:
Procedure DeCatTimpEpornitCompu;
var Hi64,Lo64:int64;
CalcPerSecLo1,CalcPerSecLo2,CalcPerSecHi1,CalcPerSecHi2:DWORD;
CalcPerSec,secunde:int64;
begin
asm
RDTSC
MOV CalcPerSecHi1,EDX
MOV CalcPerSecLo1,EAX
push $3E8
call sleep
RDTSC
MOV CalcPerSecHi2,EDX
MOV CalcPerSecLo2,EAX
end;
Lo64:=CalcPerSecLo2;
Hi64:=CalcPerSecHi2;
CalcPerSec:=(CalcPerSecHi2 shl 32+CalcPerSecLo2) - (CalcPerSecHi1 shl 32 + CalcPerSecLo1);
secunde:=(Hi64 shl 32+Lo64) div CalcPerSec;
|
|