Merge lp:~vanvugt/compiz-core/bettertimers into lp:compiz-core/0.9.5

Proposed by Daniel van Vugt
Status: Merged
Merged at revision: 2894
Proposed branch: lp:~vanvugt/compiz-core/bettertimers
Merge into: lp:compiz-core/0.9.5
Diff against target: 321 lines (+108/-83)
4 files modified
src/privatetimeoutsource.h (+0/-4)
src/privatetimer.h (+2/-2)
src/timer.cpp (+35/-56)
tests/timer/callbacks/test-timer-callbacks.cpp (+71/-21)
To merge this branch: bzr merge lp:~vanvugt/compiz-core/bettertimers
Reviewer Review Type Date Requested Status
Sam Spilsbury Approve
Compiz Maintainers Pending
Review via email: mp+82812@code.launchpad.net

Description of the change

Add support for CompTimers with a minTime of 0.

Previously, calling setTimes(0,0) would cause an infinite loop in
CompTimeoutSource::callback and/or non-zero timers to never be called.
This new code avoids infinite loops, avoids non-zero timer starvation and
improves timer accuracy in general.

To post a comment you must log in.
lp:~vanvugt/compiz-core/bettertimers updated
2895. By Daniel van Vugt

Fixed implicit parameter handling in setExpiryTimes.

Revision history for this message
Marco Trevisan (TreviƱo) (3v1n0) wrote :

Shouldn't you include the changes for this:

+ /*
+ * Note the use of delay = 1 instead of 0, even though 0 would be better.
+ * A delay of zero is presently broken due to CompTimer bugs;
+ * 1. Infinite loop in CompTimeoutSource::callback when a zero
+ * timer is set.
+ * 2. Priority set too high in CompTimeoutSource::CompTimeoutSource
+ * causing the glib main event loop to be starved of X events.
+ * Fixes for both of these issues are being worked on separately.
+ */
+ paintTimer.start
+ (boost::bind (&CompositeScreen::handlePaintTimeout, cScreen),
+ delay);

And setting lp:~vanvugt/compiz-core/fix-880707.2 as a prerequisite of this branch?

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

No, that comment is misleading as mentioned in the other merge proposal. Changing the delay to 0 instead of 1 actually does not seem improve performance. So no need for a prereq.

We really do not need the complexity of mashing two large proposals together when they can be safely dealt with separately.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

And I did experiment with putting the 2 fixes together. They did not affect each other in any way.

Revision history for this message
Sam Spilsbury (smspillaz) wrote :

156 + gint64 now = g_get_monotonic_time ();
157 + priv->mMinDeadline = now + ((gint64)min * 1000);
158 + priv->mMaxDeadline = now + ((gint64)(max >= min ? max : min) * 1000);

Glib::Source::get_time wraps g_get_monotonic_time () - you can use get_time () here.

Also, put spaces betwene casts and variables.

+#include <ctime>
199 +
200 +static time_t starttime = 0;

No need to have a global variable there - it can go inside of the testing base class, and get_time () can probably be re-used here. I can fix these when I merge it.

review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

I used g_get_monotonic_time because get_time is not available outside of Source classes. Is it??
And if you have to use g_get_monotonic_time in at least one place then it should be used everywhere so all locations/classes agree on the current time.

