Adds TCP fairness test to GoogCC.

Bug: webrtc:9883
Change-Id: Ie78e51edb08f6c22dbf02168b1d3b067b2c0c55e
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/140293
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28193}
This commit is contained in:
Sebastian Jansson
2019-06-07 13:06:00 +02:00
committed by Commit Bot
parent 26b5e35276
commit b13ccc5288
8 changed files with 251 additions and 75 deletions

View File

@ -685,5 +685,29 @@ TEST_F(GoogCcNetworkControllerTest, NoRttBackoffCollapseWhenVideoStops) {
EXPECT_GT(client->send_bandwidth().kbps(), 1000);
}
TEST_F(GoogCcNetworkControllerTest, IsFairToTCP) {
Scenario s("googcc_unit/tcp_fairness");
NetworkSimulationConfig net_conf;
net_conf.bandwidth = DataRate::kbps(1000);
net_conf.delay = TimeDelta::ms(50);
auto* client = s.CreateClient("send", [&](CallClientConfig* c) {
c->transport.rates.start_rate = DataRate::kbps(1000);
});
auto send_net = {s.CreateSimulationNode(net_conf)};
auto ret_net = {s.CreateSimulationNode(net_conf)};
auto* route = s.CreateRoutes(
client, send_net, s.CreateClient("return", CallClientConfig()), ret_net);
s.CreateVideoStream(route->forward(), VideoStreamConfig());
s.net()->StartFakeTcpCrossTraffic(s.net()->CreateRoute(send_net),
s.net()->CreateRoute(ret_net),
FakeTcpConfig());
s.RunFor(TimeDelta::seconds(10));
// Currently only testing for the upper limit as we in practice back out
// quite a lot in this scenario. If this behavior is fixed, we should add a
// lower bound to ensure it stays fixed.
EXPECT_LT(client->send_bandwidth().kbps(), 750);
}
} // namespace test
} // namespace webrtc

View File

@ -114,5 +114,70 @@ ColumnPrinter PulsedPeaksCrossTraffic::StatsPrinter() {
32);
}
FakeTcpCrossTraffic::FakeTcpCrossTraffic(FakeTcpConfig config,
EmulatedRoute* send_route,
EmulatedRoute* ret_route)
: conf_(config), route_(this, send_route, ret_route) {}
void FakeTcpCrossTraffic::Process(Timestamp at_time) {
SendPackets(at_time);
}
void FakeTcpCrossTraffic::OnRequest(int sequence_number, Timestamp at_time) {
const size_t kAckPacketSize = 20;
route_.SendResponse(kAckPacketSize, sequence_number);
}
void FakeTcpCrossTraffic::OnResponse(int sequence_number, Timestamp at_time) {
ack_received_ = true;
auto it = in_flight_.find(sequence_number);
if (it != in_flight_.end()) {
last_rtt_ = at_time - in_flight_.at(sequence_number);
in_flight_.erase(sequence_number);
}
if (sequence_number - last_acked_seq_num_ > 1) {
HandleLoss(at_time);
} else if (cwnd_ <= ssthresh_) {
cwnd_ += 1;
} else {
cwnd_ += 1.0f / cwnd_;
}
last_acked_seq_num_ = std::max(sequence_number, last_acked_seq_num_);
SendPackets(at_time);
}
void FakeTcpCrossTraffic::HandleLoss(Timestamp at_time) {
if (at_time - last_reduction_time_ < last_rtt_)
return;
last_reduction_time_ = at_time;
ssthresh_ = std::max(static_cast<int>(in_flight_.size() / 2), 2);
cwnd_ = ssthresh_;
}
void FakeTcpCrossTraffic::SendPackets(Timestamp at_time) {
int cwnd = std::ceil(cwnd_);
int packets_to_send = std::max(cwnd - static_cast<int>(in_flight_.size()), 0);
bool timeouts = false;
for (auto it = in_flight_.begin(); it != in_flight_.end();) {
if (it->second < at_time - conf_.packet_timeout) {
it = in_flight_.erase(it);
timeouts = true;
} else {
++it;
}
}
if (timeouts)
HandleLoss(at_time);
for (int i = 0; i < packets_to_send; ++i) {
if ((total_sent_ + conf_.packet_size) > conf_.send_limit) {
break;
}
in_flight_.insert({next_sequence_number_, at_time});
route_.SendRequest(conf_.packet_size.bytes<size_t>(),
next_sequence_number_++);
total_sent_ += conf_.packet_size;
}
}
} // namespace test
} // namespace webrtc

