45e84a0
From fe5c13ebf1161d0f324229cfb36cb5fb87ec6248 Mon Sep 17 00:00:00 2001
45e84a0
From: Avi Kivity <avi@redhat.com>
45e84a0
Date: Mon, 5 Dec 2011 19:20:12 +0200
45e84a0
Subject: [PATCH 22/25] coroutine: switch per-thread free pool to a global
45e84a0
 pool
45e84a0
45e84a0
ucontext-based coroutines use a free pool to reduce allocations and
45e84a0
deallocations of coroutine objects.  The pool is per-thread, presumably
45e84a0
to improve locality.  However, as coroutines are usually allocated in
45e84a0
a vcpu thread and freed in the I/O thread, the pool accounting gets
45e84a0
screwed up and we end allocating and freeing a coroutine for every I/O
45e84a0
request.  This is expensive since large objects are allocated via the
45e84a0
kernel, and are not cached by the C runtime.
45e84a0
45e84a0
Fix by switching to a global pool.  This is safe since we're protected
45e84a0
by the global mutex.
45e84a0
45e84a0
Signed-off-by: Avi Kivity <avi@redhat.com>
45e84a0
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
45e84a0
---
45e84a0
 coroutine-ucontext.c |   30 ++++++++++++++++--------------
45e84a0
 1 files changed, 16 insertions(+), 14 deletions(-)
45e84a0
45e84a0
diff --git a/coroutine-ucontext.c b/coroutine-ucontext.c
45e84a0
index 2b8d3e9..3d01075 100644
45e84a0
--- a/coroutine-ucontext.c
45e84a0
+++ b/coroutine-ucontext.c
45e84a0
@@ -35,6 +35,10 @@ enum {
45e84a0
     POOL_MAX_SIZE = 64,
45e84a0
 };
45e84a0
45e84a0
+/** Free list to speed up creation */
45e84a0
+static QLIST_HEAD(, Coroutine) pool = QLIST_HEAD_INITIALIZER(pool);
45e84a0
+static unsigned int pool_size;
45e84a0
+
45e84a0
 typedef struct {
45e84a0
     Coroutine base;
45e84a0
     void *stack;
45e84a0
@@ -48,10 +52,6 @@ typedef struct {
45e84a0
     /** Currently executing coroutine */
45e84a0
     Coroutine *current;
45e84a0
45e84a0
-    /** Free list to speed up creation */
45e84a0
-    QLIST_HEAD(, Coroutine) pool;
45e84a0
-    unsigned int pool_size;
45e84a0
-
45e84a0
     /** The default coroutine */
45e84a0
     CoroutineUContext leader;
45e84a0
 } CoroutineThreadState;
45e84a0
@@ -75,7 +75,6 @@ static CoroutineThreadState *coroutine_get_thread_state(void)
45e84a0
     if (!s) {
45e84a0
         s = g_malloc0(sizeof(*s));
45e84a0
         s->current = &s->leader.base;
45e84a0
-        QLIST_INIT(&s->pool);
45e84a0
         pthread_setspecific(thread_state_key, s);
45e84a0
     }
45e84a0
     return s;
45e84a0
@@ -84,14 +83,19 @@ static CoroutineThreadState *coroutine_get_thread_state(void)
45e84a0
 static void qemu_coroutine_thread_cleanup(void *opaque)
45e84a0
 {
45e84a0
     CoroutineThreadState *s = opaque;
45e84a0
+
45e84a0
+    g_free(s);
45e84a0
+}
45e84a0
+
45e84a0
+static void __attribute__((destructor)) coroutine_cleanup(void)
45e84a0
+{
45e84a0
     Coroutine *co;
45e84a0
     Coroutine *tmp;
45e84a0
45e84a0
-    QLIST_FOREACH_SAFE(co, &s->pool, pool_next, tmp) {
45e84a0
+    QLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
45e84a0
         g_free(DO_UPCAST(CoroutineUContext, base, co)->stack);
45e84a0
         g_free(co);
45e84a0
     }
45e84a0
-    g_free(s);
45e84a0
 }
45e84a0
45e84a0
 static void __attribute__((constructor)) coroutine_init(void)
45e84a0
@@ -169,13 +173,12 @@ static Coroutine *coroutine_new(void)
45e84a0
45e84a0
 Coroutine *qemu_coroutine_new(void)
45e84a0
 {
45e84a0
-    CoroutineThreadState *s = coroutine_get_thread_state();
45e84a0
     Coroutine *co;
45e84a0
45e84a0
-    co = QLIST_FIRST(&s->pool);
45e84a0
+    co = QLIST_FIRST(&pool);
45e84a0
     if (co) {
45e84a0
         QLIST_REMOVE(co, pool_next);
45e84a0
-        s->pool_size--;
45e84a0
+        pool_size--;
45e84a0
     } else {
45e84a0
         co = coroutine_new();
45e84a0
     }
45e84a0
@@ -184,13 +187,12 @@ Coroutine *qemu_coroutine_new(void)
45e84a0
45e84a0
 void qemu_coroutine_delete(Coroutine *co_)
45e84a0
 {
45e84a0
-    CoroutineThreadState *s = coroutine_get_thread_state();
45e84a0
     CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
45e84a0
45e84a0
-    if (s->pool_size < POOL_MAX_SIZE) {
45e84a0
-        QLIST_INSERT_HEAD(&s->pool, &co->base, pool_next);
45e84a0
+    if (pool_size < POOL_MAX_SIZE) {
45e84a0
+        QLIST_INSERT_HEAD(&pool, &co->base, pool_next);
45e84a0
         co->base.caller = NULL;
45e84a0
-        s->pool_size++;
45e84a0
+        pool_size++;
45e84a0
         return;
45e84a0
     }
45e84a0
45e84a0
-- 
45e84a0
1.7.7.5
45e84a0