]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
OPTIM: quic: do not call qc_send() if nothing to emit
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 10 Apr 2024 08:14:01 +0000 (10:14 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 10 Apr 2024 09:17:21 +0000 (11:17 +0200)
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.

include/haproxy/quic_tx.h
src/quic_conn.c
src/quic_tx.c

index 73f59dbdc4839e1ae8baa6ff89e2b6c031f7e46c..55530d9fcab7edfc02b3be6f7dc9c4f4a37989f8 100644 (file)
@@ -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);
index e2dc28a8d0483d4c8630ad5f656a1530f24bfbb2..d5c34d158d5f997b08ee1076c249126b520cba89 100644 (file)
@@ -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);
index 0766f0eadd76205fb7004a33e55dd166c88c38b6..99f2a59cafa669085c33df1d0e14a93a290a0f70 100644 (file)
@@ -761,6 +761,18 @@ void qel_register_send(struct list *send_list, struct quic_enc_level *qel,
        qel->send_frms = frms;
 }
 
+/* Returns true if <qel> should be registered for sending. This is the case if
+ * frames are prepared, probing is set, <qc> 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.
  */