Recent

Author Topic: [SOLVED] How to determine nanoseconds using Freepascal?  (Read 16129 times)

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: How to determine nanoseconds using Freepascal?
« Reply #15 on: June 22, 2014, 04:03:19 pm »
The article has multiple problems and solutions but windows is not a real time OS what ever solution you choose I doubt that you can measure reliably below 25ms.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: How to determine nanoseconds using Freepascal?
« Reply #16 on: June 22, 2014, 05:37:16 pm »
windows is not a real-time OS what ever solution you choose
I agree Windows is not a real time OS. I do not consider measuring the CPU ticks between two instructions a RTOS function. You are simply reading the Time Stamp Counter value.

I doubt that you can measure reliably below 25ms.
I am not measuring anything. If your CPU's TSC ticks once every nano second (1 GHz) then when you find the difference between two readings to be, for instance, 5 ticks then I would understand that this is equal to around 5 nanoseconds. As for the 25ms, IIRC that applies to system timers and this is an old value, today that number is smaller and depends on your hardware and OS.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: How to determine nanoseconds using Freepascal?
« Reply #17 on: June 22, 2014, 06:32:50 pm »
as I said I'm no expert on the subject I agree that measurement should be as easy as you describe it but you can't rely on it as it is, that is why the queryperformanceXXXXX were introduced. You can not dictate system wide settings on a users computer even if it means that they are in effect only when your application is running. As for the 25ms number you might be right that in todays computer it has been lowered bu I doubt it has been lowered to nanosecond accuracy infact I doubt that it has been lower below 15ms you have to keep in mind that although your application is running the system will do other things in the background for you those things will influence the final result so every measurement is not clean you just assume that all measurements have the same error in them so they are comparable.

EDIT:
I keep talking about measurement because that is what the OP is after to measure execution with nanosecond accuracy.
« Last Edit: June 22, 2014, 06:36:41 pm by taazz »
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

Gizmo

  • Hero Member
  • *****
  • Posts: 831
Re: How to determine nanoseconds using Freepascal?
« Reply #18 on: June 22, 2014, 11:25:48 pm »
Cracked it, in the end.

Step 1) Extend the number of loops before checking for the time elapsed. So I wait for 5000 loops of 64Kb before working out anything.

Step 2) Have two time elements. One for every repeat, and one inside my progress loop (which is called after 5000 loops) which records the end time that the progress loop was last called. It is then used for the next loop, in another 5000 cycles, to compare the time of the most recent loop against that last computed time.

Step 3) Work out the total secotrs of the disk, less those processed since the last progress loop. Divide by the times computed and then multiply from Ms to S and from S to Mins.

Below is a snippet of code if it can help others:

Code: [Select]
var
  Buffer                                  : array [0..65535] of Byte;   // 65536, 64Kb buffer
  Offset                                  : DWORD;
  ctx                                     : TSHA1Context;
  Digest                                  : TSHA1Digest;
  index, ProgressCounter                  : integer;

  NewPos, ExactDiskSize, SectorCount,
    BytesPerMinute, TimeToRead,
    TimeTakenForInterval, BytesExaminedDuringInterval,
    BytesPerSecond, RemainingBytes        : Int64;

  StartTime, IntervalReadTime,
    TimeStartRead, EndTime                : TDateTime;

const
  DataTransferTrigger : Integer = 5000; // The number of buffer reads to allow before a transfer speed computation

begin
...
try
// Does some disk seeking and stuff
 repeat
          ProgressCounter := ProgressCounter + 1; // We use this update the progress display occasionally, instead of every buffer read
          TimeStartRead   := Now; // For every repeat, we get the time.

          // Stuff is done with the disk, reading bytes and stuff - the stuff I want to time!
   
          // Only if the loop has gone round a while (2000 times?), update the progress display
          if ProgressCounter = DataTransferTrigger then // If X disk loops have taken place, calculate progress
             begin
               BytesExaminedDuringInterval := 0;
               // Work out how many bytes are left to do
               RemainingBytes := ExactDiskSize - NewPos;
               // This should always be the same but it is whatever loop cycle is chosen by the size of the chosen buffer, e.g. 5000 * 65536
               BytesExaminedDuringInterval := (DataTransferTrigger * SizeOf(Buffer));
               // Now compute the number of Ms between the start time of this
               // particular buffer read and the time from when the last loop was execute, and convert to seconds
               TimeTakenForInterval := Round(MilliSecondsBetween(IntervalReadTime, TimeStartRead) DIV 1000);
               // So with the number of bytes examined since the last progress loop known,
               // and with the time in seconds since the last progress loop know,
               // divide the two for bytes p\s
               BytesPerSecond := Round(BytesExaminedDuringInterval DIV TimeTakenForInterval);
               // Then multiply by 60 seconds for a p\m rate
               BytesPerMinute := BytesPerSecond * 60;
               lblSpeedB.Caption := FormatByteSize(BytesPerMinute) + ' p\min';
               // Reset the counter for another looping cycle
               ProgressCounter := 0;
               // And now get the time that this progress loop ended,
               // in order to compute the time taken for next time
               IntervalReadTime := Now;
            end;
          Application.ProcessMessages;
        until (NewPos >= ExactDiskSize) or (Stop = true); // Stop looping over the disk     
                                 
« Last Edit: June 23, 2014, 04:03:19 pm by Gizmo »

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: [SOLVED] How to determine nanoseconds using Freepascal?
« Reply #19 on: June 23, 2014, 11:42:52 am »
Code: [Select]
TimeTakenForInterval := Round(MilliSecondsBetween(IntervalReadTime, TimeStartRead) DIV 1000);
BytesPerSecond := Round(BytesExaminedDuringInterval DIV TimeTakenForInterval);
Just quick advice, you don't need Round() in those lines. You are using integer-division "div", so it results an integer already. (In a way that 9 div 10 = 0, not rounded to 1)

BrunoK

  • Hero Member
  • *****
  • Posts: 766
  • Retired programmer
Re: [SOLVED] How to determine nanoseconds using Freepascal?
« Reply #20 on: June 23, 2014, 02:54:28 pm »
How about trying (and validating) my version for >>> i386/Win32 <<<

4 useful methods :

                  // Start with correction
                 procedure PC_SWStart(var aStopWatch:TPerfCntr);
                 // Stop/suspend with correction (correction set at 0)
                 procedure PC_SWStop(var aStopWatch:TPerfCntr);
                 // Continue a stopped StopWatch with correction
                 procedure PC_SWCont(var aStopWatch:TPerfCntr);
                 // Get string representation of aStopWatch
                 function PC_DeltaStr(aStopWatch: TPerfCntr): String;

Unit in attachment change .txt extension to .pp

 

TinyPortal © 2005-2018