MEDIUM: session: maintain per-backend and per-server time statistics
Using the last rate counters, we now compute the queue, connect, response
and total times per server and per backend with a 95% accuracy over the last
1024 samples. The operation is cheap so we don't need to condition it.
diff --git a/include/common/defaults.h b/include/common/defaults.h
index bdd75cf..8d5d62a 100644
--- a/include/common/defaults.h
+++ b/include/common/defaults.h
@@ -219,4 +219,15 @@
#define SSL_DEFAULT_DH_PARAM 0
#endif
+/* Number of samples used to compute the times reported in stats. A power of
+ * two is highly recommended, and this value multiplied by the largest response
+ * time must not overflow and unsigned int. See freq_ctr.h for more information.
+ * We consider that values are accurate to 95% with two batches of samples below,
+ * so in order to advertise accurate times across 1k samples, we effectively
+ * measure over 512.
+ */
+#ifndef TIME_STATS_SAMPLES
+#define TIME_STATS_SAMPLES 512
+#endif
+
#endif /* _COMMON_DEFAULTS_H */
diff --git a/include/proto/session.h b/include/proto/session.h
index fc83989..c835bf0 100644
--- a/include/proto/session.h
+++ b/include/proto/session.h
@@ -50,6 +50,9 @@
struct track_ctr_prm *prm,
struct proxy *defpx, char **err);
+/* Update the session's backend and server time stats */
+void session_update_time_stats(struct session *s);
+
/* returns the session from a void *owner */
static inline struct session *session_from_task(struct task *t)
{
diff --git a/include/types/counters.h b/include/types/counters.h
index ecdc7cb..172f8a6 100644
--- a/include/types/counters.h
+++ b/include/types/counters.h
@@ -3,7 +3,7 @@
* This file contains structure declarations for statistics counters.
*
* Copyright 2008-2009 Krzysztof Piotr Oledzki <ole@ans.pl>
- * Copyright 2011 Willy Tarreau <w@1wt.eu>
+ * Copyright 2011-2014 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
@@ -55,6 +55,8 @@
long long redispatches; /* retried and redispatched connections (BE only) */
long long intercepted_req; /* number of monitoring or stats requests intercepted by the frontend */
+ unsigned int q_time, c_time, d_time, t_time; /* sums of conn_time, queue_time, data_time, total_time */
+
union {
struct {
long long cum_req; /* cumulated number of processed HTTP requests */
@@ -96,6 +98,8 @@
long long retries, redispatches; /* retried and redispatched connections */
long long failed_secu; /* blocked responses because of security concerns */
+ unsigned int q_time, c_time, d_time, t_time; /* sums of conn_time, queue_time, data_time, total_time */
+
union {
struct {
long long rsp[6]; /* http response codes */
diff --git a/src/proto_http.c b/src/proto_http.c
index 082f161..48dbc43 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -4714,6 +4714,8 @@
s->do_log(s);
}
+ session_update_time_stats(s);
+
s->logs.accept_date = date; /* user-visible date for logging */
s->logs.tv_accept = now; /* corrected date for internal use */
tv_zero(&s->logs.tv_request);
diff --git a/src/session.c b/src/session.c
index 4412125..f828d9c 100644
--- a/src/session.c
+++ b/src/session.c
@@ -2600,6 +2600,9 @@
s->do_log(s);
}
+ /* update time stats for this session */
+ session_update_time_stats(s);
+
/* the task MUST not be in the run queue anymore */
session_free(s);
task_delete(t);
@@ -2607,6 +2610,48 @@
return NULL;
}
+/* Update the session's backend and server time stats */
+void session_update_time_stats(struct session *s)
+{
+ int t_request;
+ int t_queue;
+ int t_connect;
+ int t_data;
+ int t_close;
+ struct server *srv;
+
+ t_request = 0;
+ t_queue = s->logs.t_queue;
+ t_connect = s->logs.t_connect;
+ t_close = s->logs.t_close;
+ t_data = s->logs.t_data;
+
+ if (s->be->mode != PR_MODE_HTTP)
+ t_data = t_connect;
+
+ if (t_connect < 0 || t_data < 0)
+ return;
+
+ if (tv_isge(&s->logs.tv_request, &s->logs.tv_accept))
+ t_request = tv_ms_elapsed(&s->logs.tv_accept, &s->logs.tv_request);
+
+ t_data -= t_connect;
+ t_connect -= t_queue;
+ t_queue -= t_request;
+
+ srv = objt_server(s->target);
+ if (srv) {
+ swrate_add(&srv->counters.q_time, TIME_STATS_SAMPLES, t_queue);
+ swrate_add(&srv->counters.c_time, TIME_STATS_SAMPLES, t_connect);
+ swrate_add(&srv->counters.d_time, TIME_STATS_SAMPLES, t_data);
+ swrate_add(&srv->counters.t_time, TIME_STATS_SAMPLES, t_close);
+ }
+ swrate_add(&s->be->be_counters.q_time, TIME_STATS_SAMPLES, t_queue);
+ swrate_add(&s->be->be_counters.c_time, TIME_STATS_SAMPLES, t_connect);
+ swrate_add(&s->be->be_counters.d_time, TIME_STATS_SAMPLES, t_data);
+ swrate_add(&s->be->be_counters.t_time, TIME_STATS_SAMPLES, t_close);
+}
+
/*
* This function adjusts sess->srv_conn and maintains the previous and new
* server's served session counts. Setting newsrv to NULL is enough to release