Skip to content

Commit a23341e

Browse files
authored
fix ack aggregation compensation (holepunchto#259)
* fix ack aggregation estimator
1 parent 30445ee commit a23341e

4 files changed

Lines changed: 22 additions & 10 deletions

File tree

docs/debug_throughput/stevens.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def processFile(path_to_file):
8888
for (x, label) in vlines:
8989
print("x=", x, "label=", label)
9090
plot.axvline(x=x, color=colors[color_index], ls="--", label=label)
91-
color_index = color_index + 1 % len(colors)
91+
color_index = (color_index + 1) % len(colors)
9292

9393
axes.legend()
9494
d.legend()

include/udx.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -314,11 +314,14 @@ struct udx_stream_s {
314314
uint32_t prior_cwnd;
315315
double full_bw;
316316

317-
uint64_t ack_epoch_start;
318-
uint16_t extra_acked[2]; // volume of data that estimates the degree of aggregation in the network path.
319-
uint32_t ack_epoch_acked; // packets (S)ACKed in sampling epoch
320-
uint8_t extra_acked_win_rtts;
321-
uint8_t extra_acked_win_index;
317+
// track windowed maximum of ACK aggregation This enables increasing cwnd
318+
// on networks with high ACK aggregation to continue sending during interruptions in the ACK stream.
319+
320+
uint64_t ack_epoch_start; // timestamp of current ack epoch. reset when ack rate is <= expected
321+
uint16_t extra_acked[2]; // track the windowed maximum degree of ack aggregation
322+
uint32_t ack_epoch_acked; // packets (S)ACKed in current sampling epoch
323+
uint8_t extra_acked_win_rtts; // after extra_acked_win_rtts intervals rotate extra_acked_win_index
324+
uint8_t extra_acked_win_index; // position in bbr.extra_acked[]
322325

323326
} bbr;
324327

src/debug.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ static inline void
3434
open_throughput_file (udx_stream_t *stream) {
3535
if (!stream->throughput_fd) {
3636
char filename[100];
37-
snprintf(filename, sizeof(filename), "stream.%d.dat", stream->local_id);
37+
snprintf(filename, sizeof(filename), "stream.%u.dat", stream->local_id);
3838
stream->throughput_fd = fopen(filename, "w");
3939
}
4040
}

src/udx_bbr.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,12 +176,18 @@ bbr_inflight (udx_stream_t *stream, double bw, double gain) {
176176
return bbr_bdp(stream, bw, gain);
177177
}
178178

179-
// unneccessary?
179+
// Return the highest recently seen degree of ack aggregation. unit is packets.
180+
// aggregation is the amount acked during an rtt interval greater than
181+
// the amount predicted by the current pacing rate. (acked - expected_acked)
182+
// This is used to set a higher cwnd, allowing us to continue sending
183+
// during interruptions of the ack stream.
184+
180185
static uint32_t
181186
bbr_ack_aggregation_cwnd (udx_stream_t *stream) {
182187
uint32_t aggr_cwnd = 0;
183188
if (bbr_extra_acked_gain && bbr_full_bw_reached(stream)) {
184-
uint32_t max_aggr_cwnd = (bbr_bw(stream) * bbr_extra_acked_max_ms) / 1000;
189+
// clamps extra aggregation packets to at most extra_acked_max_ms (100ms) of packets at current bw
190+
uint32_t max_aggr_cwnd = bbr_bw(stream) * bbr_extra_acked_max_ms;
185191

186192
aggr_cwnd = (bbr_extra_acked_gain * bbr_extra_acked(stream));
187193
aggr_cwnd = min_uint32(aggr_cwnd, max_aggr_cwnd);
@@ -356,6 +362,7 @@ bbr_update_ack_aggregation (udx_stream_t *stream, udx_rate_sample_t *rs) {
356362
}
357363

358364
if (stream->bbr.round_start) {
365+
// redundant since we clamp to bbr_extra_acked_win_rtts
359366
stream->bbr.extra_acked_win_rtts = min_uint32(0xff, stream->bbr.extra_acked_win_rtts + 1);
360367
if (stream->bbr.extra_acked_win_rtts >= bbr_extra_acked_win_rtts) {
361368
stream->bbr.extra_acked_win_rtts = 0;
@@ -367,7 +374,9 @@ bbr_update_ack_aggregation (udx_stream_t *stream, udx_rate_sample_t *rs) {
367374
uint32_t epoch_ms = time_delta_ms(stream->delivered_ts, stream->bbr.ack_epoch_start);
368375
uint32_t expected_acked = bbr_bw(stream) * epoch_ms;
369376

370-
// reset aggregation epoch if ACK rate is below expected or significanly large no of ack received since epoch
377+
// reset aggregation epoch if
378+
// 1. ACK rate is below expected or
379+
// 2. an (improbably large) # of acks that would overflow ack_epoch_acked arrives
371380
if (stream->bbr.ack_epoch_acked <= expected_acked || ((uint64_t) stream->bbr.ack_epoch_acked + rs->acked_sacked >= bbr_ack_epoch_acked_reset_thresh)) {
372381
stream->bbr.ack_epoch_acked = 0;
373382
stream->bbr.ack_epoch_start = stream->delivered_ts;

0 commit comments

Comments
 (0)