[MEDIUM] stats: split frontend and backend stats

It's very annoying that frontend and backend stats are merged because we
don't know what we're observing. For instance, if a "listen" instance
makes use of a distinct backend, it's impossible to know what the bytes_out
means.

Some points take care of not updating counters twice if the backend points
to the frontend, indicating a "listen" instance. The thing becomes more
complex when we try to add support for server side keep-alive, because we
have to maintain a pointer to the backend used for last request, and to
update its stats. But we can't perform such comparisons anymore because
the counters will not match anymore.

So in order to get rid of this situation, let's have both frontend AND
backend stats in the "struct proxy". We simply update the relevant ones
during activity. Some of them are only accounted for in the backend,
while others are just for frontend. Maybe we can improve a bit on that
later, but the essential part is that those counters now reflect what
they really mean.
diff --git a/src/backend.c b/src/backend.c
index e2ad5b2..93a8fc8 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -613,7 +613,7 @@
 			goto out;
 		}
 		else if (srv != prev_srv) {
-			s->be->counters.cum_lbconn++;
+			s->be->be_counters.cum_lbconn++;
 			srv->counters.cum_lbconn++;
 		}
 		set_target_server(&s->target, srv);
@@ -800,10 +800,10 @@
 				}
 				s->flags |= SN_REDISP;
 				prev_srv->counters.redispatches++;
-				s->be->counters.redispatches++;
+				s->be->be_counters.redispatches++;
 			} else {
 				prev_srv->counters.retries++;
-				s->be->counters.retries++;
+				s->be->be_counters.retries++;
 			}
 		}
 	}
@@ -1036,7 +1036,7 @@
 		}
 
 		srv->counters.failed_conns++;
-		t->be->counters.failed_conns++;
+		t->be->be_counters.failed_conns++;
 		return 1;
 
 	case SRV_STATUS_NOSRV:
@@ -1046,7 +1046,7 @@
 			t->req->cons->err_loc = NULL;
 		}
 
-		t->be->counters.failed_conns++;
+		t->be->be_counters.failed_conns++;
 		return 1;
 
 	case SRV_STATUS_QUEUED:
@@ -1066,7 +1066,7 @@
 			srv_inc_sess_ctr(srv);
 		if (srv)
 			srv->counters.failed_conns++;
-		t->be->counters.failed_conns++;
+		t->be->be_counters.failed_conns++;
 
 		/* release other sessions waiting for this server */
 		if (may_dequeue_tasks(srv, t->be))
