EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

newlib and time()

Started by pozz September 30, 2022
On 9/30/2022 4:51 AM, Clifford Heath wrote:
> When I implmented this, I used a 64-bit counter in 100's of nanoseconds since a > date about 6000BC, measuring in TAI. You can convert to UTC easily enough, and > then use the timezone tables to get local times.
How did you address calls for times during the Gregorian changeover? Or, times before leap seconds were "created" (misnomer)? Going back "too far" opens the door for folks to think values before "recent times" are valid. I find it easier to treat "system time" as an arbitrary metric that runs at a nominal 1Hz per second and is never "reset". (an external timebase allows you to keep adjusting your notion of a "second"). This ensures that there are always N seconds between any two *system* times, X and X+N (for all X). Then, "wall time" is a bogus concept introduced just for human convenience. Do you prevent a user (or an external reference) from ever setting the wall time backwards? What if he *wants* to? Then, anything you've done relying on that is suspect. You don't FORCE system time to remain in sync with wall time (even at a specific relative offset) but, rather, treat them as separate things. So, if I (the user) want to "schedule an appointment" at 9:00AM, the code uses the *current* notion of the wall time -- which might change hundreds of times between now and then, at the whim of the user. If the wall time suddenly changes, then the time to the appointment will also change -- including being overshot. Damn near everything else wants to rely on relative times which track the system time. If a user wants to do something "in 5 minutes", you don't convert that to "current wall time + 5 minutes" but, rather, schedule it at "current SYSTEM time + 300 seconds". OTOH, if it is now 11:50 and he wants something to happen at 11:55 (now+5 minutes) then he must *say* "11:55". This allows a user to know what to expect in light of the fact that he can change one notion of time but not the other.
On 30/9/22 23:48, Richard Damon wrote:
> There are other time systems (Like the TAI) that keep track of leap > seconds, but then to use those to convert to wall-clock time, you need a > historical table of when leap seconds occured,
There haven't been that many of them, so it's not a very big table.
> and you need to either > refuse to handle the farther future or admit you are needing to "Guess" > when those leap seconds will need to be applied.
There is a proposal to never add more leap seconds anyhow. They never did anyone any good. Astronomers don't use UTC anyway.
> Most uses of TAI time are for just short intervals without a need to > convert to wall clock.
Yes. But if you're going to implement a monotonic system, you may as well do it properly. Clifford Heath
On 1/10/22 04:55, Don Y wrote:
> On 9/30/2022 4:51 AM, Clifford Heath wrote: >> When I implmented this, I used a 64-bit counter in 100's of >> nanoseconds since a date about 6000BC, measuring in TAI. You can >> convert to UTC easily enough, and then use the timezone tables to get >> local times. > > How did you address calls for times during the Gregorian changeover?
You're asking a question about calendars, not time. Different problem.
> I find it easier to treat "system time" as an arbitrary metric > that runs at a nominal 1Hz per second and is never "reset".
...> Then, "wall time" is a bogus concept introduced just for human
> convenience.  Do you prevent a user (or an external reference) > from ever setting the wall time backwards?
That doesn't work for someone who's travelling between timezones. Time keeps advancing regardless, but wall clock time jumps about. Same problem for DST. Quite a lot of enterprise (financial) systems are barred from running any transaction processing for an hour during DST switch-over, because of software that might malfunction. Correctness is difficult, especially when you build systems on shifting sands. Clifford Heath.
On 9/30/2022 3:48 PM, Clifford Heath wrote:
> On 1/10/22 04:55, Don Y wrote: >> On 9/30/2022 4:51 AM, Clifford Heath wrote: >>> When I implmented this, I used a 64-bit counter in 100's of nanoseconds >>> since a date about 6000BC, measuring in TAI. You can convert to UTC easily >>> enough, and then use the timezone tables to get local times. >> >> How did you address calls for times during the Gregorian changeover? > > You're asking a question about calendars, not time. Different problem.
They are related as time is often interpreted relative to some *other* "bogus concept" (e.g., calendar) related to how humans want to frame time references.
>> I find it easier to treat "system time" as an arbitrary metric >> that runs at a nominal 1Hz per second and is never "reset". >> Then, "wall time" is a bogus concept introduced just for human >> convenience.  Do you prevent a user (or an external reference) >> from ever setting the wall time backwards? > > That doesn't work for someone who's travelling between timezones.
Or for someone who wants to change the current wall time. Note that these library functions were created when "only god" (sysadm) could change the current notion of time -- and didn't do so casually. Now, damn near ever device (c.a.EMBEDDED) allows the user to dick with the wall clock with impunity. Including intentionally setting the time incorrectly (e.g., folks who set their alarm clocks "5 minutes fast" thinking it will somehow trick them to getting out of bed promptly whereas the CORRECT time might not?) And, one can have a suite of devices in a single environment each with their own notion of "now".
> Time keeps advancing regardless, but wall clock time jumps about.
Because wall time has an ill-defined reference point -- that can often be changed, at will! E.g., we don't observer DST, here. So, the broadcast TV schedules are "off" by an hour. When something is advertised as airing at X mountain time (or pacific time), what does that really mean for us?
> Same problem for DST. Quite a lot of enterprise (financial) systems are barred > from running any transaction processing for an hour during DST switch-over, > because of software that might malfunction. > > Correctness is difficult, especially when you build systems on shifting sands.
The issue is considerably larger than many folks would think. Because there are a multitude of time references in most environments; what your phone claims, what your TV thinks, what your PC/time server thinks, how you've set the clock on your microwave, bedside alarm, etc. If you have two "systems" (appliances) interacting, which one's notion of time should you abide? How do you *report* a timestamp on an event that happened 5 minutes ago -- if the wall clock was set BACKWARDS by an hour in the intervening interval? Should the timestamp reflect a *future* time ("The event happen-ED 55 minutes *from* now")? Should it be adjusted to reflect the time at which it occurred relative to the current notion of wall time? How do you *order* events /ex post factum/ in the presence of such ambiguity? (i.e., I map everything, internally, to system time as that lets me KNOW their relative orders, regardless of what the "wall clock" said at the time.) If you've scheduled "something" to happen at 11:55 and the user sets the wall clock forward, an hour (perhaps accidentally), do you trigger that event (assuming the new "now" > 11:55) instantly? If you automatically clear "completed events", then setting the wall clock back to the "correct" time won't resurrect the 11:55 event at the originally intended "absolute time".
Il 30/09/2022 20:42, Don Y ha scritto:
> On 9/30/2022 2:29 AM, pozz wrote: >> Another bonus is when you have NTP, that returns seconds in UTC, so >> you can set your counter with the exact number retrived by NTP. > > No.  You always have to ensure that time keeps flowing in one direction. > > So, time either "doesn't exist" before your initial sync with the > time server (what if the server isn't available when you want to > do that?)
At startup, if NTP server is not available and I don't have any notion of "now", I start from a date in the past, i.e. 01/01/2020.
> *or* you have to look at your current notion of "now" > and ensure that the "real" value of now, when obtained from the > time server, is always in the future relative to your notion.
Actually I don't do that and I replace the timer counter with the value retrieved from NTP. What happens if the local timer is clocked by a faster clock then nominal? For example, 16.001MHz with 16M prescaler. If I try to NTP re-sync every 1-hour, it's probably the local counter is greater than the value retrieved from NTP. I'm forced to decrease the local counter, my notion of "now". What happens if the time doesn't flow in one direction only?
> [Note that NTP slaves don't blindly assume the current time is > as reported but *slew* to the new value, over some interval.] > > This also ignores the possibility of computations with relative > *intervals* being inconsistent with these spontaneous "resets". >
On 10/2/2022 3:09 PM, pozz wrote:
> Il 30/09/2022 20:42, Don Y ha scritto: >> On 9/30/2022 2:29 AM, pozz wrote: >>> Another bonus is when you have NTP, that returns seconds in UTC, so you can >>> set your counter with the exact number retrived by NTP. >> >> No.  You always have to ensure that time keeps flowing in one direction. >> >> So, time either "doesn't exist" before your initial sync with the >> time server (what if the server isn't available when you want to >> do that?) > > At startup, if NTP server is not available and I don't have any notion of > "now", I start from a date in the past, i.e. 01/01/2020.
Then you have to be able to accept a BIG skew in the time when the first update arrives. What if that takes an hour, a day or more (because the server is down, badly configured or incorrect routing)? What if it *never* arrives? If you apply the new time in a step function, then all of the potential time related events between ~1/1/2020 and "now" will appear to occur at the same instant -- *now* -- or, not at all. And, any time-related calculations will be grossly incorrect. start_time := now() dispenser(on) wait_until(start_time + interval) Imagine what will happen if the time is changed during this fragment. If the change adds >= interval to the local notion of now, then the dispenser will be "on" only momentarily. If it adds (0,interval), then it will be on for some period LESS than the "interval" intended. [I'm ignoring the possibility of it going BACKWARDS, for now] Note that wait_until() could have been expressed as delay(interval) and, depending on how this is internally implemented, it might be silently translated to a wait_until() and thus dependant on the actual value of now(). Likewise, imagine trying to measure the duration of an event: wait_until(event) start_time := now() wait_until(!event) duration = now() - start_time Similarly, any implied ordering of actions is vulnerable: do(THIS, time1) do(THAT, time2) What if the value of now() makes a jump from some time prior to time1 to some time after time1, but before time2. Will THIS happen? (i.e., will it be scheduled to happen?) How much ACTUAL (execution) time will there be between THIS being started and THAT? What if the value of now() makes a jump from some time prior to time1 to some time after time2. Will THIS happen before THAT? Will both start (be made ready) concurrently? Who will win the unintended race? [Note that many NTP clients won't "accept" a time declaration that is "too far" from the local notion of now. If you want to *set* the current time, you use something like ntpdate to impose a specific time regardless of how far that deviates from your own notion.]
>> *or* you have to look at your current notion of "now" >> and ensure that the "real" value of now, when obtained from the >> time server, is always in the future relative to your notion. > > Actually I don't do that and I replace the timer counter with the value > retrieved from NTP.
Then you run the risk that the local counter may have already surpassed the NTP "count" by, for example, N seconds. And, time now jerks backwards as the previous N seconds appear to be relived. Will you AGAIN do the task that was scheduled for "a few seconds ago"? (even though it has already been completed) Will you remember to ALSO do the task that expected to be done an hour before that -- if the "jerk back" wasn't a full hour? You likely wrote your code (or, your user scheduled events) on the assumption that there are roughly 60 seconds between any two "minutes", etc. And, that time1 precedes time2 by (time2 - time1) actual seconds.
> What happens if the local timer is clocked by a faster clock then nominal? For > example, 16.001MHz with 16M prescaler. > If I try to NTP re-sync every 1-hour, it's probably the local counter is > greater than the value retrieved from NTP. I'm forced to decrease the local > counter, my notion of "now".
No. You change the rate at which you run the local "clock" -- whatever timebase you are counting. So, if your jiffy was designed to happen at 100ms intervals (counted down from some XTAL reference by a divisor of MxN) and you now discover that your notion of 100 was actually 98.7 REAL ms (because your time has been noted as moving faster than the NTP reference), then you change the divisor used to generate the jiffy to something slightly larger to effectively slow the jiffy down to 100+ ms (the "+" being present to ensure the local time eventually slows enough so that "real" time falls into sync). This is an continuous process. (read the NTP sources and how the kernel implements "adjtime()")
> What happens if the time doesn't flow in one direction only?
Then everything that (implicitly) relies on time to be monotonic is hosed. Repeat the examples at the start of my post with the case of time jumping backwards and see what happens. What if time goes backwards enough to muck with some calculation or event sequence -- but, not far enough to cause the code that *schedules* those events to reflect the difference. What would you do if you saw entries in a log file: 12:01:07 start something 12:01:08 did whatever 12:01:15 did something else 12:01:04 finished up
>> [Note that NTP slaves don't blindly assume the current time is >> as reported but *slew* to the new value, over some interval.] >> >> This also ignores the possibility of computations with relative >> *intervals* being inconsistent with these spontaneous "resets".
It's important that the RATE of time passage is reasonably accurate and consistent (and monotonically increasing). But, the notion of the "time of day" is dubious and exists just as a convenience for humans to order events relative to the outside world (which uses wall clocks). How accurate is YOUR wall clock? Does it agree with your cell phone's notion of now? The alarm clock in your bedroom? Your neighbor's timepiece when he comes to visit? etc.
NTP has solved this question, just get publications of prof. Mills.

There is a short description in Wikipedia article on NTP.

-- 

-TV


On 3.10.22 1.09, pozz wrote:
> Il 30/09/2022 20:42, Don Y ha scritto: >> On 9/30/2022 2:29 AM, pozz wrote: >>> Another bonus is when you have NTP, that returns seconds in UTC, so >>> you can set your counter with the exact number retrived by NTP. >> >> No.  You always have to ensure that time keeps flowing in one direction. >> >> So, time either "doesn't exist" before your initial sync with the >> time server (what if the server isn't available when you want to >> do that?) > > At startup, if NTP server is not available and I don't have any notion > of "now", I start from a date in the past, i.e. 01/01/2020. > > >> *or* you have to look at your current notion of "now" >> and ensure that the "real" value of now, when obtained from the >> time server, is always in the future relative to your notion. > > Actually I don't do that and I replace the timer counter with the value > retrieved from NTP. > What happens if the local timer is clocked by a faster clock then > nominal? For example, 16.001MHz with 16M prescaler. > If I try to NTP re-sync every 1-hour, it's probably the local counter is > greater than the value retrieved from NTP. I'm forced to decrease the > local counter, my notion of "now". > > What happens if the time doesn't flow in one direction only? > > >> [Note that NTP slaves don't blindly assume the current time is >> as reported but *slew* to the new value, over some interval.] >> >> This also ignores the possibility of computations with relative >> *intervals* being inconsistent with these spontaneous "resets". >> > >
Eventualli I had some free time to read this interesting post and reply.

Il 03/10/2022 04:02, Don Y ha scritto:
> On 10/2/2022 3:09 PM, pozz wrote: >> Il 30/09/2022 20:42, Don Y ha scritto: >>> On 9/30/2022 2:29 AM, pozz wrote: >>>> Another bonus is when you have NTP, that returns seconds in UTC, so >>>> you can set your counter with the exact number retrived by NTP. >>> >>> No.  You always have to ensure that time keeps flowing in one direction. >>> >>> So, time either "doesn't exist" before your initial sync with the >>> time server (what if the server isn't available when you want to >>> do that?) >> >> At startup, if NTP server is not available and I don't have any notion >> of "now", I start from a date in the past, i.e. 01/01/2020. > > Then you have to be able to accept a BIG skew in the time when the first > update arrives.  What if that takes an hour, a day or more (because the > server is down, badly configured or incorrect routing)?   What if it > *never* arrives?
Certainly there's an exception at startup. When the *first* NTP response received, the code should accept a BIG shock of the current notion of now (that could be undefined or 2020 or another epoch until now). I read that ntpd accepts -g command line option that enable one (and only one) big difference between current system notion of now and "NTP now". I admit that this could lead to odd behaviours as you explained. IMHO however there aren't many solutions at startup, mainly if the embedded device should be autonomous and can't accept suggestions from the user. One is to suspend, at startup, all the device activites until a "fresh now" is received from NTP server. After that, the normal tasks are started. As you noted, this could introduce a delay (even a BIG delay, depending on Internet connection and NTP servers) between the power on and the start of tasks. I think this isn't compatible with many applications. Another solution is to fix the code in such a way it correctly faces the situation of a big afterward or backward step in the "now" counter. The code I'm thinking of is not the one that manages normal timers that can depend on a local reference (XTAL, ceramic resonator, ...) completely independent from calendar counter. Most of the time, the precision of timers isn't strict and intervals are short: we need to activate a relay for 3 seconds (but nothing happens if it is activated for 3.01 seconds) or we need to generate a pulse on an output of 100ms (but no problem if it is 98ms). This means having a main counter clocked at 10ms (or whatever) from a local clock of 100Hz (or whatever). This counter isn't corrected with NTP. The only code that must be fixed is the one that manages events that must occurs at specific calendar times (at 12 o'clock of 1st January, at 8:30 of everyday, and so on). So you should have *another* counter clocked at 1Hz (or 10Hz or 100Hz) that is adjusted by NTP. And abrupt changes should be taken into account (event if I don't know how).
> If you apply the new time in a step function, then all of the potential > time related events between ~1/1/2020 and "now" will appear to occur > at the same instant -- *now* -- or, not at all.  And, any time-related > calculations will be grossly incorrect. > >     start_time := now() >     dispenser(on) >     wait_until(start_time + interval) > > Imagine what will happen if the time is changed during this fragment. > If the change adds >= interval to the local notion of now, then the > dispenser will be "on" only momentarily.  If it adds (0,interval), > then it will be on for some period LESS than the "interval" intended. > > [I'm ignoring the possibility of it going BACKWARDS, for now] > > Note that wait_until() could have been expressed as delay(interval) > and, depending on how this is internally implemented, it might be > silently translated to a wait_until() and thus dependant on the > actual value of now().
Good point. As I wrote before, events that aren't strictly related to wall clock shouldn't be coded with functions() that use now(). If the code that makes a 100ms pulse at an output uses now(), it is wrong and must be corrected.
> Likewise, imagine trying to measure the duration of an event: > >     wait_until(event) >     start_time := now() >     wait_until(!event) >     duration = now() - start_time
Same thing. Instead of using now(), that returns "calendar seconds" related to NTP, this code should returns ticks or jiffies that are related only to local reference.
> Similarly, any implied ordering of actions is vulnerable: > >     do(THIS, time1) >     do(THAT, time2) > > What if the value of now() makes a jump from some time prior to > time1 to some time after time1, but before time2.  Will THIS happen? > (i.e., will it be scheduled to happen?)  How much ACTUAL (execution) > time will there be between THIS being started and THAT? > > What if the value of now() makes a jump from some time prior to > time1 to some time after time2.  Will THIS happen before THAT? > Will both start (be made ready) concurrently?  Who will win the > unintended race? > > [Note that many NTP clients won't "accept" a time declaration that is > "too far" from the local notion of now.  If you want to *set* the > current time, you use something like ntpdate to impose a specific time > regardless of how far that deviates from your own notion.
If you implement in this way: void do(action_fn fn, uint32_t delay_ms) { timer_add(delay_ms, fn); } and timer_add() uses the counter that is clocked *only* from local reference, no problem occurs. Some problems could occur when time1 and time2 are calendar times. One solution could be to have one module that manages calendar events with the following interface: cevent_hdl_t cevent_add(time_t time, cevent_fn fn, void *arg); void cevents_do(time_t now); Every second cevents_do() is called with the new calendar time (seconds from an epoch). void cevents_do(time_t now) { static time_t old_now; if (now != old_now + 1) { /* There's a discontinuity in now. What can we do? * - Remove expired events without calling callback * - Remove expired events and call callback for each of them * I think the choice is application dependent */ } /* Process the first elements of FIFO queue (that is sorted) */ cevent_s *ev; while((ev = cevents_queue_peek())->time == now) { ev->fn(ev->arg); cevents_queue_pop(); } old_now = now; }
>>> *or* you have to look at your current notion of "now" >>> and ensure that the "real" value of now, when obtained from the >>> time server, is always in the future relative to your notion. >> >> Actually I don't do that and I replace the timer counter with the >> value retrieved from NTP. > > Then you run the risk that the local counter may have already surpassed > the NTP "count" by, for example, N seconds.  And, time now jerks backwards > as the previous N seconds appear to be relived. > > Will you AGAIN do the task that was scheduled for "a few seconds ago"? > (even though it has already been completed)  Will you remember to ALSO > do the task that expected to be done an hour before that -- if the "jerk > back" wasn't a full hour?
Good questions. You could try to implement a complex calendar time system in your device, one that mimics full featured OS. I mean the counter that tracks "now" (seconds or milliseconds from an epoch) isn't changed abruptly, but its reference is slowed down or accelerated. You should have an hw that supports this. Many processors have timers that can be used as counters, but their clock reference is limited to a prescaled main clock and the prescaler value is usually an integer, maybe only one from a limited set of values (1, 2, 4, 8, 32, 64, 256). Anyway, even if you are so smart to implement this in a correct way, you have to solve the "startup issue". What happens if the first NTP response arrived after 5 minutes from startup and your notion of now at startup is completely useless (i.e., no battery is present)? Maybe during initialization code you already added some calendar events.
> You likely wrote your code (or, your user scheduled events) on the > assumption > that there are roughly 60 seconds between any two "minutes", etc.  And, > that > time1 precedes time2 by (time2 - time1) actual seconds. > >> What happens if the local timer is clocked by a faster clock then >> nominal? For example, 16.001MHz with 16M prescaler. >> If I try to NTP re-sync every 1-hour, it's probably the local counter >> is greater than the value retrieved from NTP. I'm forced to decrease >> the local counter, my notion of "now". > > No.  You change the rate at which you run the local "clock" -- whatever > timebase you are counting.  So, if your jiffy was designed to happen at > 100ms intervals (counted down from some XTAL reference by a divisor of > MxN) and you now discover that your notion of 100 was actually 98.7 REAL ms > (because your time has been noted as moving faster than the NTP reference), > then you change the divisor used to generate the jiffy to something > slightly larger to effectively slow the jiffy down to 100+ ms (the "+" > being present > to ensure the local time eventually slows enough so that "real" time > falls into sync). > > This is an continuous process.  (read the NTP sources and how the kernel > implements "adjtime()")
I got the point, but IMHO is not so simple to implement this in a correct way and anyway you have the "startup issue".
>> What happens if the time doesn't flow in one direction only? > > Then everything that (implicitly) relies on time to be monotonic is > hosed. > > Repeat the examples at the start of my post with the case of time > jumping backwards and see what happens. > > What if time goes backwards enough to muck with some calculation > or event sequence -- but, not far enough to cause the code that > *schedules* those events to reflect the difference. > > What would you do if you saw entries in a log file: > > 12:01:07  start something > 12:01:08  did whatever > 12:01:15  did something else > 12:01:04  finished up
In a real world, could this happen? Except at startup, the seconds reported from NTP should be very similar to "local seconds" that is clocked from local reference. I didn't make any test, but I expect offsets measured by NTP are well below 1s in normal situations. The worst case should be: 12:01:07 start something 12:01:08 did whatever 12:01:15 did something else 12:01:14 finished up I admit it's not very good.
>>> [Note that NTP slaves don't blindly assume the current time is >>> as reported but *slew* to the new value, over some interval.] >>> >>> This also ignores the possibility of computations with relative >>> *intervals* being inconsistent with these spontaneous "resets". > > It's important that the RATE of time passage is reasonably accurate > and consistent (and monotonically increasing).  But, the notion of > the "time of day" is dubious and exists just as a convenience for > humans to order events relative to the outside world (which uses > wall clocks).  How accurate is YOUR wall clock?  Does it agree > with your cell phone's notion of now?  The alarm clock in your > bedroom?  Your neighbor's timepiece when he comes to visit?  etc. >
On 12/30/2022 9:08 AM, pozz wrote:
>>> At startup, if NTP server is not available and I don't have any notion of >>> "now", I start from a date in the past, i.e. 01/01/2020. >> >> Then you have to be able to accept a BIG skew in the time when the first >> update arrives.  What if that takes an hour, a day or more (because the >> server is down, badly configured or incorrect routing)?   What if it >> *never* arrives? > > Certainly there's an exception at startup. When the *first* NTP response > received, the code should accept a BIG shock of the current notion of now (that > could be undefined or 2020 or another epoch until now). > I read that ntpd accepts -g command line option that enable one (and only one) > big difference between current system notion of now and "NTP now".
Yes. But, your system design still has to "make sense" if it NEVER gets told the current time.
> I admit that this could lead to odd behaviours as you explained. IMHO however > there aren't many solutions at startup, mainly if the embedded device should be > autonomous and can't accept suggestions from the user.
Note that "wall/calendar time" is strictly a user convenience. A device need only deal with it if it has to interact with a world in which the user relates to temporal events using some external timepiece -- which may actually be inaccurate! But, your device can always have its own notion of time that monotonically increases -- even if the rate of time that it increases isn't entirely accurate wrt "real units" (i.e., if YOUR second is 1.001 REAL seconds, that's likely not too important) So, if you can postpone binding YOUR "system time" (counting jiffies) to "wall time", then the problem is postponed. E.g., I deal with events as referenced to *my* timebase (bogounits): 00000006 system initialized 00001003 network on-line 00001100 accepting requests 00020348 request from 10.0.1.88 00020499 reply to 10.0.1.88 issued ... Eventually, there will be an entry: XXXXXXXX NTPclient receives update (12:42:00.444) At this point, you can retroactively update the times in the "log" with "real" times, relative to the time delivered to the NTP client. (or, leave the log in bogounits and not worry about it) The real problem comes when <someone> wants <something> to happen at some *specific* wall time -- and, you don't yet know what the current wall time happens to be! If that will be guaranteed to be sufficiently far in the future that you (think!) the actual wall time will be known to you, then you can just cross your fingers and wait to sort out "when" that will be.
> One is to suspend, at startup, all the device activites until a "fresh now" is > received from NTP server. After that, the normal tasks are started. As you > noted, this could introduce a delay (even a BIG delay, depending on Internet > connection and NTP servers) between the power on and the start of tasks. I > think this isn't compatible with many applications. > > Another solution is to fix the code in such a way it correctly faces the > situation of a big afterward or backward step in the "now" counter.
You're better off picking a time you KNOW to be in the past so that any adjustments continue to run time *forwards*. We inherently think of A happening after B implying that time(A) > time(B). It's so fundamental that you likely don't even notice these dependencies in your code/algorithms.
> The code I'm thinking of is not the one that manages normal timers that can > depend on a local reference (XTAL, ceramic resonator, ...) completely > independent from calendar counter. Most of the time, the precision of timers > isn't strict and intervals are short: we need to activate a relay for 3 seconds > (but nothing happens if it is activated for 3.01 seconds) or we need to > generate a pulse on an output of 100ms (but no problem if it is 98ms). > This means having a main counter clocked at 10ms (or whatever) from a local > clock of 100Hz (or whatever). This counter isn't corrected with NTP. > The only code that must be fixed is the one that manages events that must > occurs at specific calendar times (at 12 o'clock of 1st January, at 8:30 of > everyday, and so on). So you should have *another* counter clocked at 1Hz (or > 10Hz or 100Hz) that is adjusted by NTP. And abrupt changes should be taken into > account (event if I don't know how).
You can use NTP to discipline the local oscillator so that times measured from it are "more accurate". This, regardless of whether or not the local time tracks the wall time.
>> If you apply the new time in a step function, then all of the potential >> time related events between ~1/1/2020 and "now" will appear to occur >> at the same instant -- *now* -- or, not at all.&nbsp; And, any time-related >> calculations will be grossly incorrect. >> >> &nbsp;&nbsp;&nbsp;&nbsp; start_time := now() >> &nbsp;&nbsp;&nbsp;&nbsp; dispenser(on) >> &nbsp;&nbsp;&nbsp;&nbsp; wait_until(start_time + interval) >> >> Imagine what will happen if the time is changed during this fragment. >> If the change adds >= interval to the local notion of now, then the >> dispenser will be "on" only momentarily.&nbsp; If it adds (0,interval), >> then it will be on for some period LESS than the "interval" intended. >> >> [I'm ignoring the possibility of it going BACKWARDS, for now] >> >> Note that wait_until() could have been expressed as delay(interval) >> and, depending on how this is internally implemented, it might be >> silently translated to a wait_until() and thus dependant on the >> actual value of now(). > > Good point. As I wrote before, events that aren't strictly related to wall > clock shouldn't be coded with functions() that use now(). If the code that > makes a 100ms pulse at an output uses now(), it is wrong and must be corrected.
Time should always be treated "fuzzily". So, if (now() == CONSTANT) may NEVER be satisfied! E.g., if the code runs at time CONSTANT+1, then you can know that it's never going to meet that condition (imagine it in a wait_till loop) If, instead, you assume that something may delay that statement from being executed *prior* to CONSTANT, you may, instead, want to code it as "if (now() >= CONSTANT)" to ensure it gets executed. (and, if you only want it to be executed ONCE, then take steps to note when you *have* executed it so you don't execute it again) For example, my system is real-time so every action has an associated deadline. But, it is entirely possible that some actions will be blocked until long after their deadlines have expired. Checking for "now() == deadline" would lead to erroneous behavior; the time between deadline and now() effectively doesn't exist, from the perspective of the action in question. So, the deadline handler should be invoked for ANY now() >= deadline.
>> Similarly, any implied ordering of actions is vulnerable: >> >> &nbsp;&nbsp;&nbsp;&nbsp; do(THIS, time1) >> &nbsp;&nbsp;&nbsp;&nbsp; do(THAT, time2) >> >> What if the value of now() makes a jump from some time prior to >> time1 to some time after time1, but before time2.&nbsp; Will THIS happen? >> (i.e., will it be scheduled to happen?)&nbsp; How much ACTUAL (execution) >> time will there be between THIS being started and THAT? >> >> What if the value of now() makes a jump from some time prior to >> time1 to some time after time2.&nbsp; Will THIS happen before THAT? >> Will both start (be made ready) concurrently?&nbsp; Who will win the >> unintended race? >> >> [Note that many NTP clients won't "accept" a time declaration that is >> "too far" from the local notion of now.&nbsp; If you want to *set* the >> current time, you use something like ntpdate to impose a specific time >> regardless of how far that deviates from your own notion. > If you implement in this way: > > void do(action_fn fn, uint32_t delay_ms) { > &nbsp; timer_add(delay_ms, fn); > } > > and timer_add() uses the counter that is clocked *only* from local reference, > no problem occurs. > > Some problems could occur when time1 and time2 are calendar times. One solution > could be to have one module that manages calendar events with the following > interface: > > &nbsp; cevent_hdl_t cevent_add(time_t time, cevent_fn fn, void *arg); > &nbsp; void cevents_do(time_t now); > > Every second cevents_do() is called with the new calendar time (seconds from an > epoch).
What if a "second" is skipped (because some higher priority activity was using the processor)?
> void cevents_do(time_t now) { > &nbsp; static time_t old_now; > &nbsp; if (now != old_now + 1) { > &nbsp;&nbsp;&nbsp; /* There's a discontinuity in now. What can we do? > &nbsp;&nbsp;&nbsp;&nbsp; * - Remove expired events without calling callback > &nbsp;&nbsp;&nbsp;&nbsp; * - Remove expired events and call callback for each of them > &nbsp;&nbsp;&nbsp;&nbsp; * I think the choice is application dependent */ > &nbsp; } > &nbsp; /* Process the first elements of FIFO queue (that is sorted) */ > &nbsp; cevent_s *ev; > &nbsp; while((ev = cevents_queue_peek())->time == now) { > &nbsp;&nbsp;&nbsp; ev->fn(ev->arg); > &nbsp;&nbsp;&nbsp; cevents_queue_pop(); > &nbsp; } > &nbsp; old_now = now; > }
You have to figure out how to generalize this FOR YOUR APPLICATION. Some things may not be important enough to waste effort on; others may be considerably more sensitive.
>>>> *or* you have to look at your current notion of "now" >>>> and ensure that the "real" value of now, when obtained from the >>>> time server, is always in the future relative to your notion. >>> >>> Actually I don't do that and I replace the timer counter with the value >>> retrieved from NTP. >> >> Then you run the risk that the local counter may have already surpassed >> the NTP "count" by, for example, N seconds.&nbsp; And, time now jerks backwards >> as the previous N seconds appear to be relived. >> >> Will you AGAIN do the task that was scheduled for "a few seconds ago"? >> (even though it has already been completed)&nbsp; Will you remember to ALSO >> do the task that expected to be done an hour before that -- if the "jerk >> back" wasn't a full hour? > > Good questions. You could try to implement a complex calendar time system in > your device, one that mimics full featured OS. I mean the counter that tracks > "now" (seconds or milliseconds from an epoch) isn't changed abruptly, but its > reference is slowed down or accelerated.
If you ensure time always moves forward, most of these issues are easy to resolve. You *know* you haven't done things scheduled for t > now().
> You should have an hw that supports this. Many processors have timers that can > be used as counters, but their clock reference is limited to a prescaled main > clock and the prescaler value is usually an integer, maybe only one from a > limited set of values (1, 2, 4, 8, 32, 64, 256).
You can dither the timebase so the average rate tracks your intent.
> Anyway, even if you are so smart to implement this in a correct way, you have > to solve the "startup issue". What happens if the first NTP response arrived > after 5 minutes from startup and your notion of now at startup is completely > useless (i.e., no battery is present)? > Maybe during initialization code you already added some calendar events.
So, those may *never* get executed -- if the NTP server never replies OR if you've coded for "time == now()". Or, may get executed (much) later than intended (e.g., if the NTP server tells you it is 6:00, now, and you had something scheduled for 5:00...)
>>> What happens if the time doesn't flow in one direction only? >> >> Then everything that (implicitly) relies on time to be monotonic is >> hosed. >> >> Repeat the examples at the start of my post with the case of time >> jumping backwards and see what happens. >> >> What if time goes backwards enough to muck with some calculation >> or event sequence -- but, not far enough to cause the code that >> *schedules* those events to reflect the difference. >> >> What would you do if you saw entries in a log file: >> >> 12:01:07&nbsp; start something >> 12:01:08&nbsp; did whatever >> 12:01:15&nbsp; did something else >> 12:01:04&nbsp; finished up > > In a real world, could this happen?
In a multithreaded application, of course it can! task0() { spawn(task1); log("finished up"); } task1() { log("start something"); ... log("did whatever"); log("did something else") } Assume log() prepends a timestamp to the message emitted. Assume task1 is lower priority than task0. It is spawned by task0 but doesn't get a chance to execute until after task0 has already printed its final message and quit. If multiple processors/nodes are involved, then the uncertainty between their individual clocks further complicates this. And, of course, what do you do if <something> deliberately introduces a delta to the current time? Imagine Bob wants to set an alarm for a meeting at 5:00PM. He then changes the current time to one hour later -- presumably because he noticed that the clock was incorrect. Does that mean the meeting will be one hour *sooner* than it would appear to have been, previously? What if he notices the date is off and it's really "tomorrow" and advances the date by one day. Should the alarm be canceled as the appointed time has already passed? Or, should the date component of the alarm time be similarly advanced? And, what will *Bob* think the correct answers to these questions should be? Will he be pissed because the alarm didn't go off when he *expected* it? Or, pissed because the alarm went off even though the meeting was YESTERDAY?
> Except at startup, the seconds reported > from NTP should be very similar to "local seconds" that is clocked from local > reference. I didn't make any test, but I expect offsets measured by NTP are > well below 1s in normal situations. The worst case should be: > > 12:01:07&nbsp; start something > 12:01:08&nbsp; did whatever > 12:01:15&nbsp; did something else > 12:01:14&nbsp; finished up > > I admit it's not very good. > >>>> [Note that NTP slaves don't blindly assume the current time is >>>> as reported but *slew* to the new value, over some interval.] >>>> >>>> This also ignores the possibility of computations with relative >>>> *intervals* being inconsistent with these spontaneous "resets". >> >> It's important that the RATE of time passage is reasonably accurate >> and consistent (and monotonically increasing).&nbsp; But, the notion of >> the "time of day" is dubious and exists just as a convenience for >> humans to order events relative to the outside world (which uses >> wall clocks).&nbsp; How accurate is YOUR wall clock?&nbsp; Does it agree >> with your cell phone's notion of now?&nbsp; The alarm clock in your >> bedroom?&nbsp; Your neighbor's timepiece when he comes to visit?&nbsp; etc.
Il 31/12/2022 01:35, Don Y ha scritto:
> On 12/30/2022 9:08 AM, pozz wrote: >>>> At startup, if NTP server is not available and I don't have any >>>> notion of "now", I start from a date in the past, i.e. 01/01/2020. >>> >>> Then you have to be able to accept a BIG skew in the time when the first >>> update arrives.&nbsp; What if that takes an hour, a day or more (because the >>> server is down, badly configured or incorrect routing)?&nbsp;&nbsp; What if it >>> *never* arrives? >> >> Certainly there's an exception at startup. When the *first* NTP >> response received, the code should accept a BIG shock of the current >> notion of now (that could be undefined or 2020 or another epoch until >> now). >> I read that ntpd accepts -g command line option that enable one (and >> only one) big difference between current system notion of now and "NTP >> now". > > Yes.&nbsp; But, your system design still has to "make sense" if it NEVER gets > told the current time.
Yes, the only solution that comes to my mind is to have a startup calendar time, such as 01/01/2023 00:00:00. Until a new time is received from NTP, that is the calendar time that the system will use. Of course, with this wrong "now", any event that is related to a calendar time would fail.
>> I admit that this could lead to odd behaviours as you explained. IMHO >> however there aren't many solutions at startup, mainly if the embedded >> device should be autonomous and can't accept suggestions from the user. > > Note that "wall/calendar time" is strictly a user convenience.&nbsp; A device > need only deal with it if it has to interact with a world in which the > user relates to temporal events using some external timepiece -- which > may actually be inaccurate!
Yes, of course. At the contrary, NTP is useless at all.
> But, your device can always have its own notion of time that monotonically > increases -- even if the rate of time that it increases isn't entirely > accurate wrt "real units" (i.e., if YOUR second is 1.001 REAL seconds, > that's likely not too important) > > So, if you can postpone binding YOUR "system time" (counting jiffies) > to "wall time", then the problem is postponed. > > E.g., I deal with events as referenced to *my* timebase (bogounits): > &nbsp; 00000006 system initialized > &nbsp; 00001003 network on-line > &nbsp; 00001100 accepting requests > &nbsp; 00020348 request from 10.0.1.88 > &nbsp; 00020499 reply to 10.0.1.88 issued > &nbsp; ... > Eventually, there will be an entry: > &nbsp; XXXXXXXX NTPclient receives update (12:42:00.444) > > At this point, you can retroactively update the times in the "log" with > "real" times, relative to the time delivered to the NTP client. > (or, leave the log in bogounits and not worry about it)
Yes, a log with timestamps can be managed in these ways.
> The real problem comes when <someone> wants <something> to happen at > some *specific* wall time -- and, you don't yet know what the current > wall time happens to be! > > If that will be guaranteed to be sufficiently far in the future that > you (think!) the actual wall time will be known to you, then you > can just cross your fingers and wait to sort out "when" that will be.
Yes.
>> One is to suspend, at startup, all the device activites until a "fresh >> now" is received from NTP server. After that, the normal tasks are >> started. As you noted, this could introduce a delay (even a BIG delay, >> depending on Internet connection and NTP servers) between the power on >> and the start of tasks. I think this isn't compatible with many >> applications. >> >> Another solution is to fix the code in such a way it correctly faces >> the situation of a big afterward or backward step in the "now" counter. > > You're better off picking a time you KNOW to be in the past so that > any adjustments continue to run time *forwards*.&nbsp; We inherently think > of A happening after B implying that time(A) > time(B).&nbsp; It's so > fundamental that you likely don't even notice these dependencies in > your code/algorithms. > >> The code I'm thinking of is not the one that manages normal timers >> that can depend on a local reference (XTAL, ceramic resonator, ...) >> completely independent from calendar counter. Most of the time, the >> precision of timers isn't strict and intervals are short: we need to >> activate a relay for 3 seconds (but nothing happens if it is activated >> for 3.01 seconds) or we need to generate a pulse on an output of 100ms >> (but no problem if it is 98ms). >> This means having a main counter clocked at 10ms (or whatever) from a >> local clock of 100Hz (or whatever). This counter isn't corrected with >> NTP. >> The only code that must be fixed is the one that manages events that >> must occurs at specific calendar times (at 12 o'clock of 1st January, >> at 8:30 of everyday, and so on). So you should have *another* counter >> clocked at 1Hz (or 10Hz or 100Hz) that is adjusted by NTP. And abrupt >> changes should be taken into account (event if I don't know how). > > You can use NTP to discipline the local oscillator so that times > measured from it are "more accurate".&nbsp; This, regardless of whether > or not the local time tracks the wall time.
Yes, but I don't remember an application I worked on that didn't track the wall time and, at the same time, needed a greater precision than the local oscillator.
>>> If you apply the new time in a step function, then all of the potential >>> time related events between ~1/1/2020 and "now" will appear to occur >>> at the same instant -- *now* -- or, not at all.&nbsp; And, any time-related >>> calculations will be grossly incorrect. >>> >>> &nbsp;&nbsp;&nbsp;&nbsp; start_time := now() >>> &nbsp;&nbsp;&nbsp;&nbsp; dispenser(on) >>> &nbsp;&nbsp;&nbsp;&nbsp; wait_until(start_time + interval) >>> >>> Imagine what will happen if the time is changed during this fragment. >>> If the change adds >= interval to the local notion of now, then the >>> dispenser will be "on" only momentarily.&nbsp; If it adds (0,interval), >>> then it will be on for some period LESS than the "interval" intended. >>> >>> [I'm ignoring the possibility of it going BACKWARDS, for now] >>> >>> Note that wait_until() could have been expressed as delay(interval) >>> and, depending on how this is internally implemented, it might be >>> silently translated to a wait_until() and thus dependant on the >>> actual value of now(). >> >> Good point. As I wrote before, events that aren't strictly related to >> wall clock shouldn't be coded with functions() that use now(). If the >> code that makes a 100ms pulse at an output uses now(), it is wrong and >> must be corrected. > > Time should always be treated "fuzzily". > > So, if (now() == CONSTANT) may NEVER be satisfied! E.g., if the code > runs at time CONSTANT+1, then you can know that it's never going to > meet that condition (imagine it in a wait_till loop) > > If, instead, you assume that something may delay that statement from > being executed *prior* to CONSTANT, you may, instead, want to > code it as "if (now() >= CONSTANT)" to ensure it gets executed. > (and, if you only want it to be executed ONCE, then take steps to > note when you *have* executed it so you don't execute it again) > > For example, my system is real-time so every action has an > associated deadline. But, it is entirely possible that some > actions will be blocked until long after their deadlines > have expired. Checking for "now() == deadline" would lead > to erroneous behavior; the time between deadline and now() > effectively doesn't exist, from the perspective of the > action in question. So, the deadline handler should be > invoked for ANY now() >= deadline.
Suppose you have some alarms scheduled weekly, for example at 8:00:00 every Monday and at 9:00:00 every Saturday. In the week you have 604'800 seconds. 8:00 on Monday is at 28'800 seconds from the beginning of the week (I'm considering Monday as the first day of the week). 9:00 on Saturday is at 194'400 secs. If the alarms manager is called exactly one time each second, it should be very simple to understand if we are on time for an alarm: if (now_weekly_secs == 28800) fire_alarm(ALARM1); if (now_weekly_secs == 194400) fire_alarm(ALARM2); Note the equality test. With disequality you can't use this: if (now_weekly_secs > 28800) fire_alarm(ALARM1); if (now_weekly_secs > 194400) fire_alarm(ALARM2); otherwise alarms will occur countinuously after the deadline. You should tag the alarm as occured for the current week to avoid firing it again at the next call. Is it so difficult to *guarantee* calling alarms_manager(weekly_secs) every second?
>>> Similarly, any implied ordering of actions is vulnerable: >>> >>> do(THIS, time1) >>> do(THAT, time2) >>> >>> What if the value of now() makes a jump from some time prior to >>> time1 to some time after time1, but before time2. Will THIS happen? >>> (i.e., will it be scheduled to happen?) How much ACTUAL (execution) >>> time will there be between THIS being started and THAT? >>> >>> What if the value of now() makes a jump from some time prior to >>> time1 to some time after time2. Will THIS happen before THAT? >>> Will both start (be made ready) concurrently? Who will win the >>> unintended race? >>> >>> [Note that many NTP clients won't "accept" a time declaration that is >>> "too far" from the local notion of now. If you want to *set* the >>> current time, you use something like ntpdate to impose a specific time >>> regardless of how far that deviates from your own notion. >> If you implement in this way: >> >> void do(action_fn fn, uint32_t delay_ms) { >> timer_add(delay_ms, fn); >> } >> >> and timer_add() uses the counter that is clocked *only* from local >> reference, no problem occurs. >> >> Some problems could occur when time1 and time2 are calendar times. One >> solution could be to have one module that manages calendar events with >> the following interface: >> >> cevent_hdl_t cevent_add(time_t time, cevent_fn fn, void *arg); >> void cevents_do(time_t now); >> >> Every second cevents_do() is called with the new calendar time >> (seconds from an epoch). > > What if a "second" is skipped (because some higher priority activity > was using the processor)?
A second is a very long interval. It's difficult to think of a system that isn't able to satisfy programmatically a deadline of a second.
>> void cevents_do(time_t now) { >> static time_t old_now; >> if (now != old_now + 1) { >> /* There's a discontinuity in now. What can we do? >> * - Remove expired events without calling callback >> * - Remove expired events and call callback for each of them >> * I think the choice is application dependent */ >> } >> /* Process the first elements of FIFO queue (that is sorted) */ >> cevent_s *ev; >> while((ev = cevents_queue_peek())->time == now) { >> ev->fn(ev->arg); >> cevents_queue_pop(); >> } >> old_now = now; >> } > > You have to figure out how to generalize this FOR YOUR APPLICATION. > > Some things may not be important enough to waste effort on; > others may be considerably more sensitive. > >>>>> *or* you have to look at your current notion of "now" >>>>> and ensure that the "real" value of now, when obtained from the >>>>> time server, is always in the future relative to your notion. >>>> >>>> Actually I don't do that and I replace the timer counter with the >>>> value retrieved from NTP. >>> >>> Then you run the risk that the local counter may have already surpassed >>> the NTP "count" by, for example, N seconds. And, time now jerks >>> backwards >>> as the previous N seconds appear to be relived. >>> >>> Will you AGAIN do the task that was scheduled for "a few seconds ago"? >>> (even though it has already been completed) Will you remember to ALSO >>> do the task that expected to be done an hour before that -- if the "jerk >>> back" wasn't a full hour? >> >> Good questions. You could try to implement a complex calendar time >> system in your device, one that mimics full featured OS. I mean the >> counter that tracks "now" (seconds or milliseconds from an epoch) >> isn't changed abruptly, but its reference is slowed down or accelerated. > > If you ensure time always moves forward, most of these issues are > easy to resolve. You *know* you haven't done things scheduled for > t > now(). > >> You should have an hw that supports this. Many processors have timers >> that can be used as counters, but their clock reference is limited to >> a prescaled main clock and the prescaler value is usually an integer, >> maybe only one from a limited set of values (1, 2, 4, 8, 32, 64, 256). > > You can dither the timebase so the average rate tracks your intent.
Simple to write.
>> Anyway, even if you are so smart to implement this in a correct way, >> you have to solve the "startup issue". What happens if the first NTP >> response arrived after 5 minutes from startup and your notion of now >> at startup is completely useless (i.e., no battery is present)? >> Maybe during initialization code you already added some calendar events. > > So, those may *never* get executed -- if the NTP server never replies OR > if you've coded for "time == now()". Or, may get executed (much) later > than intended (e.g., if the NTP server tells you it is 6:00, now, and > you had something scheduled for 5:00...) > >>>> What happens if the time doesn't flow in one direction only? >>> >>> Then everything that (implicitly) relies on time to be monotonic is >>> hosed. >>> >>> Repeat the examples at the start of my post with the case of time >>> jumping backwards and see what happens. >>> >>> What if time goes backwards enough to muck with some calculation >>> or event sequence -- but, not far enough to cause the code that >>> *schedules* those events to reflect the difference. >>> >>> What would you do if you saw entries in a log file: >>> >>> 12:01:07 start something >>> 12:01:08 did whatever >>> 12:01:15 did something else >>> 12:01:04 finished up >> >> In a real world, could this happen? > > In a multithreaded application, of course it can! > > task0() { > spawn(task1); > log("finished up"); > } > > task1() { > log("start something"); > ... > log("did whatever"); > log("did something else") > } > > Assume log() prepends a timestamp to the message emitted. > Assume task1 is lower priority than task0. It is spawned by > task0 but doesn't get a chance to execute until after > task0 has already printed its final message and quit. > > If multiple processors/nodes are involved, then the uncertainty > between their individual clocks further complicates this. > > And, of course, what do you do if <something> deliberately > introduces a delta to the current time? > > Imagine Bob wants to set an alarm for a meeting at 5:00PM. > He then changes the current time to one hour later -- presumably > because he noticed that the clock was incorrect. Does that > mean the meeting will be one hour *sooner* than it would > appear to have been, previously?
No. The meeting is always at 5:00PM.
> What if he notices the date is off and it's really "tomorrow" > and advances the date by one day. Should the alarm be > canceled as the appointed time has already passed? Or, > should the date component of the alarm time be similarly > advanced?
IMHO if the user set a time using the wall clock convention (shut the door at 8:00PM every afternoon), it shouldn't be changed when the calendar time used by the system is adjusted. Anyway this should be application dependent.
> And, what will *Bob* think the correct answers to these > questions should be? Will he be pissed because the alarm > didn't go off when he *expected* it? Or, pissed because the > alarm went off even though the meeting was YESTERDAY? > >> Except at startup, the seconds reported from NTP should be very >> similar to "local seconds" that is clocked from local reference. I >> didn't make any test, but I expect offsets measured by NTP are well >> below 1s in normal situations. The worst case should be: >> >> 12:01:07 start something >> 12:01:08 did whatever >> 12:01:15 did something else >> 12:01:14 finished up >> >> I admit it's not very good. >> >>>>> [Note that NTP slaves don't blindly assume the current time is >>>>> as reported but *slew* to the new value, over some interval.] >>>>> >>>>> This also ignores the possibility of computations with relative >>>>> *intervals* being inconsistent with these spontaneous "resets". >>> >>> It's important that the RATE of time passage is reasonably accurate >>> and consistent (and monotonically increasing). But, the notion of >>> the "time of day" is dubious and exists just as a convenience for >>> humans to order events relative to the outside world (which uses >>> wall clocks). How accurate is YOUR wall clock? Does it agree >>> with your cell phone's notion of now? The alarm clock in your >>> bedroom? Your neighbor's timepiece when he comes to visit? etc. > >

The 2024 Embedded Online Conference