From 7de19ce86214ce0348d979a00d4d9593bea640ae Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 14 Feb 2012 11:15:01 +0100 Subject: [PATCH 96/99] coroutine: switch per-thread free pool to a global pool RH-Author: Kevin Wolf Message-id: <1329218101-24213-97-git-send-email-kwolf@redhat.com> Patchwork-id: 37284 O-Subject: [RHEL-6.3 qemu-kvm PATCH v2 96/96] coroutine: switch per-thread free pool to a global pool Bugzilla: 783950 RH-Acked-by: Paolo Bonzini RH-Acked-by: Marcelo Tosatti RH-Acked-by: Laszlo Ersek From: Avi Kivity Bugzilla: 783950 ucontext-based coroutines use a free pool to reduce allocations and deallocations of coroutine objects. The pool is per-thread, presumably to improve locality. However, as coroutines are usually allocated in a vcpu thread and freed in the I/O thread, the pool accounting gets screwed up and we end allocating and freeing a coroutine for every I/O request. This is expensive since large objects are allocated via the kernel, and are not cached by the C runtime. Fix by switching to a global pool. This is safe since we're protected by the global mutex. Signed-off-by: Avi Kivity Signed-off-by: Kevin Wolf (cherry picked from commit 39a7a362e16bb27e98738d63f24d1ab5811e26a8) Conflicts: coroutine-ucontext.c Signed-off-by: Kevin Wolf --- coroutine-ucontext.c | 34 ++++++++++++++++++---------------- 1 files changed, 18 insertions(+), 16 deletions(-) Signed-off-by: Michal Novotny --- coroutine-ucontext.c | 34 ++++++++++++++++++---------------- 1 files changed, 18 insertions(+), 16 deletions(-) diff --git a/coroutine-ucontext.c b/coroutine-ucontext.c index 41c2379..ed1fc4c 100644 --- a/coroutine-ucontext.c +++ b/coroutine-ucontext.c @@ -35,6 +35,10 @@ enum { POOL_MAX_SIZE = 64, }; +/** Free list to speed up creation */ +static QLIST_HEAD(, Coroutine) pool = QLIST_HEAD_INITIALIZER(pool); +static unsigned int pool_size; + typedef struct { Coroutine base; void *stack; @@ -48,10 +52,6 @@ typedef struct { /** Currently executing coroutine */ Coroutine *current; - /** Free list to speed up creation */ - QLIST_HEAD(, Coroutine) pool; - unsigned int pool_size; - /** The default coroutine */ CoroutineUContext leader; } CoroutineThreadState; @@ -75,7 +75,6 @@ static CoroutineThreadState *coroutine_get_thread_state(void) if (!s) { s = qemu_mallocz(sizeof(*s)); s->current = &s->leader.base; - QLIST_INIT(&s->pool); pthread_setspecific(thread_state_key, s); } return s; @@ -84,14 +83,19 @@ static CoroutineThreadState *coroutine_get_thread_state(void) static void qemu_coroutine_thread_cleanup(void *opaque) { CoroutineThreadState *s = opaque; + + g_free(s); +} + +static void __attribute__((destructor)) coroutine_cleanup(void) +{ Coroutine *co; Coroutine *tmp; - QLIST_FOREACH_SAFE(co, &s->pool, pool_next, tmp) { - qemu_free(DO_UPCAST(CoroutineUContext, base, co)->stack); - qemu_free(co); + QLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) { + g_free(DO_UPCAST(CoroutineUContext, base, co)->stack); + g_free(co); } - qemu_free(s); } static void __attribute__((constructor)) coroutine_init(void) @@ -169,13 +173,12 @@ static Coroutine *coroutine_new(void) Coroutine *qemu_coroutine_new(void) { - CoroutineThreadState *s = coroutine_get_thread_state(); Coroutine *co; - co = QLIST_FIRST(&s->pool); + co = QLIST_FIRST(&pool); if (co) { QLIST_REMOVE(co, pool_next); - s->pool_size--; + pool_size--; } else { co = coroutine_new(); } @@ -184,13 +187,12 @@ Coroutine *qemu_coroutine_new(void) void qemu_coroutine_delete(Coroutine *co_) { - CoroutineThreadState *s = coroutine_get_thread_state(); CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_); - if (s->pool_size < POOL_MAX_SIZE) { - QLIST_INSERT_HEAD(&s->pool, &co->base, pool_next); + if (pool_size < POOL_MAX_SIZE) { + QLIST_INSERT_HEAD(&pool, &co->base, pool_next); co->base.caller = NULL; - s->pool_size++; + pool_size++; return; } -- 1.7.7.5