[MEDIUM] measure and report session rate on frontend, backends and servers

With this change, all frontends, backends, and servers maintain a session
counter and a timer to compute a session rate over the last second. This
value will be very useful because it varies instantly and can be used to
check thresholds. This value is also reported in the stats in a new "rate"
column.
diff --git a/Makefile b/Makefile
index 855c902..3d87d70 100644
--- a/Makefile
+++ b/Makefile
@@ -460,7 +460,7 @@
        src/proto_http.o src/stream_sock.o src/appsession.o src/backend.o \
        src/stream_interface.o src/dumpstats.o src/proto_tcp.o \
        src/session.o src/hdr_idx.o src/ev_select.o \
-       src/acl.o src/memory.o \
+       src/acl.o src/memory.o src/freq_ctr.o \
        src/ebtree.o src/eb32tree.o
 
 haproxy: $(OBJS) $(OPTIONS_OBJS)
diff --git a/Makefile.bsd b/Makefile.bsd
index 22dc3e7..d1f3e68 100644
--- a/Makefile.bsd
+++ b/Makefile.bsd
@@ -106,7 +106,7 @@
        src/stream_interface.o src/dumpstats.o src/proto_tcp.o \
        src/session.o src/hdr_idx.o src/ev_select.o \
        src/ev_poll.o src/ev_kqueue.o \
-       src/acl.o src/memory.o \
+       src/acl.o src/memory.o src/freq_ctr.o \
        src/ebtree.o src/eb32tree.o
 
 all: haproxy
diff --git a/Makefile.osx b/Makefile.osx
index cb4d4c8..b736eef 100644
--- a/Makefile.osx
+++ b/Makefile.osx
@@ -103,7 +103,7 @@
        src/stream_interface.o src/dumpstats.o src/proto_tcp.o \
        src/session.o src/hdr_idx.o src/ev_select.o \
        src/ev_poll.o \
-       src/acl.o src/memory.o \
+       src/acl.o src/memory.o src/freq_ctr.o \
        src/ebtree.o src/eb32tree.o
 
 all: haproxy
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 0590b61..84465e8 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -5778,6 +5778,9 @@
 2.7) CSV format
 ---------------
 
+The statistics may be consulted either from the unix socket or from the HTTP
+page. Both means provide a CSV format whose fields follow.
+
   0. pxname: proxy name
   1. svname: service name (FRONTEND for frontend, BACKEND for backend, any name
     for server)
@@ -5812,6 +5815,7 @@
  30. lbtot: total number of times a server was selected
  31. tracked: id of proxy/server if tracking is enabled
  32. type (0=frontend, 1=backend, 2=server)
+ 33. rate (number of sessions per second over last elapsed second)
 
 
 2.8) Unix Socket commands
diff --git a/include/common/standard.h b/include/common/standard.h
index 892f516..84f768c 100644
--- a/include/common/standard.h
+++ b/include/common/standard.h
@@ -280,4 +280,13 @@
 #define TIME_UNIT_DAY  0x0005
 #define TIME_UNIT_MASK 0x0007
 
+/* Multiply the two 32-bit operands and shift the 64-bit result right 32 bits.
+ * This is used to compute fixed ratios by setting one of the operands to
+ * (2^32*ratio).
+ */
+static inline unsigned int mul32hi(unsigned int a, unsigned int b)
+{
+	return ((unsigned long long)a * b) >> 32;
+}
+
 #endif /* _COMMON_STANDARD_H */