View File

@ -90,6 +90,43 @@ class PulsedPeaksCrossTraffic {
bool sending_ RTC_GUARDED_BY(sequence_checker_) = false;
};
struct FakeTcpConfig {
DataSize packet_size = DataSize::bytes(1200);
DataSize send_limit = DataSize::PlusInfinity();
int packet_window;
TimeDelta process_interval = TimeDelta::ms(200);
TimeDelta packet_timeout = TimeDelta::seconds(1);
};
class FakeTcpCrossTraffic
: public TwoWayFakeTrafficRoute<int, int>::TrafficHandlerInterface {
public:
FakeTcpCrossTraffic(FakeTcpConfig config,
EmulatedRoute* send_route,
EmulatedRoute* ret_route);
void Process(Timestamp at_time);
void OnRequest(int sequence_number, Timestamp at_time) override;
void OnResponse(int sequence_number, Timestamp at_time) override;
void HandleLoss(Timestamp at_time);
void SendPackets(Timestamp at_time);
private:
const FakeTcpConfig conf_;
TwoWayFakeTrafficRoute<int, int> route_;
std::map<int, Timestamp> in_flight_;
double cwnd_ = 10;
double ssthresh_ = INFINITY;
bool ack_received_ = false;
int last_acked_seq_num_ = 0;
int next_sequence_number_ = 0;
Timestamp last_reduction_time_ = Timestamp::MinusInfinity();
TimeDelta last_rtt_ = TimeDelta::Zero();
DataSize total_sent_ = DataSize::Zero();
};
} // namespace test
} // namespace webrtc

View File

