From: Amaury Denoyelle Date: Wed, 10 Apr 2024 08:14:01 +0000 (+0200) Subject: OPTIM: quic: do not call qc_send() if nothing to emit X-Git-Tag: v3.0-dev8~104 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=34b31d85cba4fb3d82860deadf16c4163b419ea8;p=thirdparty%2Fhaproxy.git OPTIM: quic: do not call qc_send() if nothing to emit qc_send() was systematically called by quic_conn IO handlers with all instantiated quic_enc_level. Change this to only register quic_enc_level for send if needed. Do not call at all qc_send() if no qel registered. A new function qel_need_sending() is defined to detect if sending is required. First, it checks if quic_enc_level has prepared frames or probing is set. It can also returns true if ACK required either on quic_enc_level itself or because of quic_conn ack timer fired. Finally, a CONNECTION_CLOSE emission for quic_conn is also a valid case. This should reduce the number of invocations of qc_send(). This could improve slightly performance, as well as simplify traces debugging. --- diff --git a/include/haproxy/quic_tx.h b/include/haproxy/quic_tx.h index 73f59dbdc4..55530d9fca 100644 --- a/include/haproxy/quic_tx.h +++ b/include/haproxy/quic_tx.h @@ -35,6 +35,7 @@ struct buffer *qc_get_txb(struct quic_conn *qc); void qel_register_send(struct list *send_list, struct quic_enc_level *qel, struct list *frms); +int qel_need_sending(struct quic_enc_level *qel, struct quic_conn *qc); int qc_send(struct quic_conn *qc, int old_data, struct list *send_list); int qc_dgrams_retransmit(struct quic_conn *qc); diff --git a/src/quic_conn.c b/src/quic_conn.c index e2dc28a8d0..d5c34d158d 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -592,6 +592,9 @@ struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int sta goto out; } + if (!qel_need_sending(qel, qc)) + goto out; + /* XXX TODO: how to limit the list frames to send */ qel_register_send(&send_list, qel, &qel->pktns->tx.frms); if (!qc_send(qc, 0, &send_list)) { @@ -793,9 +796,15 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state) } } - /* Insert each QEL into sending list. */ - list_for_each_entry(qel, &qc->qel_list, list) - qel_register_send(&send_list, qel, &qel->pktns->tx.frms); + /* Insert each QEL into sending list if needed. */ + list_for_each_entry(qel, &qc->qel_list, list) { + if (qel_need_sending(qel, qc)) + qel_register_send(&send_list, qel, &qel->pktns->tx.frms); + } + + /* Skip sending if no QEL with frames to sent. */ + if (LIST_ISEMPTY(&send_list)) + goto out; if (!qc_send(qc, 0, &send_list)) { TRACE_DEVEL("qc_send() failed", QUIC_EV_CONN_IO_CB, qc); diff --git a/src/quic_tx.c b/src/quic_tx.c index 0766f0eadd..99f2a59caf 100644 --- a/src/quic_tx.c +++ b/src/quic_tx.c @@ -761,6 +761,18 @@ void qel_register_send(struct list *send_list, struct quic_enc_level *qel, qel->send_frms = frms; } +/* Returns true if should be registered for sending. This is the case if + * frames are prepared, probing is set, ACK timer has fired or a + * CONNECTION_CLOSE is required. + */ +int qel_need_sending(struct quic_enc_level *qel, struct quic_conn *qc) +{ + return !LIST_ISEMPTY(&qel->pktns->tx.frms) || + qel->pktns->tx.pto_probe || + (qel->pktns->flags & QUIC_FL_PKTNS_ACK_REQUIRED) || + (qc->flags & (QUIC_FL_CONN_ACK_TIMER_FIRED|QUIC_FL_CONN_IMMEDIATE_CLOSE)); +} + /* Retransmit up to two datagrams depending on packet number space. * Return 0 when failed, 0 if not. */