diff --git a/include/proto/freq_ctr.h b/include/proto/freq_ctr.h
new file mode 100644
index 0000000..caa2b6b
--- /dev/null
+++ b/include/proto/freq_ctr.h
@@ -0,0 +1,70 @@
+/*
+  include/proto/freq_ctr.h
+  This file contains macros and inline functions for frequency counters.
+
+  Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation, version 2.1
+  exclusively.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#ifndef _PROTO_FREQ_CTR_H
+#define _PROTO_FREQ_CTR_H
+
+#include <common/config.h>
+#include <types/freq_ctr.h>
+
+/* Rotate a frequency counter when current period is over. Must not be called
+ * during a valid period. It is important that it correctly initializes a null
+ * area.
+ */
+static inline void rotate_freq_ctr(struct freq_ctr *ctr)
+{
+	ctr->prev_ctr = ctr->curr_ctr;
+	if (likely(now.tv_sec - ctr->curr_sec != 1)) {
+		/* we missed more than one second */
+		ctr->prev_ctr = 0;
+	}
+	ctr->curr_sec = now.tv_sec;
+	ctr->curr_ctr = 0; /* leave it at the end to help gcc optimize it away */
+}
+
+/* Update a frequency counter by <inc> incremental units. It is automatically
+ * rotated if the period is over. It is important that it correctly initializes
+ * a null area.
+ */
+static inline void update_freq_ctr(struct freq_ctr *ctr, unsigned int inc)
+{
+	if (likely(ctr->curr_sec == now.tv_sec)) {
+		ctr->curr_ctr += inc;
+		return;
+	}
+	rotate_freq_ctr(ctr);
+	ctr->curr_ctr = inc;
+	/* Note: later we may want to propagate the update to other counters */
+}
+
+/* Read a frequency counter taking history into account for missing time in
+ * current period.
+ */
+unsigned int read_freq_ctr(struct freq_ctr *ctr);
+
+#endif /* _PROTO_FREQ_CTR_H */
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ * End:
+  */
diff --git a/include/proto/proxy.h b/include/proto/proxy.h
index 30a1247..012c1b2 100644
--- a/include/proto/proxy.h
+++ b/include/proto/proxy.h
@@ -26,6 +26,7 @@
 #include <common/ticks.h>
 #include <common/time.h>
 #include <types/proxy.h>
+#include <proto/freq_ctr.h>
 
 int start_proxies(int verbose);
 void maintain_proxies(int *next);
@@ -62,6 +63,20 @@
 	proxy->timeout.check = TICK_ETERNITY;
 }
 
+/* increase the number of cumulated connections on the designated frontend */
+static void inline proxy_inc_fe_ctr(struct proxy *fe)
+{
+	fe->cum_feconn++;
+	update_freq_ctr(&fe->fe_sess_per_sec, 1);
+}
+
+/* increase the number of cumulated connections on the designated backend */
+static void inline proxy_inc_be_ctr(struct proxy *be)
+{
+	be->cum_beconn++;
+	update_freq_ctr(&be->be_sess_per_sec, 1);
+}
+
 #endif /* _PROTO_PROXY_H */
 
 /*
diff --git a/include/proto/server.h b/include/proto/server.h
index f3b5e16..e05a4ac 100644
--- a/include/proto/server.h
+++ b/include/proto/server.h
@@ -2,7 +2,7 @@
   include/proto/server.h
   This file defines everything related to servers.
 
-  Copyright (C) 2000-2006 Willy Tarreau - w@1wt.eu
+  Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu
   
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -30,10 +30,18 @@
 #include <types/server.h>
 
 #include <proto/queue.h>
+#include <proto/freq_ctr.h>
 
 int srv_downtime(struct server *s);
 int srv_getinter(struct server *s);
 
+/* increase the number of cumulated connections on the designated server */
+static void inline srv_inc_sess_ctr(struct server *s)
+{
+	s->cum_sess++;
+	update_freq_ctr(&s->sess_per_sec, 1);
+}
+
 #endif /* _PROTO_SERVER_H */
 
 /*
diff --git a/include/types/freq_ctr.h b/include/types/freq_ctr.h
new file mode 100644
index 0000000..a8cfbd7
--- /dev/null
+++ b/include/types/freq_ctr.h
@@ -0,0 +1,40 @@
+/*
+  include/types/freq_ctr.h
+  This file contains structure declarations for frequency counters.
+
+  Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation, version 2.1
+  exclusively.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#ifndef _TYPES_FREQ_CTR_H
+#define _TYPES_FREQ_CTR_H
+
+#include <common/config.h>
+
+struct freq_ctr {
+	unsigned int curr_sec; /* start date of current period (seconds from now.tv_sec) */
+	unsigned int curr_ctr; /* cumulated value for current period */
+	unsigned int prev_ctr; /* value for last period */
+};
+
+#endif /* _TYPES_FREQ_CTR_H */
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ * End:
+ */
diff --git a/include/types/proxy.h b/include/types/proxy.h
index 9adf5cd..87b6f14 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -2,7 +2,7 @@
   include/types/proxy.h
   This file defines everything related to proxies.
 
-  Copyright (C) 2000-2008 Willy Tarreau - w@1wt.eu
+  Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu
   
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -37,6 +37,7 @@
 
 #include <types/acl.h>
 #include <types/buffers.h>
