MINOR: quic: account Tx data per stream

Add accounting at qc_stream_desc level to be able to report the number
of allocated Tx buffers and the sum of their data. This represents data
ready for emission or already emitted and waiting on ACK.

To simplify this accounting, a new counter type bdata_ctr is defined in
quic_utils.h. This regroups both buffers and data counter, plus a
maximum on the buffer value.

These values are now displayed on QCS info used both on logline and
traces, and also on "show quic" output.
This commit is contained in:
Amaury Denoyelle 2025-05-07 17:32:46 +02:00
parent 9a05c1f574
commit a1dc9070e7
6 changed files with 86 additions and 1 deletions

View File

@ -7,6 +7,7 @@
#include <haproxy/buf-t.h>
#include <haproxy/list-t.h>
#include <haproxy/quic_utils-t.h>
/* A QUIC STREAM buffer used for Tx.
*
@ -43,6 +44,7 @@ struct qc_stream_desc {
uint64_t ack_offset; /* last acknowledged offset */
struct eb_root buf_tree; /* list of active and released buffers */
struct bdata_ctr data; /* data utilization counter */
int flags; /* QC_SD_FL_* values */

View File

@ -0,0 +1,17 @@
#ifndef _HAPROXY_QUIC_UTILS_T_H
#define _HAPROXY_QUIC_UTILS_T_H
#ifdef USE_QUIC
#include <haproxy/api-t.h>
/* Counter which can be used to measure data amount accross several buffers. */
struct bdata_ctr {
uint64_t tot; /* sum of data present in all underlying buffers */
uint8_t bcnt; /* current number of allocated underlying buffers */
uint8_t bmax; /* max number of allocated buffers during stream lifetime */
};
#endif /* USE_QUIC */
#endif /* _HAPROXY_QUIC_UTILS_T_H */

View File

@ -0,0 +1,49 @@
#ifndef _HAPROXY_QUIC_UTILS_H
#define _HAPROXY_QUIC_UTILS_H
#ifdef USE_QUIC
#include <haproxy/quic_utils-t.h>
#include <haproxy/buf-t.h>
#include <haproxy/chunk.h>
static inline void bdata_ctr_init(struct bdata_ctr *ctr)
{
ctr->tot = 0;
ctr->bcnt = 0;
ctr->bmax = 0;
}
static inline void bdata_ctr_binc(struct bdata_ctr *ctr)
{
++ctr->bcnt;
ctr->bmax = MAX(ctr->bcnt, ctr->bmax);
}
static inline void bdata_ctr_bdec(struct bdata_ctr *ctr)
{
--ctr->bcnt;
}
static inline void bdata_ctr_add(struct bdata_ctr *ctr, size_t data)
{
ctr->tot += data;
}
static inline void bdata_ctr_del(struct bdata_ctr *ctr, size_t data)
{
ctr->tot -= data;
}
static inline void bdata_ctr_print(struct buffer *chunk,
const struct bdata_ctr *ctr,
const char *prefix)
{
chunk_appendf(chunk, " %s%d(%d)/%llu",
prefix, ctr->bcnt, ctr->bmax, (ullong)ctr->tot);
}
#endif /* USE_QUIC */
#endif /* _HAPROXY_QUIC_UTILS_H */

View File

