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
1=== modified file 'src/privatetimeoutsource.h'
2--- src/privatetimeoutsource.h 2011-07-04 16:25:20 +0000
3+++ src/privatetimeoutsource.h 2011-11-21 02:45:27 +0000
4@@ -47,10 +47,6 @@
5 explicit CompTimeoutSource (Glib::RefPtr <Glib::MainContext> &ctx);
6 virtual ~CompTimeoutSource ();
7
8- private:
9-
10- gint64 mLastTime;
11-
12 friend class CompTimer;
13 };
14
15
16=== modified file 'src/privatetimer.h'
17--- src/privatetimer.h 2011-07-05 19:15:16 +0000
18+++ src/privatetimer.h 2011-11-21 02:45:27 +0000
19@@ -38,8 +38,8 @@
20 bool mActive;
21 unsigned int mMinTime;
22 unsigned int mMaxTime;
23- int mMinLeft;
24- int mMaxLeft;
25+ gint64 mMinDeadline;
26+ gint64 mMaxDeadline;
27 CompTimer::CallBack mCallBack;
28 };
29
30
31=== modified file 'src/timer.cpp'
32--- src/timer.cpp 2011-07-05 19:15:24 +0000
33+++ src/timer.cpp 2011-11-21 02:45:27 +0000
34@@ -38,8 +38,6 @@
35 set_priority (G_PRIORITY_HIGH);
36 attach (ctx);
37
38- mLastTime = get_time ();
39-
40 connect (sigc::mem_fun <bool, CompTimeoutSource> (this, &CompTimeoutSource::callback));
41 }
42
43@@ -95,51 +93,20 @@
44 timeout = t->maxLeft ();
45 it++;
46 }
47-
48- mLastTime = get_time ();
49-
50- return false;
51 }
52 else
53 {
54 timeout = 0;
55-
56- mLastTime = get_time ();
57-
58- return true;
59 }
60+
61+ return timeout <= 0;
62 }
63
64 bool
65 CompTimeoutSource::check ()
66 {
67- gint64 fixedTimeDiff;
68- gdouble timeDiff;
69- gint64 currentTime = get_time ();
70- bool ready = false;
71-
72- timeDiff = (currentTime - mLastTime) / 1000.0;
73-
74- mLastTime = currentTime;
75-
76- /* prefer over-estimating rather than waking up */
77- fixedTimeDiff = ceil (timeDiff);
78-
79- /* Handle clock rollback */
80- if (fixedTimeDiff < 0)
81- {
82- fixedTimeDiff = 0;
83- }
84-
85- foreach (CompTimer *t, TimeoutHandler::Default ()->timers ())
86- {
87- t->decrement (fixedTimeDiff);
88- }
89-
90- ready = (!TimeoutHandler::Default ()->timers ().empty () &&
91+ return (!TimeoutHandler::Default ()->timers ().empty () &&
92 TimeoutHandler::Default ()->timers ().front ()->minLeft () <= 0);
93-
94- return ready;
95 }
96
97 bool
98@@ -152,29 +119,37 @@
99 bool
100 CompTimeoutSource::callback ()
101 {
102- while (TimeoutHandler::Default ()->timers ().begin () != TimeoutHandler::Default ()->timers ().end () &&
103- TimeoutHandler::Default ()->timers ().front ()->minLeft () <= 0)
104+ TimeoutHandler *handler = TimeoutHandler::Default ();
105+ std::list<CompTimer*> requeue, &timers = handler->timers ();
106+
107+ while (!timers.empty ())
108 {
109- CompTimer *t = TimeoutHandler::Default ()->timers ().front ();
110- TimeoutHandler::Default ()->timers ().pop_front ();
111-
112+ CompTimer *t = timers.front ();
113+ if (t->minLeft () > 0)
114+ break;
115+ timers.pop_front ();
116 t->setActive (false);
117 if (t->triggerCallback ())
118- {
119- TimeoutHandler::Default ()->addTimer (t);
120- t->setActive (true);
121- }
122- }
123-
124- return !TimeoutHandler::Default ()->timers ().empty ();
125+ requeue.push_back (t);
126+ }
127+
128+ std::list<CompTimer*>::const_iterator i = requeue.begin ();
129+ for (; i != requeue.end (); i++)
130+ {
131+ CompTimer *t = *i;
132+ handler->addTimer (t);
133+ t->setActive (true);
134+ }
135+
136+ return !timers.empty ();
137 }
138
139 PrivateTimer::PrivateTimer () :
140 mActive (false),
141 mMinTime (0),
142 mMaxTime (0),
143- mMinLeft (0),
144- mMaxLeft (0),
145+ mMinDeadline (0),
146+ mMaxDeadline (0),
147 mCallBack (NULL)
148 {
149 }
150@@ -211,15 +186,15 @@
151 void
152 CompTimer::setExpiryTimes (unsigned int min, unsigned int max)
153 {
154- priv->mMinLeft = min;
155- priv->mMaxLeft = (min <= max) ? max : min;
156+ gint64 now = g_get_monotonic_time ();
157+ priv->mMinDeadline = now + ((gint64)min * 1000);
158+ priv->mMaxDeadline = now + ((gint64)(max >= min ? max : min) * 1000);
159 }
160
161 void
162 CompTimer::decrement (unsigned int diff)
163 {
164- priv->mMinLeft -= diff;
165- priv->mMaxLeft -= diff;
166+ /* deprecated */
167 }
168
169 void
170@@ -305,13 +280,17 @@
171 unsigned int
172 CompTimer::minLeft ()
173 {
174- return (priv->mMinLeft < 0)? 0 : priv->mMinLeft;
175+ gint64 now = g_get_monotonic_time ();
176+ return (priv->mMinDeadline > now) ?
177+ (unsigned int)(priv->mMinDeadline - now + 500) / 1000 : 0;
178 }
179
180 unsigned int
181 CompTimer::maxLeft ()
182 {
183- return (priv->mMaxLeft < 0)? 0 : priv->mMaxLeft;
184+ gint64 now = g_get_monotonic_time ();
185+ return (priv->mMaxDeadline > now) ?
186+ (unsigned int)(priv->mMaxDeadline - now + 500) / 1000 : 0;
187 }
188
189 bool
190
191=== modified file 'tests/timer/callbacks/test-timer-callbacks.cpp'
192--- tests/timer/callbacks/test-timer-callbacks.cpp 2011-07-06 18:58:47 +0000
193+++ tests/timer/callbacks/test-timer-callbacks.cpp 2011-11-21 02:45:27 +0000
194@@ -24,42 +24,85 @@
195 */
196
197 #include "test-timer.h"
198+#include <ctime>
199+
200+static time_t starttime = 0;
201
202 bool
203 CompTimerTestCallbacks::cb (int timernum)
204 {
205- if (lastTimerTriggered == 0 && timernum == 1)
206- {
207- std::cout << "FAIL: timer with a higher timeout value triggered before the timer with the lower timeout" << std::endl;
208- exit (1);
209- return false;
210- }
211- else if (lastTimerTriggered == 2 && timernum != 1)
212- {
213- std::cout << "FAIL: the second timer should have triggered" << std::endl;
214- exit (1);
215- return false;
216- }
217-
218- std::cout << "INFO: triggering timer " << timernum << std::endl;
219+ static bool complete = false;
220+ static int count[4] = {0, 0, 0, 0};
221+
222+ if (timernum < 4)
223+ count[timernum]++;
224+
225+ if (complete)
226+ return false;
227+
228+ if (time (NULL) - starttime > 5) /* Wait no more than 5 seconds */
229+ {
230+ std::cout << "FAIL: some timers are never being triggered" << std::endl;
231+ exit (1);
232+ return false;
233+ }
234+ else if (lastTimerTriggered == 0 && timernum != 3)
235+ {
236+ std::cout << "FAIL: timer 3 was not triggered first" << std::endl;
237+ exit (1);
238+ return false;
239+ }
240+ else if (lastTimerTriggered == 2 && timernum != 3)
241+ {
242+ std::cout << "FAIL: timer 3 was not after 2" << std::endl;
243+ exit (1);
244+ return false;
245+ }
246+ else if (timernum == 1 && count[2] < 1)
247+ {
248+ std::cout << "FAIL: timer 1 was not preceded by 2" << std::endl;
249+ exit (1);
250+ return false;
251+ }
252+
253+ if (timernum < 3 || lastTimerTriggered != 3)
254+ {
255+ std::cout
256+ << "INFO: triggering timer "
257+ << timernum
258+ << ((timernum == 3) ? " (many times)" : "")
259+ << std::endl;
260+ }
261
262 lastTimerTriggered = timernum;
263
264 if (timernum == 1)
265 {
266- std::cout << "PASS: basic timers" << std::endl;
267+ complete = true;
268+ std::cout
269+ << "PASS: basic timers. Total calls: "
270+ << count[1]
271+ << ", "
272+ << count[2]
273+ << ", "
274+ << count[3]
275+ << std::endl;
276 ml->quit ();
277 }
278
279- return false;
280+ return !complete;
281 }
282
283 void
284 CompTimerTestCallbacks::precallback ()
285 {
286+ starttime = time (NULL);
287+
288 /* Test 2: Adding timers */
289 std::cout << "-= TEST: adding timers and callbacks" << std::endl;
290- timers.push_back (new CompTimer ());
291+
292+ CompTimer *t1 = new CompTimer ();
293+ timers.push_back (t1);
294 timers.front ()->setTimes (100, 110);
295 timers.front ()->setCallback (boost::bind (&CompTimerTestCallbacks::cb, this, 1));
296
297@@ -70,13 +113,20 @@
298 exit (1);
299 }
300
301- timers.push_back (new CompTimer ());
302+ CompTimer *t2 = new CompTimer ();
303+ timers.push_back (t2);
304 timers.back ()->setTimes (50, 90);
305 timers.back ()->setCallback (boost::bind (&CompTimerTestCallbacks::cb, this, 2));
306
307- /* Start both timers */
308- timers.front ()->start ();
309- timers.back ()->start ();
310+ CompTimer *t3 = new CompTimer ();
311+ timers.push_back (t3);
312+ timers.back ()->setTimes (0, 0);
313+ timers.back ()->setCallback (boost::bind (&CompTimerTestCallbacks::cb, this, 3));
314+
315+ /* Start all timers */
316+ t1->start ();
317+ t2->start ();
318+ t3->start ();
319
320 /* TimeoutHandler::timers should have the timer that
321 * is going to trigger first at the front of the

Subscribers

People subscribed via source and target branches