From: Willy Tarreau Date: Tue, 22 Oct 2024 14:35:04 +0000 (+0200) Subject: MINOR: stream: maintain per-stream counters of the number of passes on code X-Git-Tag: v3.1-dev11~78 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=37d5c6fe3a2c7c526f5a3c647c359c3e40d7feb7;p=thirdparty%2Fhaproxy.git MINOR: stream: maintain per-stream counters of the number of passes on code Process_stream() is a complex function and a few times some lopos were either witnessed or suspected. Each time this happens it's extremely difficult to figure why because it involves combinations of analysers, filters, errors etc. Let's at least maintain a set of 4 counters per stream that report the number of times we've been through each of the 4 most important blocks (stconn changes, request analysers, response analysers, and propagation of changes down). These ones are stored in the stream and reported in "show sess all", just like they will be reported in panic dumps. --- diff --git a/include/haproxy/stream-t.h b/include/haproxy/stream-t.h index ad79f5dece..363b7eb755 100644 --- a/include/haproxy/stream-t.h +++ b/include/haproxy/stream-t.h @@ -246,6 +246,10 @@ struct stream { uint64_t lat_time; /* total latency time experienced */ uint64_t cpu_time; /* total CPU time consumed */ struct freq_ctr call_rate; /* stream task call rate without making progress */ + uint32_t passes_stconn; /* number of passes on the stconn evaluation code */ + uint32_t passes_reqana; /* number of passes on the req analysers block */ + uint32_t passes_resana; /* number of passes on the res analysers block */ + uint32_t passes_propag; /* number of passes on the shut/err propag code */ unsigned short max_retries; /* Maximum number of connection retried (=0 is backend is not set) */ short store_count; diff --git a/src/stream.c b/src/stream.c index 0fa942944c..1553b2ff87 100644 --- a/src/stream.c +++ b/src/stream.c @@ -421,6 +421,7 @@ struct stream *stream_new(struct session *sess, struct stconn *sc, struct buffer s->lat_time = s->cpu_time = 0; s->call_rate.curr_tick = s->call_rate.curr_ctr = s->call_rate.prev_ctr = 0; + s->passes_stconn = s->passes_reqana = s->passes_resana = s->passes_propag = 0; s->pcli_next_pid = 0; s->pcli_flags = 0; s->unique_id = IST_NULL; @@ -1840,6 +1841,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) * the client cannot have connect (hence retryable) errors. Also, the * connection setup code must be able to deal with any type of abort. */ + s->passes_stconn++; srv = objt_server(s->target); if (unlikely(scf->flags & SC_FL_ERROR)) { if (sc_state_in(scf->state, SC_SB_EST|SC_SB_DIS)) { @@ -1969,6 +1971,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) */ resync_request: + s->passes_reqana++; /* Analyse request */ if (((req->flags & ~rqf_last) & CF_MASK_ANALYSER) || ((scf->flags ^ scf_flags) & (SC_FL_EOS|SC_FL_ABRT_DONE|SC_FL_ABRT_WANTED)) || @@ -2073,6 +2076,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) req_ana_back = req->analysers; resync_response: + s->passes_resana++; /* Analyse response */ if (((res->flags & ~rpf_last) & CF_MASK_ANALYSER) || @@ -2155,7 +2159,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) * both buffers. */ - + s->passes_propag++; /* * Now we propagate unhandled errors to the stream. Normally * we're just in a data phase here since it means we have not @@ -3308,6 +3312,9 @@ void strm_dump_to_buffer(struct buffer *buf, const struct stream *strm, const ch strm->conn_err_type, strm->srv_conn, strm->pend_pos, LIST_INLIST(&strm->buffer_wait.list), strm->stream_epoch); + chunk_appendf(buf, "%s p_stc=%u p_req=%u p_res=%u p_prp=%u\n", pfx, + strm->passes_stconn, strm->passes_reqana, strm->passes_resana, strm->passes_propag); + chunk_appendf(buf, "%s frontend=%s (id=%u mode=%s), listener=%s (id=%u)", pfx, HA_ANON_STR(anon_key, strm_fe(strm)->id), strm_fe(strm)->uuid, proxy_mode_str(strm_fe(strm)->mode),