Clock precision and accuracy Lassi Kortela 11 May 2019 10:48 UTC
Here are some more thoughts about time. They are from a devil's advocate perspective (which I think is the best perspective when it comes to OS stuff, and especially time stuff) so unfortunately it's all nitpicking, all the time. Should we just return all timestamps (file time, current time of day, anything else) as two nonnegative integers: [seconds nanoseconds]? (A nanosecond is a billionth of a second so it fits in 30 bits, making it somewhat fixnum-friendly also.) All timestamps would have nanosecond precision, and the accuracy of the nanoseconds part is "make of it what you will". We would not provide procedures to ask "how precise is the nanosecond part really?" This is based on the observation that timestamp precision is a tricky thing. A more precise timestamp is often just a copy of a less precise timestamp upstream. So although some APIs can advertise a "precision", the real precision is up to file system, or a network host, or a hardware oscillator with thermal issues - often a combination of those. FAT stores last modified timestamps with two-second precision, UFS stores with nanosecond precision (which no computer can actually supply it). Both are "advertised" by stat() as having nanosecond precision. Likewise, different CPUs and motherboards have different clock sources, etc. I read on the internet that the Raspberry Pi can keep time at microsecond precision. Asking about timestamp precision in a high-level language sounds like an XY problem (<http://xyproblem.info/>) by default: - How do I know how precise the time from the xyz function is? - What problem are you _really_ trying to solve? Another thing is that you can't really _use_ an _actual_ nanosecond precision timer in the same way as a microsecond precision timer, which in turn can't be used in the same way as a millisecond timer, etc. When you use very precise timers it leads to problems where the code around the timer needs to be written carefully to not take so long to run that it distrubs the intended purpose of the timer. So the current draft would be changed as follows: (current-nanosecond) ---> [secs nsecs] I would add this procedure by analogy to current-second in R7RS. With the proviso that the accuracy of nsecs is "make of it what you will". R7RS current-second uses (or aspires to use) TAI; this one could as well. What bothers me a bit about this is that the name says nanosecond but it will never have a real precision (never mind accuracy) of anything close to a nanosecond. But it's consistent with many on-disk formats and APIs that use nanoseconds so the interoperability is nice. And ultimately we would have more or less the same problems is we specified a current-microsecond procedure. We just need to add a prominent warning about the real precision so people don't expect miracles. (time+ticks) ---> [secs ticks] I would leave out this procedure that combines a precise second with a variable-precision sub-second tick counter: * Getting the current time with _some_ unspecified sub-second precision is served well by (current-nanosecond). * Giving users more information about the tick precision or frequency is misleading, as context switch overhead and many other things always weaken the precision at sub-microsecond timescales. I can't figure out how to give users a reliable estimate of the real precision (again, ignoring accuracy concerns) and how users would make use of that information. * Getting a high-performance sub-second counter would be: 1) Better served by some kind of low-overhead CPU counter which is really more CPU- than OS-dependent so it would be out of scope for an OS SRFI. Perhaps better suited for a dedicated high-performance timer SRFI. There is SRFI 120: Timer APIs. 2) Not useful to tie into a clock that measures human time, because the relevant computations weaken the real precision of the timer. Probably in practice you can have _either_ sub-microsecond precision _or_ a time based on a standard epoch of society's timekeeping. It seems ill-advised to ask for both at once unless you have some kind of cutting edge research equipment. Remarks on specific parts of the procedure specification: "This would be important for a system that wanted to precisely time the duration of some event." --> I would recommend a cycle counter for durations with sub-millisecond precision in a portable context. Since it's a duration it doesn't need reference to a standard timescale like UTC or TAI - a monotonically increasing clock is enough (if the clock wraps around, subtracting two timestamps can undo the wraparound). "Time stamps could be collected with little overhead, deferring the overhead of precisely calculating with them until after collection." --> This is a very good principle. (ticks/sec) ---> real I would remove this procedure altogether, as I can't think of any use cases for it. For example, to find out that the RasPi's clock is accurate to one microsecond, instead of calling a function I had to read a blog post that did some measurements to find out. If we don't pretend to know anything about the precision/accuracy, we don't give misleading information and false hope to users :) (file-info:atime file-info) → integer (file-info:mtime file-info) → integer (file-info:ctime file-info) → integer These could also return [secs nsecs] instead of one integer (does that integer store seconds only in Scsh?) In fact, the Unix timespec from stat() is already happily factored into second and nanosecond parts.