+#include <types/freq_ctr.h>
 #include <types/httperr.h>
 #include <types/log.h>
 #include <types/protocols.h>
@@ -220,6 +221,8 @@
 	int totpend;				/* total number of pending connections on this instance (for stats) */
 	unsigned int feconn, feconn_max;	/* # of active frontend sessions */
 	unsigned int beconn, beconn_max;	/* # of active backend sessions */
+	struct freq_ctr fe_sess_per_sec;	/* sessions per second on the frontend */
+	struct freq_ctr be_sess_per_sec;	/* sessions per second on the backend */
 	unsigned int cum_feconn, cum_beconn;	/* cumulated number of processed sessions */
 	unsigned int cum_lbconn;		/* cumulated number of sessions processed by load balancing */
 	unsigned int maxconn;			/* max # of active sessions on the frontend */
diff --git a/include/types/server.h b/include/types/server.h
index 5c0186a..8fb8a1f 100644
--- a/include/types/server.h
+++ b/include/types/server.h
@@ -2,7 +2,7 @@
   include/types/server.h
   This file defines everything related to servers.
 
-  Copyright (C) 2000-2008 Willy Tarreau - w@1wt.eu
+  Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu
   
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -30,6 +30,7 @@
 #include <common/mini-clist.h>
 
 #include <types/buffers.h>
+#include <types/freq_ctr.h>
 #include <types/proxy.h>
 #include <types/queue.h>
 #include <types/task.h>
@@ -122,6 +123,7 @@
 	unsigned failed_conns, failed_resp;	/* failed connect() and responses */
 	unsigned retries, redispatches;		/* retried and redispatched connections */
 	unsigned failed_secu;			/* blocked responses because of security concerns */
+	struct freq_ctr sess_per_sec;		/* sessions per second on this server */
 	unsigned cum_sess;			/* cumulated number of sessions really sent to this server */
 	unsigned cum_lbconn;			/* cumulated number of sessions directed by load balancing */
 
diff --git a/src/backend.c b/src/backend.c
index e1911c5..ed291da 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -36,6 +36,7 @@
 #include <proto/proto_http.h>
 #include <proto/proto_tcp.h>
 #include <proto/queue.h>
+#include <proto/server.h>
 #include <proto/session.h>
 #include <proto/stream_sock.h>
 #include <proto/task.h>
@@ -1912,7 +1913,7 @@
 		}
 
 		if (t->srv)
-			t->srv->cum_sess++;
+			srv_inc_sess_ctr(t->srv);
 		if (t->srv)
 			t->srv->failed_conns++;
 		t->be->failed_conns++;
diff --git a/src/client.c b/src/client.c
index 4cc3d7e..3e1ff58 100644
--- a/src/client.c
+++ b/src/client.c
@@ -33,6 +33,7 @@
 #include <proto/log.h>
 #include <proto/hdr_idx.h>
 #include <proto/proto_http.h>
+#include <proto/proxy.h>
 #include <proto/session.h>
 #include <proto/stream_interface.h>
 #include <proto/stream_sock.h>
@@ -236,7 +237,7 @@
 		s->data_source = DATA_SRC_NONE;
 
 		s->uniq_id = totalconn;
-		p->cum_feconn++;	/* cum_beconn will be increased once assigned */
+		proxy_inc_fe_ctr(p);	/* note: cum_beconn will be increased once assigned */
 
 		txn = &s->txn;
 		txn->flags = 0;
@@ -444,7 +445,7 @@
 			p->feconn_max = p->feconn;
 
 		if (s->flags & SN_BE_ASSIGNED) {
-			s->be->cum_beconn++;
+			proxy_inc_be_ctr(s->be);
 			s->be->beconn++;
 			if (s->be->beconn > s->be->beconn_max)
 				s->be->beconn_max = s->be->beconn;
diff --git a/src/dumpstats.c b/src/dumpstats.c
index dd047b7..97443a1 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -41,6 +41,7 @@
 #include <proto/buffers.h>
 #include <proto/dumpstats.h>
 #include <proto/fd.h>
+#include <proto/freq_ctr.h>
 #include <proto/pipe.h>
 #include <proto/proto_uxst.h>
 #include <proto/session.h>
@@ -173,7 +174,7 @@
 			    "wretr,wredis,"
 			    "status,weight,act,bck,"
 			    "chkfail,chkdown,lastchg,downtime,qlimit,"
-			    "pid,iid,sid,throttle,lbtot,tracked,type,"
+			    "pid,iid,sid,throttle,lbtot,tracked,type,rate,"
 			    "\n");
 }
 
