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