Recent

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

Gizmo

  • Hero Member
  • *****
  • Posts: 831
[SOLVED] How to determine nanoseconds using Freepascal?
« on: June 21, 2014, 03:01:20 pm »
Hi

I am trying to implement a timer, which is based on the time taken to read a 64Kb block from disk into a buffer repeatedly.

Based on the time taken to read each buffer, I want to compute a Gb per minute transfer rate indicate for the GUI.

I have tried using the epikTimer 3rd party module, but (maybe I used it wrong) it slowed my prgram down by a factor of 10! So I have tried to implement as seen below.

However, the problem is that the lowest unit of time I can go to using FPC is milliseconds. And it is taking less than a millisecond to read each buffer. I determined this by two things a) the time in Ms that the read started is the same in Ms as the time it ended. So EndTime - StartTime = 0. ANd b) the epikTimer module, which does use nanoseconds, reported a rate of something like 0.00160. Given that ET is millisecond based, I can surely assume the reported time is nanoseconds...i.e 0 milliseconds and 0.00160 nanoseconds. 

Given the code below, or some smilar derivative, how can I compute the times to a nanosecond basis? Is there no nanosecond procedure in FPC? DecodeTime doesn't quite make it.
 
Code: [Select]
FileSeek(hSelectedDisk, 0, 0);
    repeat
      ProgressCounter := ProgressCounter + 1; // We use this update the progress display occasionally, instead of every buffer read
      TimeStartRead   := GetTimeInMilliSeconds(Time); // Starting time, in Ms
      // Program then does stuff I wish to time
      TimeEndRead      := GetTimeInMilliSeconds(Time);;  // End time in Ms
      MillisecondsElapsed := (TimeEndRead - TimeStartRead); // Record how many Ms's have elapsed - HOW CAN THIS BE DONE IN nanoseconds?

              BytesTransferred := SizeOf(Buffer);
              BytesPerMillisecond := Round(BytesTransferred DIV MilliSecondsElapsed);
              BytesPerSecond := BytesPerMillisecond * 1000;  // Convert the bytes read per millisecond into bytes read per second
              BytesPerMinute := BytesPerSecond * 60; // Convert the bytes read per second into bytes read per minute
              lblSpeedB.Caption := FormatByteSize(BytesPerMinute) + ' p\min'; // now convert the large "bytes per minute" figure into Mb, Gb or Tb using my other custom function - converts pure integers like 1234567 into a number of Kb, Mb, Gb or Tb
              .....
    until....// Stop looping over the disk
   finally
...

Function GetTimeInMilliSeconds(theTime : TTime): Int64;
// http://www.delphipages.com/forum/archive/index.php/t-135103.html
var
  Hour, Min, Sec, MSec: Word;
begin
  DecodeTime(theTime,Hour, Min, Sec, MSec);
  Result := (Hour * 3600000) + (Min * 60000) + (Sec * 1000) + MSec;
end;

