change to add only one _XAsyncHandler per display, speeding things up a
2002-10-06 Havoc Pennington <hp@pobox.com> * src/async-getprop.c: change to add only one _XAsyncHandler per display, speeding things up a bit.
This commit is contained in:
parent
a1bb0e0015
commit
fc4a0aef0d
@ -1,8 +1,13 @@
|
|||||||
|
2002-10-06 Havoc Pennington <hp@pobox.com>
|
||||||
|
|
||||||
|
* src/async-getprop.c: change to add only one _XAsyncHandler per
|
||||||
|
display, speeding things up a bit.
|
||||||
|
|
||||||
2002-10-06 Havoc Pennington <hp@pobox.com>
|
2002-10-06 Havoc Pennington <hp@pobox.com>
|
||||||
|
|
||||||
* src/async-getprop.c: Add wacky hack suggested by Keith Packard
|
* src/async-getprop.c: Add wacky hack suggested by Keith Packard
|
||||||
to get X properties asynchronously. Not actually used by metacity
|
to get X properties asynchronously. Not actually used by metacity
|
||||||
yet, but thinking about it.
|
yet, but thinking about it.
|
||||||
|
|
||||||
2002-10-04 Havoc Pennington <hp@redhat.com>
|
2002-10-04 Havoc Pennington <hp@redhat.com>
|
||||||
|
|
||||||
|
@ -43,14 +43,22 @@
|
|||||||
#define NULL ((void*)0)
|
#define NULL ((void*)0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef struct _ListNode ListNode;
|
||||||
|
typedef struct _AgPerDisplayData AgPerDisplayData;
|
||||||
|
|
||||||
|
struct _ListNode
|
||||||
|
{
|
||||||
|
ListNode *next;
|
||||||
|
};
|
||||||
|
|
||||||
struct _AgGetPropertyTask
|
struct _AgGetPropertyTask
|
||||||
{
|
{
|
||||||
Display *display;
|
ListNode node;
|
||||||
|
|
||||||
|
AgPerDisplayData *dd;
|
||||||
Window window;
|
Window window;
|
||||||
Atom property;
|
Atom property;
|
||||||
|
|
||||||
_XAsyncHandler async;
|
|
||||||
|
|
||||||
unsigned long request_seq;
|
unsigned long request_seq;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
@ -62,21 +70,29 @@ struct _AgGetPropertyTask
|
|||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
|
|
||||||
Bool have_reply;
|
Bool have_reply;
|
||||||
|
|
||||||
AgGetPropertyTask *next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static AgGetPropertyTask *pending_tasks = NULL;
|
struct _AgPerDisplayData
|
||||||
static AgGetPropertyTask *pending_tasks_tail = NULL;
|
{
|
||||||
static AgGetPropertyTask *completed_tasks = NULL;
|
ListNode node;
|
||||||
static AgGetPropertyTask *completed_tasks_tail = NULL;
|
_XAsyncHandler async;
|
||||||
static int n_tasks_pending = 0;
|
|
||||||
static int n_tasks_completed = 0;
|
Display *display;
|
||||||
|
ListNode *pending_tasks;
|
||||||
|
ListNode *pending_tasks_tail;
|
||||||
|
ListNode *completed_tasks;
|
||||||
|
ListNode *completed_tasks_tail;
|
||||||
|
int n_tasks_pending;
|
||||||
|
int n_tasks_completed;
|
||||||
|
};
|
||||||
|
|
||||||
|
static ListNode *display_datas = NULL;
|
||||||
|
static ListNode *display_datas_tail = NULL;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
append_to_list (AgGetPropertyTask **head,
|
append_to_list (ListNode **head,
|
||||||
AgGetPropertyTask **tail,
|
ListNode **tail,
|
||||||
AgGetPropertyTask *task)
|
ListNode *task)
|
||||||
{
|
{
|
||||||
task->next = NULL;
|
task->next = NULL;
|
||||||
|
|
||||||
@ -94,12 +110,12 @@ append_to_list (AgGetPropertyTask **head,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
remove_from_list (AgGetPropertyTask **head,
|
remove_from_list (ListNode **head,
|
||||||
AgGetPropertyTask **tail,
|
ListNode **tail,
|
||||||
AgGetPropertyTask *task)
|
ListNode *task)
|
||||||
{
|
{
|
||||||
AgGetPropertyTask *prev;
|
ListNode *prev;
|
||||||
AgGetPropertyTask *node;
|
ListNode *node;
|
||||||
|
|
||||||
prev = NULL;
|
prev = NULL;
|
||||||
node = *head;
|
node = *head;
|
||||||
@ -129,18 +145,60 @@ remove_from_list (AgGetPropertyTask **head,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
move_to_completed (AgGetPropertyTask *task)
|
move_to_completed (AgPerDisplayData *dd,
|
||||||
|
AgGetPropertyTask *task)
|
||||||
{
|
{
|
||||||
remove_from_list (&pending_tasks,
|
remove_from_list (&dd->pending_tasks,
|
||||||
&pending_tasks_tail,
|
&dd->pending_tasks_tail,
|
||||||
task);
|
&task->node);
|
||||||
|
|
||||||
append_to_list (&completed_tasks,
|
append_to_list (&dd->completed_tasks,
|
||||||
&completed_tasks_tail,
|
&dd->completed_tasks_tail,
|
||||||
task);
|
&task->node);
|
||||||
|
|
||||||
--n_tasks_pending;
|
dd->n_tasks_pending -= 1;
|
||||||
++n_tasks_completed;
|
dd->n_tasks_completed += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AgGetPropertyTask*
|
||||||
|
find_pending_by_request_sequence (AgPerDisplayData *dd,
|
||||||
|
unsigned long request_seq)
|
||||||
|
{
|
||||||
|
ListNode *node;
|
||||||
|
|
||||||
|
/* if the sequence is after our last pending task, we
|
||||||
|
* aren't going to find a match
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
AgGetPropertyTask *task = (AgGetPropertyTask*) dd->pending_tasks_tail;
|
||||||
|
if (task != NULL)
|
||||||
|
{
|
||||||
|
if (task->request_seq < request_seq)
|
||||||
|
return NULL;
|
||||||
|
else if (task->request_seq == request_seq)
|
||||||
|
return task; /* why not check this */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generally we should get replies in the order we sent
|
||||||
|
* requests, so we should usually be using the task
|
||||||
|
* at the head of the list, if we use any task at all.
|
||||||
|
* I'm not sure this is 100% guaranteed, if it is,
|
||||||
|
* it would be a big speedup.
|
||||||
|
*/
|
||||||
|
|
||||||
|
node = dd->pending_tasks;
|
||||||
|
while (node != NULL)
|
||||||
|
{
|
||||||
|
AgGetPropertyTask *task = (AgGetPropertyTask*) node;
|
||||||
|
|
||||||
|
if (task->request_seq == request_seq)
|
||||||
|
return task;
|
||||||
|
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bool
|
static Bool
|
||||||
@ -153,20 +211,25 @@ async_get_property_handler (Display *dpy,
|
|||||||
xGetPropertyReply replbuf;
|
xGetPropertyReply replbuf;
|
||||||
xGetPropertyReply *reply;
|
xGetPropertyReply *reply;
|
||||||
AgGetPropertyTask *task;
|
AgGetPropertyTask *task;
|
||||||
|
AgPerDisplayData *dd;
|
||||||
int bytes_read;
|
int bytes_read;
|
||||||
|
|
||||||
task = (AgGetPropertyTask*) data;
|
dd = (AgPerDisplayData*) data;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
printf ("%s: waiting for %ld seeing %ld buflen %d\n", __FUNCTION__,
|
printf ("%s: seeing request seq %ld buflen %d\n", __FUNCTION__,
|
||||||
task->request_seq, dpy->last_request_read, len);
|
dpy->last_request_read, len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
task = find_pending_by_request_sequence (dd, dpy->last_request_read);
|
||||||
|
|
||||||
if (dpy->last_request_read != task->request_seq)
|
if (task == NULL)
|
||||||
return False;
|
return False;
|
||||||
|
|
||||||
|
assert (dpy->last_request_read == task->request_seq);
|
||||||
|
|
||||||
task->have_reply = True;
|
task->have_reply = True;
|
||||||
move_to_completed (task);
|
move_to_completed (dd, task);
|
||||||
|
|
||||||
/* read bytes so far */
|
/* read bytes so far */
|
||||||
bytes_read = SIZEOF (xReply);
|
bytes_read = SIZEOF (xReply);
|
||||||
@ -366,6 +429,57 @@ async_get_property_handler (Display *dpy,
|
|||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AgPerDisplayData*
|
||||||
|
get_display_data (Display *display,
|
||||||
|
Bool create)
|
||||||
|
{
|
||||||
|
ListNode *node;
|
||||||
|
AgPerDisplayData *dd;
|
||||||
|
|
||||||
|
node = display_datas;
|
||||||
|
while (node != NULL)
|
||||||
|
{
|
||||||
|
dd = (AgPerDisplayData*) node;
|
||||||
|
|
||||||
|
if (dd->display == display)
|
||||||
|
return dd;
|
||||||
|
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!create)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
dd = Xcalloc (1, sizeof (AgPerDisplayData));
|
||||||
|
if (dd == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
dd->display = display;
|
||||||
|
dd->async.next = display->async_handlers;
|
||||||
|
dd->async.handler = async_get_property_handler;
|
||||||
|
dd->async.data = (XPointer) dd;
|
||||||
|
dd->display->async_handlers = &dd->async;
|
||||||
|
|
||||||
|
append_to_list (&display_datas,
|
||||||
|
&display_datas_tail,
|
||||||
|
&dd->node);
|
||||||
|
|
||||||
|
return dd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
maybe_free_display_data (AgPerDisplayData *dd)
|
||||||
|
{
|
||||||
|
if (dd->pending_tasks == NULL &&
|
||||||
|
dd->completed_tasks == NULL)
|
||||||
|
{
|
||||||
|
DeqAsyncHandler (dd->display, &dd->async);
|
||||||
|
remove_from_list (&display_datas, &display_datas_tail,
|
||||||
|
&dd->node);
|
||||||
|
XFree (dd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AgGetPropertyTask*
|
AgGetPropertyTask*
|
||||||
ag_task_create (Display *dpy,
|
ag_task_create (Display *dpy,
|
||||||
Window window,
|
Window window,
|
||||||
@ -378,9 +492,18 @@ ag_task_create (Display *dpy,
|
|||||||
AgGetPropertyTask *task;
|
AgGetPropertyTask *task;
|
||||||
xGetPropertyReq *req;
|
xGetPropertyReq *req;
|
||||||
xError error;
|
xError error;
|
||||||
|
AgPerDisplayData *dd;
|
||||||
|
|
||||||
/* Fire up our request */
|
/* Fire up our request */
|
||||||
LockDisplay (dpy);
|
LockDisplay (dpy);
|
||||||
|
|
||||||
|
dd = get_display_data (dpy, True);
|
||||||
|
if (dd == NULL)
|
||||||
|
{
|
||||||
|
UnlockDisplay (dpy);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
GetReq (GetProperty, req);
|
GetReq (GetProperty, req);
|
||||||
req->window = window;
|
req->window = window;
|
||||||
req->property = property;
|
req->property = property;
|
||||||
@ -399,19 +522,15 @@ ag_task_create (Display *dpy,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
task->display = dpy;
|
task->dd = dd;
|
||||||
task->window = window;
|
task->window = window;
|
||||||
task->property = property;
|
task->property = property;
|
||||||
task->request_seq = dpy->request;
|
task->request_seq = dpy->request;
|
||||||
task->async.next = dpy->async_handlers;
|
|
||||||
task->async.handler = async_get_property_handler;
|
|
||||||
task->async.data = (XPointer) task;
|
|
||||||
dpy->async_handlers = &task->async;
|
|
||||||
|
|
||||||
append_to_list (&pending_tasks,
|
append_to_list (&dd->pending_tasks,
|
||||||
&pending_tasks_tail,
|
&dd->pending_tasks_tail,
|
||||||
task);
|
&task->node);
|
||||||
++n_tasks_pending;
|
dd->n_tasks_pending += 1;
|
||||||
|
|
||||||
UnlockDisplay (dpy);
|
UnlockDisplay (dpy);
|
||||||
|
|
||||||
@ -420,6 +539,17 @@ ag_task_create (Display *dpy,
|
|||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_task (AgGetPropertyTask *task)
|
||||||
|
{
|
||||||
|
remove_from_list (&task->dd->completed_tasks,
|
||||||
|
&task->dd->completed_tasks_tail,
|
||||||
|
&task->node);
|
||||||
|
task->dd->n_tasks_completed -= 1;
|
||||||
|
maybe_free_display_data (task->dd);
|
||||||
|
XFree (task);
|
||||||
|
}
|
||||||
|
|
||||||
Status
|
Status
|
||||||
ag_task_get_reply_and_free (AgGetPropertyTask *task,
|
ag_task_get_reply_and_free (AgGetPropertyTask *task,
|
||||||
Atom *actual_type,
|
Atom *actual_type,
|
||||||
@ -432,24 +562,21 @@ ag_task_get_reply_and_free (AgGetPropertyTask *task,
|
|||||||
|
|
||||||
*prop = NULL;
|
*prop = NULL;
|
||||||
|
|
||||||
dpy = task->display; /* Xlib macros require a variable named "dpy" */
|
dpy = task->dd->display; /* Xlib macros require a variable named "dpy" */
|
||||||
|
|
||||||
if (task->error != Success)
|
if (task->error != Success)
|
||||||
{
|
{
|
||||||
Status s = task->error;
|
Status s = task->error;
|
||||||
DeqAsyncHandler (task->display, &task->async);
|
|
||||||
remove_from_list (&completed_tasks, &completed_tasks_tail, task);
|
free_task (task);
|
||||||
--n_tasks_completed;
|
|
||||||
XFree (task);
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!task->have_reply)
|
if (!task->have_reply)
|
||||||
{
|
{
|
||||||
DeqAsyncHandler (task->display, &task->async);
|
free_task (task);
|
||||||
remove_from_list (&completed_tasks, &completed_tasks_tail, task);
|
|
||||||
--n_tasks_completed;
|
|
||||||
XFree (task);
|
|
||||||
return BadAlloc; /* not Success */
|
return BadAlloc; /* not Success */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,10 +589,7 @@ ag_task_get_reply_and_free (AgGetPropertyTask *task,
|
|||||||
|
|
||||||
SyncHandle ();
|
SyncHandle ();
|
||||||
|
|
||||||
DeqAsyncHandler (dpy, &task->async);
|
free_task (task);
|
||||||
remove_from_list (&completed_tasks, &completed_tasks_tail, task);
|
|
||||||
--n_tasks_completed;
|
|
||||||
XFree (task);
|
|
||||||
|
|
||||||
return Success;
|
return Success;
|
||||||
}
|
}
|
||||||
@ -491,26 +615,24 @@ ag_task_get_window (AgGetPropertyTask *task)
|
|||||||
Display*
|
Display*
|
||||||
ag_task_get_display (AgGetPropertyTask *task)
|
ag_task_get_display (AgGetPropertyTask *task)
|
||||||
{
|
{
|
||||||
return task->display;
|
return task->dd->display;
|
||||||
}
|
}
|
||||||
|
|
||||||
AgGetPropertyTask*
|
AgGetPropertyTask*
|
||||||
ag_get_next_completed_task (Display *display)
|
ag_get_next_completed_task (Display *display)
|
||||||
{
|
{
|
||||||
AgGetPropertyTask *node;
|
AgPerDisplayData *dd;
|
||||||
|
|
||||||
#ifdef DEBUG_SPEW
|
dd = get_display_data (display, False);
|
||||||
printf ("%d pending %d completed\n", n_tasks_pending, n_tasks_completed);
|
|
||||||
#endif
|
if (dd == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
node = completed_tasks;
|
#ifdef DEBUG_SPEW
|
||||||
while (node != NULL)
|
printf ("%d pending %d completed\n",
|
||||||
{
|
dd->n_tasks_pending,
|
||||||
if (node->display == display)
|
dd->n_tasks_completed);
|
||||||
return node;
|
#endif
|
||||||
|
|
||||||
node = node->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
return (AgGetPropertyTask*) dd->completed_tasks;
|
||||||
}
|
}
|
||||||
|
@ -374,13 +374,11 @@ run_speed_comparison (Display *xdisplay,
|
|||||||
int n_left;
|
int n_left;
|
||||||
|
|
||||||
/* We just use atom values 0 to n_props, many are probably BadAtom,
|
/* We just use atom values 0 to n_props, many are probably BadAtom,
|
||||||
* that's fine. The larger this number the worse the async case
|
* that's fine.
|
||||||
* looks; my guess is it's because of display->async_handlers
|
|
||||||
* becoming a very long list. Need to modify async-getprop.c
|
|
||||||
* to install only a single async handler per display.
|
|
||||||
*/
|
*/
|
||||||
n_props = 200;
|
n_props = 4000;
|
||||||
|
printf ("Timing with %d property requests\n", n_props);
|
||||||
|
|
||||||
gettimeofday (&start, NULL);
|
gettimeofday (&start, NULL);
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user