diff options
author | Thomas Haller <thaller@redhat.com> | 2021-01-25 14:32:51 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2021-01-25 15:58:42 +0100 |
commit | b26706ca49cf2cda6bdcde3383e5a837067bb814 (patch) | |
tree | 33d814ac014a3e37810def4875f5c0bd12fe9b98 | |
parent | 462668b0c33c10eda2ef1845a7e29d057c4eaa4e (diff) | |
download | NetworkManager-b26706ca49cf2cda6bdcde3383e5a837067bb814.tar.gz |
shared: stack allocate GPollFD array in _ctx_integ_source_prepare()
The prepare() step of the GSource called frequently when the outer
GMainContext is preparing.
In the common case we have
- few file descriptors in the inner context to track
- the file descriptors don't change
We also need to consider whether the file descriptors change, because
some book-keeping is necessary when they do. But usually they don't
change.
Hence, let's optimize the prepare step to avoid a heap allocation
in the common case.
Also, because we use nm_utils_g_main_context_create_integrate_source()
with the internal GMainContext of NMClient. That context always has
a small number of file descriptors to track and it doesn't see much
change. In the vast majority of cases, the heap allocation can be
avoided.
-rw-r--r-- | shared/nm-glib-aux/nm-shared-utils.c | 77 |
1 files changed, 51 insertions, 26 deletions
diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index f42b53c394..8e3f1879bd 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -4799,7 +4799,7 @@ typedef struct { GMainContext *context; GHashTable * fds; GPollFD * fds_arr; - int fds_len; + guint fds_len; int max_priority; bool acquired : 1; } CtxIntegSource; @@ -4842,13 +4842,15 @@ _ctx_integ_source_prepare(GSource *source, int *out_timeout) int max_priority; int timeout = -1; gboolean any_ready; - int fds_allocated; - int fds_len_old; - gs_free GPollFD *fds_arr_old = NULL; - GHashTableIter h_iter; - PollData * poll_data; - gboolean fds_changed; - int i; + GHashTableIter h_iter; + PollData * poll_data; + gboolean fds_changed; + GPollFD new_fds_stack[300u / sizeof(GPollFD)]; + gs_free GPollFD *new_fds_heap = NULL; + GPollFD * new_fds; + guint new_fds_len; + guint new_fds_alloc; + guint i; _CTX_LOG("prepare..."); @@ -4856,30 +4858,44 @@ _ctx_integ_source_prepare(GSource *source, int *out_timeout) any_ready = g_main_context_prepare(ctx_src->context, &max_priority); - fds_arr_old = g_steal_pointer(&ctx_src->fds_arr); - fds_len_old = ctx_src->fds_len; + new_fds_alloc = NM_MAX(G_N_ELEMENTS(new_fds_stack), ctx_src->fds_len); - fds_allocated = NM_MAX(1, fds_len_old); /* there is at least the wakeup's FD */ - ctx_src->fds_arr = g_new(GPollFD, fds_allocated); + if (new_fds_alloc > G_N_ELEMENTS(new_fds_stack)) { + new_fds_heap = g_new(GPollFD, new_fds_alloc); + new_fds = new_fds_heap; + } else + new_fds = new_fds_stack; - while ((ctx_src->fds_len = g_main_context_query(ctx_src->context, - max_priority, - &timeout, - ctx_src->fds_arr, - fds_allocated)) - > fds_allocated) { - fds_allocated = ctx_src->fds_len; - g_free(ctx_src->fds_arr); - ctx_src->fds_arr = g_new(GPollFD, fds_allocated); + for (;;) { + int l; + + nm_assert(new_fds_alloc <= (guint) G_MAXINT); + + l = g_main_context_query(ctx_src->context, + max_priority, + &timeout, + new_fds, + (int) new_fds_alloc); + nm_assert(l >= 0); + + new_fds_len = (guint) l; + + if (G_LIKELY(new_fds_len <= new_fds_alloc)) + break; + + new_fds_alloc = new_fds_len; + g_free(new_fds_heap); + new_fds_heap = g_new(GPollFD, new_fds_alloc); + new_fds = new_fds_heap; } fds_changed = FALSE; - if (fds_len_old != ctx_src->fds_len) + if (new_fds_len != ctx_src->fds_len) fds_changed = TRUE; else { - for (i = 0; i < ctx_src->fds_len; i++) { - if (fds_arr_old[i].fd != ctx_src->fds_arr[i].fd - || fds_arr_old[i].events != ctx_src->fds_arr[i].events) { + for (i = 0; i < new_fds_len; i++) { + if (new_fds[i].fd != ctx_src->fds_arr[i].fd + || new_fds[i].events != ctx_src->fds_arr[i].events) { fds_changed = TRUE; break; } @@ -4887,6 +4903,13 @@ _ctx_integ_source_prepare(GSource *source, int *out_timeout) } if (G_UNLIKELY(fds_changed)) { + g_free(ctx_src->fds_arr); + ctx_src->fds_len = new_fds_len; + if (G_LIKELY(new_fds == new_fds_stack) || new_fds_alloc != new_fds_len) + ctx_src->fds_arr = nm_memdup(new_fds, sizeof(*new_fds) * new_fds_len); + else + ctx_src->fds_arr = g_steal_pointer(&new_fds_heap); + g_hash_table_iter_init(&h_iter, ctx_src->fds); while (g_hash_table_iter_next(&h_iter, (gpointer *) &poll_data, NULL)) poll_data->stale = TRUE; @@ -5021,10 +5044,12 @@ _ctx_integ_source_check(GSource *source) ctx_src->fds_arr[poll_data->idx.one].revents = revents; } + nm_assert(ctx_src->fds_len <= (guint) G_MAXINT); + some_ready = g_main_context_check(ctx_src->context, ctx_src->max_priority, ctx_src->fds_arr, - ctx_src->fds_len); + (int) ctx_src->fds_len); _CTX_LOG("check (some-ready=%d)...", some_ready); |