Merge lp:~smspillaz/compiz-core/compiz-core.optimization-inlining into lp:compiz-core/0.9.8

Proposed by Sam Spilsbury
Status: Work in progress
Proposed branch: lp:~smspillaz/compiz-core/compiz-core.optimization-inlining
Merge into: lp:compiz-core/0.9.8
Diff against target: 342 lines (+132/-78) (has conflicts)
9 files modified
include/core/region.h (+1/-1)
include/core/window.h (+11/-7)
src/privatewindow.h (+19/-0)
src/rect/include/core/rect.h (+19/-0)
src/region.cpp (+0/-6)
src/window.cpp (+9/-0)
src/window/geometry/include/core/windowgeometry.h (+1/-1)
src/window/geometry/src/windowgeometry.cpp (+0/-6)
src/windowgeometry.cpp (+72/-57)
Text conflict in src/privatewindow.h
To merge this branch: bzr merge lp:~smspillaz/compiz-core/compiz-core.optimization-inlining
Reviewer Review Type Date Requested Status
Daniel van Vugt Pending
Alan Griffiths Pending
Review via email: mp+102682@code.launchpad.net

This proposal supersedes a proposal from 2012-02-29.

Description of the change

Optimize and inline some hot-spots in CompWindow.

server*Rect and *Rect were being called quite a lot and unnecessarily being recalculated and copy-constructed (eg XCreateRegion madness). This branch inlines some functions that were being called a ton (compiz::window::Geometry::border () about 600,000 times) and adds a new RecalcRect class. RecalcRect takes a function object to recalculate a CompRect. At the moment, we use the old behaviour of recalculating server*Rect and *Rect every time they are called but once https://code.launchpad.net/~smspillaz/compiz-core/compiz-core.work_923683 is merged then we can optimize there.

To post a comment you must log in.
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

Not really relevant to the change, but as "Region handle () const" compiles there's already a declaration of Region visible - so why is priv a "void*" and cast all the while?

review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

priv is a void* because in the penultimate revision before that change was merged, priv could represent different types (Region or PrivateRegion). Now that PrivateRegion is gone however you are correct that priv could be simply "Region priv".

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

I haven't tested it yet, but I'm pretty sure this branch should contain a CORE_ABIVERSION bump.

review: Needs Fixing
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> I haven't tested it yet, but I'm pretty sure this branch should contain a
> CORE_ABIVERSION bump.

Good catch

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

8 - Region handle () const;
9 + Region handle () const { return static_cast<Region> (priv); }

I noticed also that CompRegion::handle is the most commonly called function in compiz. However it is also tiny and only accounts for 1% of compiz CPU usage. Which is why I didn't touch it.

Another problem with changing handle() is that if we change the implementation of CompRegion in future then we will need to change handle() again and that would be another ABI bump.

I think a better solution to solve all of these problems is to keep handle() unchanged, and add a new method:
    private:
        Region privHandle () const { return static_cast<Region> (priv); }
for use in region.cpp only.

review: Needs Fixing
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Or simply:
    #define REGIONHANDLE (static_cast<Region> (priv))
in region.cpp

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Also, testing this code I notice another windows-shifted-horizontally regression (though I suspect it's the same one and we haven't fixed the root cause yet). When a window is maximized or restored, it's contents are shifted to the right/left of where they should be. When you move the window, the shift corrects itself.

