test_bw_sampler.c revision 8ae5ecb4
1/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */ 2/* Test adapted from Chromium bandwidth_sampler_test.cc */ 3// Copyright 2016 The Chromium Authors. All rights reserved. 4 5#include <assert.h> 6#include <stdbool.h> 7#include <stdint.h> 8#include <string.h> 9#include <sys/queue.h> 10 11#include "lsquic.h" 12#include "lsquic_int_types.h" 13#include "lsquic_hash.h" 14#include "lsquic_packet_common.h" 15#include "lsquic_packet_out.h" 16#include "lsquic_bw_sampler.h" 17#include "lsquic_conn.h" 18#include "lsquic_malo.h" 19 20 21/* Convert seconds to microseconds */ 22#define sec(val) ((val) * 1000 * 1000) 23 24/* Convert milliseconds to lsquic_time_t, which is microseconds */ 25#define ms(val) ((val) * 1000) 26 27/* Microseconds */ 28#define us(val) (val) 29 30#define kRegularPacketSize 1280 31 32#define PacketsToBytes(count_) ((count_) * kRegularPacketSize) 33 34#define FromKBytesPerSecond(size_) (size_ * 8000) 35 36// Enforce divisibility for some of the tests: 37// "kRegularPacketSize has to be five times divisible by 2" 38typedef char packet_size_has_to_be_five_times_divisible_by_2[ 39 (kRegularPacketSize & 31) == 0 ? 1 : -1]; 40 41struct sampler_test 42{ 43 struct bw_sampler sampler; 44 lsquic_time_t time; 45 uint64_t bytes_in_flight; 46 struct lsquic_conn conn; 47 struct malo *malo_po; 48}; 49 50 51static void 52sampler_test_init (struct sampler_test *stest) 53{ 54 memset(stest, 0, sizeof(*stest)); 55 stest->time = ms(1000); /* Time must not be zero, or test breaks */ 56 LSCONN_INITIALIZE(&stest->conn); 57 lsquic_bw_sampler_init(&stest->sampler, &stest->conn, QUIC_FTBIT_STREAM); 58 stest->malo_po = lsquic_malo_create(sizeof(struct lsquic_packet_out)); 59 assert(stest->malo_po); 60} 61 62 63static void 64sampler_test_cleanup (struct sampler_test *stest) 65{ 66 lsquic_bw_sampler_cleanup(&stest->sampler); 67 lsquic_malo_destroy(stest->malo_po); 68} 69 70 71static struct lsquic_packet_out * 72sampler_test_send_packet (struct sampler_test *stest, lsquic_packno_t packno, 73 bool retx) 74{ 75 struct lsquic_packet_out *packet_out; 76 77 packet_out = lsquic_malo_get(stest->malo_po); 78 assert(packet_out); 79 memset(packet_out, 0, sizeof(*packet_out)); 80 packet_out->po_packno = packno; 81 packet_out->po_flags |= PO_SENT_SZ; 82 packet_out->po_flags |= PO_HELLO; /* Bypass sanity check */ 83 packet_out->po_sent_sz = kRegularPacketSize; 84 packet_out->po_sent = stest->time; 85 if (retx) 86 packet_out->po_frame_types |= QUIC_FTBIT_STREAM; 87 lsquic_bw_sampler_packet_sent(&stest->sampler, packet_out, 88 stest->bytes_in_flight); 89 if (retx) 90 stest->bytes_in_flight += packet_out->po_sent_sz; 91 return packet_out; 92} 93 94 95static struct bw_sample * 96sampler_test_ack_packet (struct sampler_test *stest, 97 struct lsquic_packet_out *packet_out) 98{ 99 if (packet_out->po_frame_types & QUIC_FTBIT_STREAM) 100 stest->bytes_in_flight -= packet_out->po_sent_sz; 101 return lsquic_bw_sampler_packet_acked(&stest->sampler, packet_out, 102 stest->time); 103} 104 105 106static void 107sampler_test_lose_packet (struct sampler_test *stest, 108 struct lsquic_packet_out *packet_out) 109{ 110 if (packet_out->po_frame_types & QUIC_FTBIT_STREAM) 111 stest->bytes_in_flight -= packet_out->po_sent_sz; 112 lsquic_bw_sampler_packet_lost(&stest->sampler, packet_out); 113} 114 115 116static void 117sampler_test_send_40_packets_and_ack_first_20 (struct sampler_test *stest, 118 lsquic_time_t time_between_packets, struct lsquic_packet_out *packets[]) 119{ 120 struct bw_sample *sample; 121 unsigned i; 122 123 // Send 20 packets at a constant inter-packet time. 124 for (i = 1; i <= 20; i++) 125 { 126 packets[i] = sampler_test_send_packet(stest, i, true); 127 stest->time += time_between_packets; 128 } 129 130 // Ack packets 1 to 20, while sending new packets at the same rate as 131 // before. 132 for (i = 1; i <= 20; i++) 133 { 134 sample = sampler_test_ack_packet(stest, packets[i]); 135 assert(sample); 136 lsquic_malo_put(sample); 137 packets[i + 20] = sampler_test_send_packet(stest, i + 20, true); 138 stest->time += time_between_packets; 139 } 140} 141 142 143// Test the sampler in a simple stop-and-wait sender setting. 144static void 145test_send_and_wait (void) 146{ 147 struct sampler_test stest; 148 lsquic_time_t time_between_packets = ms(10); 149 uint64_t expected_bandwidth = kRegularPacketSize * 100 * 8; 150 unsigned i; 151 struct bw_sample *sample; 152 struct lsquic_packet_out *packet; 153 154 sampler_test_init(&stest); 155 156 // Send packets at the constant bandwidth. 157 for (i = 1; i < 20; ++i) 158 { 159 packet = sampler_test_send_packet(&stest, i, true); 160 stest.time += time_between_packets; 161 sample = sampler_test_ack_packet(&stest, packet); 162 assert(sample); 163 assert(expected_bandwidth == BW_VALUE(&sample->bandwidth)); 164 lsquic_malo_put(sample); 165 } 166 167 // Send packets at the exponentially decreasing bandwidth. 168 for (i = 20; i < 25; i++) 169 { 170 time_between_packets = time_between_packets * 2; 171 expected_bandwidth = expected_bandwidth / 2; 172 packet = sampler_test_send_packet(&stest, i, true); 173 stest.time += time_between_packets; 174 sample = sampler_test_ack_packet(&stest, packet); 175 assert(sample); 176 assert(expected_bandwidth == BW_VALUE(&sample->bandwidth)); 177 lsquic_malo_put(sample); 178 } 179 180 assert(lsquic_bw_sampler_entry_count(&stest.sampler) == 0); 181 assert(stest.bytes_in_flight == 0); 182 183 sampler_test_cleanup(&stest); 184} 185 186 187static void 188test_send_time_state (void) 189{ 190 struct sampler_test stest; 191 lsquic_time_t time_between_packets = ms(10); 192 struct bw_sample *sample; 193 unsigned i; 194 struct lsquic_packet_out *packets[11]; 195 196 sampler_test_init(&stest); 197 198 // Send packets 1-5. 199 for (i = 1; i <= 5; i++) { 200 packets[i] = sampler_test_send_packet(&stest, i, true); 201 assert(PacketsToBytes(i) == stest.sampler.bws_total_sent); 202 stest.time += time_between_packets; 203 } 204 205 /* The order of tests here is different. Because the send state is 206 * deleted when packet is acked, we have to check its values first. 207 */ 208#define SEND_STATE(idx_) (&packets[idx_]->po_bwp_state->bwps_send_state) 209 210 // Ack packet 1. 211 assert(PacketsToBytes(1) == SEND_STATE(1)->total_bytes_sent); 212 assert(0 == SEND_STATE(1)->total_bytes_acked); 213 assert(0 == SEND_STATE(1)->total_bytes_lost); 214 sample = sampler_test_ack_packet(&stest, packets[1]); 215 assert(sample); 216 lsquic_malo_put(sample); 217 assert(PacketsToBytes(1) == stest.sampler.bws_total_acked); 218 219 // Lose packet 2. 220 assert(PacketsToBytes(2) == SEND_STATE(2)->total_bytes_sent); 221 assert(0 == SEND_STATE(2)->total_bytes_acked); 222 assert(0 == SEND_STATE(2)->total_bytes_lost); 223 sampler_test_lose_packet(&stest, packets[2]); 224 assert(PacketsToBytes(1) == stest.sampler.bws_total_lost); 225 226 // Lose packet 3. 227 assert(PacketsToBytes(3) == SEND_STATE(3)->total_bytes_sent); 228 assert(0 == SEND_STATE(3)->total_bytes_acked); 229 assert(0 == SEND_STATE(3)->total_bytes_lost); 230 sampler_test_lose_packet(&stest, packets[3]); 231 assert(PacketsToBytes(2) == stest.sampler.bws_total_lost); 232 233 // Send packets 6-10. 234 for (i = 6; i <= 10; i++) 235 { 236 packets[i] = sampler_test_send_packet(&stest, i, true); 237 assert(PacketsToBytes(i) == stest.sampler.bws_total_sent); 238 stest.time += time_between_packets; 239 } 240 241 // Ack all inflight packets. 242 unsigned acked_packet_count = 1; 243 assert(PacketsToBytes(acked_packet_count) == 244 stest.sampler.bws_total_acked); 245 for (i = 4; i <= 10; i++) 246 { 247 assert(PacketsToBytes(i) == SEND_STATE(i)->total_bytes_sent); 248 if (i <= 5) 249 { 250 assert(0 == SEND_STATE(i)->total_bytes_acked); 251 assert(0 == SEND_STATE(i)->total_bytes_lost); 252 } 253 else 254 { 255 assert(PacketsToBytes(1) == SEND_STATE(i)->total_bytes_acked); 256 assert(PacketsToBytes(2) == SEND_STATE(i)->total_bytes_lost); 257 } 258 sample = sampler_test_ack_packet(&stest, packets[i]); 259 assert(sample); 260 lsquic_malo_put(sample); 261 ++acked_packet_count; 262 assert(PacketsToBytes(acked_packet_count) == 263 stest.sampler.bws_total_acked); 264 stest.time += time_between_packets; 265 } 266 267 assert(lsquic_bw_sampler_entry_count(&stest.sampler) == 0); 268 269 sampler_test_cleanup(&stest); 270} 271 272 273// Test the sampler during regular windowed sender scenario with fixed 274// CWND of 20. 275static void 276test_send_paced (void) 277{ 278 struct sampler_test stest; 279 const lsquic_time_t time_between_packets = ms(1); 280 uint64_t expected_bw = FromKBytesPerSecond(kRegularPacketSize); 281 unsigned i; 282 struct bw_sample *sample; 283 struct lsquic_packet_out *packets[41]; 284 285 sampler_test_init(&stest); 286 sampler_test_send_40_packets_and_ack_first_20(&stest, 287 time_between_packets, packets); 288 289 // Ack the packets 21 to 40, arriving at the correct bandwidth. 290 for (i = 21; i <= 40; ++i) 291 { 292 sample = sampler_test_ack_packet(&stest, packets[i]); 293 assert(sample); 294 assert(expected_bw == BW_VALUE(&sample->bandwidth)); 295 stest.time += time_between_packets; 296 lsquic_malo_put(sample); 297 } 298 299 assert(lsquic_bw_sampler_entry_count(&stest.sampler) == 0); 300 assert(stest.bytes_in_flight == 0); 301 302 sampler_test_cleanup(&stest); 303} 304 305 306// Test the sampler in a scenario where 50% of packets is consistently lost. 307static void 308test_send_with_losses (void) 309{ 310 struct sampler_test stest; 311 const lsquic_time_t time_between_packets = ms(1); 312 uint64_t expected_bw = FromKBytesPerSecond(kRegularPacketSize) / 2; 313 unsigned i; 314 struct bw_sample *sample; 315 struct lsquic_packet_out *packets[41]; 316 317 sampler_test_init(&stest); 318 319 // Send 20 packets, each 1 ms apart. 320 for (i = 1; i <= 20; i++) 321 { 322 packets[i] = sampler_test_send_packet(&stest, i, true); 323 stest.time += time_between_packets; 324 } 325 326 // Ack packets 1 to 20, losing every even-numbered packet, while sending new 327 // packets at the same rate as before. 328 for (i = 1; i <= 20; i++) 329 { 330 if (i % 2 == 0) 331 { 332 sample = sampler_test_ack_packet(&stest, packets[i]); 333 assert(sample); 334 lsquic_malo_put(sample); 335 } 336 else 337 sampler_test_lose_packet(&stest, packets[i]); 338 packets[i + 20] = sampler_test_send_packet(&stest, i + 20, true); 339 stest.time += time_between_packets; 340 } 341 342 // Ack the packets 21 to 40 with the same loss pattern. 343 for (i = 21; i <= 40; i++) 344 { 345 if (i % 2 == 0) 346 { 347 sample = sampler_test_ack_packet(&stest, packets[i]); 348 assert(sample); 349 assert(expected_bw == BW_VALUE(&sample->bandwidth)); 350 lsquic_malo_put(sample); 351 } 352 else 353 sampler_test_lose_packet(&stest, packets[i]); 354 stest.time += time_between_packets; 355 } 356 357 assert(lsquic_bw_sampler_entry_count(&stest.sampler) == 0); 358 assert(stest.bytes_in_flight == 0); 359 360 sampler_test_cleanup(&stest); 361} 362 363 364// Test the sampler in a scenario where the 50% of packets are not 365// congestion controlled (specifically, non-retransmittable data is not 366// congestion controlled). Should be functionally consistent in behavior with 367// the SendWithLosses test. 368static void 369test_not_congestion_controlled (void) 370{ 371 struct sampler_test stest; 372 const lsquic_time_t time_between_packets = ms(1); 373 uint64_t expected_bw = FromKBytesPerSecond(kRegularPacketSize) / 2; 374 unsigned i; 375 struct bw_sample *sample; 376 struct lsquic_packet_out *packets[41]; 377 378 sampler_test_init(&stest); 379 380 /* Note the mismatch between the comment and the code. This is 381 * inherited from the original code. 382 */ 383 // Send 20 packets, each 1 ms apart. Every even packet is not congestion 384 // controlled. 385 for (i = 1; i <= 20; i++) 386 { 387 packets[i] = sampler_test_send_packet(&stest, i, 388 i % 2 == 0 ? true : false); 389 stest.time += time_between_packets; 390 } 391 392 assert(lsquic_bw_sampler_entry_count(&stest.sampler) == 10); 393 394 // Ack packets 2 to 21, ignoring every even-numbered packet, while sending new 395 // packets at the same rate as before. 396 for (i = 1; i <= 20; i++) 397 { 398 if (i % 2 == 0) 399 { 400 sample = sampler_test_ack_packet(&stest, packets[i]); 401 assert(sample); 402 lsquic_malo_put(sample); 403 } 404 packets[i + 20] = sampler_test_send_packet(&stest, i + 20, 405 i % 2 == 0 ? true : false); 406 stest.time += time_between_packets; 407 } 408 409 // Ack the packets 22 to 41 with the same congestion controlled pattern. 410 for (i = 21; i <= 40; i++) 411 { 412 if (i % 2 == 0) 413 { 414 sample = sampler_test_ack_packet(&stest, packets[i]); 415 assert(sample); 416 assert(expected_bw == BW_VALUE(&sample->bandwidth)); 417 lsquic_malo_put(sample); 418 } 419 stest.time += time_between_packets; 420 } 421 422 // Since only congestion controlled packets are entered into the map, it has 423 // to be empty at this point. 424 assert(lsquic_bw_sampler_entry_count(&stest.sampler) == 0); 425 assert(stest.bytes_in_flight == 0); 426 427 sampler_test_cleanup(&stest); 428} 429 430 431// Simulate a situation where ACKs arrive in burst and earlier than usual, thus 432// producing an ACK rate which is higher than the original send rate. 433static void 434test_compressed_ack (void) 435{ 436 struct sampler_test stest; 437 const lsquic_time_t time_between_packets = ms(1), 438 ridiculously_small_time_delta = us(20); 439 uint64_t expected_bw = FromKBytesPerSecond(kRegularPacketSize); 440 uint64_t bw; 441 unsigned i; 442 struct bw_sample *sample; 443 struct lsquic_packet_out *packets[41]; 444 445 sampler_test_init(&stest); 446 sampler_test_send_40_packets_and_ack_first_20(&stest, 447 time_between_packets, packets); 448 449 // Simulate an RTT somewhat lower than the one for 1-to-21 transmission. 450 stest.time += time_between_packets * 15; 451 452 // Ack the packets 21 to 40 almost immediately at once. 453 for (i = 21; i <= 40; i++) 454 { 455 sample = sampler_test_ack_packet(&stest, packets[i]); 456 assert(sample); 457 stest.time += ridiculously_small_time_delta; 458 bw = BW_VALUE(&sample->bandwidth); 459 lsquic_malo_put(sample); 460 } 461 462 assert(bw == expected_bw); 463 assert(lsquic_bw_sampler_entry_count(&stest.sampler) == 0); 464 assert(stest.bytes_in_flight == 0); 465 466 sampler_test_cleanup(&stest); 467} 468 469 470// Tests receiving ACK packets in the reverse order. 471static void 472test_reordered_ack (void) 473{ 474 struct sampler_test stest; 475 const lsquic_time_t time_between_packets = ms(1); 476 uint64_t expected_bw = FromKBytesPerSecond(kRegularPacketSize); 477 unsigned i; 478 struct bw_sample *sample; 479 struct lsquic_packet_out *packets[61]; 480 481 sampler_test_init(&stest); 482 sampler_test_send_40_packets_and_ack_first_20(&stest, 483 time_between_packets, packets); 484 485 // Ack the packets 21 to 40 in the reverse order, while sending packets 41 to 486 // 60. 487 for (i = 0; i < 20; i++) 488 { 489 sample = sampler_test_ack_packet(&stest, packets[40 - i]); 490 assert(sample); 491 assert(expected_bw == BW_VALUE(&sample->bandwidth)); 492 packets[41 + i] = sampler_test_send_packet(&stest, 41 + i, true); 493 stest.time += time_between_packets; 494 lsquic_malo_put(sample); 495 } 496 497 // Ack the packets 41 to 60, now in the regular order. 498 for (i = 41; i <= 60; i++) 499 { 500 sample = sampler_test_ack_packet(&stest, packets[i]); 501 assert(sample); 502 assert(expected_bw == BW_VALUE(&sample->bandwidth)); 503 stest.time += time_between_packets; 504 lsquic_malo_put(sample); 505 } 506 507 assert(lsquic_bw_sampler_entry_count(&stest.sampler) == 0); 508 assert(stest.bytes_in_flight == 0); 509 510 sampler_test_cleanup(&stest); 511} 512 513 514// Test the app-limited logic. 515static void 516test_app_limited (void) 517{ 518 struct sampler_test stest; 519 const lsquic_time_t time_between_packets = ms(1); 520 uint64_t expected_bw = FromKBytesPerSecond(kRegularPacketSize); 521 unsigned i; 522 struct bw_sample *sample; 523 struct lsquic_packet_out *packets[81]; 524 525 sampler_test_init(&stest); 526 sampler_test_send_40_packets_and_ack_first_20(&stest, 527 time_between_packets, packets); 528 529 // We are now app-limited. Ack 21 to 40 as usual, but do not send anything for 530 // now. 531 lsquic_bw_sampler_app_limited(&stest.sampler); 532 for (i = 21; i <= 40; i++) 533 { 534 sample = sampler_test_ack_packet(&stest, packets[i]); 535 assert(sample); 536 assert(expected_bw == BW_VALUE(&sample->bandwidth)); 537 stest.time += time_between_packets; 538 lsquic_malo_put(sample); 539 } 540 541 stest.time += sec(1); 542 543 // Send packets 41 to 60, all of which would be marked as app-limited. 544 for (i = 41; i <= 60; i++) 545 { 546 packets[i] = sampler_test_send_packet(&stest, i, true); 547 stest.time += time_between_packets; 548 } 549 550 // Ack packets 41 to 60, while sending packets 61 to 80. 41 to 60 should be 551 // app-limited and underestimate the bandwidth due to that. 552 for (i = 41; i <= 60; i++) 553 { 554 sample = sampler_test_ack_packet(&stest, packets[i]); 555 assert(sample); 556 assert(sample->is_app_limited); 557 assert(BW_VALUE(&sample->bandwidth) < 0.7 * expected_bw); 558 packets[i + 20] = sampler_test_send_packet(&stest, i + 20, true); 559 stest.time += time_between_packets; 560 lsquic_malo_put(sample); 561 } 562 563 // Run out of packets, and then ack packet 61 to 80, all of which should have 564 // correct non-app-limited samples. 565 for (i = 61; i <= 80; i++) 566 { 567 sample = sampler_test_ack_packet(&stest, packets[i]); 568 assert(sample); 569 assert(BW_VALUE(&sample->bandwidth) == expected_bw); 570 stest.time += time_between_packets; 571 lsquic_malo_put(sample); 572 } 573 574 assert(lsquic_bw_sampler_entry_count(&stest.sampler) == 0); 575 assert(stest.bytes_in_flight == 0); 576 577 sampler_test_cleanup(&stest); 578} 579 580 581// Test the samples taken at the first flight of packets sent. 582static void 583test_first_round_trip (void) 584{ 585 struct sampler_test stest; 586 const lsquic_time_t time_between_packets = ms(1), 587 rtt = ms(800); 588 const unsigned num_packets = 10; 589 const uint64_t num_bytes = num_packets * kRegularPacketSize; 590 struct bandwidth real_bandwidth = BW_FROM_BYTES_AND_DELTA(num_bytes, rtt); 591 uint64_t last_bw; 592 unsigned i; 593 struct bw_sample *sample; 594 struct lsquic_packet_out *packets[11]; 595 596 sampler_test_init(&stest); 597 598 for (i = 1; i <= 10; i++) 599 { 600 packets[i] = sampler_test_send_packet(&stest, i, true); 601 stest.time += time_between_packets; 602 } 603 604 stest.time += rtt - num_packets * time_between_packets; 605 606 last_bw = 0; 607 for (i = 1; i <= 10; i++) 608 { 609 sample = sampler_test_ack_packet(&stest, packets[i]); 610 assert(sample); 611 assert(BW_VALUE(&sample->bandwidth) > last_bw); 612 last_bw = BW_VALUE(&sample->bandwidth); 613 stest.time += time_between_packets; 614 lsquic_malo_put(sample); 615 } 616 617 // The final measured sample for the first flight of sample is expected to be 618 // smaller than the real bandwidth, yet it should not lose more than 10%. The 619 // specific value of the error depends on the difference between the RTT and 620 // the time it takes to exhaust the congestion window (i.e. in the limit when 621 // all packets are sent simultaneously, last sample would indicate the real 622 // bandwidth). 623 assert(last_bw < real_bandwidth.value); 624 assert(last_bw > 0.9f * real_bandwidth.value); 625 626 sampler_test_cleanup(&stest); 627} 628 629 630int 631main (void) 632{ 633 test_send_and_wait(); 634 test_send_time_state(); 635 test_send_paced(); 636 test_send_with_losses(); 637 test_not_congestion_controlled(); 638 test_compressed_ack(); 639 test_reordered_ack(); 640 test_app_limited(); 641 test_first_round_trip(); 642 643 return 0; 644} 645