@ -25,6 +25,7 @@
#include <haproxy/quic_tp-t.h>
#include <haproxy/quic_tune.h>
#include <haproxy/quic_tx.h>
#include <haproxy/quic_utils.h>
#include <haproxy/session.h>
#include <haproxy/ssl_sock-t.h>
#include <haproxy/stconn.h>
@ -1637,6 +1638,7 @@ void qcc_send_stream(struct qcs *qcs, int urg, int count)
if (count) {
qfctl_sinc(&qcc->tx.fc, count);
qfctl_sinc(&qcs->tx.fc, count);
bdata_ctr_add(&qcs->stream->data, count);
}
TRACE_LEAVE(QMUX_EV_QCS_SEND, qcc->conn, qcs);
@ -4118,13 +4120,18 @@ void qcc_show_quic(struct qcc *qcc)
chunk_appendf(&trash, " qcs=0x%p id=%llu flags=0x%x st=%s",
qcs, (ullong)qcs->id, qcs->flags,
qcs_st_to_str(qcs->st));
if (!quic_stream_is_uni(qcs->id) || !quic_stream_is_local(qcc, qcs->id))
chunk_appendf(&trash, " rxoff=%llu", (ullong)qcs->rx.offset);
if (!quic_stream_is_uni(qcs->id) || !quic_stream_is_remote(qcc, qcs->id))
if (!quic_stream_is_uni(qcs->id) || !quic_stream_is_remote(qcc, qcs->id)) {
if (qcs->stream)
bdata_ctr_print(&trash, &qcs->stream->data, "txb=");
chunk_appendf(&trash, " txoff=%llu(%llu) msd=%llu",
(ullong)qcs->tx.fc.off_real,
(ullong)qcs->tx.fc.off_soft - (ullong)qcs->tx.fc.off_real,
(ullong)qcs->tx.fc.limit);
}
chunk_appendf(&trash, "\n");
node = eb64_next(node);
}

View File

@ -7,6 +7,7 @@
#include <haproxy/mux_quic.h>
#include <haproxy/quic_conn-t.h>
#include <haproxy/quic_frame-t.h>
#include <haproxy/quic_utils.h>
/* trace source and events */
static void qmux_trace(enum trace_level level, uint64_t mask,
@ -166,6 +167,9 @@ void qmux_dump_qcs_info(struct buffer *msg, const struct qcs *qcs)
(ullong)qcs->tx.fc.off_real,
(ullong)qcs->tx.fc.limit);
if (qcs->stream)
bdata_ctr_print(msg, &qcs->stream->data, " buf=");
chunk_appendf(msg, " .ti=%u/%u/%u",
tot_time_read(&qcs->timer.base),
tot_time_read(&qcs->timer.buf),

View File

@ -9,6 +9,7 @@
#include <haproxy/mux_quic.h>
#include <haproxy/pool.h>
#include <haproxy/quic_conn.h>
#include <haproxy/quic_utils.h>
#include <haproxy/task.h>
DECLARE_STATIC_POOL(pool_head_quic_stream_desc, "qc_stream_desc",
@ -45,6 +46,8 @@ static void qc_stream_buf_free(struct qc_stream_desc *stream,
pool_free(pool_head_sbuf, buf->area);
}
else {
bdata_ctr_del(&stream->data, b_data(buf));
bdata_ctr_bdec(&stream->data);
b_free(buf);
offer_buffers(NULL, 1);
}
@ -84,6 +87,7 @@ struct qc_stream_desc *qc_stream_desc_new(uint64_t id, enum qcs_type type, void
stream->buf = NULL;
stream->buf_tree = EB_ROOT_UNIQUE;
stream->buf_offset = 0;
bdata_ctr_init(&stream->data);
stream->ack_offset = 0;
stream->flags = 0;
@ -263,6 +267,7 @@ static struct qc_stream_buf *qc_stream_buf_ack(struct qc_stream_buf *buf,
diff = offset + len - stream->ack_offset;
b_del(&buf->buf, diff);
stream->ack_offset += diff;
bdata_ctr_del(&stream->data, diff);
/* notify room from acked data if buffer has been released. */
if (stream->notify_room && qc_stream_buf_is_released(buf, stream)) {
@ -481,6 +486,7 @@ struct buffer *qc_stream_buf_alloc(struct qc_stream_desc *stream,
}
eb64_insert(&stream->buf_tree, &stream->buf->offset_node);
bdata_ctr_binc(&stream->data);
return &stream->buf->buf;
}