diff --git a/src/dumpstats.c b/src/dumpstats.c
index b04b297..34f0901 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -493,16 +493,22 @@
 			}
 
 			for (px = proxy; px; px = px->next) {
-				if (clrall)
-					memset(&px->counters, 0, sizeof(px->counters));
+				if (clrall) {
+					memset(&px->be_counters, 0, sizeof(px->be_counters));
+					memset(&px->fe_counters, 0, sizeof(px->fe_counters));
+				}
 				else {
-					px->counters.feconn_max = 0;
-					px->counters.beconn_max = 0;
-					px->counters.fe_rps_max = 0;
-					px->counters.fe_sps_max = 0;
-					px->counters.fe_cps_max = 0;
-					px->counters.be_sps_max = 0;
-					px->counters.nbpend_max = 0;
+					px->be_counters.conn_max = 0;
+					px->be_counters.p.http.rps_max = 0;
+					px->be_counters.sps_max = 0;
+					px->be_counters.cps_max = 0;
+					px->be_counters.nbpend_max = 0;
+
+					px->fe_counters.conn_max = 0;
+					px->fe_counters.p.http.rps_max = 0;
+					px->fe_counters.sps_max = 0;
+					px->fe_counters.cps_max = 0;
+					px->fe_counters.nbpend_max = 0;
 				}
 
 				for (sv = px->srv; sv; sv = sv->next)
@@ -1761,8 +1767,8 @@
 						     "",
 						     read_freq_ctr(&px->fe_req_per_sec),
 						     U2H0(read_freq_ctr(&px->fe_sess_per_sec)),
-						     px->counters.fe_rps_max,
-						     U2H1(px->counters.fe_sps_max),
+						     px->fe_counters.p.http.rps_max,
+						     U2H1(px->fe_counters.sps_max),
 						     LIM2A2(px->fe_sps_lim, "-"));
 				} else {
 					chunk_printf(&msg,
@@ -1770,7 +1776,7 @@
 						     "<td>%s</td><td>%s</td><td>%s</td>"
 						     "",
 						     U2H0(read_freq_ctr(&px->fe_sess_per_sec)),
-						     U2H1(px->counters.fe_sps_max), LIM2A2(px->fe_sps_lim, "-"));
+						     U2H1(px->fe_counters.sps_max), LIM2A2(px->fe_sps_lim, "-"));
 				}
 
 				chunk_printf(&msg,
@@ -1778,18 +1784,18 @@
 				     "<td>%s</td><td>%s</td><td>%s</td>"
 				     "<td"
 				     "",
-				     U2H3(px->feconn), U2H4(px->counters.feconn_max), U2H5(px->maxconn));
+				     U2H3(px->feconn), U2H4(px->fe_counters.conn_max), U2H5(px->maxconn));
 
 				/* http response (via td title): 1xx, 2xx, 3xx, 4xx, 5xx, other */
 				if (px->mode == PR_MODE_HTTP) {
 					int i;
 
-					chunk_printf(&msg, " title=\"%lld requests:", px->counters.cum_fe_req);
+					chunk_printf(&msg, " title=\"%lld requests:", px->fe_counters.p.http.cum_req);
 
 					for (i = 1; i < 6; i++)
-						chunk_printf(&msg, " %dxx=%lld,", i, px->counters.fe.http.rsp[i]);
+						chunk_printf(&msg, " %dxx=%lld,", i, px->fe_counters.p.http.rsp[i]);
 
-					chunk_printf(&msg, " other=%lld\"", px->counters.fe.http.rsp[0]);
+					chunk_printf(&msg, " other=%lld\"", px->fe_counters.p.http.rsp[0]);
 				}
 
 				chunk_printf(&msg,
@@ -1799,9 +1805,9 @@
 				     "<td>%s</td><td>%s</td>"
 				     "",
 				     (px->mode == PR_MODE_HTTP)?"<u>":"",
-				     U2H6(px->counters.cum_fesess),
+				     U2H6(px->fe_counters.cum_sess),
 				     (px->mode == PR_MODE_HTTP)?"</u>":"",
-				     U2H7(px->counters.bytes_in), U2H8(px->counters.bytes_out));
+				     U2H7(px->fe_counters.bytes_in), U2H8(px->fe_counters.bytes_out));
 
 				chunk_printf(&msg,
 				     /* denied: req, resp */
@@ -1815,8 +1821,8 @@
 				     /* rest of server: nothing */
 				     "<td class=ac colspan=8></td></tr>"
 				     "",
-				     U2H0(px->counters.denied_req), U2H1(px->counters.denied_resp),
-				     U2H2(px->counters.failed_req),
+				     U2H0(px->fe_counters.denied_req), U2H1(px->fe_counters.denied_resp),
+				     U2H2(px->fe_counters.failed_req),
 				     px->state == PR_STRUN ? "OPEN" :
 				     px->state == PR_STIDLE ? "FULL" : "STOP");
 			} else {
@@ -1844,24 +1850,24 @@
 				     /* check_status, check_code, check_duration */
 				     ",,,",
 				     px->id,
-				     px->feconn, px->counters.feconn_max, px->maxconn, px->counters.cum_fesess,
-				     px->counters.bytes_in, px->counters.bytes_out,
-				     px->counters.denied_req, px->counters.denied_resp,
-				     px->counters.failed_req,
+				     px->feconn, px->fe_counters.conn_max, px->maxconn, px->fe_counters.cum_sess,
+				     px->fe_counters.bytes_in, px->fe_counters.bytes_out,
+				     px->fe_counters.denied_req, px->fe_counters.denied_resp,
+				     px->fe_counters.failed_req,
 				     px->state == PR_STRUN ? "OPEN" :
 				     px->state == PR_STIDLE ? "FULL" : "STOP",
 				     relative_pid, px->uuid, STATS_TYPE_FE,
 				     read_freq_ctr(&px->fe_sess_per_sec),
-				     px->fe_sps_lim, px->counters.fe_sps_max);
+				     px->fe_sps_lim, px->fe_counters.sps_max);
 
 				/* http response: 1xx, 2xx, 3xx, 4xx, 5xx, other */
 				if (px->mode == PR_MODE_HTTP) {
 					int i;
 
 					for (i=1; i<6; i++)
-						chunk_printf(&msg, "%lld,", px->counters.fe.http.rsp[i]);
+						chunk_printf(&msg, "%lld,", px->fe_counters.p.http.rsp[i]);
 
-					chunk_printf(&msg, "%lld,", px->counters.fe.http.rsp[0]);
+					chunk_printf(&msg, "%lld,", px->fe_counters.p.http.rsp[0]);
 				} else {
 					chunk_printf(&msg, ",,,,,,");
 				}
@@ -1872,7 +1878,7 @@
 				/* requests : req_rate, req_rate_max, req_tot, */
 				chunk_printf(&msg, "%u,%u,%lld,",
 					     read_freq_ctr(&px->fe_req_per_sec),
-					     px->counters.fe_rps_max, px->counters.cum_fe_req);
+					     px->fe_counters.p.http.rps_max, px->fe_counters.p.http.cum_req);
 
 				/* errors: cli_aborts, srv_aborts */
 				chunk_printf(&msg, ",,");
@@ -2485,15 +2491,15 @@
 				     (uri->flags & ST_SHLGNDS)?"<u>":"",
 				     px->id, px->id,
 				     (uri->flags & ST_SHLGNDS)?"</u>":"",
