gtkbuilder: Eliminate array reallocations in get_parameters()
`gtk_builder_get_parameters()` is a hot path, being called twice for each object in each UI file in an application. The majority of objects have ≤ 8 properties, which are each filtered into either `parameters` or `filtered_parameters`. Unfortunately, both of those arrays are created as empty `GArray`s, and adding 8 elements to an empty `GArray` hits the worst possible case of reallocating and `memcpy()`ing the array 3 times. As the array size is doubled with each reallocation, the cost is not particularly well amortised when the array size is small. From the `ObjectInfo`, we actually know how many properties there are in total, so just allocate the arrays at the right size to begin with. This saves 7% of the instruction cycles needed to start up gnome-software to the point where it’s showing its main window, according to callgrind. gnome-software is making around 5500 calls to `gtk_builder_get_parameters()`. Signed-off-by: Philip Withnall <withnall@endlessm.com>
This commit is contained in:
parent
996e22bde9
commit
fb998ff52d
@ -458,6 +458,7 @@ gtk_builder_get_parameters (GtkBuilder *builder,
|
|||||||
GType object_type,
|
GType object_type,
|
||||||
const gchar *object_name,
|
const gchar *object_name,
|
||||||
GSList *properties,
|
GSList *properties,
|
||||||
|
gsize n_properties,
|
||||||
GParamFlags filter_flags,
|
GParamFlags filter_flags,
|
||||||
GArray **parameters,
|
GArray **parameters,
|
||||||
GArray **filtered_parameters)
|
GArray **filtered_parameters)
|
||||||
@ -466,10 +467,23 @@ gtk_builder_get_parameters (GtkBuilder *builder,
|
|||||||
DelayedProperty *property;
|
DelayedProperty *property;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
|
/* Create the two arrays with size @n_properties. The total number of elements
|
||||||
|
* between them will eventually be @n_properties, but it’s more important to
|
||||||
|
* avoid realloc()/memcpy() calls on these arrays than to be tight with memory
|
||||||
|
* allocations (and overallocating by 100% is no worse than what #GArray does
|
||||||
|
* internally with doubling its size every time it’s full).
|
||||||
|
*
|
||||||
|
* @n_properties is typically ≤ 8, so it’s
|
||||||
|
* (a) not much of an impact to overallocate
|
||||||
|
* (b) disproportionally subject to realloc()/memcpy() since the array size
|
||||||
|
* doubles 3 times in the first 8 elements
|
||||||
|
*
|
||||||
|
* gtk_builder_get_parameters() gets called twice for every object in every
|
||||||
|
* #GtkBuilder file, so it’s a fairly hot path. */
|
||||||
if (parameters)
|
if (parameters)
|
||||||
*parameters = g_array_new (FALSE, FALSE, sizeof (GParameter));
|
*parameters = g_array_sized_new (FALSE, FALSE, sizeof (GParameter), n_properties);
|
||||||
if (filtered_parameters)
|
if (filtered_parameters)
|
||||||
*filtered_parameters = g_array_new (FALSE, FALSE, sizeof (GParameter));
|
*filtered_parameters = g_array_sized_new (FALSE, FALSE, sizeof (GParameter), n_properties);
|
||||||
|
|
||||||
for (l = properties; l; l = l->next)
|
for (l = properties; l; l = l->next)
|
||||||
{
|
{
|
||||||
@ -670,6 +684,7 @@ _gtk_builder_construct (GtkBuilder *builder,
|
|||||||
gtk_builder_get_parameters (builder, info->type,
|
gtk_builder_get_parameters (builder, info->type,
|
||||||
info->id,
|
info->id,
|
||||||
info->properties,
|
info->properties,
|
||||||
|
info->n_properties,
|
||||||
param_filter_flags,
|
param_filter_flags,
|
||||||
¶meters,
|
¶meters,
|
||||||
&construct_parameters);
|
&construct_parameters);
|
||||||
@ -814,6 +829,7 @@ _gtk_builder_apply_properties (GtkBuilder *builder,
|
|||||||
gtk_builder_get_parameters (builder, info->type,
|
gtk_builder_get_parameters (builder, info->type,
|
||||||
info->id,
|
info->id,
|
||||||
info->properties,
|
info->properties,
|
||||||
|
info->n_properties,
|
||||||
G_PARAM_CONSTRUCT_ONLY,
|
G_PARAM_CONSTRUCT_ONLY,
|
||||||
¶meters, NULL);
|
¶meters, NULL);
|
||||||
|
|
||||||
|
@ -1112,6 +1112,7 @@ end_element (GMarkupParseContext *context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
object_info->properties = g_slist_prepend (object_info->properties, prop_info);
|
object_info->properties = g_slist_prepend (object_info->properties, prop_info);
|
||||||
|
object_info->n_properties++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
|
@ -36,6 +36,7 @@ typedef struct {
|
|||||||
gchar *id;
|
gchar *id;
|
||||||
gchar *constructor;
|
gchar *constructor;
|
||||||
GSList *properties;
|
GSList *properties;
|
||||||
|
gsize n_properties;
|
||||||
GSList *signals;
|
GSList *signals;
|
||||||
GSList *bindings;
|
GSList *bindings;
|
||||||
GObject *object;
|
GObject *object;
|
||||||
|
Loading…
Reference in New Issue
Block a user