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 7a71aedf46)
This commit is contained in:
Thomas Haller 2021-06-14 19:29:18 +02:00
parent 1c6b50f6ea
commit 5ccbe04788
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
3 changed files with 133 additions and 50 deletions

View file

@ -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)
{

View file

@ -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:
*

View file

@ -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