Changed dreamtime calculation.

Tue, 06 Feb 2018 20:16:59 +0000

author
Tuomo Valkonen <tuomov@iki.fi>
date
Tue, 06 Feb 2018 20:16:59 +0000
changeset 111
c3bc27cf5ece
parent 110
a79409c72565
child 112
173d9d7048b6

Changed dreamtime calculation.
The monotonic clock (time.monotonic()) sometimes advances unreliably
in sleep, so isn't reliable for calculating sleeping time. We have to
use time.time(). But this may be changed by the user, so we only use
it to track sleep periods, and still use time.monotonic() to track
wake periods.

borgend/dreamtime.py file | annotate | diff | comparison | revisions
borgend/ui.py file | annotate | diff | comparison | revisions
--- a/borgend/dreamtime.py	Tue Feb 06 08:30:20 2018 +0000
+++ b/borgend/dreamtime.py	Tue Feb 06 20:16:59 2018 +0000
@@ -215,10 +215,16 @@
     class SleepHandler(Foundation.NSObject):
         """ Handle wake/sleep notifications """
 
+        # We need to use the actual time.time() to monitor sleep, as
+        # time.monotonic() many not run during sleep. But time.time()
+        # may encounter adjustments, so we also use time.monotonic() to
+        # monitor wake periods.
+
         def init(self):
             self.__sleeptime=None
-            self.__slept=0
-            self.__epoch=time.monotonic()
+            self.__dreamtime_last_sleep=0
+            self.__monotonic_last_wakeup=time.monotonic()
+            self.__slept=0 # Only used to store the statistic
             self.__lock=threading.Lock()
             self.__callbacks=weakref.WeakKeyDictionary()
 
@@ -227,18 +233,21 @@
         @protect_noreturn
         def handleSleepNotification_(self, aNotification):
             logger.info("System going to sleep")
-            now=time.monotonic()
             with self.__lock:
-                self.__sleeptime=now
+                self.__sleeptime=time.time()
+                now_m=time.monotonic()
+                self.__dreamtime_last_sleep=(self.__dreamtime_last_sleep+now_m
+                                             -self.__monotonic_last_wakeup)
                 callbacks=self.__callbacks.copy()
             do_callbacks(callbacks, False)
 
         @protect_noreturn
         def handleWakeNotification_(self, aNotification):
             logger.info("System waking up from sleep")
-            now=time.monotonic()
             with self.__lock:
                 if self.__sleeptime:
+                    self.__monotonic_last_wakeup=time.monotonic()
+                    now=time.time()
                     slept=max(0, now-self.__sleeptime)
                     logger.info("Slept %f seconds" % slept)
                     self.__slept=self.__slept+slept
@@ -248,7 +257,6 @@
 
         # Return dreamtime
         def dreamtime_sleeping(self, snapshot=Snapshot()):
-            sleeping=False
             with self.__lock:
                 # macOS "sleep" signals / status are complete bollocks: at least
                 # when plugged in, the system is actually sometimes running all
@@ -256,11 +264,13 @@
                 # Therefore, we need our timers to work in a sane manner when
                 # we should be sleeping!
                 if self.__sleeptime is not None:
-                    now_monotonic=self.__sleeptime
                     sleeping=True
+                    now_dreamtime=self.__dreamtime_last_sleep
                 else:
-                    now_monotonic=snapshot.monotonic()
-                now_dreamtime=max(0, now_monotonic-self.__epoch-self.__slept)
+                    sleeping=False
+                    now=snapshot.monotonic()
+                    now_dreamtime=(self.__dreamtime_last_sleep
+                                   +now-self.__monotonic_last_wakeup);
             return now_dreamtime, sleeping
 
         # Weirdo (Py)ObjC naming to stop it form choking up
--- a/borgend/ui.py	Tue Feb 06 08:30:20 2018 +0000
+++ b/borgend/ui.py	Tue Feb 06 20:16:59 2018 +0000
@@ -129,7 +129,7 @@
             diff=datetime.timedelta(seconds=when-now)
 
             if twhen<tnow:
-                whenstr='overdue'
+                whenstr='overdue' + (' on %s' % twhen.isoformat())
             elif twhen>tendtomorrow:
                 # Display date if scheduled event is after tomorrow
                 whenday=datetime.date.fromtimestamp(when)

mercurial