Replies: 1 comment 2 replies
-
On 5/31/25 06:03, Dariusz Knociński wrote:
I recently had a need to measure stretches of time shorter than one microsecond. The standard Time interface, in my case on FreeBSD it's a |TimePosix| implementation, provides a |Now()| function and a |Grain| variable to set the resolution of the clock. Both values are of type |LONGREAL|. Unfortunately, this module provides clock resolution of only one microsecond.
Accordingly, I modified the contents of the file |m3-libs/m3core/src/time/POSIX/TimePosixC.c| and implemented a simple time reading with an accuracy of one nanosecond:
|LONGREAL /*Time.T*/ __cdecl TimePosix__Now(void) { #if defined(__FreeBSD__) struct timespec res = { 0 }; int i = -1; i = clock_gettime(CLOCK_REALTIME, &res); assert(i == 0); return (LONGREAL)(((double)res.tv_sec) + ((double)res.tv_nsec) / 1000000000.0); #else |
For FreeBSD in addition I made the |TimePosix__FromNanotime| function visible:
|#if defined (__osf__) || defined (__FreeBSD__) /* defined(CLOCK_HIGHRES) || defined(CLOCK_REALTIME) */ static LONGREAL/*Time.T*/ __cdecl TimePosix__FromNanotime(const struct timespec* tv) |
And calculating the function |TimePosix__ComputeGrain()|:
|TimePosix__ComputeGrain(void) { /* ComputeGrainViaSampling has a strong propensity to hang on OSF/1. I don't know why. On other platforms, ComputeGrainViaClockGetRes and ComputeGrainViaSampling vary by a lot. */ #if defined (__osf__) || defined (__FreeBSD__) /* defined(CLOCK_HIGHRES) || defined(CLOCK_REALTIME) */ return ComputeGrainViaClockGetRes(); #else |
Unfortunately, this solution did not produce the expected results. It turned out that I had not taken into account the errors that must inevitably occur due to the use of |LONGREAL| type. If I had taken measurements in the early 1970s I would not have even noticed this problem ;)
The time in implementations based on the /POSIX/ standard is read from the system using the |clock_gettime| function, which typically returns the number of seconds since January 1, 1970 and the number of microseconds or nanoseconds in a second. The fractional part has a fixed number of significant digits of 6 or 9, while the integer part has a variable number of significant digits from 1 to 10, depending on how far from zero the moment of measurement is. To get accuracy on the order of microseconds, just use the |LONGREAL| type: 10 + 6 gives 16 significant digits, which is one less than the maximum number of significant digits for the |LONGREAL| type.
For timing accuracy of one nanosecond, the situation is different. Already on March 4, 1970, the obtained time would have a value greater than |99,999,999 . 999,999,999,999|, i.e. it would have exceeded 17 significant digits, which is a boundary value for the |LONGREAL| type. A natural solution to this problem would seem to be to replace the |LONGREAL| type with |EXTENDED| type. Unfortunately, this approach will not work. Most implementations of the |EXTENDED| type are the same as the |LONGREAL| type and we will not get an improvement. To show what effect the |Now():LONGREAL| function has on the interval measurement, I wrote a corresponding program that calculates the relative error of the measurement:
https://www.dropbox.com/scl/fi/d1k595gf6wn2eu8l3nfzl/TimeInterval.tar.xz?rlkey=u261dlej27zovs69rbdkuzxb5&st=pmkitx33&dl=0 <https://www.dropbox.com/scl/fi/d1k595gf6wn2eu8l3nfzl/TimeInterval.tar.xz?rlkey=u261dlej27zovs69rbdkuzxb5&st=pmkitx33&dl=0>
and compiled the results into a table and graph:
Average Relative Error Test's Results:
From [ns] To [ns] Average [%] StdDev
1 9 100.000000 0.000000000
10 99 100.000000 0.000000000
100 999 16.491683 20.101103938
1000 9999 1.544443 1.597432104
10000 99999 0.152404 0.155141359
100000 999999 0.015250 0.015532840
1000000 9999999 0.001525 0.001552962
10000000 99999999 0.000152 0.000155290
100000000 999999999 0.000015 0.000015529
https://www.dropbox.com/scl/fi/a4cn14dqiw8v9bdysd4ro/CM3-TimeInterval-Errors.png?rlkey=00xehee43pt9zu1i6iv5kjrhe&st=kq2aj880&dl=0 <https://www.dropbox.com/scl/fi/a4cn14dqiw8v9bdysd4ro/CM3-TimeInterval-Errors.png?rlkey=00xehee43pt9zu1i6iv5kjrhe&st=kq2aj880&dl=0>
The posted chart shows that a reasonably error-free reading of the time intervals can be obtained with an accuracy of at most of one millisecond.
In order to avoid such measurement errors, it is necessary to provide a Time.T type in the Time interface, which is a record containing the number of seconds and the number of ticks per second:
|TimeSpec = RECORD seconds: INTEGER; ticks: INTEGER; END; |
Sounds like a good idea to me.
But do we want to preclude embedded devices from ever utilizing this? Why not make both fields
LONGINT. This will work just as well on 64-bit machines, with possible minor inconvenience of
explicit type conversion to INTEGER, if you don't want to just work in LONGINT, and still support
iot, and such.
… Most modern workstations are 64 bit systems so there will be no nanosecond or even attosecond problems ;)
—
Reply to this email directly, view it on GitHub <#1207>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/ABSVZNDIWU22NTL2JBBPXMD3BGD6TAVCNFSM6AAAAAB6JYMA4GVHI2DSMVQWIX3LMV43ERDJONRXK43TNFXW4OZYGM4TMNBUGU>.
You are receiving this because you are subscribed to this thread.Message ID: ***@***.***>
|
Beta Was this translation helpful? Give feedback.
2 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
I recently had a need to measure stretches of time shorter than one microsecond. The standard Time interface, in my case on FreeBSD it's a
TimePosix
implementation, provides aNow()
function and aGrain
variable to set the resolution of the clock. Both values are of typeLONGREAL
. Unfortunately, this module provides clock resolution of only one microsecond.Accordingly, I modified the contents of the file
m3-libs/m3core/src/time/POSIX/TimePosixC.c
and implemented a simple time reading with an accuracy of one nanosecond:For FreeBSD in addition I made the
TimePosix__FromNanotime
function visible:And calculating the function
TimePosix__ComputeGrain()
:Unfortunately, this solution did not produce the expected results. It turned out that I had not taken into account the errors that must inevitably occur due to the use of
LONGREAL
type. If I had taken measurements in the early 1970s I would not have even noticed this problem ;)The time in implementations based on the POSIX standard is read from the system using the
clock_gettime
function, which typically returns the number of seconds since January 1, 1970 and the number of microseconds or nanoseconds in a second. The fractional part has a fixed number of significant digits of 6 or 9, while the integer part has a variable number of significant digits from 1 to 10, depending on how far from zero the moment of measurement is. To get accuracy on the order of microseconds, just use theLONGREAL
type: 10 + 6 gives 16 significant digits, which is one less than the maximum number of significant digits for theLONGREAL
type.For timing accuracy of one nanosecond, the situation is different. Already on March 4, 1970, the obtained time would have a value greater than
99,999,999 . 999,999,999,999
, i.e. it would have exceeded 17 significant digits, which is a boundary value for theLONGREAL
type. A natural solution to this problem would seem to be to replace theLONGREAL
type withEXTENDED
type. Unfortunately, this approach will not work. Most implementations of theEXTENDED
type are the same as theLONGREAL
type and we will not get an improvement. To show what effect theNow():LONGREAL
function has on the interval measurement, I wrote a corresponding program that calculates the relative error of the measurement:https://www.dropbox.com/scl/fi/d1k595gf6wn2eu8l3nfzl/TimeInterval.tar.xz?rlkey=u261dlej27zovs69rbdkuzxb5&st=pmkitx33&dl=0
and compiled the results into a table and graph:
Average Relative Error Test's Results:
https://www.dropbox.com/scl/fi/a4cn14dqiw8v9bdysd4ro/CM3-TimeInterval-Errors.png?rlkey=00xehee43pt9zu1i6iv5kjrhe&st=kq2aj880&dl=0
The posted chart shows that a reasonably error-free reading of the time intervals can be obtained with an accuracy of at most of one millisecond.
In order to avoid such measurement errors, it is necessary to provide a Time.T type in the Time interface, which is a record containing the number of seconds and the number of ticks per second:
Most modern workstations are 64 bit systems so there will be no nanosecond or even attosecond problems ;)
Beta Was this translation helpful? Give feedback.
All reactions