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.
This commit is contained in:
Amaury Denoyelle 2024-04-10 10:14:01 +02:00
parent 7fc1ce5bc8
commit 34b31d85cb
3 changed files with 25 additions and 3 deletions

View 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);

View 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);

View 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.
*/