:(

review: Needs Fixing
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Though it's possible the shift regression would be fixed by merging the other branch Sam mentions...

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Confirmed: The shift regression seen with this branch is fixed if you also merge:
lp:~smspillaz/compiz-core/compiz-core.work_923683
But that branch has its own problems.

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

> 8 - Region handle () const;
> 9 + Region handle () const { return static_cast<Region> (priv); }
>
> I noticed also that CompRegion::handle is the most commonly called function in
> compiz. However it is also tiny and only accounts for 1% of compiz CPU usage.
> Which is why I didn't touch it.
>
> Another problem with changing handle() is that if we change the implementation
> of CompRegion in future then we will need to change handle() again and that
> would be another ABI bump.

We change the ABI for other reasons too, and I really don't think the implementation of CompRegion is going to change (except, perhaps to cairo_region_t), so this is just a total non-issue.

>
> I think a better solution to solve all of these problems is to keep handle()
> unchanged, and add a new method:
> private:
> Region privHandle () const { return static_cast<Region> (priv); }
> for use in region.cpp only.

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

CompRegion::handle()
I think this may be worth inlining privately. As mentioned earlier. We shouldn't make handle() inline for external users of the class. FYI, CompRegion::handle() is consistently the single most called function in compiz, however it never accounts for more than 1.3% of the total CPU usage.

compiz::window::Geometry::border ()
Makes no sense to inline AFAICS. It may well be around the 25th most called function, however it only accounts for 0.07% of the CPU usage.

CompWindow::borderRect()
Does not need to optimizing at all. Is almost never called and contributes absolutely nothing to the total CPU usage.

*Rect()
Contribute almost nothing measurable to the CPU usage.

All-in-all, these optimizations don't seem to provide any significant benefit. I think CompRegion::handle() could be optimized using a private inline version of that function. But even then, the maximum gain is going to be about 1%. The rest of the changes break the ABI, cause a regression, and do not appear to be required at all.

If I'm wrong, then please log a bug with the profile data showing why all this existing code needs optimizing.

review: Disapprove
Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

On Mon, 5 Mar 2012, Daniel van Vugt wrote:

> Review: Disapprove
>
> CompRegion::handle()
> I think this may be worth inlining privately. As mentioned earlier. We shouldn't make handle() inline for external users of the class. FYI, CompRegion::handle() is consistently the single most called function in compiz, however it never accounts for more than 1.3% of the total CPU usage.
>

Ack, although other plugins use the handle directly.

> compiz::window::Geometry::border ()
> Makes no sense to inline AFAICS. It may well be around the 25th most called function, however it only accounts for 0.07% of the CPU usage.
>

Why not ? Avoids the JMP

> CompWindow::borderRect()
> Does not need to optimizing at all. Is almost never called and contributes absolutely nothing to the total CPU usage.
>

> *Rect()
> Contribute almost nothing measurable to the CPU usage.
>

They account for about 5% ish of usage, and are called during paint
functions. There is no reason for them to operate in the way that they
currently do. The constructors also involve XCreateRegion and
XDestroyRegion pairs.

Just because the optimization isn't "significant" that doesn't mean that
it is useless. In fact, the code as it was written makes no sense
whatsoever, and there isn't any reason to keep it as it is.

> All-in-all, these optimizations don't seem to provide any significant benefit. I think CompRegion::handle() could be optimized using a private inline version of that function. But even then, the maximum gain is going to be about 1%. The rest of the changes break the ABI, cause a regression, and do not appear to be required at all.
>

The regression is unrelated, see
lp:~smspillaz/compiz-core/compiz-core.backport_2988_work_923683

> If I'm wrong, then please log a bug with the profile data showing why all this existing code needs optimizing.
> --
> https://code.launchpad.net/~smspillaz/compiz-core/compiz-core.optimization-inlining/+merge/95094
> You are the owner of lp:~smspillaz/compiz-core/compiz-core.optimization-inlining.
>

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Still causes the shift regression, despite us thinking it was fixed by:
https://code.launchpad.net/+branch/~smspillaz/compiz-core/compiz-core.backport_2988_work_923683
It seems that fix has not worked.

Aside from the shift regression which still needs fixing, I strongly recommend not breaking the ABI (now and again in future) by inlining handle() or border(). If anything, I suggest adding new inline functions "inlineHandle" and "inlineBorder". Ideally they should be private. If not private, then they should be documented as "only safe to use in core or core plugins".

CORE_ABIVERSION still needs bumping too.

review: Needs Fixing
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

And yes, when I say "causes the shift regression" I actually mean "triggers the shift regression". I'm pretty sure the bug is not in the below diff, only exploited by it.

Unmerged revisions

3027. By Sam Spilsbury

Added RecalcRect, a class which has a function to recalculate a rectangle on demand,
currently replaces *Rect () in window and allows them to be const &, soon we will be
able to only recalculate these when necessary and not all the time

3026. By Sam Spilsbury

Inline some heavily called CompRegion and compiz::window::Geometry types

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/core/region.h'
2--- include/core/region.h 2012-02-27 03:41:13 +0000
3+++ include/core/region.h 2012-04-19 11:47:45 +0000
4@@ -71,7 +71,7 @@
5 /**
6 * Returns the internal XRegion handle
7 */
8- Region handle () const;
9+ Region handle () const { return static_cast<Region> (priv); }
10
11 /**
12 * Returns true if the specified CompPoint falls within the
13
14=== modified file 'include/core/window.h'
15--- include/core/window.h 2012-03-22 17:00:51 +0000
16+++ include/core/window.h 2012-04-19 11:47:45 +0000
17@@ -321,19 +321,23 @@
18 /* With border */
19 int serverWidth () const;
20 int serverHeight () const;
21- const CompSize serverSize () const;
22+ CompSize serverSize () const;
23
24 /* effective decoration extents */
25- CompRect borderRect () const;
26- CompRect serverBorderRect () const;
27+ const CompRect & borderRect () const;
28+ const CompRect & serverBorderRect () const;
29
30 /* frame window geometry */
31- CompRect inputRect () const;
32- CompRect serverInputRect () const;
33+ const CompRect & inputRect () const;
34+ const CompRect & serverInputRect () const;
35
36 /* includes decorations and shadows */
37- CompRect outputRect () const;
38- CompRect serverOutputRect () const;
39+ const CompRect & outputRect () const;
40+ const CompRect & serverOutputRect () const;
41+
42+ /* only includes X11 borders */
43+ const CompRect & geometryBorders () const;
44+ const CompRect & serverGeometryBorders () const;
45
46 Window id ();
47 Window frame ();
48
49=== modified file 'src/privatewindow.h'
50--- src/privatewindow.h 2012-03-02 18:02:07 +0000
51+++ src/privatewindow.h 2012-04-19 11:47:45 +0000
52@@ -209,7 +209,17 @@
53
54 bool checkClear ();
55
56+<<<<<<< TREE
57 static CompWindow* createCompWindow (Window aboveId, XWindowAttributes &wa, Window id);
58+=======
59+ void recalcExtentsRect (CompRect &rect,
60+ const CompWindow::Geometry *geometry,
61+ const CompWindowExtents *extents);
62+
63+ void recalcGeometryBordersRect (CompRect &rect,
64+ const CompWindow::Geometry *geometry);
65+
66+>>>>>>> MERGE-SOURCE
67 public:
68
69 PrivateWindow *priv;
70@@ -252,6 +262,15 @@
71 CompRegion inputRegion;
72 CompRegion frameRegion;
73
74+ compiz::rect::RecalcRect borderRect;
75+ compiz::rect::RecalcRect serverBorderRect;
76+ compiz::rect::RecalcRect inputRect;
77+ compiz::rect::RecalcRect serverInputRect;
78+ compiz::rect::RecalcRect outputRect;
79+ compiz::rect::RecalcRect serverOutputRect;
80+ compiz::rect::RecalcRect geometryBorders;
81+ compiz::rect::RecalcRect serverGeometryBorders;
82+
83 unsigned int wmType;
84 unsigned int type;
85 unsigned int state;
86
87=== modified file 'src/rect/include/core/rect.h'
88--- src/rect/include/core/rect.h 2012-01-19 19:32:29 +0000
89+++ src/rect/include/core/rect.h 2012-04-19 11:47:45 +0000
90@@ -33,6 +33,8 @@
91 #include <X11/Xlib.h>
92 #include <X11/Xutil.h>
93 #include <X11/Xregion.h>
94+#include <boost/function.hpp>
95+#include <boost/bind.hpp>
96 #include "core/point.h"
97
98
99@@ -144,6 +146,23 @@
100 {
101 CompPoint wraparoundPoint (const CompRect &bounds,
102 const CompPoint &p);
103+
104+ class RecalcRect
105+ {
106+ public:
107+
108+ typedef boost::function <void (CompRect &rect)> RecalcFunc;
109+
110+ RecalcRect (const RecalcFunc &func);
111+
112+ const CompRect & rect () const { return mRect; }
113+ void refresh () { mRecalcFunc (mRect); }
114+
115+ private:
116+
117+ CompRect mRect;
118+ RecalcFunc mRecalcFunc;
119+ };
120 }
121 }
122
123
124=== modified file 'src/region.cpp'
125--- src/region.cpp 2012-02-27 08:05:51 +0000
126+++ src/region.cpp 2012-04-19 11:47:45 +0000
127@@ -118,12 +118,6 @@
128 priv = XCreateRegion ();
129 }
130
131-Region
132-CompRegion::handle () const
133-{
134- return static_cast<Region> (priv);
135-}
136-
137 CompRegion &
138 CompRegion::operator= (const CompRegion &c)
139 {
140
141=== modified file 'src/window.cpp'
142--- src/window.cpp 2012-04-19 03:51:42 +0000
143+++ src/window.cpp 2012-04-19 11:47:45 +0000
144@@ -6537,6 +6537,15 @@
145 width (0),
146 height (0),
147 region (),
148+ frameRegion (),
149+ borderRect (boost::bind (&PrivateWindow::recalcExtentsRect, this, _1, &geometry, &border)),
150+ serverBorderRect (boost::bind (&PrivateWindow::recalcExtentsRect, this, _1, &serverGeometry, &border)),
151+ inputRect (boost::bind (&PrivateWindow::recalcExtentsRect, this, _1, &geometry, &input)),
152+ serverInputRect (boost::bind (&PrivateWindow::recalcExtentsRect, this, _1, &serverGeometry, &serverInput)),
153+ outputRect (boost::bind (&PrivateWindow::recalcExtentsRect, this, _1, &geometry, &output)),
154+ serverOutputRect (boost::bind (&PrivateWindow::recalcExtentsRect, this, _1, &serverGeometry, &output)),
155+ geometryBorders (boost::bind (&PrivateWindow::recalcGeometryBordersRect, this, _1, &geometry)),
156+ serverGeometryBorders (boost::bind (&PrivateWindow::recalcGeometryBordersRect, this, _1, &serverGeometry)),
157 wmType (0),
158 type (CompWindowTypeUnknownMask),
159 state (0),
160
161=== modified file 'src/window/geometry/include/core/windowgeometry.h'
162--- src/window/geometry/include/core/windowgeometry.h 2012-01-19 20:08:32 +0000
163+++ src/window/geometry/include/core/windowgeometry.h 2012-04-19 11:47:45 +0000
164@@ -55,7 +55,7 @@
165 Geometry ();
166 Geometry (int x, int y, int width, int height, int border);
167
168- int border () const;
169+ int border () const { return mBorder; }
170
171 void set (int x, int y, int width, int height, int border);
172 void setBorder (int border);
173
174=== modified file 'src/window/geometry/src/windowgeometry.cpp'
175--- src/window/geometry/src/windowgeometry.cpp 2012-01-19 20:08:32 +0000
176+++ src/window/geometry/src/windowgeometry.cpp 2012-04-19 11:47:45 +0000
177@@ -41,12 +41,6 @@
178 {
179 }
180
181-int
182-compiz::window::Geometry::border () const
183-{
184- return mBorder;
185-}
186-
187 void
188 compiz::window::Geometry::setBorder (int border)
189 {
190
191=== modified file 'src/windowgeometry.cpp'
192--- src/windowgeometry.cpp 2012-01-23 05:44:19 +0000
193+++ src/windowgeometry.cpp 2012-04-19 11:47:45 +0000
194@@ -113,7 +113,7 @@
195 2 * priv->serverGeometry.border ();
196 }
197
198-const CompSize
199+CompSize
200 CompWindow::serverSize () const
201 {
202 return CompSize (priv->serverGeometry.width () +
203@@ -122,68 +122,83 @@
204 2 * priv->serverGeometry.border ());
205 }
206
207-CompRect
208+void
209+PrivateWindow::recalcExtentsRect (CompRect &rect, const CompWindow::Geometry *geometry, const CompWindowExtents *extents)
210+{
211+ rect.setGeometry (geometry->x () - geometry->border () - extents->left,
212+ geometry->y () - geometry->border () - extents->top,
213+ geometry->width () + geometry->border () * 2 +
214+ extents->left + extents->right,
215+ geometry->height () + geometry->border () * 2 +
216+ extents->top + extents->bottom);
217+}
218+
219+void
220+PrivateWindow::recalcGeometryBordersRect (CompRect &rect, const CompWindow::Geometry *geometry)
221+{
222+ rect.setGeometry (geometry->x () - geometry->border (),
223+ geometry->y () - geometry->border (),
224+ geometry->width () + geometry->border () * 2,
225+ geometry->height () + geometry->border () * 2);
226+}
227+
228+compiz::rect::RecalcRect::RecalcRect (const RecalcFunc &func) :
229+ mRecalcFunc (func)
230+{
231+}
232+
233+const CompRect &
234 CompWindow::borderRect () const
235 {
236- return CompRect (priv->geometry.x () - priv->geometry.border () - priv->border.left,
237- priv->geometry.y () - priv->geometry.border () - priv->border.top,
238- priv->geometry.width () + priv->geometry.border () * 2 +
239- priv->border.left + priv->border.right,
240- priv->geometry.height () + priv->geometry.border () * 2 +
241- priv->border.top + priv->border.bottom);
242-}
243-
244-CompRect
245+ priv->borderRect.refresh ();
246+ return priv->borderRect.rect ();
247+}
248+
249+const CompRect &
250+CompWindow::inputRect () const
251+{
252+ priv->inputRect.refresh ();
253+ return priv->inputRect.rect ();
254+}
255+
256+const CompRect &
257+CompWindow::outputRect () const
258+{
259+ priv->outputRect.refresh ();
260+ return priv->outputRect.rect ();
261+}
262+
263+const CompRect &
264 CompWindow::serverBorderRect () const
265 {
266- return CompRect (priv->serverGeometry.x () - priv->geometry.border () - priv->border.left,
267- priv->serverGeometry.y () - priv->geometry.border () - priv->border.top,
268- priv->serverGeometry.width () + priv->geometry.border () * 2 +
269- priv->border.left + priv->border.right,
270- priv->serverGeometry.height () + priv->geometry.border () * 2 +
271- priv->border.top + priv->border.bottom);
272-}
273-
274-CompRect
275-CompWindow::inputRect () const
276-{
277- return CompRect (priv->geometry.x () - priv->geometry.border () - priv->serverInput.left,
278- priv->geometry.y () - priv->geometry.border () - priv->serverInput.top,
279- priv->geometry.width () + priv->geometry.border () * 2 +
280- priv->serverInput.left + priv->serverInput.right,
281- priv->geometry.height () +priv->geometry.border () * 2 +
282- priv->serverInput.top + priv->serverInput.bottom);
283-}
284-
285-CompRect
286+ priv->serverBorderRect.refresh ();
287+ return priv->serverBorderRect.rect ();
288+}
289+
290+const CompRect &
291 CompWindow::serverInputRect () const
292 {
293- return CompRect (priv->serverGeometry.x () - priv->serverGeometry.border () - priv->serverInput.left,
294- priv->serverGeometry.y () - priv->serverGeometry.border () - priv->serverInput.top,
295- priv->serverGeometry.width () + priv->serverGeometry.border () * 2 +
296- priv->serverInput.left + priv->serverInput.right,
297- priv->serverGeometry.height () + priv->serverGeometry.border () * 2 +
298- priv->serverInput.top + priv->serverInput.bottom);
299-}
300-
301-CompRect
302-CompWindow::outputRect () const
303-{
304- return CompRect (priv->geometry.x () - priv->serverGeometry.border ()- priv->output.left,
305- priv->geometry.y () - priv->serverGeometry.border () - priv->output.top,
306- priv->geometry.width () + priv->serverGeometry.border () * 2 +
307- priv->output.left + priv->output.right,
308- priv->geometry.height () + priv->serverGeometry.border () * 2 +
309- priv->output.top + priv->output.bottom);
310-}
311-
312-CompRect
313+ priv->serverInputRect.refresh ();
314+ return priv->serverInputRect.rect ();
315+}
316+
317+const CompRect &
318 CompWindow::serverOutputRect () const
319 {
320- return CompRect (priv->serverGeometry.x () - priv->serverGeometry.border () - priv->output.left,
321- priv->serverGeometry.y () - priv->serverGeometry.border () - priv->output.top,
322- priv->serverGeometry.width () + priv->serverGeometry.border () * 2 +
323- priv->output.left + priv->output.right,
324- priv->serverGeometry.height () + priv->serverGeometry.border () * 2 +
325- priv->output.top + priv->output.bottom);
326+ priv->serverOutputRect.refresh ();
327+ return priv->serverOutputRect.rect ();
328+}
329+
330+const CompRect &
331+CompWindow::geometryBorders () const
332+{
333+ priv->geometryBorders.refresh ();
334+ return priv->geometryBorders.rect ();
335+}
336+
337+const CompRect &
338+CompWindow::serverGeometryBorders () const
339+{
340+ priv->serverGeometryBorders.refresh ();
341+ return priv->serverGeometryBorders.rect ();
342 }

Subscribers

People subscribed via source and target branches