(Also posted at SO if anyone is a member there : http://forum.lazarus.freepascal.org/index.php?topic=24955.msg150796#msg150796)
« Last Edit: June 22, 2014, 11:25:59 pm by Gizmo »

wp

  • Hero Member
  • *****
  • Posts: 13583
Re: How to determine nanoseconds using Freepascal?
« Reply #1 on: June 21, 2014, 04:52:33 pm »
Something is wrong here: With nowadays CPUs running at GHz speed the shortest time period to be expected in a PC is in the order of nanoseconds. It is impossible that a process takes only 0.00160 nanoseconds. Maybe your units are microseconds? 0.00160 microseconds = 1.60 nanoseconds?

Gizmo

  • Hero Member
  • *****
  • Posts: 831
Re: How to determine nanoseconds using Freepascal?
« Reply #2 on: June 21, 2014, 04:57:50 pm »
Thanks for the spot, but the number was from memory - it was 0.XXX milliseconds (i.e. less than 1 millisecond) but I can't recall the figure exactly.

My point is, though, that the measurement of speed I need is in nanoseconds, not milliseconds, and I am hoping for a solution to compute that using FPC? Math is not my strong point at the best time and I assumed\hoped it would be easier to come up with a solution to compute : if it takes X seconds\milliseconds\nanoseconds to read 64Kb, then it will process XGb in one minute." 

I know Windows NTFS date stamps are computed in the number of nanoseconds since 1601, so there must be a way.

I am open to any solution.
« Last Edit: June 21, 2014, 05:00:45 pm by Gizmo »

BigChimp

  • Hero Member
  • *****
  • Posts: 5740
  • Add to the wiki - it's free ;)
    • FPCUp, PaperTiger scanning and other open source projects
Re: How to determine nanoseconds using Freepascal?
« Reply #3 on: June 21, 2014, 04:59:19 pm »
Is there anything at the operating system level that even provides nanosecond precision? I wonder...
See also
http://stackoverflow.com/questions/1825720/c-high-precision-time-measurement-in-windows
Want quicker answers to your questions? Read http://wiki.lazarus.freepascal.org/Lazarus_Faq#What_is_the_correct_way_to_ask_questions_in_the_forum.3F

Open source including papertiger OCR/PDF scanning:
https://bitbucket.org/reiniero

Lazarus trunk+FPC trunk x86, Windows x64 unless otherwise specified

Mike.Cornflake

  • Hero Member
  • *****
  • Posts: 1272
Re: How to determine nanoseconds using Freepascal?
« Reply #4 on: June 21, 2014, 05:01:26 pm »
There's been quite a marathon discussion on this issue on the lazarus mailing list.

If you're using Windows, EpikTimer is the go.   

I admit, I got lost with the marathon discussion.  Someone has been working on getting decent precision for EpikTimer under Linux, but I honestly don't know the state of play...

http://wiki.lazarus.freepascal.org/EpikTimer
Lazarus Trunk/FPC latest fixes on Windows 11
  I'm getting old and stale.  Slowly getting used to git, I'll get there...

BigChimp

  • Hero Member
  • *****
  • Posts: 5740
  • Add to the wiki - it's free ;)
    • FPCUp, PaperTiger scanning and other open source projects
Re: How to determine nanoseconds using Freepascal?
« Reply #5 on: June 21, 2014, 05:04:44 pm »
I admit, I got lost with the marathon discussion.  Someone has been working on getting decent precision for EpikTimer under Linux, but I honestly don't know the state of play...
IIRC, a lot of hot air but no code at all. (Nor is there any workable code likely to appear shortly, I suspect)
Want quicker answers to your questions? Read http://wiki.lazarus.freepascal.org/Lazarus_Faq#What_is_the_correct_way_to_ask_questions_in_the_forum.3F

Open source including papertiger OCR/PDF scanning:
https://bitbucket.org/reiniero

Lazarus trunk+FPC trunk x86, Windows x64 unless otherwise specified

Mike.Cornflake

  • Hero Member
  • *****
  • Posts: 1272
Re: How to determine nanoseconds using Freepascal?
« Reply #6 on: June 21, 2014, 05:09:17 pm »
Quote
IIRC, a lot of hot air but no code at all.

Maybe.   

Quote
I have tried using the epikTimer 3rd party module, but (maybe I used it wrong) it slowed my prgram down by a factor of 10! So I have tried to implement as seen below.

I've just realised Gizmo has already tried epiktimer...

Sorry, no idea...
Lazarus Trunk/FPC latest fixes on Windows 11
  I'm getting old and stale.  Slowly getting used to git, I'll get there...

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: How to determine nanoseconds using Freepascal?
« Reply #7 on: June 21, 2014, 05:24:20 pm »
I'm not an expert on the subject but as far as I know windows has a granularity of 25ms (thats milliseconds) below that is impossible to measure and it falls inside the error margin that the OS defines. that is why in order to get a good time measurement you run the same operation a few thousand times just and you calculate the average ee Yms/Xtimes = avg per operation. although this minimizes any measurement errors it does not erase them.
I have various thoughts on the measuring subject on a multitasking os but at this point they are only assumptions so I"m going to keep them to my self for now.
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 #8 on: June 21, 2014, 06:08:49 pm »
Code: [Select]
{unit EpikTimer;}
// Execute the Pentium's RDTSC instruction to access the counter value.
function HardwareTicks: TickType; assembler; asm DW 0310FH end;

Laksen

  • Hero Member
  • *****
  • Posts: 802
    • J-Software
Re: How to determine nanoseconds using Freepascal?
« Reply #9 on: June 21, 2014, 07:01:19 pm »
There's no good way to get that level of precision in user space. You should time many blocks and average them out.

Gizmo

  • Hero Member
  • *****
  • Posts: 831
Re: How to determine nanoseconds using Freepascal?
« Reply #10 on: June 21, 2014, 09:41:54 pm »
Thanks all for the contributions.

Maybe I need to revist epikTimer. My implementation was basically a procedure to create the ET instance for each measurement. Then ET.Start at the start of the read and compuations. Then ET.Stop, followed by ET.Elapsed (from memory - not got access to the code off hand). But it was REALLY slow.

The points about averaging all make sense of course. Measure the time to do 10 blocks, or 100 blocks, and average them. But, if the start time in MS is 1234 and the end time is 1234, then there is no measure of time to measure, and ergo, average. If Block one reads an average time of 0, and block two reads an average time of 0 (because all the reads are taking less than 1 Ms) then the average is 0.

I will perhaps just discard the idea. There has to be a way to do it because I know of tools that do so, like WinHex, FTK Imager and others. They can all measure the speed that the task is running (reading the disk) so I obviously just need to do what programers do best and think of and arrive at another solution. I guess I could incoporate a counter and have a timed start, and say when the counter has looped 100 times, have an end time, compute the time elapsed, divided by the number of loops and multiplied by the number of bytes processed? Then reset the counter to zero again and initiliase the timers again
« Last Edit: June 21, 2014, 09:48:28 pm by Gizmo »

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: How to determine nanoseconds using Freepascal?
« Reply #11 on: June 21, 2014, 10:11:44 pm »
less than 10,000 or so iterations isn't worth talking in todays hardware(this is highly process dependand you need to find your own minimum), if the measuring result is less than 100ms then its very volatile. If you search this forums for natural sorting you will see that I measured the compare function with at least 500,000 iterations to have any kind of meaningful result.
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

minesadorada

  • Sr. Member
  • ****
  • Posts: 453
  • Retired
Re: How to determine nanoseconds using Freepascal?
« Reply #12 on: June 21, 2014, 10:34:34 pm »
I wrote some pascal/asm routines in 1998 (Delphi 3) that implemented low-level timing routines - some of the code snippets may still be usable (with some tweaks) for your purpose..

http://bderecreator.googlecode.com/svn/trunk/CPUID.pas
GPL Apps: Health MonitorRetro Ski Run
OnlinePackageManager Components: LazAutoUpdate, LongTimer, PoweredBy, ScrollText, PlaySound, CryptINI

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: How to determine nanoseconds using Freepascal?
« Reply #13 on: June 22, 2014, 01:39:50 am »
http://bderecreator.googlecode.com/svn/trunk/CPUID.pas

http://en.wikipedia.org/wiki/Time_Stamp_Counter

Quote
The time stamp counter has, until recently, been an excellent high-resolution, low-overhead way of getting CPU timing information. With the advent of multi-core/hyper-threaded CPUs, systems with multiple CPUs, and hibernating operating systems, the TSC cannot be relied on to provide accurate results — unless great care is taken to correct the possible flaws:

Quote
Under Windows platforms, Microsoft strongly discourages using the TSC for high-resolution timing for exactly these reasons, providing instead the Windows APIs QueryPerformanceCounter and QueryPerformanceFrequency.[2] Under *nix, similar functionality is provided by reading the value of CLOCK_MONOTONIC clock using the POSIX clock_gettime function.

If I remember correctly epiktimer already uses QueryPerformanceCounter and QueryPerformanceFrequency on windows which is as good as it can get but that does not give a nanosecond granularity.
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 #14 on: June 22, 2014, 03:44:43 pm »
Quote
unless great care is taken to correct the possible flaws:
I'm not sure why they used the word "great".

As for "the possible flaws":
Quote
rate of tick and whether all cores (processors) have identical values in their time-keeping registers. There is no promise that the timestamp counters of multiple CPUs on a single motherboard will be synchronized. In such cases, programmers can only get reliable results by locking their code to a single CPU.
As you can see the solution is already mentioned, and it translates, on Windows, to a call to either SetThreadAffinityMask or SetProcessAffinityMask.

Quote
Even then, the CPU speed may change due to power-saving measures
Which translates into disabling power saving. On Windows, setting power scheme to "Home/Office Desk" should be good enough.

Quote
or the system may be hibernated and later resumed
They forgot to mention power suspension as well, which is easy to discover using WM_POWERBROADCAST message.

Quote
Under Windows platforms, Microsoft strongly discourages using the TSC for high-resolution timing for exactly these reasons, providing instead the Windows APIs QueryPerformanceCounter and QueryPerformanceFrequency.
The reference for this paragraph takes us to Game Timing and Multicore Processors. As the title indicates, this is not exactly what we have here in this thread.

If the target range is nanoseconds it is possible to discover if the process got interrupted and discard that measurement, or to start the measurement after a call to sleep.

 

TinyPortal © 2005-2018