runtime configurable timer precision
authorbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 13 Nov 2008 20:42:01 +0000 (20:42 +0000)
committerbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 13 Nov 2008 20:42:01 +0000 (20:42 +0000)
One can now configure the maximum acceptable delay to be introduced by
Ecore so possibly more timers will be dispatched together, reducing
wakeups and saving more power.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/ecore@37607 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/lib/ecore/Ecore.h
src/lib/ecore/ecore_timer.c

index ba16915..7403442 100644 (file)
@@ -302,6 +302,9 @@ extern "C" {
    EAPI void         ecore_timer_delay(Ecore_Timer *timer, double add);
    EAPI double       ecore_timer_pending_get(Ecore_Timer *timer);
 
+   EAPI double       ecore_timer_precision_get(void);
+   EAPI void         ecore_timer_precision_set(double precision);
+
    EAPI Ecore_Animator *ecore_animator_add(int (*func) (void *data), const void *data);
    EAPI void           *ecore_animator_del(Ecore_Animator *animator);
    EAPI void            ecore_animator_frametime_set(double frametime);
index c270b7f..f795eff 100644 (file)
@@ -8,6 +8,7 @@ static int          timers_delete_me = 0;
 static Ecore_Timer *timers = NULL;
 static Ecore_Timer *suspended = NULL;
 static double       last_check = 0.0;
+static double       precision = 10.0 / 1000000.0;
 
 /**
  * @defgroup Ecore_Time_Group Ecore Time Functions
@@ -17,6 +18,52 @@ static double       last_check = 0.0;
  */
 
 /**
+ * Retrieves the current precision used by timer infrastructure.
+ *
+ * @see ecore_timer_precision_set()
+ */
+EAPI double
+ecore_timer_precision_get(void)
+{
+   return precision;
+}
+
+/**
+ * Sets the precision to be used by timer infrastructure.
+ *
+ * When system calculates time to expire the next timer we'll be able
+ * to delay the timer by the given amount so more timers will fit in
+ * the same dispatch, waking up the system less often and thus being
+ * able to save power.
+ *
+ * Be aware that kernel may delay delivery even further, these delays
+ * are always possible due other tasks having higher priorities or
+ * other scheduler policies.
+ *
+ * Example:
+ *  We have 2 timers, one that expires in a 2.0s and another that
+ *  expires in 2.1s, if precision is 0.1s, then the Ecore will request
+ *  for the next expire to happen in 2.1s and not 2.0s and another one
+ *  of 0.1 as it would before.
+ *
+ * @note Ecore is smart enough to see if there are timers in the
+ * precision range, if it does not, in our example if no second timer
+ * in (T + precision) existed, then it would use the minimum timeout.
+ *
+ * @param value allowed introduced timeout delay, in seconds.
+ */
+EAPI void
+ecore_timer_precision_set(double value)
+{
+   if (value < 0.0)
+     {
+       fprintf(stderr, "ERROR: precision %f less than zero, ignored\n", value);
+       return;
+     }
+   precision = value;
+}
+
+/**
  * Creates a timer to call the given function in the given period of time.
  * @param   in   The interval in seconds.
  * @param   func The given function.  If @p func returns 1, the timer is
@@ -281,23 +328,51 @@ _ecore_timer_enable_new(void)
      }
 }
 
+static inline Ecore_Timer *
+_ecore_timer_first_get(void)
+{
+   Ecore_Timer *timer = (Ecore_Timer *)timers;
+
+   while ((timer) && ((timer->delete_me) || (timer->just_added)))
+     timer = (Ecore_Timer *)((Ecore_List2 *)timer)->next;
+
+   return timer;
+}
+
+static inline Ecore_Timer *
+_ecore_timer_after_get(Ecore_Timer *base)
+{
+   Ecore_Timer *timer = (Ecore_Timer *)((Ecore_List2 *)base)->next;
+   double maxtime = base->at + precision;
+
+   while ((timer) && ((timer->delete_me) || (timer->just_added)) && (timer->at <= maxtime))
+     timer = (Ecore_Timer *)((Ecore_List2 *)timer)->next;
+
+   if ((!timer) || (timer->at > maxtime))
+     return NULL;
+
+   return timer;
+}
+
 double
 _ecore_timer_next_get(void)
 {
    double now;
    double in;
-   Ecore_Timer *timer;
-   
-   if (!timers) return -1;
+   Ecore_Timer *first, *second;
+
+   first = _ecore_timer_first_get();
+   if (!first) return -1;
+
+   second = _ecore_timer_after_get(first);
+   if (second)
+     first = second;
+
    now = ecore_loop_time_get();
-   timer = (Ecore_Timer *)timers;
-   while ((timer) && ((timer->delete_me) || (timer->just_added)))
-     timer = (Ecore_Timer *)((Ecore_List2 *)timer)->next;
-   if (!timer) return -1;
-   in = timer->at - now;
+   in = first->at - now;
    if (in < 0) in = 0;
    return in;
-}  
+}
 
 int
 _ecore_timer_call(double when)