Allow FakeNetworkPipe to drop packets in bursts.

The fake network pipe will still only drop packets at an average rate of
|loss_percent| but in bursts at an average length specified by
|avg_burst_loss_length|.

Also added the flag -avg_burst_loss_length to video loopback.

BUG=

Review-Url: https://codereview.webrtc.org/1995683003
Cr-Commit-Position: refs/heads/master@{#12969}
This commit is contained in:
philipel
2016-05-31 03:20:23 -07:00
committed by Commit bot
parent 6c2eab34f8
commit 536378bf37
4 changed files with 89 additions and 3 deletions

View File

@ -13,7 +13,9 @@
#include <assert.h>
#include <math.h>
#include <string.h>
#include <algorithm>
#include <cmath>
#include "webrtc/call.h"
#include "webrtc/system_wrappers/include/clock.h"
@ -34,7 +36,27 @@ FakeNetworkPipe::FakeNetworkPipe(Clock* clock,
dropped_packets_(0),
sent_packets_(0),
total_packet_delay_(0),
next_process_time_(clock_->TimeInMilliseconds()) {}
bursting_(false),
next_process_time_(clock_->TimeInMilliseconds()) {
double prob_loss = config.loss_percent / 100.0;
if (config_.avg_burst_loss_length == -1) {
// Uniform loss
prob_loss_bursting_ = prob_loss;
prob_start_bursting_ = prob_loss;
} else {
// Lose packets according to a gilbert-elliot model.
int avg_burst_loss_length = config.avg_burst_loss_length;
int min_avg_burst_loss_length = std::ceil(prob_loss / (1 - prob_loss));
RTC_CHECK_GT(avg_burst_loss_length, min_avg_burst_loss_length)
<< "For a total packet loss of " << config.loss_percent << "%% then"
<< " avg_burst_loss_length must be " << min_avg_burst_loss_length + 1
<< " or higher.";
prob_loss_bursting_ = (1.0 - 1.0 / avg_burst_loss_length);
prob_start_bursting_ = prob_loss / (1 - prob_loss) / avg_burst_loss_length;
}
}
FakeNetworkPipe::~FakeNetworkPipe() {
while (!capacity_link_.empty()) {
@ -118,10 +140,15 @@ void FakeNetworkPipe::Process() {
NetworkPacket* packet = capacity_link_.front();
capacity_link_.pop();
// Packets are randomly dropped after being affected by the bottleneck.
if (random_.Rand(100) < static_cast<uint32_t>(config_.loss_percent)) {
// Drop packets at an average rate of |config_.loss_percent| with
// and average loss burst length of |config_.avg_burst_loss_length|.
if ((bursting_ && random_.Rand<double>() < prob_loss_bursting_) ||
(!bursting_ && random_.Rand<double>() < prob_start_bursting_)) {
bursting_ = true;
delete packet;
continue;
} else {
bursting_ = false;
}
int arrival_time_jitter = random_.Gaussian(

View File

@ -80,6 +80,8 @@ class FakeNetworkPipe {
int loss_percent = 0;
// If packets are allowed to be reordered.
bool allow_reordering = false;
// The average length of a burst of lost packets.
int avg_burst_loss_length = -1;
};
FakeNetworkPipe(Clock* clock, const FakeNetworkPipe::Config& config);
@ -133,6 +135,16 @@ class FakeNetworkPipe {
size_t sent_packets_;
int64_t total_packet_delay_;
// Are we currently dropping a burst of packets?
bool bursting_;
// The probability to drop the packet if we are currently dropping a
// burst of packet
double prob_loss_bursting_;
// The probability to drop a burst of packets.
double prob_start_bursting_;
int64_t next_process_time_;
RTC_DISALLOW_COPY_AND_ASSIGN(FakeNetworkPipe);

View File

@ -379,4 +379,45 @@ TEST_F(FakeNetworkPipeTest, DisallowReorderingThenAllowReordering) {
}
EXPECT_TRUE(reordering_has_occured);
}
TEST_F(FakeNetworkPipeTest, BurstLoss) {
const int kLossPercent = 5;
const int kAvgBurstLength = 3;
const int kNumPackets = 10000;
const int kPacketSize = 10;
FakeNetworkPipe::Config config;
config.queue_length_packets = kNumPackets;
config.loss_percent = kLossPercent;
config.avg_burst_loss_length = kAvgBurstLength;
std::unique_ptr<FakeNetworkPipe> pipe(
new FakeNetworkPipe(&fake_clock_, config));
ReorderTestReceiver* receiver = new ReorderTestReceiver();
receiver_.reset(receiver);
pipe->SetReceiver(receiver_.get());
SendPackets(pipe.get(), kNumPackets, kPacketSize);
fake_clock_.AdvanceTimeMilliseconds(1000);
pipe->Process();
// Check that the average loss is |kLossPercent| percent.
int lost_packets = kNumPackets - receiver->delivered_sequence_numbers_.size();
double loss_fraction = lost_packets / static_cast<double>(kNumPackets);
EXPECT_NEAR(kLossPercent / 100.0, loss_fraction, 0.05);
// Find the number of bursts that has occurred.
size_t received_packets = receiver->delivered_sequence_numbers_.size();
int num_bursts = 0;
for (size_t i = 0; i < received_packets - 1; ++i) {
int diff = receiver->delivered_sequence_numbers_[i + 1] -
receiver->delivered_sequence_numbers_[i];
if (diff > 1)
++num_bursts;
}
double average_burst_length = static_cast<double>(lost_packets) / num_bursts;
EXPECT_NEAR(kAvgBurstLength, average_burst_length, 0.3);
}
} // namespace webrtc

View File

@ -101,6 +101,11 @@ int LossPercent() {
return static_cast<int>(FLAGS_loss_percent);
}
DEFINE_int32(avg_burst_loss_length, 1, "Average burst length of lost packets.");
int AvgBurstLossLength() {
return static_cast<int>(FLAGS_avg_burst_loss_length);
}
DEFINE_int32(link_capacity,
0,
"Capacity (kbps) of the fake link. 0 means infinite.");
@ -201,6 +206,7 @@ std::string Clip() {
void Loopback() {
FakeNetworkPipe::Config pipe_config;
pipe_config.loss_percent = flags::LossPercent();
pipe_config.avg_burst_loss_length = flags::AvgBurstLossLength();
pipe_config.link_capacity_kbps = flags::LinkCapacityKbps();
pipe_config.queue_length_packets = flags::QueueSize();
pipe_config.queue_delay_ms = flags::AvgPropagationDelayMs();