From 5ccbe04788f9eeaf1565a2b6a26449de04620e9e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 14 Jun 2021 19:29:18 +0200 Subject: [PATCH] libnm: optimize NM_CONNECTION_GET_PRIVATE() for NMSimpleConnection NMConnection is a glib interface, implemented only by NMSimpleConnection and NMRemoteConnection. Inside the daemon, every NMConnection instance is always a NMSimpleConnection. Using glib interfaces has an overhead, for example NM_IS_CONNECTION() needs to search the implemented types for the pointer. And NM_CONNECTION_GET_PRIVATE() is implemented by attaching user data to the GObject instance. Both have measurable overhead. Special case them for NMSimpleConnection. This optimizes primarily the call to nm_connection_get_setting_connection(), which easily gets called millions of times. This is easily measurable. (cherry picked from commit 7a71aedf46e59e66bba4cbb304617ee85200f4c3) --- src/libnm-core-impl/nm-connection.c | 136 ++++++++++++++------- src/libnm-core-impl/nm-setting-private.h | 16 +++ src/libnm-core-impl/nm-simple-connection.c | 31 ++++- 3 files changed, 133 insertions(+), 50 deletions(-) diff --git a/src/libnm-core-impl/nm-connection.c b/src/libnm-core-impl/nm-connection.c index 3ab2cafcb2..5555a20a51 100644 --- a/src/libnm-core-impl/nm-connection.c +++ b/src/libnm-core-impl/nm-connection.c @@ -46,19 +46,98 @@ enum { static guint signals[LAST_SIGNAL] = {0}; -typedef struct { - NMConnection *self; - - NMSetting *settings[_NM_META_SETTING_TYPE_NUM]; - - /* D-Bus path of the connection, if any */ - char *path; -} NMConnectionPrivate; - G_DEFINE_INTERFACE(NMConnection, nm_connection, G_TYPE_OBJECT) -static NMConnectionPrivate *nm_connection_get_private(NMConnection *connection); -#define NM_CONNECTION_GET_PRIVATE(o) (nm_connection_get_private((NMConnection *) o)) +/*****************************************************************************/ + +static gboolean _nm_connection_clear_settings(NMConnection *connection, NMConnectionPrivate *priv); + +/*****************************************************************************/ + +#undef NM_IS_SIMPLE_CONNECTION +#define NM_IS_SIMPLE_CONNECTION(self) \ + ({ \ + gconstpointer _self1 = (self); \ + gboolean _result; \ + \ + _result = \ + (_self1 \ + && (((GTypeInstance *) _self1)->g_class == _nm_simple_connection_class_instance)); \ + \ + nm_assert(_result == G_TYPE_CHECK_INSTANCE_TYPE(_self1, NM_TYPE_SIMPLE_CONNECTION)); \ + \ + _result; \ + }) + +#undef NM_IS_CONNECTION +#define NM_IS_CONNECTION(self) \ + ({ \ + gconstpointer _self0 = (self); \ + \ + (_self0 \ + && (NM_IS_SIMPLE_CONNECTION(_self0) \ + || G_TYPE_CHECK_INSTANCE_TYPE(_self0, NM_TYPE_CONNECTION))); \ + }) + +/*****************************************************************************/ + +void +_nm_connection_private_clear(NMConnectionPrivate *priv) +{ + if (priv->self) { + _nm_connection_clear_settings(priv->self, priv); + nm_clear_g_free(&priv->path); + priv->self = NULL; + } +} + +static void +_nm_connection_private_free(gpointer data) +{ + NMConnectionPrivate *priv = data; + + _nm_connection_private_clear(priv); + + nm_g_slice_free(priv); +} + +static NMConnectionPrivate * +_nm_connection_get_private_from_qdata(NMConnection *connection) +{ + GQuark key; + NMConnectionPrivate *priv; + + nm_assert(NM_IS_CONNECTION(connection)); + nm_assert(!NM_IS_SIMPLE_CONNECTION(connection)); + + key = NM_CACHED_QUARK("NMConnectionPrivate"); + + priv = g_object_get_qdata((GObject *) connection, key); + if (G_UNLIKELY(!priv)) { + priv = g_slice_new(NMConnectionPrivate); + *priv = (NMConnectionPrivate){ + .self = connection, + }; + g_object_set_qdata_full((GObject *) connection, key, priv, _nm_connection_private_free); + } + + return priv; +} + +#define NM_CONNECTION_GET_PRIVATE(connection) \ + ({ \ + NMConnection * _connection = (connection); \ + NMConnectionPrivate *_priv; \ + \ + if (G_LIKELY(NM_IS_SIMPLE_CONNECTION(_connection))) \ + _priv = (gpointer) (&(((char *) _connection)[_nm_simple_connection_private_offset])); \ + else \ + _priv = _nm_connection_get_private_from_qdata(_connection); \ + \ + nm_assert(_priv && _priv->self == _connection); \ + \ + _priv; \ + }) /*****************************************************************************/ @@ -3557,41 +3636,6 @@ _nm_connection_get_setting_bluetooth_for_nap(NMConnection *connection) /*****************************************************************************/ -static void -nm_connection_private_free(NMConnectionPrivate *priv) -{ - NMConnection *self = priv->self; - - _nm_connection_clear_settings(self, priv); - g_free(priv->path); - - g_slice_free(NMConnectionPrivate, priv); -} - -static NMConnectionPrivate * -nm_connection_get_private(NMConnection *connection) -{ - GQuark key; - NMConnectionPrivate *priv; - - nm_assert(NM_IS_CONNECTION(connection)); - - key = NM_CACHED_QUARK("NMConnectionPrivate"); - - priv = g_object_get_qdata((GObject *) connection, key); - if (G_UNLIKELY(!priv)) { - priv = g_slice_new0(NMConnectionPrivate); - g_object_set_qdata_full((GObject *) connection, - key, - priv, - (GDestroyNotify) nm_connection_private_free); - - priv->self = connection; - } - - return priv; -} - static void nm_connection_default_init(NMConnectionInterface *iface) { diff --git a/src/libnm-core-impl/nm-setting-private.h b/src/libnm-core-impl/nm-setting-private.h index 4185629e22..e8373f8e63 100644 --- a/src/libnm-core-impl/nm-setting-private.h +++ b/src/libnm-core-impl/nm-setting-private.h @@ -19,6 +19,22 @@ /*****************************************************************************/ +typedef struct { + NMConnection *self; + + NMSetting *settings[_NM_META_SETTING_TYPE_NUM]; + + /* D-Bus path of the connection, if any */ + char *path; +} NMConnectionPrivate; + +extern GTypeClass *_nm_simple_connection_class_instance; +extern int _nm_simple_connection_private_offset; + +void _nm_connection_private_clear(NMConnectionPrivate *priv); + +/*****************************************************************************/ + /** * NMSetting: * diff --git a/src/libnm-core-impl/nm-simple-connection.c b/src/libnm-core-impl/nm-simple-connection.c index 185d47fc4f..6b5b118413 100644 --- a/src/libnm-core-impl/nm-simple-connection.c +++ b/src/libnm-core-impl/nm-simple-connection.c @@ -20,6 +20,11 @@ /*****************************************************************************/ +GTypeClass *_nm_simple_connection_class_instance = NULL; +int _nm_simple_connection_private_offset; + +/*****************************************************************************/ + /** * NMSimpleConnection: */ @@ -42,11 +47,20 @@ G_DEFINE_TYPE_WITH_CODE(NMSimpleConnection, G_IMPLEMENT_INTERFACE(NM_TYPE_CONNECTION, nm_simple_connection_interface_init);) +#define _GET_PRIVATE(self) \ + G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_SIMPLE_CONNECTION, NMConnectionPrivate) + /*****************************************************************************/ static void nm_simple_connection_init(NMSimpleConnection *self) -{} +{ + NMConnectionPrivate *priv; + + priv = _GET_PRIVATE(self); + + priv->self = (NMConnection *) self; +} /** * nm_simple_connection_new: @@ -143,22 +157,31 @@ nm_simple_connection_new_clone(NMConnection *connection) static void dispose(GObject *object) { + NMConnection *connection = NM_CONNECTION(object); + #if NM_MORE_ASSERTS g_signal_handlers_disconnect_by_data(object, (gpointer) &_nmtst_connection_unchanging_user_data); #endif - nm_connection_clear_secrets(NM_CONNECTION(object)); + nm_connection_clear_secrets(connection); + + _nm_connection_private_clear(_GET_PRIVATE(connection)); G_OBJECT_CLASS(nm_simple_connection_parent_class)->dispose(object); } static void -nm_simple_connection_class_init(NMSimpleConnectionClass *simple_class) +nm_simple_connection_class_init(NMSimpleConnectionClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS(simple_class); + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(NMConnectionPrivate)); object_class->dispose = dispose; + + _nm_simple_connection_private_offset = g_type_class_get_instance_private_offset(klass); + _nm_simple_connection_class_instance = (GTypeClass *) klass; } static void