-				     U2H0(px->nbpend) /* or px->totpend ? */, U2H1(px->counters.nbpend_max),
-				     U2H2(read_freq_ctr(&px->be_sess_per_sec)), U2H3(px->counters.be_sps_max));
+				     U2H0(px->nbpend) /* or px->totpend ? */, U2H1(px->be_counters.nbpend_max),
+				     U2H2(read_freq_ctr(&px->be_sess_per_sec)), U2H3(px->be_counters.sps_max));
 
 				chunk_printf(&msg,
 				     /* sessions: current, max, limit */
 				     "<td>%s</td><td>%s</td><td>%s</td>"
 				     "<td"
 				     "",
-				     U2H2(px->beconn), U2H3(px->counters.beconn_max), U2H4(px->fullconn));
+				     U2H2(px->beconn), U2H3(px->be_counters.conn_max), U2H4(px->fullconn));
 
 				/* http response (via td title): 1xx, 2xx, 3xx, 4xx, 5xx, other */
 				if (px->mode == PR_MODE_HTTP) {
@@ -2502,9 +2508,9 @@
 					chunk_printf(&msg, " title=\"rsp codes:");
 
 					for (i = 1; i < 6; i++)
-						chunk_printf(&msg, " %dxx=%lld", i, px->counters.be.http.rsp[i]);
+						chunk_printf(&msg, " %dxx=%lld", i, px->be_counters.p.http.rsp[i]);
 
-					chunk_printf(&msg, " other=%lld\"", px->counters.be.http.rsp[0]);
+					chunk_printf(&msg, " other=%lld\"", px->be_counters.p.http.rsp[0]);
 				}
 
 				chunk_printf(&msg,
@@ -2514,10 +2520,10 @@
 				     "<td>%s</td><td>%s</td>"
 				     "",
 				     (px->mode == PR_MODE_HTTP)?"<u>":"",
-				     U2H6(px->counters.cum_beconn),
+				     U2H6(px->be_counters.cum_conn),
 				     (px->mode == PR_MODE_HTTP)?"</u>":"",
-				     U2H7(px->counters.cum_lbconn),
-				     U2H8(px->counters.bytes_in), U2H9(px->counters.bytes_out));
+				     U2H7(px->be_counters.cum_lbconn),
+				     U2H8(px->be_counters.bytes_in), U2H9(px->be_counters.bytes_out));
 
 				chunk_printf(&msg,
 				     /* denied: req, resp */
@@ -2535,12 +2541,12 @@
 				     "<td class=ac>%s %s</td><td class=ac>&nbsp;</td><td class=ac>%d</td>"
 				     "<td class=ac>%d</td><td class=ac>%d</td>"
 				     "",
-				     U2H0(px->counters.denied_req), U2H1(px->counters.denied_resp),
-				     U2H2(px->counters.failed_conns),
-				     px->counters.cli_aborts,
-				     px->counters.srv_aborts,
-				     U2H5(px->counters.failed_resp),
-				     px->counters.retries, px->counters.redispatches,
+				     U2H0(px->be_counters.denied_req), U2H1(px->be_counters.denied_resp),
+				     U2H2(px->be_counters.failed_conns),
+				     px->be_counters.cli_aborts,
+				     px->be_counters.srv_aborts,
+				     U2H5(px->be_counters.failed_resp),
+				     px->be_counters.retries, px->be_counters.redispatches,
 				     human_time(now.tv_sec - px->last_change, 1),
 				     (px->lbprm.tot_weight > 0 || !px->srv) ? "UP" :
 					     "<font color=\"red\"><b>DOWN</b></font>",
@@ -2586,30 +2592,30 @@
 				     /* check_status, check_code, check_duration */
 				     ",,,",
 				     px->id,
-				     px->nbpend /* or px->totpend ? */, px->counters.nbpend_max,
-				     px->beconn, px->counters.beconn_max, px->fullconn, px->counters.cum_beconn,
-				     px->counters.bytes_in, px->counters.bytes_out,
-				     px->counters.denied_req, px->counters.denied_resp,
-				     px->counters.failed_conns, px->counters.failed_resp,
-				     px->counters.retries, px->counters.redispatches,
+				     px->nbpend /* or px->totpend ? */, px->be_counters.nbpend_max,
+				     px->beconn, px->be_counters.conn_max, px->fullconn, px->be_counters.cum_conn,
+				     px->be_counters.bytes_in, px->be_counters.bytes_out,
+				     px->be_counters.denied_req, px->be_counters.denied_resp,
+				     px->be_counters.failed_conns, px->be_counters.failed_resp,
+				     px->be_counters.retries, px->be_counters.redispatches,
 				     (px->lbprm.tot_weight > 0 || !px->srv) ? "UP" : "DOWN",
 				     (px->lbprm.tot_weight * px->lbprm.wmult + px->lbprm.wdiv - 1) / px->lbprm.wdiv,
 				     px->srv_act, px->srv_bck,
 				     px->down_trans, (int)(now.tv_sec - px->last_change),
 				     px->srv?be_downtime(px):0,
 				     relative_pid, px->uuid,
-				     px->counters.cum_lbconn, STATS_TYPE_BE,
+				     px->be_counters.cum_lbconn, STATS_TYPE_BE,
 				     read_freq_ctr(&px->be_sess_per_sec),
-				     px->counters.be_sps_max);
+				     px->be_counters.sps_max);
 
 				/* http response: 1xx, 2xx, 3xx, 4xx, 5xx, other */
 				if (px->mode == PR_MODE_HTTP) {
 					int i;
 
 					for (i=1; i<6; i++)
-						chunk_printf(&msg, "%lld,", px->counters.be.http.rsp[i]);
+						chunk_printf(&msg, "%lld,", px->be_counters.p.http.rsp[i]);
 
-					chunk_printf(&msg, "%lld,", px->counters.be.http.rsp[0]);
+					chunk_printf(&msg, "%lld,", px->be_counters.p.http.rsp[0]);
 				} else {
 					chunk_printf(&msg, ",,,,,,");
 				}
