[master] 38ee783 The mutex protecting summing of stats into the global VSC counters is a contention point and scales negatively with number of thread-pools.

Poul-Henning Kamp phk at FreeBSD.org
Tue May 20 12:34:48 CEST 2014


commit 38ee7837bb5129276e4c75d45a554fb56ddbeb37
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Tue May 20 10:31:48 2014 +0000

    The mutex protecting summing of stats into the global VSC counters
    is a contention point and scales negatively with number of thread-pools.
    
    Sum into a per-pool dstat structure instead, and have the first
    idle thread summ that into the global counters without blocking the
    pool mutex.
    
    Fixes	#1495
    
    (I hope)

diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index cab075b..da77ecb 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -248,6 +248,7 @@ struct acct_bereq {
 #define L1(t, n)		t n;
 #define VSC_F(n,t,l,f,v,e,d)	L##l(t, n)
 struct dstat {
+	unsigned		summs;
 #include "tbl/vsc_f_main.h"
 };
 #undef VSC_F
diff --git a/bin/varnishd/cache/cache_pool.c b/bin/varnishd/cache/cache_pool.c
index f438b26..754438a 100644
--- a/bin/varnishd/cache/cache_pool.c
+++ b/bin/varnishd/cache/cache_pool.c
@@ -72,6 +72,8 @@ struct pool {
 	uintmax_t			ndropped;
 	uintmax_t			nqueued;
 	struct sesspool			*sesspool;
+	struct dstat			*a_stat;
+	struct dstat			*b_stat;
 };
 
 static struct lock		pool_mtx;
@@ -80,15 +82,17 @@ static unsigned			pool_accepting = 0;
 
 static struct lock		wstat_mtx;
 
-/*--------------------------------------------------------------------*/
+/*--------------------------------------------------------------------
+ * Summing of stats into global stats counters
+ */
 
 static void
-wrk_sumstat(const struct dstat *ds)
+pool_sumstat(const struct dstat *src)
 {
 
 	Lck_AssertHeld(&wstat_mtx);
 #define L0(n)
-#define L1(n) (VSC_C_main->n += ds->n)
+#define L1(n) (VSC_C_main->n += src->n)
 #define VSC_F(n, t, l, f, v, d, e) L##l(n);
 #include "tbl/vsc_f_main.h"
 #undef VSC_F
@@ -101,7 +105,7 @@ Pool_Sumstat(struct worker *w)
 {
 
 	Lck_Lock(&wstat_mtx);
-	wrk_sumstat(&w->stats);
+	pool_sumstat(&w->stats);
 	Lck_Unlock(&wstat_mtx);
 	memset(&w->stats, 0, sizeof w->stats);
 }
@@ -111,13 +115,32 @@ Pool_TrySumstat(struct worker *w)
 {
 	if (Lck_Trylock(&wstat_mtx))
 		return (0);
-	wrk_sumstat(&w->stats);
+	pool_sumstat(&w->stats);
 	Lck_Unlock(&wstat_mtx);
 	memset(&w->stats, 0, sizeof w->stats);
 	return (1);
 }
 
 /*--------------------------------------------------------------------
+ * Summing of stats into pool counters
+ */
+
+static void
+pool_addstat(struct dstat *dst, struct dstat *src)
+{
+
+	dst->summs++;
+#define L0(n)
+#define L1(n) (dst->n += src->n)
+#define VSC_F(n, t, l, f, v, d, e) L##l(n);
+#include "tbl/vsc_f_main.h"
+#undef VSC_F
+#undef L0
+#undef L1
+	memset(src, 0, sizeof *src);
+}
+
+/*--------------------------------------------------------------------
  * Helper function to update stats for purges under lock
  */
 
@@ -301,6 +324,27 @@ pool_kiss_of_death(struct worker *wrk, void *priv)
 }
 
 /*--------------------------------------------------------------------
+ * Special function to summ stats
+ */
+
+static void __match_proto__(pool_func_t)
+pool_stat_summ(struct worker *wrk, void *priv)
+{
+	struct dstat *src;
+
+	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
+	CHECK_OBJ_NOTNULL(wrk->pool, POOL_MAGIC);
+	VSL(SLT_Debug, 0, "STATSUMM");
+	AN(priv);
+	src = priv;
+	Lck_Lock(&wstat_mtx);
+	pool_sumstat(src);
+	Lck_Unlock(&wstat_mtx);
+	memset(src, 0, sizeof *src);
+	wrk->pool->b_stat = src;
+}
+
+/*--------------------------------------------------------------------
  * This is the work function for worker threads in the pool.
  */
 
@@ -308,13 +352,12 @@ void
 Pool_Work_Thread(void *priv, struct worker *wrk)
 {
 	struct pool *pp;
-	int stats_dirty;
 	struct pool_task *tp;
+	struct pool_task tps;
 	int i;
 
 	CAST_OBJ_NOTNULL(pp, priv, POOL_MAGIC);
 	wrk->pool = pp;
-	stats_dirty = 0;
 	while (1) {
 		Lck_Lock(&pp->mtx);
 
@@ -332,17 +375,26 @@ Pool_Work_Thread(void *priv, struct worker *wrk)
 				VTAILQ_REMOVE(&pp->back_queue, tp, list);
 		}
 
-		if (tp == NULL) {
+		if ((tp == NULL && wrk->stats.summs > 0) ||
+		    (wrk->stats.summs >= cache_param->wthread_stats_rate))
+			pool_addstat(pp->a_stat, &wrk->stats);
+
+		if (tp != NULL) {
+			wrk->stats.summs++;
+		} else if (pp->b_stat != NULL && pp->a_stat->summs) {
+			/* Nothing to do, push pool stats into global pool */
+			tps.func = pool_stat_summ;
+			tps.priv = pp->a_stat;
+			pp->a_stat = pp->b_stat;
+			pp->b_stat = NULL;
+			tp = &tps;
+		} else {
 			/* Nothing to do: To sleep, perchance to dream ... */
 			if (isnan(wrk->lastused))
 				wrk->lastused = VTIM_real();
 			wrk->task.func = NULL;
 			wrk->task.priv = wrk;
 			VTAILQ_INSERT_HEAD(&pp->idle_queue, &wrk->task, list);
-			if (stats_dirty) {
-				Pool_Sumstat(wrk);
-				stats_dirty = 0;
-			}
 			do {
 				i = Lck_CondWait(&wrk->cond, &pp->mtx,
 				    wrk->vcl == NULL ?  0 : wrk->lastused+60.);
@@ -350,6 +402,7 @@ Pool_Work_Thread(void *priv, struct worker *wrk)
 					VCL_Rel(&wrk->vcl);
 			} while (wrk->task.func == NULL);
 			tp = &wrk->task;
+			wrk->stats.summs++;
 		}
 		Lck_Unlock(&pp->mtx);
 
@@ -358,12 +411,6 @@ Pool_Work_Thread(void *priv, struct worker *wrk)
 
 		assert(wrk->pool == pp);
 		tp->func(wrk, tp->priv);
-
-		if (++stats_dirty >= cache_param->wthread_stats_rate) {
-			Pool_Sumstat(wrk);
-			stats_dirty = 0;
-		} else if (Pool_TrySumstat(wrk))
-			stats_dirty = 0;
 	}
 	wrk->pool = NULL;
 }
@@ -507,6 +554,10 @@ pool_mkpool(unsigned pool_no)
 	ALLOC_OBJ(pp, POOL_MAGIC);
 	if (pp == NULL)
 		return (NULL);
+	pp->a_stat = calloc(1, sizeof *pp->a_stat);
+	AN(pp->a_stat);
+	pp->b_stat = calloc(1, sizeof *pp->b_stat);
+	AN(pp->b_stat);
 	Lck_New(&pp->mtx, lck_wq);
 
 	VTAILQ_INIT(&pp->idle_queue);



More information about the varnish-commit mailing list