arena: Connecting importers with sources
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 9 Nov 2016 15:44:44 +0000 (10:44 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 29 Nov 2016 16:27:40 +0000 (11:27 -0500)
This allows us to see all arenas and slabs that import resources from
one another.  Eventually we'll have a reclaim ktask for base_arena that
can trigger the various reclaim functions.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/include/arena.h
kern/include/slab.h
kern/src/arena.c
kern/src/slab.c

index 3d11e26..84c08bf 100644 (file)
@@ -11,6 +11,7 @@
 #include <atomic.h>
 #include <rbtree.h>
 #include <hash_helper.h>
+#include <kthread.h>
 
 /* Boundary tags track segments.  All segments, regardless of allocation status,
  * are on the all_segs list.  BTs are on other lists, depending on their status.
@@ -42,6 +43,12 @@ BSD_LIST_HEAD(btag_list, btag);
 #define ARENA_NR_FREE_LISTS            64
 #define ARENA_NAME_SZ                  32
 
+/* Forward declarations of import lists */
+struct arena;
+TAILQ_HEAD(arena_tailq, arena);
+struct kmem_cache;
+TAILQ_HEAD(kmem_cache_tailq, kmem_cache);
+
 /* The arena maintains an in-order list of all segments, allocated or otherwise.
  * All free segments are on one of the free_segs[] lists.  There is one list for
  * each power-of-two we can allocate. */
@@ -69,6 +76,10 @@ struct arena {
        /* Accounting */
        char                                            name[ARENA_NAME_SZ];
        TAILQ_ENTRY(arena)                      next;
+       /* These lists are protected by the global arena_and_slab qlock */
+       TAILQ_ENTRY(arena)                      import_link;
+       struct arena_tailq                      __importing_arenas;
+       struct kmem_cache_tailq         __importing_slabs;
 };
 
 /* Arena allocation styles, or'd with MEM_FLAGS */
@@ -98,6 +109,16 @@ void arena_xfree(struct arena *arena, void *addr, size_t size);
 size_t arena_amt_free(struct arena *arena);
 size_t arena_amt_total(struct arena *arena);
 
+/* All lists that track the existence of arenas, slabs, and the connections
+ * between them are tracked by a global qlock.  For the most part, slabs/arenas
+ * are created rarely, and the main lockers will be a reclaim ktask and #mem
+ * accessors. */
+extern qlock_t arenas_and_slabs_lock;
+void add_importing_arena(struct arena *source, struct arena *importer);
+void del_importing_arena(struct arena *source, struct arena *importer);
+void add_importing_slab(struct arena *source, struct kmem_cache *importer);
+void del_importing_slab(struct arena *source, struct kmem_cache *importer);
+
 /* Low-level memory allocator intefaces */
 extern struct arena *base_arena;
 extern struct arena *kpages_arena;
index 3b19d24..cb188c6 100644 (file)
@@ -119,6 +119,7 @@ struct kmem_cache {
        struct kmem_bufctl_list *alloc_hash;
        struct kmem_bufctl_list static_hash[HASH_INIT_SZ];
        char name[KMC_NAME_SZ];
+       TAILQ_ENTRY(kmem_cache) import_link;
 };
 
 /* List of all kmem_caches, sorted in order of size */
index e72eca8..04f3185 100644 (file)
 #include <stdio.h>
 #include <hash.h>
 #include <slab.h>
+#include <kthread.h>
 
-TAILQ_HEAD(arena_tailq, arena);
 static struct arena_tailq all_arenas = TAILQ_HEAD_INITIALIZER(all_arenas);
 static spinlock_t all_arenas_lock = SPINLOCK_INITIALIZER;
+qlock_t arenas_and_slabs_lock = QLOCK_INITIALIZER(arenas_and_slabs_lock);
 
 struct arena *base_arena;
 struct arena *kpages_arena;
@@ -167,9 +168,14 @@ static void arena_init(struct arena *arena, char *name, size_t quantum,
        for (int i = 0; i < arena->hh.nr_hash_lists; i++)
                BSD_LIST_INIT(&arena->static_hash[i]);
 
+       TAILQ_INIT(&arena->__importing_arenas);
+       TAILQ_INIT(&arena->__importing_slabs);
+
        strlcpy(arena->name, name, ARENA_NAME_SZ);
        setup_qcaches(arena, quantum, qcache_max);
 
+       if (source)
+               add_importing_arena(source, arena);
        spin_lock(&all_arenas_lock);
        TAILQ_INSERT_TAIL(&all_arenas, arena, next);
        spin_unlock(&all_arenas_lock);
@@ -206,6 +212,8 @@ void arena_destroy(struct arena *arena)
        spin_lock(&all_arenas_lock);
        TAILQ_REMOVE(&all_arenas, arena, next);
        spin_unlock(&all_arenas_lock);
+       if (arena->source)
+               del_importing_arena(arena->source, arena);
 
        for (int i = 0; i < arena->hh.nr_hash_lists; i++)
                assert(BSD_LIST_EMPTY(&arena->alloc_hash[i]));
@@ -1189,6 +1197,34 @@ size_t arena_amt_total(struct arena *arena)
        return arena->amt_total_segs;
 }
 
+void add_importing_arena(struct arena *source, struct arena *importer)
+{
+       qlock(&arenas_and_slabs_lock);
+       TAILQ_INSERT_TAIL(&source->__importing_arenas, importer, import_link);
+       qunlock(&arenas_and_slabs_lock);
+}
+
+void del_importing_arena(struct arena *source, struct arena *importer)
+{
+       qlock(&arenas_and_slabs_lock);
+       TAILQ_REMOVE(&source->__importing_arenas, importer, import_link);
+       qunlock(&arenas_and_slabs_lock);
+}
+
+void add_importing_slab(struct arena *source, struct kmem_cache *importer)
+{
+       qlock(&arenas_and_slabs_lock);
+       TAILQ_INSERT_TAIL(&source->__importing_slabs, importer, import_link);
+       qunlock(&arenas_and_slabs_lock);
+}
+
+void del_importing_slab(struct arena *source, struct kmem_cache *importer)
+{
+       qlock(&arenas_and_slabs_lock);
+       TAILQ_REMOVE(&source->__importing_slabs, importer, import_link);
+       qunlock(&arenas_and_slabs_lock);
+}
+
 void *base_alloc(struct arena *guess, size_t size, int flags)
 {
        return arena_alloc(find_my_base(guess), size, flags);
@@ -1213,6 +1249,8 @@ void print_arena_stats(struct arena *arena, bool verbose)
 {
        struct btag *bt_i;
        struct rb_node *rb_i;
+       struct arena *a_i;
+       struct kmem_cache *s_i;
 
        size_t nr_allocs = 0;
        size_t nr_imports = 0;
@@ -1284,4 +1322,13 @@ void print_arena_stats(struct arena *arena, bool verbose)
               arena->hh.nr_hash_lists, empty_hash_chain, longest_hash_chain);
        __arena_asserter(arena);
        spin_unlock_irqsave(&arena->lock);
+
+       qlock(&arenas_and_slabs_lock);
+       printk("\tImporting Arenas:\n\t-----------------\n");
+       TAILQ_FOREACH(a_i, &arena->__importing_arenas, import_link)
+               printk("\t\t%s\n", a_i->name);
+       printk("\tImporting Slabs:\n\t-----------------\n");
+       TAILQ_FOREACH(s_i, &arena->__importing_slabs, import_link)
+               printk("\t\t%s\n", s_i->name);
+       qunlock(&arenas_and_slabs_lock);
 }
index 04c51d6..77e137b 100644 (file)
@@ -293,6 +293,7 @@ void __kmem_cache_create(struct kmem_cache *kc, const char *name,
        /* We do this last, since this will all into the magazine cache - which we
         * could be creating on this call! */
        kc->pcpu_caches = build_pcpu_caches();
+       add_importing_slab(kc->source, kc);
        /* put in cache list based on it's size */
        struct kmem_cache *i, *prev = NULL;
        spin_lock_irqsave(&kmem_caches_lock);
@@ -413,6 +414,7 @@ void kmem_cache_destroy(struct kmem_cache *cp)
 {
        struct kmem_slab *a_slab, *next;
 
+       del_importing_slab(cp->source, cp);
        drain_pcpu_caches(cp);
        depot_destroy(cp);
        spin_lock_irqsave(&cp->cache_lock);