@ -21,29 +21,11 @@ FeedbackGeneratorImpl::FeedbackGeneratorImpl(
net_{&time_controller_},
send_link_{new SimulatedNetwork(conf_.send_link)},
ret_link_{new SimulatedNetwork(conf_.return_link)},
send_ep_{net_.CreateEndpoint(EmulatedEndpointConfig())},
ret_ep_{net_.CreateEndpoint(EmulatedEndpointConfig())},
send_route_{net_.CreateRoute(
send_ep_,
{net_.CreateEmulatedNode(absl::WrapUnique(send_link_))},
ret_ep_)},
ret_route_{net_.CreateRoute(
ret_ep_,
{net_.CreateEmulatedNode(absl::WrapUnique(ret_link_))},
send_ep_)},
send_addr_{rtc::SocketAddress(send_ep_->GetPeerLocalAddress(), 0)},
ret_addr_{rtc::SocketAddress(ret_ep_->GetPeerLocalAddress(), 0)},
received_packet_handler_{send_route_,
[&](SentPacket packet, Timestamp arrival_time) {
OnPacketReceived(std::move(packet),
arrival_time);
}},
received_feedback_handler_{
ret_route_,
[&](TransportPacketsFeedback packet, Timestamp arrival_time) {
packet.feedback_time = arrival_time;
feedback_.push_back(packet);
}} {}
route_(this,
net_.CreateRoute(
{net_.CreateEmulatedNode(absl::WrapUnique(send_link_))}),
net_.CreateRoute(
{net_.CreateEmulatedNode(absl::WrapUnique(ret_link_))})) {}
Timestamp FeedbackGeneratorImpl::Now() {
return Timestamp::ms(time_controller_.GetClock()->TimeInMilliseconds());
@ -57,7 +39,7 @@ void FeedbackGeneratorImpl::SendPacket(size_t size) {
SentPacket sent;
sent.send_time = Now();
sent.size = DataSize::bytes(size);
received_packet_handler_.SendPacket(send_ep_, size, sent);
route_.SendRequest(size, sent);
}
std::vector<TransportPacketsFeedback> FeedbackGeneratorImpl::PopFeedback() {
@ -82,18 +64,23 @@ void FeedbackGeneratorImpl::SetSendLinkCapacity(DataRate capacity) {
send_link_->SetConfig(conf_.send_link);
}
void FeedbackGeneratorImpl::OnPacketReceived(SentPacket packet,
Timestamp arrival_time) {
void FeedbackGeneratorImpl::OnRequest(SentPacket packet,
Timestamp arrival_time) {
PacketResult result;
result.sent_packet = packet;
result.receive_time = arrival_time;
builder_.packet_feedbacks.push_back(result);
Timestamp first_recv = builder_.packet_feedbacks.front().receive_time;
if (Now() - first_recv > conf_.feedback_interval) {
received_feedback_handler_.SendPacket(
ret_ep_, conf_.feedback_packet_size.bytes<size_t>(), builder_);
route_.SendResponse(conf_.feedback_packet_size.bytes<size_t>(), builder_);
builder_ = {};
}
}
void FeedbackGeneratorImpl::OnResponse(TransportPacketsFeedback packet,
Timestamp arrival_time) {
packet.feedback_time = arrival_time;
feedback_.push_back(packet);
}
} // namespace webrtc

View File

@ -22,42 +22,10 @@
namespace webrtc {
template <typename FakePacketType>
class FakePacketRoute : public EmulatedNetworkReceiverInterface {
public:
FakePacketRoute(EmulatedRoute* route,
std::function<void(FakePacketType, Timestamp)> action)
: route_(route),
action_(std::move(action)),
send_addr_(route_->from->GetPeerLocalAddress(), 0),
recv_addr_(route_->to->GetPeerLocalAddress(),
*route_->to->BindReceiver(0, this)) {}
void SendPacket(EmulatedEndpoint* from, size_t size, FakePacketType packet) {
RTC_CHECK_GE(size, sizeof(int));
sent_.emplace(next_packet_id_, packet);
rtc::CopyOnWriteBuffer buf(size);
reinterpret_cast<int*>(buf.data())[0] = next_packet_id_++;
from->SendPacket(send_addr_, recv_addr_, buf);
}
void OnPacketReceived(EmulatedIpPacket packet) override {
int packet_id = reinterpret_cast<int*>(packet.data.data())[0];
action_(std::move(sent_[packet_id]), packet.arrival_time);
sent_.erase(packet_id);
}
private:
EmulatedRoute* const route_;
const std::function<void(FakePacketType, Timestamp)> action_;
const rtc::SocketAddress send_addr_;
const rtc::SocketAddress recv_addr_;
int next_packet_id_ = 0;
std::map<int, FakePacketType> sent_;
};
class FeedbackGeneratorImpl : public FeedbackGenerator {
class FeedbackGeneratorImpl
: public FeedbackGenerator,
public TwoWayFakeTrafficRoute<SentPacket, TransportPacketsFeedback>::
TrafficHandlerInterface {
public:
explicit FeedbackGeneratorImpl(Config config);
Timestamp Now() override;
@ -70,21 +38,17 @@ class FeedbackGeneratorImpl : public FeedbackGenerator {
void SetSendLinkCapacity(DataRate capacity) override;
void OnRequest(SentPacket packet, Timestamp arrival_time) override;
void OnResponse(TransportPacketsFeedback packet,
Timestamp arrival_time) override;
private:
void OnPacketReceived(SentPacket packet, Timestamp arrival_time);
Config conf_;
GlobalSimulatedTimeController time_controller_;
::webrtc::test::NetworkEmulationManagerImpl net_;
SimulatedNetwork* const send_link_;
SimulatedNetwork* const ret_link_;
EmulatedEndpoint* const send_ep_;
EmulatedEndpoint* const ret_ep_;
EmulatedRoute* const send_route_;
EmulatedRoute* const ret_route_;
const rtc::SocketAddress send_addr_;
const rtc::SocketAddress ret_addr_;
FakePacketRoute<SentPacket> received_packet_handler_;
FakePacketRoute<TransportPacketsFeedback> received_feedback_handler_;
TwoWayFakeTrafficRoute<SentPacket, TransportPacketsFeedback> route_;
TransportPacketsFeedback builder_;
std::vector<TransportPacketsFeedback> feedback_;

View File

@ -233,10 +233,9 @@ class EmulatedRoute {
EmulatedEndpoint* to;
bool active;
};
class EndpointsContainer {
public:
EndpointsContainer(const std::vector<EmulatedEndpoint*>& endpoints);
explicit EndpointsContainer(const std::vector<EmulatedEndpoint*>& endpoints);
EmulatedEndpoint* LookupByLocalAddress(const rtc::IPAddress& local_ip) const;
bool HasEndpoint(EmulatedEndpoint* endpoint) const;
@ -249,6 +248,73 @@ class EndpointsContainer {
const std::vector<EmulatedEndpoint*> endpoints_;
};
template <typename FakePacketType>
class FakePacketRoute : public EmulatedNetworkReceiverInterface {
public:
FakePacketRoute(EmulatedRoute* route,
std::function<void(FakePacketType, Timestamp)> action)
: route_(route),
action_(std::move(action)),
send_addr_(route_->from->GetPeerLocalAddress(), 0),
recv_addr_(route_->to->GetPeerLocalAddress(),
*route_->to->BindReceiver(0, this)) {}
void SendPacket(size_t size, FakePacketType packet) {
RTC_CHECK_GE(size, sizeof(int));
sent_.emplace(next_packet_id_, packet);
rtc::CopyOnWriteBuffer buf(size);
reinterpret_cast<int*>(buf.data())[0] = next_packet_id_++;
route_->from->SendPacket(send_addr_, recv_addr_, buf);
}
void OnPacketReceived(EmulatedIpPacket packet) override {
int packet_id = reinterpret_cast<int*>(packet.data.data())[0];
action_(std::move(sent_[packet_id]), packet.arrival_time);
sent_.erase(packet_id);
}
private:
EmulatedRoute* const route_;
const std::function<void(FakePacketType, Timestamp)> action_;
const rtc::SocketAddress send_addr_;
const rtc::SocketAddress recv_addr_;
int next_packet_id_ = 0;
std::map<int, FakePacketType> sent_;
};
template <typename RequestPacketType, typename ResponsePacketType>
class TwoWayFakeTrafficRoute {
public:
class TrafficHandlerInterface {
public:
virtual void OnRequest(RequestPacketType, Timestamp) = 0;
virtual void OnResponse(ResponsePacketType, Timestamp) = 0;
virtual ~TrafficHandlerInterface() = default;
};
TwoWayFakeTrafficRoute(TrafficHandlerInterface* handler,
EmulatedRoute* send_route,
EmulatedRoute* ret_route)
: handler_(handler),
request_handler_{send_route,
[&](RequestPacketType packet, Timestamp arrival_time) {
handler_->OnRequest(std::move(packet), arrival_time);
}},
response_handler_{
ret_route, [&](ResponsePacketType packet, Timestamp arrival_time) {
handler_->OnResponse(std::move(packet), arrival_time);
}} {}
void SendRequest(size_t size, RequestPacketType packet) {
request_handler_.SendPacket(size, std::move(packet));
}
void SendResponse(size_t size, ResponsePacketType packet) {
response_handler_.SendPacket(size, std::move(packet));
}
private:
TrafficHandlerInterface* handler_;
FakePacketRoute<RequestPacketType> request_handler_;
FakePacketRoute<ResponsePacketType> response_handler_;
};
} // namespace webrtc
#endif // TEST_SCENARIO_NETWORK_NETWORK_EMULATION_H_

View File

@ -145,6 +145,13 @@ EmulatedRoute* NetworkEmulationManagerImpl::CreateRoute(
return out;
}
EmulatedRoute* NetworkEmulationManagerImpl::CreateRoute(
const std::vector<EmulatedNetworkNode*>& via_nodes) {
EmulatedEndpoint* from = CreateEndpoint(EmulatedEndpointConfig());
EmulatedEndpoint* to = CreateEndpoint(EmulatedEndpointConfig());
return CreateRoute(from, via_nodes, to);
}
void NetworkEmulationManagerImpl::ClearRoute(EmulatedRoute* route) {
RTC_CHECK(route->active) << "Route already cleared";
task_queue_.SendTask([route]() {
@ -223,6 +230,24 @@ NetworkEmulationManagerImpl::CreatePulsedPeaksCrossTraffic(
return out;
}
void NetworkEmulationManagerImpl::StartFakeTcpCrossTraffic(
EmulatedRoute* send_route,
EmulatedRoute* ret_route,
FakeTcpConfig config) {
task_queue_.PostTask([=]() {
auto traffic =
absl::make_unique<FakeTcpCrossTraffic>(config, send_route, ret_route);
auto* traffic_ptr = traffic.get();
tcp_cross_traffics_.push_back(std::move(traffic));
TimeDelta process_interval = config.process_interval;
RepeatingTaskHandle::Start(task_queue_.Get(),
[this, process_interval, traffic_ptr] {
traffic_ptr->Process(Now());
return process_interval;
});
});
}
EmulatedNetworkManagerInterface*
NetworkEmulationManagerImpl::CreateEmulatedNetworkManagerInterface(
const std::vector<EmulatedEndpoint*>& endpoints) {

View File

@ -51,6 +51,10 @@ class NetworkEmulationManagerImpl : public NetworkEmulationManager {
EmulatedRoute* CreateRoute(EmulatedEndpoint* from,
const std::vector<EmulatedNetworkNode*>& via_nodes,
EmulatedEndpoint* to) override;
EmulatedRoute* CreateRoute(
const std::vector<EmulatedNetworkNode*>& via_nodes);
void ClearRoute(EmulatedRoute* route) override;
TrafficRoute* CreateTrafficRoute(
@ -61,6 +65,9 @@ class NetworkEmulationManagerImpl : public NetworkEmulationManager {
PulsedPeaksCrossTraffic* CreatePulsedPeaksCrossTraffic(
TrafficRoute* traffic_route,
PulsedPeaksConfig config);
void StartFakeTcpCrossTraffic(EmulatedRoute* send_route,
EmulatedRoute* ret_route,
FakeTcpConfig config);
EmulatedNetworkManagerInterface* CreateEmulatedNetworkManagerInterface(
const std::vector<EmulatedEndpoint*>& endpoints) override;
@ -84,6 +91,7 @@ class NetworkEmulationManagerImpl : public NetworkEmulationManager {
std::vector<std::unique_ptr<TrafficRoute>> traffic_routes_;
std::vector<std::unique_ptr<RandomWalkCrossTraffic>> random_cross_traffics_;
std::vector<std::unique_ptr<PulsedPeaksCrossTraffic>> pulsed_cross_traffics_;
std::vector<std::unique_ptr<FakeTcpCrossTraffic>> tcp_cross_traffics_;
std::vector<std::unique_ptr<EndpointsContainer>> endpoints_containers_;
std::vector<std::unique_ptr<EmulatedNetworkManager>> network_managers_;