this is a quick and simple change to add some randomness to pool
item allocation patterns.

it basically pregenerates 64 * 8 coin flips to see which end of the
free list items and pool cache pages should go on.

can someone check if there's a performance impact? i dont want to
prematurely complicate this if it's not expensive.

Index: subr_pool.c
===================================================================
RCS file: /cvs/src/sys/kern/subr_pool.c,v
retrieving revision 1.222
diff -u -p -r1.222 subr_pool.c
--- subr_pool.c 6 Feb 2018 22:35:32 -0000       1.222
+++ subr_pool.c 7 Feb 2018 04:58:30 -0000
@@ -277,6 +277,14 @@ int pool_wait_gc = 8;
 
 RBT_PROTOTYPE(phtree, pool_page_header, ph_node, phtree_compare);
 
+#define POOL_RBYTES    128 /* XXX magic */
+#define POOL_RBITS     (POOL_RBYTES * 8)
+
+static unsigned int pool_rbytes[POOL_RBYTES / sizeof(unsigned int)];
+static unsigned int pool_rbit = 0;
+
+static int pool_getrbit(void);
+
 static inline int
 phtree_compare(const struct pool_page_header *a,
     const struct pool_page_header *b)
@@ -460,6 +468,8 @@ pool_init(struct pool *pp, size_t size, 
        TAILQ_INIT(&pp->pr_requests);
 
        if (phpool.pr_size == 0) {
+               arc4random_buf(pool_rbytes, sizeof(pool_rbytes));
+
                pool_init(&phpool, sizeof(struct pool_page_header), 0,
                    IPL_HIGH, 0, "phpool", NULL);
 
@@ -851,7 +861,11 @@ pool_do_put(struct pool *pp, void *v)
 #endif /* DIAGNOSTIC */
 
        pi->pi_magic = POOL_IMAGIC(ph, pi);
-       XSIMPLEQ_INSERT_HEAD(&ph->ph_items, pi, pi_list);
+       if (pool_getrbit())
+               XSIMPLEQ_INSERT_HEAD(&ph->ph_items, pi, pi_list);
+       else
+               XSIMPLEQ_INSERT_TAIL(&ph->ph_items, pi, pi_list);
+
 #ifdef DIAGNOSTIC
        if (POOL_PHPOISON(ph))
                poison_mem(pi + 1, pp->pr_size - sizeof(*pi));
@@ -1840,7 +1854,10 @@ pool_cache_list_free(struct pool *pp, st
                pp->pr_cache_tick = ticks;
 
        pp->pr_cache_nitems += POOL_CACHE_ITEM_NITEMS(ci);
-       TAILQ_INSERT_TAIL(&pp->pr_cache_lists, ci, ci_nextl);
+       if (pool_getrbit())
+               TAILQ_INSERT_HEAD(&pp->pr_cache_lists, ci, ci_nextl);
+       else
+               TAILQ_INSERT_TAIL(&pp->pr_cache_lists, ci, ci_nextl);
 
        pc->pc_nlput++;
 
@@ -2296,3 +2313,25 @@ static const struct pool_lock_ops pool_l
        pool_lock_rw_assert_unlocked,
        pool_lock_rw_sleep,
 };
+
+static int
+pool_getrbit(void)
+{
+       unsigned int rbit;
+       unsigned int word;
+       unsigned int bit;
+
+       rbit = atomic_inc_int_nv(&pool_rbit) % POOL_RBITS;
+       if (rbit == 0) {
+               /*
+                * the next, but concurrent reader will get stale bits, but
+                * that is hard to predict, ie, sort of random?
+                */
+               arc4random_buf(pool_rbytes, sizeof(pool_rbytes));
+       }
+
+       word = rbit / (sizeof(word) * 8);
+       bit = rbit % (sizeof(word) * 8);
+
+       return (ISSET(pool_rbytes[word], 1 << bit));
+}

Reply via email to