blob: 5c92e57a05167efb3f34bf091ef3ac17fa3a5943 [file] [log] [blame]
Sebastian Jansson2b08e312019-02-25 10:24:46 +01001/*
2 * Copyright 2019 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10#include <map>
11#include <set>
12#include <vector>
13
14#include <algorithm>
15#include "absl/algorithm/container.h"
16#include "api/units/data_rate.h"
17#include "call/simulated_network.h"
18#include "test/gtest.h"
19
20namespace webrtc {
21namespace {
22constexpr int kNotReceived = PacketDeliveryInfo::kNotReceived;
23}
24
25TEST(SimulatedNetworkTest, CodelDoesNothingAtCapacity) {
26 const TimeDelta kRuntime = TimeDelta::seconds(30);
27
28 DataRate link_capacity = DataRate::kbps(1000);
29 const DataSize packet_size = DataSize::bytes(1000);
30
31 SimulatedNetwork::Config config;
32 config.codel_active_queue_management = true;
33 config.queue_delay_ms = 10;
34 config.link_capacity_kbps = link_capacity.kbps();
35 SimulatedNetwork network(config);
36
37 // Need to round up here as otherwise we actually will choke.
38 const TimeDelta packet_inverval =
39 packet_size / link_capacity + TimeDelta::ms(1);
40
41 // Send at capacity and see we get no loss.
42 Timestamp start_time = Timestamp::ms(0);
43 Timestamp current_time = start_time;
44 Timestamp next_packet_time = start_time;
45 uint64_t next_id = 0;
46 std::set<uint64_t> pending;
47 while (current_time - start_time < kRuntime) {
48 if (current_time >= next_packet_time) {
49 bool success = network.EnqueuePacket(PacketInFlightInfo{
50 packet_size.bytes<size_t>(), current_time.us(), next_id});
51 EXPECT_TRUE(success);
52 pending.insert(next_id);
53 ++next_id;
54 next_packet_time += packet_inverval;
55 }
56 Timestamp next_delivery = Timestamp::PlusInfinity();
57 if (network.NextDeliveryTimeUs())
58 next_delivery = Timestamp::us(*network.NextDeliveryTimeUs());
59 current_time = std::min(next_packet_time, next_delivery);
60 if (current_time >= next_delivery) {
61 for (PacketDeliveryInfo packet :
62 network.DequeueDeliverablePackets(current_time.us())) {
63 EXPECT_NE(packet.receive_time_us, kNotReceived);
64 pending.erase(packet.packet_id);
65 }
66 }
67 }
68 while (network.NextDeliveryTimeUs()) {
69 for (PacketDeliveryInfo packet :
70 network.DequeueDeliverablePackets(*network.NextDeliveryTimeUs())) {
71 EXPECT_NE(packet.receive_time_us, kNotReceived);
72 pending.erase(packet.packet_id);
73 }
74 }
75 EXPECT_EQ(pending.size(), 0u);
76}
77
78TEST(SimulatedNetworkTest, CodelLimitsDelayAndDropsPacketsOnOverload) {
79 const TimeDelta kRuntime = TimeDelta::seconds(30);
80 const TimeDelta kCheckInterval = TimeDelta::ms(2000);
81
82 DataRate link_capacity = DataRate::kbps(1000);
83 const DataSize rough_packet_size = DataSize::bytes(1500);
84 const double overload_rate = 1.5;
85
86 SimulatedNetwork::Config config;
87 config.codel_active_queue_management = true;
88 config.queue_delay_ms = 10;
89 config.link_capacity_kbps = link_capacity.kbps();
90 SimulatedNetwork network(config);
91
92 const TimeDelta packet_inverval = rough_packet_size / link_capacity;
93 const DataSize packet_size = overload_rate * link_capacity * packet_inverval;
94 // Send above capacity and see delays are still controlled at the cost of
95 // packet loss.
96 Timestamp start_time = Timestamp::ms(0);
97 Timestamp current_time = start_time;
98 Timestamp next_packet_time = start_time;
99 Timestamp last_check = start_time;
100 uint64_t next_id = 1;
101 std::map<uint64_t, int64_t> send_times_us;
102 int lost = 0;
103 std::vector<int64_t> delays_us;
104 while (current_time - start_time < kRuntime) {
105 if (current_time >= next_packet_time) {
106 bool success = network.EnqueuePacket(PacketInFlightInfo{
107 packet_size.bytes<size_t>(), current_time.us(), next_id});
108 send_times_us.insert({next_id, current_time.us()});
109 ++next_id;
110 EXPECT_TRUE(success);
111 next_packet_time += packet_inverval;
112 }
113 Timestamp next_delivery = Timestamp::PlusInfinity();
114 if (network.NextDeliveryTimeUs())
115 next_delivery = Timestamp::us(*network.NextDeliveryTimeUs());
116 current_time = std::min(next_packet_time, next_delivery);
117 if (current_time >= next_delivery) {
118 for (PacketDeliveryInfo packet :
119 network.DequeueDeliverablePackets(current_time.us())) {
120 if (packet.receive_time_us == kNotReceived) {
121 ++lost;
122 } else {
123 delays_us.push_back(packet.receive_time_us -
124 send_times_us[packet.packet_id]);
125 }
126 send_times_us.erase(packet.packet_id);
127 }
128 }
129 if (current_time > last_check + kCheckInterval) {
130 last_check = current_time;
131 TimeDelta average_delay =
132 TimeDelta::us(absl::c_accumulate(delays_us, 0)) / delays_us.size();
133 double loss_ratio = static_cast<double>(lost) / (lost + delays_us.size());
134 EXPECT_LT(average_delay.ms(), 200)
135 << "Time " << (current_time - start_time).ms() << "\n";
136 EXPECT_GT(loss_ratio, 0.5 * (overload_rate - 1));
137 }
138 }
139 while (network.NextDeliveryTimeUs()) {
140 for (PacketDeliveryInfo packet :
141 network.DequeueDeliverablePackets(*network.NextDeliveryTimeUs())) {
142 send_times_us.erase(packet.packet_id);
143 }
144 }
145 EXPECT_EQ(send_times_us.size(), 0u);
146}
147} // namespace webrtc