diff options
author | Thomas Haller <thaller@redhat.com> | 2018-03-23 20:06:38 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2018-03-26 19:35:26 +0200 |
commit | 640736ff65059bbe29ae7fa273015d849c78092a (patch) | |
tree | 259db002f0c76b35a9438453d52b3767eabea808 | |
parent | 0ed5cd5442887010a5ef465df4ffde5a13ef25ec (diff) | |
download | NetworkManager-640736ff65059bbe29ae7fa273015d849c78092a.tar.gz |
core/dbus: cache variants for D-Bus exported properties
GVariant is immutable and can nicely be shared and cached.
Cache the property variants. This makes getting the properties
faster, at the expense of using some extra memory.
Tested with https://tratt.net/laurie/src/multitime/
$ multitime -n 200 -s 0 bash -c 'echo -n .; exec busctl call org.freedesktop.NetworkManager /org/freedesktop org.freedesktop.DBus.ObjectManager GetManagedObjects &>/dev/null'
# Mean Std.Dev. Min Median Max
# real(before) 0.013+/-0.0000 0.001 0.012 0.013 0.019
# real(after) 0.013+/-0.0000 0.002 0.011 0.012 0.034
$ multitime -n 100 -s 0 bash -c 'for i in {1..5}; do busctl call org.freedesktop.NetworkManager /org/freedesktop org.freedesktop.DBus.ObjectManager GetManagedObjects &>/dev/null & done; wait; echo -n .'
# Mean Std.Dev. Min Median Max
# real(before) 0.040+/-0.0000 0.002 0.037 0.040 0.049
# real(after) 0.037+/-0.0000 0.002 0.034 0.036 0.045
$ multitime -n 30 -s 0 bash -c 'for i in {1..100}; do busctl call org.freedesktop.NetworkManager /org/freedesktop org.freedesktop.DBus.ObjectManager GetManagedObjects &>/dev/null & done; wait; echo -n .'
# Mean Std.Dev. Min Median Max
# real(before) 0.704+/-0.0000 0.016 0.687 0.701 0.766
# real(after) 0.639+/-0.0000 0.013 0.622 0.637 0.687
$ multitime -n 200 -s 0 bash -c 'echo -n .; exec nmcli &>/dev/null'
# Mean Std.Dev. Min Median Max
# real(before) 0.092+/-0.0000 0.005 0.081 0.092 0.119
# real(after) 0.092+/-0.0000 0.005 0.080 0.091 0.123
$ multitime -n 100 -s 0 bash -c 'for i in {1..5}; do nmcli &>/dev/null & done; wait; echo -n .'
# Mean Std.Dev. Min Median Max
# real(before) 0.436+/-0.0000 0.043 0.375 0.424 0.600
# real(after) 0.413+/-0.0000 0.022 0.380 0.410 0.558
$ multitime -n 20 -s 0 bash -c 'for i in {1..100}; do nmcli &>/dev/null & done; wait; echo -n .'
# Mean Std.Dev. Min Median Max
# real(before) 8.796+/-0.1070 0.291 8.073 8.818 9.247
# real(after) 8.736+/-0.0893 0.243 8.017 8.780 9.101
The time savings are small, but that is because caching mostly speeds up
the GetManagedObjects calls, and that is only a small part of the entire
nmcli call from client side.
-rw-r--r-- | src/nm-dbus-manager.c | 79 | ||||
-rw-r--r-- | src/nm-dbus-utils.c | 7 | ||||
-rw-r--r-- | src/nm-dbus-utils.h | 3 |
3 files changed, 65 insertions, 24 deletions
diff --git a/src/nm-dbus-manager.c b/src/nm-dbus-manager.c index e0977b1fc9..88fd9a40fd 100644 --- a/src/nm-dbus-manager.c +++ b/src/nm-dbus-manager.c @@ -46,11 +46,16 @@ /*****************************************************************************/ typedef struct { + GVariant *value; +} PropertyCacheData; + +typedef struct { CList registration_lst; NMDBusObject *obj; NMDBusObjectClass *klass; guint info_idx; guint registration_id; + PropertyCacheData property_cache[]; } RegistrationData; /* we require that @path is the first member of NMDBusManagerData @@ -807,7 +812,8 @@ dbus_vtable_method_call (GDBusConnection *connection, nm_assert (nm_streq (property_interface, interface_info->parent.name)); property_info = (const NMDBusPropertyInfoExtended *) nm_dbus_utils_interface_info_lookup_property (&interface_info->parent, - property_name); + property_name, + NULL); if ( !property_info || !NM_FLAGS_HAS (property_info->parent.flags, G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE)) g_return_if_reached (); @@ -855,6 +861,33 @@ dbus_vtable_method_call (GDBusConnection *connection, } static GVariant * +_obj_get_property (RegistrationData *reg_data, + guint property_idx, + gboolean refetch) +{ + const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); + const NMDBusPropertyInfoExtended *property_info; + GVariant *value; + + property_info = (const NMDBusPropertyInfoExtended *) (interface_info->parent.properties[property_idx]); + + if (refetch) + nm_clear_g_variant (®_data->property_cache[property_idx].value); + else { + value = reg_data->property_cache[property_idx].value; + if (value) + goto out; + } + + value = nm_dbus_utils_get_property (G_OBJECT (reg_data->obj), + property_info->parent.signature, + property_info->property_name); + reg_data->property_cache[property_idx].value = value; +out: + return g_variant_ref (value); +} + +static GVariant * dbus_vtable_get_property (GDBusConnection *connection, const char *sender, const char *object_path, @@ -865,16 +898,14 @@ dbus_vtable_get_property (GDBusConnection *connection, { RegistrationData *reg_data = user_data; const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); - const NMDBusPropertyInfoExtended *property_info; + guint property_idx; - property_info = (const NMDBusPropertyInfoExtended *) nm_dbus_utils_interface_info_lookup_property (&interface_info->parent, - property_name); - if (!property_info) + if (!nm_dbus_utils_interface_info_lookup_property (&interface_info->parent, + property_name, + &property_idx)) g_return_val_if_reached (NULL); - return nm_dbus_utils_get_property (G_OBJECT (reg_data->obj), - property_info->parent.signature, - property_info->property_name); + return _obj_get_property (reg_data, property_idx, FALSE); } static const GDBusInterfaceVTable dbus_vtable = { @@ -930,8 +961,9 @@ _obj_register (NMDBusManager *self, RegistrationData *reg_data; gs_free_error GError *error = NULL; guint registration_id; + guint prop_len = NM_PTRARRAY_LEN (interface_info->parent.properties); - reg_data = g_slice_new (RegistrationData); + reg_data = g_malloc0 (sizeof (RegistrationData) + (sizeof (PropertyCacheData) * prop_len)); registration_id = g_dbus_connection_register_object (priv->connection, obj->internal.path, @@ -997,14 +1029,23 @@ _obj_unregister (NMDBusManager *self, g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); while ((reg_data = c_list_last_entry (&obj->internal.registration_lst_head, RegistrationData, registration_lst))) { + const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); + guint i; + g_variant_builder_add (&builder, "s", - _reg_data_get_interface_info (reg_data)->parent.name); + interface_info->parent.name); c_list_unlink_stale (®_data->registration_lst); if (!g_dbus_connection_unregister_object (priv->connection, reg_data->registration_id)) nm_assert_not_reached (); + + if (interface_info->parent.properties) { + for (i = 0; interface_info->parent.properties[i]; i++) + nm_clear_g_variant (®_data->property_cache[i].value); + } + g_type_class_unref (reg_data->klass); - g_slice_free (RegistrationData, reg_data); + g_free (reg_data); } g_dbus_connection_emit_signal (priv->connection, @@ -1142,9 +1183,7 @@ _nm_dbus_manager_obj_notify (NMDBusObject *obj, if (!nm_streq (property_info->property_name, pspec->name)) continue; - value = nm_dbus_utils_get_property (G_OBJECT (obj), - property_info->parent.signature, - property_info->property_name); + value = _obj_get_property (reg_data, i, TRUE); if ( property_info->include_in_legacy_property_changed && any_legacy_signals) { @@ -1277,9 +1316,10 @@ _nm_dbus_manager_obj_emit_signal (NMDBusObject *obj, static GVariantBuilder * _obj_collect_properties_per_interface (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, + RegistrationData *reg_data, GVariantBuilder *builder) { + const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); guint i; g_variant_builder_init (builder, G_VARIANT_TYPE ("a{sv}")); @@ -1288,9 +1328,7 @@ _obj_collect_properties_per_interface (NMDBusObject *obj, const NMDBusPropertyInfoExtended *property_info = (const NMDBusPropertyInfoExtended *) interface_info->parent.properties[i]; gs_unref_variant GVariant *variant = NULL; - variant = nm_dbus_utils_get_property (G_OBJECT (obj), - property_info->parent.signature, - property_info->property_name); + variant = _obj_get_property (reg_data, i, FALSE); g_variant_builder_add (builder, "{sv}", property_info->parent.name, @@ -1309,14 +1347,13 @@ _obj_collect_properties_all (NMDBusObject *obj, g_variant_builder_init (builder, G_VARIANT_TYPE ("a{sa{sv}}")); c_list_for_each_entry (reg_data, &obj->internal.registration_lst_head, registration_lst) { - const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); GVariantBuilder properties_builder; g_variant_builder_add (builder, "{sa{sv}}", - interface_info->parent.name, + _reg_data_get_interface_info (reg_data)->parent.name, _obj_collect_properties_per_interface (obj, - interface_info, + reg_data, &properties_builder)); } diff --git a/src/nm-dbus-utils.c b/src/nm-dbus-utils.c index 514dc798c6..eab6cb6125 100644 --- a/src/nm-dbus-utils.c +++ b/src/nm-dbus-utils.c @@ -35,7 +35,8 @@ const GDBusSignalInfo nm_signal_info_property_changed_legacy = NM_DEFINE_GDBUS_S GDBusPropertyInfo * nm_dbus_utils_interface_info_lookup_property (const GDBusInterfaceInfo *interface_info, - const char *property_name) + const char *property_name, + guint *property_idx) { guint i; @@ -48,8 +49,10 @@ nm_dbus_utils_interface_info_lookup_property (const GDBusInterfaceInfo *interfac for (i = 0; interface_info->properties[i]; i++) { GDBusPropertyInfo *info = interface_info->properties[i]; - if (nm_streq (info->name, property_name)) + if (nm_streq (info->name, property_name)) { + NM_SET_OUT (property_idx, i); return info; + } } } diff --git a/src/nm-dbus-utils.h b/src/nm-dbus-utils.h index 0a28bebcae..4b0ec5c477 100644 --- a/src/nm-dbus-utils.h +++ b/src/nm-dbus-utils.h @@ -152,7 +152,8 @@ extern const GDBusSignalInfo nm_signal_info_property_changed_legacy; /*****************************************************************************/ GDBusPropertyInfo *nm_dbus_utils_interface_info_lookup_property (const GDBusInterfaceInfo *interface_info, - const char *property_name); + const char *property_name, + guint *property_idx); GDBusMethodInfo *nm_dbus_utils_interface_info_lookup_method (const GDBusInterfaceInfo *interface_info, const char *method_name); |