PDA

View Full Version : محاسبه نانو ثانیه



دلفــي
شنبه 29 خرداد 1389, 07:54 صبح
با سلام

من دو تا الگوریتم دارم که می خوام زمان اجرای اونها رو بدست بیارم تا بتونم هر کدوم بهینه تره انتخابش کنم ولی زمانی که باید محاسبه بشه در حد نانو ثانیه است , آیا کسی در این مورد اطلاعاتی داره ؟!

SAASTN
شنبه 29 خرداد 1389, 08:27 صبح
چیزی که توی این زمینه استفاده می شه همون GetTickCount هست که دقتش هزارم ثانیه است. اگه الگوریتمتون به نوعی تکرار شونده هست کاری که می شه کرد اینه که n رو توی هر دو به طور غیر واقعی بالا ببرید تا زمان بیشتری طول بکشند. و اگه خودش تکرار شونده نیست توی یه حلقه قرارش بدین تا به تعداد دفعات زیادی اجرا بشه. در نهایت زمان بدست اومده رو تقسیم بر نسبت افزایش n (یا خود n در وضعیت دوم) کنید تا زمان واقعی هر بار اجرای الگوریتم بدست بیاد.
در مورد GetTickCount هم که:
Counter := GetTickCount;
// the code comes here ...
ShowMessage(IntToStr(GetTickCount - Counter));

دلفــي
شنبه 29 خرداد 1389, 09:30 صبح
با تشکر از دوست عزیز SAASTN :
من از کد زیر استفاده کردم و خوب هم جواب داد :




Data format
Older versions of Delphi do not support the 64 bit integer format.
Therefore, a new data type is introduced to hold the 64 bits:
type TI64 = array[0..8] of byte;Bits 0..7 of byte -0- hold bits 0..7 of the clock cycle count,
byte -1- holds bits 8..15 of the clock counter etc.
An extra byte -8- is added to facilitate integer divide by 10, to convert the
number to a decimal string.


Variables, Function and Procedure calls


var CPUClock: extended; //floating point value holding cycles per microsecondprocedure GetCPUTicks(var i64 : TI64);//store CPU ticks in array[0..7]function diff64(v1,v2 : TI64) : TI64; //calculate v2 - v1function I64tofloat(I64 : TI64) : extended; //convert 64 bit integer to floating point formatfunction I64toStr(I64 : TI64) : string; //converts 64 bit integer to a stringfunction CyclesPerMicroSecond : extended;//calculate the clock speedFunction and Procedures


procedure GetCPUTicks(var i64 : TI64);//store CPU ticks in array[0..7]var i : byte;label loop1,loop2;begin asm mov ECX,i64 //save address DB $0F,$31 // RDTSC command // put CPU clock count in EAX (bits 0..31) and EDX (bits 32..63) mov i,4loop1: mov [ECX],AL shr EAX,8 inc ECX dec i jnz loop1 mov i,4loop2: mov [ECX],DL shr EDX,8 inc ECX dec i jnz loop2 end;end;function I64tofloat(I64 : TI64) : extended;var i : byte; w : extended;begin result := 0; w := 1; for i := 0 to 7 do begin result := result + I64*w; w := w * 256; end;end;function diff64(v1,v2 : TI64) : TI64;//difference v2 - v1 of 2 64 bit integersvar borrow,i : Byte;begin borrow := 0; for i := 0 to 7 do begin if v2 < v1+borrow then begin result := 256 + v2 - v1 - borrow; borrow := 1; end else begin result := v2[I] - v1[I] - borrow; borrow := 0; end; end;end;The following function is not really necessary, since values can be converted to
floating point and then to a character string.
It is only usefull to directly make a string from the clock count.




Figure 1. below shows the idea:


file:///I:/Timer/Nanoseconds%20timer%20in%20Delphi_files/fig1.giffig.1

The 64 bits are shifted 1 place to te left.





Then a (trial) subtract of 10 decimal (binary 1010) is done.
If succesfull, a "1" is inserted in bit 0 of byte -0-.
After 64 shifts and trial subtracts, byte -8- holds the remainder and
the lower bytes hold the quotient.
Then the remainder is stored as the first digit of the result string and byte -8- is cleared.
above process is repeated until the quotient equals zero.



function I64toStr(I64 : TI64) : string;[I]//convert a 64 bit integer to a stringconst d = 10; hb = $80; msk = $7f;var i,j,b,c : byte; sum : word;begin result := ''; repeat I64[8] := 0; for i := 1 to 64 do begin for j := 8 downto 1 do begin c := I64[j-1] shr 7; I64[j] := ((I64[j] and msk) shl 1) or c; end;//for j if I64[8] >= d then begin b := 1; I64[8] := I64[8] - d; end else b := 0; I64[0] := ((I64[0] and msk) shl 1) or b; end;//for i insert(chr(ord('0') + I64[8]),result,0); sum := 0; for j := 0 to 7 do inc(sum,I64[j]); until sum = 0;end;Process below calculates the clock frequency of the processor.


function CyclesPerMicroSecond : extended;[I]//calculate the clock speedvar t1,t2 : TI64; t : DWORD;begin t := GetTickCount;//get the milliseconds clock count while t=GetTickCount do;//wait for increment, start of new count GetCPUTicks(t1); //get the proc. cycles counter t := t + 500;//set t to end time while GetTickCount < t do; // wait .... GetCPUTicks(t2); // cycle counter after 500millisecs t1 := Diff64(t1,t2); result := I64ToFloat(t1)*2e-6;end;When 64 bit integers are supported (type Int64)
Some websites list function below, however, this code does not work in Delphi-7



function GetCPUTicks: Int64;asm RDTSC; [I]// = DB $0F,$31 end;Code below does work:



procedure getCPUticks(var i : int64);begin asm mov ECX,i; RDTSC; //cpu clock in EAX,EDX mov [ECX],EAX; mov [ECX+4],EDX; end;end;The other functions above (except "cyclespermicrosecond") are obsolete in this case.


Application
Store clock frequency in CPUclock
Show frequency in statictext1



procedure TForm1.Button1Click(Sender: TObject);begin CPUclock := CyclesperMicroSecond; statictext1.caption := 'CPU clock= '+formatfloat('####0.00',cpuclock) + 'Mhz');end; Measure the speed of a process.
The clock cycles are stored in statictext2.
Microseconds are stored in statictext3.





[i][i]procedure TForm1.Button2Click(Sender: TObject);[I]//CPUclock must be setvar t1,t2 : TI64; sum, i : LongInt; et : extended; s : string;begin sum := 0; getCPUTicks(t1); for i := 0 to 1000000 do inc(sum,i);[I]//this is the process to measure getCPUTicks(t2); t1 := Diff64(t1,t2); s := I64toStr(t1); et := I64ToFloat(t1)/CPUclock; statictext2.Caption := s; statictext3.caption := formatfloat('####0.000',et);end;