@@ -2622,7 +2628,7 @@
 
 				/* errors: cli_aborts, srv_aborts */
 				chunk_printf(&msg, "%lld,%lld,",
-					     px->counters.cli_aborts, px->counters.srv_aborts);
+					     px->be_counters.cli_aborts, px->be_counters.srv_aborts);
 
 				/* finish with EOL */
 				chunk_printf(&msg, "\n");
diff --git a/src/frontend.c b/src/frontend.c
index 9c6ff0b..75218df 100644
--- a/src/frontend.c
+++ b/src/frontend.c
@@ -449,7 +449,7 @@
 	buffer_abort(s->rep);
 	req->analysers = 0;
 
-	s->fe->counters.failed_req++;
+	s->fe->fe_counters.failed_req++;
 	if (s->listener->counters)
 		s->listener->counters->failed_req++;
 
diff --git a/src/haproxy.c b/src/haproxy.c
index d1f7195..064c49c 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -1,6 +1,6 @@
 /*
  * HA-Proxy : High Availability-enabled HTTP/TCP proxy
- * Copyright 2000-2010  Willy Tarreau <w@1wt.eu>.
+ * Copyright 2000-2011  Willy Tarreau <w@1wt.eu>.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -310,19 +310,19 @@
 			snprintf(trash, sizeof(trash),
 				 "SIGHUP: Proxy %s has no servers. Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
 				 p->id,
-				 p->feconn, p->beconn, p->totpend, p->nbpend, p->counters.cum_feconn, p->counters.cum_beconn);
+				 p->feconn, p->beconn, p->totpend, p->nbpend, p->fe_counters.cum_conn, p->be_counters.cum_conn);
 		} else if (p->srv_act == 0) {
 			snprintf(trash, sizeof(trash),
 				 "SIGHUP: Proxy %s %s ! Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
 				 p->id,
 				 (p->srv_bck) ? "is running on backup servers" : "has no server available",
-				 p->feconn, p->beconn, p->totpend, p->nbpend, p->counters.cum_feconn, p->counters.cum_beconn);
+				 p->feconn, p->beconn, p->totpend, p->nbpend, p->fe_counters.cum_conn, p->be_counters.cum_conn);
 		} else {
 			snprintf(trash, sizeof(trash),
 				 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
 				 " Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
 				 p->id, p->srv_act, p->srv_bck,
-				 p->feconn, p->beconn, p->totpend, p->nbpend, p->counters.cum_feconn, p->counters.cum_beconn);
+				 p->feconn, p->beconn, p->totpend, p->nbpend, p->fe_counters.cum_conn, p->be_counters.cum_conn);
 		}
 		Warning("%s\n", trash);
 		send_log(p, LOG_NOTICE, "%s\n", trash);
diff --git a/src/proto_http.c b/src/proto_http.c
index ff2f44c..c72cddf 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -2530,7 +2530,7 @@
 
 			session_inc_http_req_ctr(s);
 			proxy_inc_fe_req_ctr(s->fe);
-			s->fe->counters.failed_req++;
+			s->fe->fe_counters.failed_req++;
 			if (s->listener->counters)
 				s->listener->counters->failed_req++;
 
@@ -2559,7 +2559,7 @@
 
 			session_inc_http_req_ctr(s);
 			proxy_inc_fe_req_ctr(s->fe);
-			s->fe->counters.failed_req++;
+			s->fe->fe_counters.failed_req++;
 			if (s->listener->counters)
 				s->listener->counters->failed_req++;
 
@@ -2586,7 +2586,7 @@
 			session_inc_http_err_ctr(s);
 			session_inc_http_req_ctr(s);
 			proxy_inc_fe_req_ctr(s->fe);
-			s->fe->counters.failed_req++;
+			s->fe->fe_counters.failed_req++;
 			if (s->listener->counters)
 				s->listener->counters->failed_req++;
 
@@ -2862,7 +2862,7 @@
 	txn->status = 400;
 	stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_400));
 
-	s->fe->counters.failed_req++;
+	s->fe->fe_counters.failed_req++;
 	if (s->listener->counters)
 		s->listener->counters->failed_req++;
 
@@ -3433,7 +3433,7 @@
 	txn->status = 400;
 	stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_400));
 
-	s->fe->counters.failed_req++;
+	s->fe->fe_counters.failed_req++;
 	if (s->listener->counters)
 		s->listener->counters->failed_req++;
 
@@ -3683,7 +3683,7 @@
 	req->analysers = 0;
 	stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_400));
 
-	s->fe->counters.failed_req++;
+	s->fe->fe_counters.failed_req++;
 	if (s->listener->counters)
 		s->listener->counters->failed_req++;
 
@@ -3727,7 +3727,7 @@
 	req->analysers = 0;
 	req->analyse_exp = TICK_ETERNITY;
 
-	s->fe->counters.failed_req++;
+	s->fe->fe_counters.failed_req++;
 	if (s->listener->counters)
 		s->listener->counters->failed_req++;
 
@@ -3867,7 +3867,7 @@
 
  return_err_msg:
 	req->analysers = 0;
-	s->fe->counters.failed_req++;
+	s->fe->fe_counters.failed_req++;
 	if (s->listener->counters)
 		s->listener->counters->failed_req++;
 	return 0;
@@ -3906,11 +3906,11 @@
 			n = 0;
 
 		if (s->fe->mode == PR_MODE_HTTP)
-			s->fe->counters.fe.http.rsp[n]++;
+			s->fe->fe_counters.p.http.rsp[n]++;
 
 		if ((s->flags & SN_BE_ASSIGNED) &&
 		    (s->be->mode == PR_MODE_HTTP))
-			s->be->counters.be.http.rsp[n]++;
+			s->be->be_counters.p.http.rsp[n]++;
 	}
 
 	/* don't count other requests' data */
