Mega Code Archive

 
Categories / Delphi / Algorithm Math
 

Calculate the execution time of code

Title: Calculate the execution time of code Question: How one can calculate the execution time of code? Answer: Processors Intel Pentium have a powerful command RDTSC. This is an extraction from Intel documentation on this command: "Loads the current value of the processor's time-stamp counter into the EDX:EAX registers. The time-stamp counter is contained in a 64-bit MSR. The high-order 32 bits of the MSR are loaded into the EDX register, and the low-order 32 bits are loaded into the EAX register. The processor increments the time-stamp counter MSR every clock cycle and resets it to 0 whenever the processor is reset." Note that RDTSC command returns the values in Int64 format used in Delphi. function GetCPUTick: Int64; asm DB $0F,$31 // this is RDTSC command. Assembler, built in Delphi, // does not support it, // that is why one needs to overcome this obstacle. end; Such a simple function allows the user to get the current value of the processor 's time-stamp counter. The difference between the processor's time-stamp counter values, returned before and after execution of a code, allows one to get the ex ecution time. In our exampe: var ticks: int64; s: string; ..... ticks := GetCPUTick; //get the processor's time-stamp counter value isTextString(s); ticks := GetCPUTick - ticks; // number of processor clock cycles Label1.Caption := Format('Execute time %u ticks', [ticks]); ..... At the same time, it is not convenient to express the execution time in clock cycles and it should be converted, for example, in microseconds. To do such a conversion, it is necessary to know how many clock cycles of the processor correspond to a microsecond of its work. var CPUClock: extended; .... function CalibrateCPU: int64; var t: cardinal; begin t := GetTickCount; while t=GetTickCount do; Result := GetCPUTick; //get the time-stamp counter value while GetTickCount Result := GetCPUTick - result; // clock cycle number in 0,4 second CPUClock := 2.5e-6*Result; // clock cycle number in 1 microsecond end; Now it is easy to calculate the code execution time in microseconds: function TicksToStr(const Value: int64): string; begin Result := FloatToStrF(Value/CPUClock,fffixed,10,2)+ ' ms'; end; in addition, it is possible to get the processor frequency: procedure TForm1.Button1Click(Sender: TObject); begin CalibrateCPU; Label1.Caption := Format('CPU clock = %f MHz', [CPUClock]); end; The defined source of code for calculations of the execution time is below: var ticks: int64; s: string; CPUClock: extended; ..... CalibrateCPU; ticks := GetCPUTick; //get the time-stamp value isTextString(s); ticks := GetCPUTick - ticks; //number of clock cycles Label1.Caption := Format('Execute time %s', [TicksToStr(ticks)]); ..... Let us examine the above mentioned code. A program with such a code has to contain at least an additional declaration of several variables (ticks, CPUClock), a call of CalibrateCPU, a call of the tested code "surrounded" by calls of GetCPUTick. However, this way is not suitable for frequent estimations of the code efficiency. To facilitate a procedure of routing testing, let us try to develop a class designed for the code efficiency estimations. This class has to provide the user with additional service possibilities which have to meet the following requirements: it is desirable to estimate simultaneously the efficiencies of several fragments of a code; if a testing code is used several times in the program, it is desirable to get a minimum, maximum and average execution time. Two classes met to the above requirements have been developed: TrsProfilerPoint - it contains data on one estimation point (testing fragment). TrsProfiler - it contains the list of points TrsProfilerPoint. The code using these classes and designed for calculations of the execution time of a procedure is below: uses ....., UrsProfiler; ..... rsProfiler.Clear; // remove old points rsProfiler[0].Start; // use of 0-point, start calculation isTextString(s); rsProfiler[0].Stop; // use of 0-point. stop calculation Label1.Caption := rsProfiler[0].asString; ..... Let us consider a practical use of the developed classes. One can try to accelerate the execution of a procedure whose efficiency is under estimation. Let us develop a project with several versions of such a procedure and estimate their execution time. This demo project can be downloaded. This project also contains the module UrsProfiler, which can be used in your project to estimate the execution time of your own procedures. Of course, its use does not replace some special "optimizers", e.g. VTune developed by Intel, but this module is more suitable if one needs to estimate the execution time of a procedure during its programming and optimization.