@@ -650,21 +651,21 @@
 		if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
 			/* print a new table */
 			chunk_printf(&msg, sizeof(trash),
-				     "<table cols=\"26\" class=\"tbl\" width=\"100%%\">\n"
+				     "<table cols=\"27\" class=\"tbl\" width=\"100%%\">\n"
 				     "<tr align=\"center\" class=\"titre\">"
 				     "<th colspan=2 class=\"pxname\">%s</th>"
-				     "<th colspan=24 class=\"empty\"></th>"
+				     "<th colspan=25 class=\"empty\"></th>"
 				     "</tr>\n"
 				     "<tr align=\"center\" class=\"titre\">"
 				     "<th rowspan=2></th>"
-				     "<th colspan=3>Queue</th><th colspan=5>Sessions</th>"
+				     "<th colspan=3>Queue</th><th colspan=6>Sessions</th>"
 				     "<th colspan=2>Bytes</th><th colspan=2>Denied</th>"
 				     "<th colspan=3>Errors</th><th colspan=2>Warnings</th>"
 				     "<th colspan=8>Server</th>"
 				     "</tr>\n"
 				     "<tr align=\"center\" class=\"titre\">"
 				     "<th>Cur</th><th>Max</th><th>Limit</th><th>Cur</th><th>Max</th>"
-				     "<th>Limit</th><th>Total</th><th>LbTot</th><th>In</th><th>Out</th>"
+				     "<th>Limit</th><th>Rate</th><th>Total</th><th>LbTot</th><th>In</th><th>Out</th>"
 				     "<th>Req</th><th>Resp</th><th>Req</th><th>Conn</th>"
 				     "<th>Resp</th><th>Retr</th><th>Redis</th>"
 				     "<th>Status</th><th>Wght</th><th>Act</th>"
@@ -688,10 +689,10 @@
 				chunk_printf(&msg, sizeof(trash),
 				     /* name, queue */
 				     "<tr align=center class=\"frontend\"><td>Frontend</td><td colspan=3></td>"
-				     /* sessions : current, max, limit, total, lbtot */
+				     /* sessions : current, max, limit, rate, total, lbtot */
 				     "<td align=right>%d</td><td align=right>%d</td>"
 				     "<td align=right>%d</td><td align=right>%d</td>"
-				     "<td align=right></td>"
+				     "<td align=right>%d</td><td align=right></td>"
 				     /* bytes : in, out */
 				     "<td align=right>%lld</td><td align=right>%lld</td>"
 				     /* denied: req, resp */
@@ -705,7 +706,8 @@
 				     /* rest of server: nothing */
 				     "<td align=center colspan=7></td></tr>"
 				     "",
-				     px->feconn, px->feconn_max, px->maxconn, px->cum_feconn,
+				     px->feconn, px->feconn_max, px->maxconn,
+				     read_freq_ctr(&px->fe_sess_per_sec), px->cum_feconn,
 				     px->bytes_in, px->bytes_out,
 				     px->denied_req, px->denied_resp,
 				     px->failed_req,
@@ -731,6 +733,8 @@
 				     ",,,,,,,,"
 				     /* pid, iid, sid, throttle, lbtot, tracked, type */
 				     "%d,%d,0,,,,%d,"
+				     /* rate */
+				     "%u,"
 				     "\n",
 				     px->id,
 				     px->feconn, px->feconn_max, px->maxconn, px->cum_feconn,
@@ -739,7 +743,8 @@
 				     px->failed_req,
 				     px->state == PR_STRUN ? "OPEN" :
 				     px->state == PR_STIDLE ? "FULL" : "STOP",
-				     relative_pid, px->uuid, STATS_TYPE_FE);
+				     relative_pid, px->uuid, STATS_TYPE_FE,
+				     read_freq_ctr(&px->fe_sess_per_sec));
 			}
 
 			if (buffer_write_chunk(rep, &msg) >= 0)
@@ -805,10 +810,10 @@
 				     "<tr align=\"center\" class=\"%s%d\"><td>%s</td>"
 				     /* queue : current, max, limit */
 				     "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td>"
