gmain: Optimize insertion of matching or higher priority sources

Calling g_source_attach() does an O(n) iteration over all current
sources until it found the insertion point, while holding the context
mutex.  This is a serious performance hit for heavy asynchronous I/O,
because GIOScheduler sends results back to the source context via
g_source_attach().

A more correct fix for this would be a priority queue, but this patch
is quite simple - we just walk the source list in reverse instead of
forwards.  For applications where most sources are the same priority
(or they have just a few lower-priority sources), this patch is a
large speedup.

However, this patch will degrade performance in the case of inserting
a high-priority source for applications which have many lower-priority
sources.

https://bugzilla.gnome.org/show_bug.cgi?id=619329
This commit is contained in:
Colin Walters 2012-06-21 10:16:21 -04:00
parent 211d50ac74
commit 11ba8eb445

View File

@ -233,6 +233,7 @@ struct _GMainContext
guint next_id;
GSource *source_list;
GSource *source_list_last;
gint in_check_or_prepare;
GPollRec *poll_records, *poll_records_tail;
@ -819,13 +820,13 @@ g_source_list_add (GSource *source,
last_source = source->priv->parent_source->prev;
}
else
{
last_source = NULL;
tmp_source = context->source_list;
while (tmp_source && tmp_source->priority <= source->priority)
{
tmp_source = NULL;
last_source = context->source_list_last;
while (last_source && last_source->priority > source->priority)
{
last_source = tmp_source;
tmp_source = tmp_source->next;
tmp_source = last_source;
last_source = last_source->prev;
}
}
@ -838,6 +839,9 @@ g_source_list_add (GSource *source,
last_source->next = source;
else
context->source_list = source;
if (source->next == NULL)
context->source_list_last = source;
}
/* Holds context's lock
@ -853,6 +857,8 @@ g_source_list_remove (GSource *source,
if (source->next)
source->next->prev = source->prev;
else
context->source_list_last = context->source_list_last->prev;
source->prev = NULL;
source->next = NULL;