client_stack(): Only stack windows once per mainloop

I was creating 2000 wiboxes in a loop (don't ask) and creating them took
forever. According to callgrind, there were about 2 million calls to
xcb_configure_window() and most (if not all) of them were from client_stack().
Awesome spent 70% of its cpu time in these client_stack() calls.

client_stack() is O(N^2) on the number of clients (it walks the list of clients
itself twice and each call to client_stack_above() walks the list too) and O(N)
on the number of wiboxes (it walks the wibox list twice). So obviously calls to
it should be rare.

This patch makes client_stack() only set a flag which is later checked. This
should reduce the number of restacks to the bare minimum. With this patch,
neither xcb_configure_window() nor anything else client_stack() related shows
up as having a lot of calls or using much cpu time.

Signed-off-by: Uli Schlachter <psychon@znc.in>
Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Uli Schlachter 2009-04-10 18:15:48 +02:00 committed by Julien Danjou
parent 4b82608952
commit 2a6d5d207d
4 changed files with 22 additions and 3 deletions

View File

@ -344,8 +344,8 @@ client_layer_translator(client_t *c)
* \todo It might be worth stopping to restack everyone and only stack `c' * \todo It might be worth stopping to restack everyone and only stack `c'
* relatively to the first matching in the list. * relatively to the first matching in the list.
*/ */
void static void
client_stack() client_real_stack(void)
{ {
uint32_t config_win_vals[2]; uint32_t config_win_vals[2];
client_node_t *node, *last = *client_node_list_last(&globalconf.stack); client_node_t *node, *last = *client_node_list_last(&globalconf.stack);
@ -400,6 +400,15 @@ client_stack()
} }
} }
void
client_stack_refresh()
{
if (!globalconf.client_need_stack_refresh)
return;
globalconf.client_need_stack_refresh = false;
client_real_stack();
}
/** Manage a new client. /** Manage a new client.
* \param w The window. * \param w The window.
* \param wgeom Window geometry. * \param wgeom Window geometry.

View File

@ -55,7 +55,6 @@ DO_RCNT(client_t, client, client_delete)
bool client_maybevisible(client_t *, int); bool client_maybevisible(client_t *, int);
client_t * client_getbywin(xcb_window_t); client_t * client_getbywin(xcb_window_t);
void client_stack(void);
void client_ban(client_t *); void client_ban(client_t *);
void client_unban(client_t *); void client_unban(client_t *);
void client_manage(xcb_window_t, xcb_get_geometry_reply_t *, int, bool); void client_manage(xcb_window_t, xcb_get_geometry_reply_t *, int, bool);
@ -79,6 +78,7 @@ void client_focus(client_t *);
void client_focus_update(client_t *); void client_focus_update(client_t *);
void client_unfocus(client_t *); void client_unfocus(client_t *);
void client_unfocus_update(client_t *); void client_unfocus_update(client_t *);
void client_stack_refresh(void);
int luaA_client_newindex(lua_State *); int luaA_client_newindex(lua_State *);
@ -86,6 +86,12 @@ int luaA_client_userdata_new(lua_State *, client_t *);
DO_SLIST(client_t, client, client_unref) DO_SLIST(client_t, client, client_unref)
static inline void
client_stack(void)
{
globalconf.client_need_stack_refresh = true;
}
/** Put client on top of the stack. /** Put client on top of the stack.
* \param c The client to raise. * \param c The client to raise.
*/ */

View File

@ -26,12 +26,14 @@
#include "wibox.h" #include "wibox.h"
#include "layout.h" #include "layout.h"
#include "client.h"
static inline int static inline int
awesome_refresh(void) awesome_refresh(void)
{ {
layout_refresh(); layout_refresh();
wibox_refresh(); wibox_refresh();
client_stack_refresh();
return xcb_flush(globalconf.connection); return xcb_flush(globalconf.connection);
} }

View File

@ -381,6 +381,8 @@ struct awesome_t
luaA_ref mousegrabber; luaA_ref mousegrabber;
/** Focused screen */ /** Focused screen */
screen_t *screen_focus; screen_t *screen_focus;
/** Need to call client_stack_refresh() */
bool client_need_stack_refresh;
}; };
DO_ARRAY(const void *, void, DO_NOTHING) DO_ARRAY(const void *, void, DO_NOTHING)