-				     /* sessions : current, max, limit, total, lbtot */
+				     /* sessions : current, max, limit, rate, total, lbtot */
 				     "<td align=right>%d</td><td align=right>%d</td>"
 				     "<td align=right>%s</td><td align=right>%d</td>"
-				     "<td align=right>%d</td>"
+				     "<td align=right>%d</td><td align=right>%d</td>"
 				     /* bytes : in, out */
 				     "<td align=right>%lld</td><td align=right>%lld</td>"
 				     /* denied: req, resp */
@@ -822,6 +827,7 @@
 				     sv_state, sv->id,
 				     sv->nbpend, sv->nbpend_max, LIM2A0(sv->maxqueue, "-"),
 				     sv->cur_sess, sv->cur_sess_max, LIM2A1(sv->maxconn, "-"),
+				     read_freq_ctr(&sv->sess_per_sec),
 				     sv->cum_sess, sv->cum_lbconn,
 				     sv->bytes_in, sv->bytes_out,
 				     sv->failed_secu,
@@ -956,8 +962,14 @@
 				else
 					chunk_printf(&msg, sizeof(trash), ",");
 
-				/* type, then EOL */
-				chunk_printf(&msg, sizeof(trash), "%d,\n", STATS_TYPE_SV);
+				/* type */
+				chunk_printf(&msg, sizeof(trash), "%d,", STATS_TYPE_SV);
+
+				/* rate */
+				chunk_printf(&msg, sizeof(trash), "%u,", read_freq_ctr(&sv->sess_per_sec));
+
+				/* finish with EOL */
+				chunk_printf(&msg, sizeof(trash), "\n");
 			}
 			if (buffer_write_chunk(rep, &msg) >= 0)
 				return 0;
@@ -976,10 +988,10 @@
 				     "<tr align=center class=\"backend\"><td>Backend</td>"
 				     /* queue : current, max */
 				     "<td align=right>%d</td><td align=right>%d</td><td></td>"
-				     /* sessions : current, max, limit, total, lbtot */
+				     /* sessions : current, max, limit, rate, total, lbtot */
 				     "<td align=right>%d</td><td align=right>%d</td>"
 				     "<td align=right>%d</td><td align=right>%d</td>"
-				     "<td align=right>%d</td>"
+				     "<td align=right>%d</td><td align=right>%d</td>"
 				     /* bytes : in, out */
 				     "<td align=right>%lld</td><td align=right>%lld</td>"
 				     /* denied: req, resp */
@@ -995,7 +1007,9 @@
 				     "<td align=center nowrap>%s %s</td><td align=center>%d</td>"
 				     "<td align=center>%d</td><td align=center>%d</td>",
 				     px->nbpend /* or px->totpend ? */, px->nbpend_max,
-				     px->beconn, px->beconn_max, px->fullconn, px->cum_beconn, px->cum_lbconn,
+				     px->beconn, px->beconn_max, px->fullconn,
+				     read_freq_ctr(&px->be_sess_per_sec),
+				     px->cum_beconn, px->cum_lbconn,
 				     px->bytes_in, px->bytes_out,
 				     px->denied_req, px->denied_resp,
 				     px->failed_conns, px->failed_resp,
@@ -1040,6 +1054,8 @@
 				     ",%d,%d,%d,,"
 				     /* pid, iid, sid, throttle, lbtot, tracked, type */
 				     "%d,%d,0,,%d,,%d,"
+				     /* rate */
+				     "%u,"
 				     "\n",
 				     px->id,
 				     px->nbpend /* or px->totpend ? */, px->nbpend_max,
@@ -1054,7 +1070,8 @@
 				     px->down_trans, now.tv_sec - px->last_change,
 				     px->srv?be_downtime(px):0,
 				     relative_pid, px->uuid,
-				     px->cum_lbconn, STATS_TYPE_BE);
+				     px->cum_lbconn, STATS_TYPE_BE,
+				     read_freq_ctr(&px->be_sess_per_sec));
 			}
 			if (buffer_write_chunk(rep, &msg) >= 0)
 				return 0;