The global variable was just to avoid changing headers and increasing the size of the diff :)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/privatetimeoutsource.h'
--- src/privatetimeoutsource.h 2011-07-04 16:25:20 +0000
+++ src/privatetimeoutsource.h 2011-11-21 02:45:27 +0000
@@ -47,10 +47,6 @@
47 explicit CompTimeoutSource (Glib::RefPtr <Glib::MainContext> &ctx);47 explicit CompTimeoutSource (Glib::RefPtr <Glib::MainContext> &ctx);
48 virtual ~CompTimeoutSource ();48 virtual ~CompTimeoutSource ();
4949
50 private:
51
52 gint64 mLastTime;
53
54 friend class CompTimer;50 friend class CompTimer;
55};51};
5652
5753
=== modified file 'src/privatetimer.h'
--- src/privatetimer.h 2011-07-05 19:15:16 +0000
+++ src/privatetimer.h 2011-11-21 02:45:27 +0000
@@ -38,8 +38,8 @@
38 bool mActive;38 bool mActive;
39 unsigned int mMinTime;39 unsigned int mMinTime;
40 unsigned int mMaxTime;40 unsigned int mMaxTime;
41 int mMinLeft;41 gint64 mMinDeadline;
42 int mMaxLeft;42 gint64 mMaxDeadline;
43 CompTimer::CallBack mCallBack;43 CompTimer::CallBack mCallBack;
44};44};
4545
4646
=== modified file 'src/timer.cpp'
--- src/timer.cpp 2011-07-05 19:15:24 +0000
+++ src/timer.cpp 2011-11-21 02:45:27 +0000
@@ -38,8 +38,6 @@
38 set_priority (G_PRIORITY_HIGH);38 set_priority (G_PRIORITY_HIGH);
39 attach (ctx);39 attach (ctx);
4040
41 mLastTime = get_time ();
42
43 connect (sigc::mem_fun <bool, CompTimeoutSource> (this, &CompTimeoutSource::callback));41 connect (sigc::mem_fun <bool, CompTimeoutSource> (this, &CompTimeoutSource::callback));
44}42}
4543
@@ -95,51 +93,20 @@
95 timeout = t->maxLeft ();93 timeout = t->maxLeft ();
96 it++;94 it++;
97 }95 }
98
99 mLastTime = get_time ();
100
101 return false;
102 }96 }
103 else97 else
104 {98 {
105 timeout = 0;99 timeout = 0;
106
107 mLastTime = get_time ();
108
109 return true;
110 }100 }
101
102 return timeout <= 0;
111}103}
112104
113bool105bool
114CompTimeoutSource::check ()106CompTimeoutSource::check ()
115{107{
116 gint64 fixedTimeDiff;108 return (!TimeoutHandler::Default ()->timers ().empty () &&
117 gdouble timeDiff;
118 gint64 currentTime = get_time ();
119 bool ready = false;
120
121 timeDiff = (currentTime - mLastTime) / 1000.0;
122
123 mLastTime = currentTime;
124
125 /* prefer over-estimating rather than waking up */
126 fixedTimeDiff = ceil (timeDiff);
127
128 /* Handle clock rollback */
129 if (fixedTimeDiff < 0)
130 {
131 fixedTimeDiff = 0;
132 }
133
134 foreach (CompTimer *t, TimeoutHandler::Default ()->timers ())
135 {
136 t->decrement (fixedTimeDiff);
137 }
138
139 ready = (!TimeoutHandler::Default ()->timers ().empty () &&
140 TimeoutHandler::Default ()->timers ().front ()->minLeft () <= 0);109 TimeoutHandler::Default ()->timers ().front ()->minLeft () <= 0);
141
142 return ready;
143}110}
144111
145bool112bool
@@ -152,29 +119,37 @@
152bool119bool
153CompTimeoutSource::callback ()120CompTimeoutSource::callback ()
154{121{
155 while (TimeoutHandler::Default ()->timers ().begin () != TimeoutHandler::Default ()->timers ().end () &&122 TimeoutHandler *handler = TimeoutHandler::Default ();
156 TimeoutHandler::Default ()->timers ().front ()->minLeft () <= 0)123 std::list<CompTimer*> requeue, &timers = handler->timers ();
124
125 while (!timers.empty ())
157 {126 {
158 CompTimer *t = TimeoutHandler::Default ()->timers ().front ();127 CompTimer *t = timers.front ();
159 TimeoutHandler::Default ()->timers ().pop_front ();128 if (t->minLeft () > 0)
160129 break;
130 timers.pop_front ();
161 t->setActive (false);131 t->setActive (false);
162 if (t->triggerCallback ())132 if (t->triggerCallback ())
163 {133 requeue.push_back (t);
164 TimeoutHandler::Default ()->addTimer (t);134 }
165 t->setActive (true);135
166 }136 std::list<CompTimer*>::const_iterator i = requeue.begin ();
167 }137 for (; i != requeue.end (); i++)
168138 {
169 return !TimeoutHandler::Default ()->timers ().empty ();139 CompTimer *t = *i;
140 handler->addTimer (t);
141 t->setActive (true);
142 }
143
144 return !timers.empty ();
170}145}
171146
172PrivateTimer::PrivateTimer () :147PrivateTimer::PrivateTimer () :
173 mActive (false),148 mActive (false),
174 mMinTime (0),149 mMinTime (0),
175 mMaxTime (0),150 mMaxTime (0),
176 mMinLeft (0),151 mMinDeadline (0),
177 mMaxLeft (0),152 mMaxDeadline (0),
178 mCallBack (NULL)153 mCallBack (NULL)
179{154{
180}155}
@@ -211,15 +186,15 @@
211void186void
212CompTimer::setExpiryTimes (unsigned int min, unsigned int max)187CompTimer::setExpiryTimes (unsigned int min, unsigned int max)
213{188{
214 priv->mMinLeft = min;189 gint64 now = g_get_monotonic_time ();
215 priv->mMaxLeft = (min <= max) ? max : min;190 priv->mMinDeadline = now + ((gint64)min * 1000);
191 priv->mMaxDeadline = now + ((gint64)(max >= min ? max : min) * 1000);
216}192}
217193
218void194void
219CompTimer::decrement (unsigned int diff)195CompTimer::decrement (unsigned int diff)
220{196{
221 priv->mMinLeft -= diff;197 /* deprecated */
222 priv->mMaxLeft -= diff;
223}198}
224199
225void200void
@@ -305,13 +280,17 @@
305unsigned int280unsigned int
306CompTimer::minLeft ()281CompTimer::minLeft ()
307{282{
308 return (priv->mMinLeft < 0)? 0 : priv->mMinLeft;283 gint64 now = g_get_monotonic_time ();
284 return (priv->mMinDeadline > now) ?
285 (unsigned int)(priv->mMinDeadline - now + 500) / 1000 : 0;
309}286}
310287
311unsigned int288unsigned int
312CompTimer::maxLeft ()289CompTimer::maxLeft ()
313{290{
314 return (priv->mMaxLeft < 0)? 0 : priv->mMaxLeft;291 gint64 now = g_get_monotonic_time ();
292 return (priv->mMaxDeadline > now) ?
293 (unsigned int)(priv->mMaxDeadline - now + 500) / 1000 : 0;
315}294}
316295
317bool296bool
318297
=== modified file 'tests/timer/callbacks/test-timer-callbacks.cpp'
--- tests/timer/callbacks/test-timer-callbacks.cpp 2011-07-06 18:58:47 +0000
+++ tests/timer/callbacks/test-timer-callbacks.cpp 2011-11-21 02:45:27 +0000
@@ -24,42 +24,85 @@
24 */24 */
2525
26#include "test-timer.h"26#include "test-timer.h"
27#include <ctime>
28
29static time_t starttime = 0;
2730
28bool31bool
29CompTimerTestCallbacks::cb (int timernum)32CompTimerTestCallbacks::cb (int timernum)
30{33{
31 if (lastTimerTriggered == 0 && timernum == 1)34 static bool complete = false;
32 {35 static int count[4] = {0, 0, 0, 0};
33 std::cout << "FAIL: timer with a higher timeout value triggered before the timer with the lower timeout" << std::endl;36
34 exit (1);37 if (timernum < 4)
35 return false;38 count[timernum]++;
36 }39
37 else if (lastTimerTriggered == 2 && timernum != 1)40 if (complete)
38 {41 return false;
39 std::cout << "FAIL: the second timer should have triggered" << std::endl;42
40 exit (1);43 if (time (NULL) - starttime > 5) /* Wait no more than 5 seconds */
41 return false;44 {
42 }45 std::cout << "FAIL: some timers are never being triggered" << std::endl;
4346 exit (1);
44 std::cout << "INFO: triggering timer " << timernum << std::endl;47 return false;
48 }
49 else if (lastTimerTriggered == 0 && timernum != 3)
50 {
51 std::cout << "FAIL: timer 3 was not triggered first" << std::endl;
52 exit (1);
53 return false;
54 }
55 else if (lastTimerTriggered == 2 && timernum != 3)
56 {
57 std::cout << "FAIL: timer 3 was not after 2" << std::endl;
58 exit (1);
59 return false;
60 }
61 else if (timernum == 1 && count[2] < 1)
62 {
63 std::cout << "FAIL: timer 1 was not preceded by 2" << std::endl;
64 exit (1);
65 return false;
66 }
67
68 if (timernum < 3 || lastTimerTriggered != 3)
69 {
70 std::cout
71 << "INFO: triggering timer "
72 << timernum
73 << ((timernum == 3) ? " (many times)" : "")
74 << std::endl;
75 }
4576
46 lastTimerTriggered = timernum;77 lastTimerTriggered = timernum;
4778
48 if (timernum == 1)79 if (timernum == 1)
49 {80 {
50 std::cout << "PASS: basic timers" << std::endl;81 complete = true;
82 std::cout
83 << "PASS: basic timers. Total calls: "
84 << count[1]
85 << ", "
86 << count[2]
87 << ", "
88 << count[3]
89 << std::endl;
51 ml->quit ();90 ml->quit ();
52 }91 }
5392
54 return false;93 return !complete;
55}94}
5695
57void96void
58CompTimerTestCallbacks::precallback ()97CompTimerTestCallbacks::precallback ()
59{98{
99 starttime = time (NULL);
100
60 /* Test 2: Adding timers */101 /* Test 2: Adding timers */
61 std::cout << "-= TEST: adding timers and callbacks" << std::endl;102 std::cout << "-= TEST: adding timers and callbacks" << std::endl;
62 timers.push_back (new CompTimer ());103
104 CompTimer *t1 = new CompTimer ();
105 timers.push_back (t1);
63 timers.front ()->setTimes (100, 110);106 timers.front ()->setTimes (100, 110);
64 timers.front ()->setCallback (boost::bind (&CompTimerTestCallbacks::cb, this, 1));107 timers.front ()->setCallback (boost::bind (&CompTimerTestCallbacks::cb, this, 1));
65108
@@ -70,13 +113,20 @@
70 exit (1);113 exit (1);
71 }114 }
72115
73 timers.push_back (new CompTimer ());116 CompTimer *t2 = new CompTimer ();
117 timers.push_back (t2);
74 timers.back ()->setTimes (50, 90);118 timers.back ()->setTimes (50, 90);
75 timers.back ()->setCallback (boost::bind (&CompTimerTestCallbacks::cb, this, 2));119 timers.back ()->setCallback (boost::bind (&CompTimerTestCallbacks::cb, this, 2));
76120
77 /* Start both timers */121 CompTimer *t3 = new CompTimer ();
78 timers.front ()->start ();122 timers.push_back (t3);
79 timers.back ()->start ();123 timers.back ()->setTimes (0, 0);
124 timers.back ()->setCallback (boost::bind (&CompTimerTestCallbacks::cb, this, 3));
125
126 /* Start all timers */
127 t1->start ();
128 t2->start ();
129 t3->start ();
80130
81 /* TimeoutHandler::timers should have the timer that131 /* TimeoutHandler::timers should have the timer that
82 * is going to trigger first at the front of the132 * is going to trigger first at the front of the

Subscribers

People subscribed via source and target branches