@@ -4232,7 +4232,7 @@
 		}
 		else if (buf->flags & BF_SHUTW) {
 			txn->rsp.msg_state = HTTP_MSG_ERROR;
-			s->be->counters.cli_aborts++;
+			s->be->be_counters.cli_aborts++;
 			if (target_srv(&s->target))
 				target_srv(&s->target)->counters.cli_aborts++;
 			goto wait_other_side;
@@ -4513,9 +4513,8 @@
 				s->flags |= SN_FINST_D;
 		}
 
-		s->fe->counters.cli_aborts++;
-		if (s->fe != s->be)
-			s->be->counters.cli_aborts++;
+		s->fe->fe_counters.cli_aborts++;
+		s->be->be_counters.cli_aborts++;
 		if (target_srv(&s->target))
 			target_srv(&s->target)->counters.cli_aborts++;
 
@@ -4536,7 +4535,7 @@
 	return 0;
 
  return_bad_req: /* let's centralize all bad requests */
-	s->fe->counters.failed_req++;
+	s->fe->fe_counters.failed_req++;
 	if (s->listener->counters)
 		s->listener->counters->failed_req++;
  return_bad_req_stats_ok:
@@ -4573,9 +4572,8 @@
 	req->analysers = 0;
 	s->rep->analysers = 0; /* we're in data phase, we want to abort both directions */
 
-	s->fe->counters.srv_aborts++;
-	if (s->fe != s->be)
-		s->be->counters.srv_aborts++;
+	s->fe->fe_counters.srv_aborts++;
+	s->be->be_counters.srv_aborts++;
 	if (target_srv(&s->target))
 		target_srv(&s->target)->counters.srv_aborts++;
 
@@ -4702,7 +4700,7 @@
 			if (msg->msg_state == HTTP_MSG_ERROR || msg->err_pos >= 0)
 				http_capture_bad_message(&s->be->invalid_rep, s, rep, msg, msg->msg_state, s->fe);
 
