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