diff --git a/src/freq_ctr.c b/src/freq_ctr.c
new file mode 100644
index 0000000..4522ff3
--- /dev/null
+++ b/src/freq_ctr.c
@@ -0,0 +1,45 @@
+/*
+ * Event rate calculation functions.
+ *
+ * Copyright 2000-2009 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
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <common/config.h>
+#include <common/standard.h>
+#include <common/time.h>
+#include <proto/freq_ctr.h>
+
+/* Read a frequency counter taking history into account for missing time in
+ * current period. Current second is sub-divided in 1000 chunks of one ms,
+ * and the missing ones are read proportionally from previous value. The
+ * return value has the same precision as one input data sample, so low rates
+ * will be inaccurate still appropriate for max checking. One trick we use for
+ * low values is to specially handle the case where the rate is between 0 and 1
+ * in order to avoid flapping while waiting for the next event.
+ */
+unsigned int read_freq_ctr(struct freq_ctr *ctr)
+{
+	unsigned int cur;
+	if (unlikely(ctr->curr_sec != now.tv_sec))
+		rotate_freq_ctr(ctr);
+
+	cur = ctr->curr_ctr;
+	if (ctr->prev_ctr <= 1 && !ctr->curr_ctr)
+		return ctr->prev_ctr; /* very low rate, avoid flapping */
+
+	return cur + mul32hi(ctr->prev_ctr, ~curr_sec_ms_scaled);
+}
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ * End:
+ */
diff --git a/src/proto_http.c b/src/proto_http.c
index 6acb0b7..a8ade23 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -47,7 +47,9 @@
 #include <proto/hdr_idx.h>
 #include <proto/proto_tcp.h>
 #include <proto/proto_http.h>
+#include <proto/proxy.h>
 #include <proto/queue.h>
+#include <proto/server.h>
 #include <proto/session.h>
 #include <proto/stream_interface.h>
 #include <proto/stream_sock.h>
@@ -692,7 +694,7 @@
 
 	/* FIXME: we should increase a counter of redirects per server and per backend. */
 	if (s->srv)
-		s->srv->cum_sess++;
+		srv_inc_sess_ctr(s->srv);
 }
 
 /* Return the error message corresponding to si->err_type. It is assumed
@@ -1943,7 +1945,7 @@
 			s->be->beconn++;
 			if (s->be->beconn > s->be->beconn_max)
 				s->be->beconn_max = s->be->beconn;
-			s->be->cum_beconn++;
+			proxy_inc_be_ctr(s->be);
 			s->flags |= SN_BE_ASSIGNED;
 		}
 
@@ -2046,7 +2048,7 @@
 					s->be->beconn++;
 					if (s->be->beconn > s->be->beconn_max)
 						s->be->beconn_max = s->be->beconn;
-					s->be->cum_beconn++;
+					proxy_inc_be_ctr(s->be);
 
 					/* assign new parameters to the session from the new backend */
 					s->rep->rto = s->req->wto = s->be->timeout.server;
@@ -2067,7 +2069,7 @@
 			s->be->beconn++;
 			if (s->be->beconn > s->be->beconn_max)
 				s->be->beconn_max = s->be->beconn;
-			s->be->cum_beconn++;
+			proxy_inc_be_ctr(s->be);
 
 			/* assign new parameters to the session from the new backend */
 			s->rep->rto = s->req->wto = s->be->timeout.server;
@@ -2085,7 +2087,7 @@
 		s->be->beconn++;
 		if (s->be->beconn > s->be->beconn_max)
 			s->be->beconn_max = s->be->beconn;
-		s->be->cum_beconn++;
+		proxy_inc_be_ctr(s->be);
 		s->flags |= SN_BE_ASSIGNED;
 	}
 
diff --git a/src/session.c b/src/session.c
index 8ced9b8..b3c50ca 100644
--- a/src/session.c
+++ b/src/session.c
@@ -28,6 +28,7 @@
 #include <proto/proto_http.h>
 #include <proto/proto_tcp.h>
 #include <proto/queue.h>
+#include <proto/server.h>
 #include <proto/stream_interface.h>
 #include <proto/stream_sock.h>
 #include <proto/task.h>
@@ -367,7 +368,7 @@
 		if (conn_err == SN_ERR_NONE) {
 			/* state = SI_ST_CON now */
 			if (s->srv)
-				s->srv->cum_sess++;
+				srv_inc_sess_ctr(s->srv);
 			return;
 		}
 
@@ -381,7 +382,7 @@
 			}
 
 			if (s->srv)
-				s->srv->cum_sess++;
+				srv_inc_sess_ctr(s->srv);
 			if (s->srv)
 				s->srv->failed_conns++;
 			s->be->failed_conns++;