-			s->be->counters.failed_resp++;
+			s->be->be_counters.failed_resp++;
 			if (target_srv(&s->target)) {
 				target_srv(&s->target)->counters.failed_resp++;
 				health_adjust(target_srv(&s->target), HANA_STATUS_HTTP_HDRRSP);
@@ -4733,7 +4731,7 @@
 			if (msg->err_pos >= 0)
 				http_capture_bad_message(&s->be->invalid_rep, s, rep, msg, msg->msg_state, s->fe);
 
-			s->be->counters.failed_resp++;
+			s->be->be_counters.failed_resp++;
 			if (target_srv(&s->target)) {
 				target_srv(&s->target)->counters.failed_resp++;
 				health_adjust(target_srv(&s->target), HANA_STATUS_HTTP_READ_ERROR);
@@ -4758,7 +4756,7 @@
 			if (msg->err_pos >= 0)
 				http_capture_bad_message(&s->be->invalid_rep, s, rep, msg, msg->msg_state, s->fe);
 
-			s->be->counters.failed_resp++;
+			s->be->be_counters.failed_resp++;
 			if (target_srv(&s->target)) {
 				target_srv(&s->target)->counters.failed_resp++;
 				health_adjust(target_srv(&s->target), HANA_STATUS_HTTP_READ_TIMEOUT);
@@ -4783,7 +4781,7 @@
 			if (msg->err_pos >= 0)
 				http_capture_bad_message(&s->be->invalid_rep, s, rep, msg, msg->msg_state, s->fe);
 
-			s->be->counters.failed_resp++;
+			s->be->be_counters.failed_resp++;
 			if (target_srv(&s->target)) {
 				target_srv(&s->target)->counters.failed_resp++;
 				health_adjust(target_srv(&s->target), HANA_STATUS_HTTP_BROKEN_PIPE);
@@ -4808,7 +4806,7 @@
 			if (msg->err_pos >= 0)
 				http_capture_bad_message(&s->be->invalid_rep, s, rep, msg, msg->msg_state, s->fe);
 
-			s->be->counters.failed_resp++;
+			s->be->be_counters.failed_resp++;
 			rep->analysers = 0;
 			buffer_auto_close(rep);
 
@@ -5130,7 +5128,7 @@
 						target_srv(&t->target)->counters.failed_resp++;
 						health_adjust(target_srv(&t->target), HANA_STATUS_HTTP_RSP);
 					}
-					cur_proxy->counters.failed_resp++;
+					t->be->be_counters.failed_resp++;
 				return_srv_prx_502:
 					rep->analysers = 0;
 					txn->status = 502;
@@ -5150,7 +5148,8 @@
 				if (target_srv(&t->target))
 					target_srv(&t->target)->counters.failed_secu++;
 
-				cur_proxy->counters.denied_resp++;
+				t->be->be_counters.denied_resp++;
+				t->fe->fe_counters.denied_resp++;
 				if (t->listener->counters)
 					t->listener->counters->denied_resp++;
 
@@ -5302,7 +5301,8 @@
 			if (target_srv(&t->target))
 				target_srv(&t->target)->counters.failed_secu++;
 
-			cur_proxy->counters.denied_resp++;
+			t->be->be_counters.denied_resp++;
+			t->fe->fe_counters.denied_resp++;
 			if (t->listener->counters)
 				t->listener->counters->denied_resp++;
 
@@ -5527,7 +5527,7 @@
 	if (res->flags & BF_SHUTR) {
 		if (!(s->flags & SN_ERR_MASK))
 			s->flags |= SN_ERR_SRVCL;
-		s->be->counters.srv_aborts++;
+		s->be->be_counters.srv_aborts++;
 		if (target_srv(&s->target))
 			target_srv(&s->target)->counters.srv_aborts++;
 		goto return_bad_res_stats_ok;
@@ -5565,7 +5565,7 @@
 	return 0;
 
  return_bad_res: /* let's centralize all bad responses */
-	s->be->counters.failed_resp++;
+	s->be->be_counters.failed_resp++;
 	if (target_srv(&s->target))
 		target_srv(&s->target)->counters.failed_resp++;
 
@@ -5591,9 +5591,8 @@
 	res->analysers = 0;
 	s->req->analysers = 0; /* we're in data phase, we want to abort both directions */
 
-	s->fe->counters.cli_aborts++;
-	if (s->fe != s->be)
-		s->be->counters.cli_aborts++;
+	s->fe->fe_counters.cli_aborts++;
+	s->be->be_counters.cli_aborts++;
 	if (target_srv(&s->target))
 		target_srv(&s->target)->counters.cli_aborts++;
 
@@ -5677,7 +5676,9 @@
 				txn->flags |= TX_CLDENY;
 				last_hdr = 1;
 
-				t->be->counters.denied_req++;
+				t->fe->fe_counters.denied_req++;
+				if (t->fe != t->be)
+					t->be->be_counters.denied_req++;
 				if (t->listener->counters)
 					t->listener->counters->denied_req++;
 
@@ -5687,7 +5688,9 @@
 				txn->flags |= TX_CLTARPIT;
 				last_hdr = 1;
 
-				t->be->counters.denied_req++;
+				t->fe->fe_counters.denied_req++;
+				if (t->fe != t->be)
+					t->be->be_counters.denied_req++;
 				if (t->listener->counters)
 					t->listener->counters->denied_req++;
 
@@ -5796,7 +5799,9 @@
 		case ACT_DENY:
 			txn->flags |= TX_CLDENY;
 
-			t->be->counters.denied_req++;
+			t->fe->fe_counters.denied_req++;
+			if (t->fe != t->be)
+				t->be->be_counters.denied_req++;
 			if (t->listener->counters)
 				t->listener->counters->denied_req++;
 
@@ -5806,7 +5811,9 @@
 		case ACT_TARPIT:
 			txn->flags |= TX_CLTARPIT;
 
-			t->be->counters.denied_req++;
+			t->fe->fe_counters.denied_req++;
+			if (t->fe != t->be)
+				t->be->be_counters.denied_req++;
 			if (t->listener->counters)
 				t->listener->counters->denied_req++;
 
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 04562f1..d40f85c 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -726,7 +726,8 @@
 				buffer_abort(s->rep);
 				req->analysers = 0;
 
-				s->be->counters.denied_req++;
+				s->be->be_counters.denied_req++;
+				s->fe->fe_counters.denied_req++;
 				if (s->listener->counters)
 					s->listener->counters->denied_req++;
 
@@ -842,7 +843,8 @@
 				buffer_abort(s->req);
 				rep->analysers = 0;
 
-				s->be->counters.denied_resp++;
+				s->be->be_counters.denied_resp++;
+				s->fe->fe_counters.denied_resp++;
 				if (s->listener->counters)
 					s->listener->counters->denied_resp++;
 
@@ -894,7 +896,7 @@
 		if (ret) {
 			/* we have a matching rule. */
 			if (rule->action == TCP_ACT_REJECT) {
-				s->fe->counters.denied_conn++;
+				s->fe->fe_counters.denied_conn++;
 				if (s->listener->counters)
 					s->listener->counters->denied_conn++;
 
diff --git a/src/proxy.c b/src/proxy.c
index 0c6640e..0129b12 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -536,9 +536,9 @@
 				t = tick_remain(now_ms, p->stop_time);
 				if (t == 0) {
 					Warning("Proxy %s stopped (FE: %lld conns, BE: %lld conns).\n",
-						p->id, p->counters.cum_feconn, p->counters.cum_beconn);
+						p->id, p->fe_counters.cum_conn, p->be_counters.cum_conn);
 					send_log(p, LOG_WARNING, "Proxy %s stopped (FE: %lld conns, BE: %lld conns).\n",
-						 p->id, p->counters.cum_feconn, p->counters.cum_beconn);
+						 p->id, p->fe_counters.cum_conn, p->be_counters.cum_conn);
 					stop_proxy(p);
 					/* try to free more memory */
 					pool_gc2();
@@ -766,8 +766,8 @@
 		return 1;
 	s->be = be;
 	be->beconn++;
-	if (be->beconn > be->counters.beconn_max)
-		be->counters.beconn_max = be->beconn;
+	if (be->beconn > be->be_counters.conn_max)
+		be->be_counters.conn_max = be->beconn;
 	proxy_inc_be_ctr(be);
 
 	/* assign new parameters to the session from the new backend */
diff --git a/src/queue.c b/src/queue.c
index ae99284..48380fc 100644
--- a/src/queue.c
+++ b/src/queue.c
@@ -159,8 +159,8 @@
 		LIST_ADDQ(&sess->be->pendconns, &p->list);
 		sess->be->nbpend++;
 		sess->logs.prx_queue_size += sess->be->nbpend;
-		if (sess->be->nbpend > sess->be->counters.nbpend_max)
-			sess->be->counters.nbpend_max = sess->be->nbpend;
+		if (sess->be->nbpend > sess->be->be_counters.nbpend_max)
+			sess->be->be_counters.nbpend_max = sess->be->nbpend;
 	}
 	sess->be->totpend++;
 	return p;
diff --git a/src/session.c b/src/session.c
index 5cd0853..2127576 100644
--- a/src/session.c
+++ b/src/session.c
@@ -130,8 +130,8 @@
 	}
 
 	/* This session was accepted, count it now */
-	if (p->feconn > p->counters.feconn_max)
-		p->counters.feconn_max = p->feconn;
+	if (p->feconn > p->fe_counters.conn_max)
+		p->fe_counters.conn_max = p->feconn;
 
 	proxy_inc_fe_sess_ctr(l, p);
 	if (s->stkctr1_entry) {
@@ -410,10 +410,9 @@
 		bytes = s->req->total - s->logs.bytes_in;
 		s->logs.bytes_in = s->req->total;
 		if (bytes) {
-			s->fe->counters.bytes_in			+= bytes;
+			s->fe->fe_counters.bytes_in			+= bytes;
 
-			if (s->be != s->fe)
-				s->be->counters.bytes_in		+= bytes;
+			s->be->be_counters.bytes_in			+= bytes;
 
 			if (target_srv(&s->target))
 				target_srv(&s->target)->counters.bytes_in		+= bytes;
@@ -461,10 +460,9 @@
 		bytes = s->rep->total - s->logs.bytes_out;
 		s->logs.bytes_out = s->rep->total;
 		if (bytes) {
-			s->fe->counters.bytes_out			+= bytes;
+			s->fe->fe_counters.bytes_out			+= bytes;
 
-			if (s->be != s->fe)
-				s->be->counters.bytes_out		+= bytes;
+			s->be->be_counters.bytes_out			+= bytes;
 
 			if (target_srv(&s->target))
 				target_srv(&s->target)->counters.bytes_out		+= bytes;
@@ -606,7 +604,7 @@
 
 		if (target_srv(&s->target))
 			target_srv(&s->target)->counters.failed_conns++;
-		s->be->counters.failed_conns++;
+		s->be->be_counters.failed_conns++;
 		sess_change_server(s, NULL);
 		if (may_dequeue_tasks(target_srv(&s->target), s->be))
 			process_srv_queue(target_srv(&s->target));
@@ -639,7 +637,7 @@
 	} else {
 		if (target_srv(&s->target))
 			target_srv(&s->target)->counters.retries++;
-		s->be->counters.retries++;
+		s->be->be_counters.retries++;
 		si->state = SI_ST_ASS;
 	}
 
@@ -743,7 +741,7 @@
 				srv_inc_sess_ctr(srv);
 			if (srv)
 				srv->counters.failed_conns++;
-			s->be->counters.failed_conns++;
+			s->be->be_counters.failed_conns++;
 
 			/* release other sessions waiting for this server */
 			sess_change_server(s, NULL);
@@ -799,7 +797,7 @@
 			s->logs.t_queue = tv_ms_elapsed(&s->logs.tv_accept, &now);
 			if (srv)
 				srv->counters.failed_conns++;
-			s->be->counters.failed_conns++;
+			s->be->be_counters.failed_conns++;
 			si->shutr(si);
 			si->shutw(si);
 			si->ob->flags |= BF_WRITE_TIMEOUT;
@@ -1279,7 +1277,8 @@
 			s->si[0].shutw(&s->si[0]);
 			stream_int_report_error(&s->si[0]);
 			if (!(s->req->analysers) && !(s->rep->analysers)) {
-				s->be->counters.cli_aborts++;
+				s->be->be_counters.cli_aborts++;
+				s->fe->fe_counters.cli_aborts++;
 				if (srv)
 					srv->counters.cli_aborts++;
 				if (!(s->flags & SN_ERR_MASK))
@@ -1295,11 +1294,12 @@
 			s->si[1].shutr(&s->si[1]);
 			s->si[1].shutw(&s->si[1]);
 			stream_int_report_error(&s->si[1]);
-			s->be->counters.failed_resp++;
+			s->be->be_counters.failed_resp++;
 			if (srv)
 				srv->counters.failed_resp++;
 			if (!(s->req->analysers) && !(s->rep->analysers)) {
-				s->be->counters.srv_aborts++;
+				s->be->be_counters.srv_aborts++;
+				s->fe->fe_counters.srv_aborts++;
 				if (srv)
 					srv->counters.srv_aborts++;
 				if (!(s->flags & SN_ERR_MASK))
@@ -1659,25 +1659,29 @@
 			/* Report it if the client got an error or a read timeout expired */
 			s->req->analysers = 0;
 			if (s->req->flags & BF_READ_ERROR) {
-				s->be->counters.cli_aborts++;
+				s->be->be_counters.cli_aborts++;
+				s->fe->fe_counters.cli_aborts++;
 				if (srv)
 					srv->counters.cli_aborts++;
 				s->flags |= SN_ERR_CLICL;
 			}
 			else if (s->req->flags & BF_READ_TIMEOUT) {
-				s->be->counters.cli_aborts++;
+				s->be->be_counters.cli_aborts++;
+				s->fe->fe_counters.cli_aborts++;
 				if (srv)
 					srv->counters.cli_aborts++;
 				s->flags |= SN_ERR_CLITO;
 			}
 			else if (s->req->flags & BF_WRITE_ERROR) {
-				s->be->counters.srv_aborts++;
+				s->be->be_counters.srv_aborts++;
+				s->fe->fe_counters.srv_aborts++;
 				if (srv)
 					srv->counters.srv_aborts++;
 				s->flags |= SN_ERR_SRVCL;
 			}
 			else {
-				s->be->counters.srv_aborts++;
+				s->be->be_counters.srv_aborts++;
+				s->fe->fe_counters.srv_aborts++;
 				if (srv)
 					srv->counters.srv_aborts++;
 				s->flags |= SN_ERR_SRVTO;
@@ -1688,25 +1692,29 @@
 			/* Report it if the server got an error or a read timeout expired */
 			s->rep->analysers = 0;
 			if (s->rep->flags & BF_READ_ERROR) {
-				s->be->counters.srv_aborts++;
+				s->be->be_counters.srv_aborts++;
+				s->fe->fe_counters.srv_aborts++;
 				if (srv)
 					srv->counters.srv_aborts++;
 				s->flags |= SN_ERR_SRVCL;
 			}
 			else if (s->rep->flags & BF_READ_TIMEOUT) {
-				s->be->counters.srv_aborts++;
+				s->be->be_counters.srv_aborts++;
+				s->fe->fe_counters.srv_aborts++;
 				if (srv)
 					srv->counters.srv_aborts++;
 				s->flags |= SN_ERR_SRVTO;
 			}
 			else if (s->rep->flags & BF_WRITE_ERROR) {
-				s->be->counters.cli_aborts++;
+				s->be->be_counters.cli_aborts++;
+				s->fe->fe_counters.cli_aborts++;
 				if (srv)
 					srv->counters.cli_aborts++;
 				s->flags |= SN_ERR_CLICL;
 			}
 			else {
-				s->be->counters.cli_aborts++;
+				s->be->be_counters.cli_aborts++;
+				s->fe->fe_counters.cli_aborts++;
 				if (srv)
 					srv->counters.cli_aborts++;
 				s->flags |= SN_ERR_CLITO;
@@ -2063,11 +2071,11 @@
 			n = 0;
 
 		if (s->fe->mode == PR_MODE_HTTP)
-			s->fe->counters.fe.http.rsp[n]++;
+			s->fe->fe_counters.p.http.rsp[n]++;
 
 		if ((s->flags & SN_BE_ASSIGNED) &&
 		    (s->be->mode == PR_MODE_HTTP))
-			s->be->counters.be.http.rsp[n]++;
+			s->be->be_counters.p.http.rsp[n]++;
 	}
 
 	/* let's do a final log if we need it */
@@ -2120,7 +2128,7 @@
 	if (!(s->flags & SN_FINST_MASK)) {
 		if (s->si[1].state < SI_ST_REQ) {
 
-			s->fe->counters.failed_req++;
+			s->fe->fe_counters.failed_req++;
 			if (s->listener->counters)
 				s->listener->counters->failed_req++;