Skip to content

Commit 17cc2f9

Browse files
authored
Merge pull request #487 from h2o/kazuho/optimize-ack-ack
opportunistically reduce the number of ack ranges added to sentmap
2 parents 5b933b2 + 2c11d69 commit 17cc2f9

File tree

2 files changed

+113
-36
lines changed

2 files changed

+113
-36
lines changed

include/quicly/sentmap.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,35 @@ typedef enum en_quicly_sentmap_event_t {
9191
*/
9292
typedef int (*quicly_sent_acked_cb)(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *data);
9393

94+
struct st_quicly_sent_ack_additional_t {
95+
uint8_t gap;
96+
uint8_t length;
97+
};
98+
99+
/**
100+
* Describes what is inside a packet or frame being sent. Within the sentmap, each packet-level entry (identified by .acked ==
101+
* quicly_sentmap__type_packet) is followed by a number of frame-level entries. Size of `quicly_sent_t` is kept as 256 bits (64-bit
102+
* * 4).
103+
*/
94104
struct st_quicly_sent_t {
95105
quicly_sent_acked_cb acked;
96106
union {
97107
quicly_sent_packet_t packet;
108+
/**
109+
* ACK frame. Represents up to 8 ack ranges. If not full, `additional` list is terminated by .gap = 0.
110+
*/
98111
struct {
99-
quicly_range_t range;
112+
uint64_t start;
113+
union {
114+
struct {
115+
uint64_t start_length;
116+
struct st_quicly_sent_ack_additional_t additional[4];
117+
} ranges64;
118+
struct {
119+
uint8_t start_length;
120+
struct st_quicly_sent_ack_additional_t additional[7];
121+
} ranges8;
122+
};
100123
} ack;
101124
struct {
102125
quicly_stream_id_t stream_id;

lib/quicly.c

Lines changed: 89 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2530,45 +2530,72 @@ static int decrypt_packet(ptls_cipher_context_t *header_protection,
25302530
return 0;
25312531
}
25322532

2533-
static int on_ack_ack(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent)
2533+
static int do_on_ack_ack(quicly_conn_t *conn, const quicly_sent_packet_t *packet, uint64_t start, uint64_t start_length,
2534+
struct st_quicly_sent_ack_additional_t *additional, size_t additional_capacity)
25342535
{
2535-
quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap));
2536-
2537-
/* TODO log */
2536+
/* find the pn space */
2537+
struct st_quicly_pn_space_t *space;
2538+
switch (packet->ack_epoch) {
2539+
case QUICLY_EPOCH_INITIAL:
2540+
space = &conn->initial->super;
2541+
break;
2542+
case QUICLY_EPOCH_HANDSHAKE:
2543+
space = &conn->handshake->super;
2544+
break;
2545+
case QUICLY_EPOCH_1RTT:
2546+
space = &conn->application->super;
2547+
break;
2548+
default:
2549+
assert(!"FIXME");
2550+
return QUICLY_TRANSPORT_ERROR_INTERNAL;
2551+
}
25382552

2539-
if (acked) {
2540-
/* find the pn space */
2541-
struct st_quicly_pn_space_t *space;
2542-
switch (packet->ack_epoch) {
2543-
case QUICLY_EPOCH_INITIAL:
2544-
space = &conn->initial->super;
2545-
break;
2546-
case QUICLY_EPOCH_HANDSHAKE:
2547-
space = &conn->handshake->super;
2548-
break;
2549-
case QUICLY_EPOCH_1RTT:
2550-
space = &conn->application->super;
2551-
break;
2552-
default:
2553-
assert(!"FIXME");
2554-
return QUICLY_TRANSPORT_ERROR_INTERNAL;
2555-
}
2556-
/* subtract given ACK range, then make adjustments */
2557-
int ret;
2558-
if ((ret = quicly_ranges_subtract(&space->ack_queue, sent->data.ack.range.start, sent->data.ack.range.end)) != 0)
2553+
/* subtract given ACK ranges */
2554+
int ret;
2555+
uint64_t end = start + start_length;
2556+
if ((ret = quicly_ranges_subtract(&space->ack_queue, start, end)) != 0)
2557+
return ret;
2558+
for (size_t i = 0; i < additional_capacity && additional[i].gap != 0; ++i) {
2559+
start = end + additional[i].gap;
2560+
end = start + additional[i].length;
2561+
if ((ret = quicly_ranges_subtract(&space->ack_queue, start, end)) != 0)
25592562
return ret;
2560-
if (space->ack_queue.num_ranges == 0) {
2561-
space->largest_pn_received_at = INT64_MAX;
2562-
space->unacked_count = 0;
2563-
} else if (space->ack_queue.num_ranges > QUICLY_MAX_ACK_BLOCKS) {
2564-
quicly_ranges_drop_by_range_indices(&space->ack_queue, space->ack_queue.num_ranges - QUICLY_MAX_ACK_BLOCKS,
2565-
space->ack_queue.num_ranges);
2566-
}
2563+
}
2564+
2565+
/* make adjustments */
2566+
if (space->ack_queue.num_ranges == 0) {
2567+
space->largest_pn_received_at = INT64_MAX;
2568+
space->unacked_count = 0;
2569+
} else if (space->ack_queue.num_ranges > QUICLY_MAX_ACK_BLOCKS) {
2570+
quicly_ranges_drop_by_range_indices(&space->ack_queue, space->ack_queue.num_ranges - QUICLY_MAX_ACK_BLOCKS,
2571+
space->ack_queue.num_ranges);
25672572
}
25682573

25692574
return 0;
25702575
}
25712576

2577+
static int on_ack_ack_ranges64(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent)
2578+
{
2579+
quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap));
2580+
2581+
/* TODO log */
2582+
2583+
return acked ? do_on_ack_ack(conn, packet, sent->data.ack.start, sent->data.ack.ranges64.start_length,
2584+
sent->data.ack.ranges64.additional, PTLS_ELEMENTSOF(sent->data.ack.ranges64.additional))
2585+
: 0;
2586+
}
2587+
2588+
static int on_ack_ack_ranges8(quicly_sentmap_t *map, const quicly_sent_packet_t *packet, int acked, quicly_sent_t *sent)
2589+
{
2590+
quicly_conn_t *conn = (quicly_conn_t *)((char *)map - offsetof(quicly_conn_t, egress.loss.sentmap));
2591+
2592+
/* TODO log */
2593+
2594+
return acked ? do_on_ack_ack(conn, packet, sent->data.ack.start, sent->data.ack.ranges8.start_length,
2595+
sent->data.ack.ranges8.additional, PTLS_ELEMENTSOF(sent->data.ack.ranges8.additional))
2596+
: 0;
2597+
}
2598+
25722599
static int on_ack_stream_ack_one(quicly_conn_t *conn, quicly_stream_id_t stream_id, quicly_sendstate_sent_t *sent)
25732600
{
25742601
quicly_stream_t *stream;
@@ -3313,12 +3340,39 @@ static int send_ack(quicly_conn_t *conn, struct st_quicly_pn_space_t *space, qui
33133340
s->dst = dst;
33143341

33153342
{ /* save what's inflight */
3316-
size_t i;
3317-
for (i = 0; i != space->ack_queue.num_ranges; ++i) {
3343+
size_t range_index = 0;
3344+
while (range_index < space->ack_queue.num_ranges) {
33183345
quicly_sent_t *sent;
3319-
if ((sent = quicly_sentmap_allocate(&conn->egress.loss.sentmap, on_ack_ack)) == NULL)
3346+
struct st_quicly_sent_ack_additional_t *additional, *additional_end;
3347+
/* allocate */
3348+
if ((sent = quicly_sentmap_allocate(&conn->egress.loss.sentmap, on_ack_ack_ranges8)) == NULL)
33203349
return PTLS_ERROR_NO_MEMORY;
3321-
sent->data.ack.range = space->ack_queue.ranges[i];
3350+
/* store the first range, as well as preparing references to the additional slots */
3351+
sent->data.ack.start = space->ack_queue.ranges[range_index].start;
3352+
uint64_t length = space->ack_queue.ranges[range_index].end - space->ack_queue.ranges[range_index].start;
3353+
if (length <= UINT8_MAX) {
3354+
sent->data.ack.ranges8.start_length = length;
3355+
additional = sent->data.ack.ranges8.additional;
3356+
additional_end = additional + PTLS_ELEMENTSOF(sent->data.ack.ranges8.additional);
3357+
} else {
3358+
sent->acked = on_ack_ack_ranges64;
3359+
sent->data.ack.ranges64.start_length = length;
3360+
additional = sent->data.ack.ranges64.additional;
3361+
additional_end = additional + PTLS_ELEMENTSOF(sent->data.ack.ranges64.additional);
3362+
}
3363+
/* store additional ranges, if possible */
3364+
for (++range_index; range_index < space->ack_queue.num_ranges && additional < additional_end;
3365+
++range_index, ++additional) {
3366+
uint64_t gap = space->ack_queue.ranges[range_index].start - space->ack_queue.ranges[range_index - 1].end;
3367+
uint64_t length = space->ack_queue.ranges[range_index].end - space->ack_queue.ranges[range_index].start;
3368+
if (gap > UINT8_MAX || length > UINT8_MAX)
3369+
break;
3370+
additional->gap = gap;
3371+
additional->length = length;
3372+
}
3373+
/* additional list is zero-terminated, if not full */
3374+
if (additional < additional_end)
3375+
additional->gap = 0;
33223376
}
33233377
}
33243378

0 commit comments

Comments
 (0)