Enabling Packet-Loss plots for BweReceiver.

Packet-loss computation and plot were added to BweReceiver class.

Objective function and plot were added to PacketReceiver class.

BUG=4550
R=stefan@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/56459004

Cr-Commit-Position: refs/heads/master@{#9391}
This commit is contained in:
Cesar Magalhaes 2015-06-08 11:29:08 +02:00
parent c1b9d4e686
commit 77cabab51a
10 changed files with 285 additions and 193 deletions

View File

@ -22,6 +22,16 @@ namespace webrtc {
namespace testing {
namespace bwe {
// With the assumption that packet loss is lower than 97%, the max gap
// between elements in the set is lower than 0x8000, hence we have a
// total order in the set. For (x,y,z) subset of the LinkedSet,
// (x<=y and y<=z) ==> x<=z so the set can be sorted.
const int kSetCapacity = 1000;
BweReceiver::BweReceiver(int flow_id)
: flow_id_(flow_id), received_packets_(kSetCapacity) {
}
class NullBweSender : public BweSender {
public:
NullBweSender() {}
@ -86,6 +96,98 @@ BweReceiver* CreateBweReceiver(BandwidthEstimatorType type,
assert(false);
return NULL;
}
float BweReceiver::GlobalPacketLossRatio() {
if (received_packets_.empty()) {
return 0.0f;
}
// Possibly there are packets missing.
const uint16_t kMaxGap = 1.5 * kSetCapacity;
uint16_t min = received_packets_.find_min();
uint16_t max = received_packets_.find_max();
int gap;
if (max - min < kMaxGap) {
gap = max - min + 1;
} else { // There was an overflow.
max = received_packets_.upper_bound(kMaxGap);
min = received_packets_.lower_bound(0xFFFF - kMaxGap);
gap = max + (0xFFFF - min) + 2;
}
return static_cast<float>(received_packets_.size()) / gap;
}
// Go through a fixed time window of most recent packets received and
// counts packets missing to obtain the packet loss ratio. If an unordered
// packet falls out of the timewindow it will be counted as missing.
// E.g.: for a timewindow covering 5 packets of the following arrival sequence
// {10 7 9 5 6} 8 3 2 4 1, the output will be 1/6 (#8 is considered as missing).
float BweReceiver::RecentPacketLossRatio() {
if (received_packets_.empty()) {
return 0.0f;
}
int number_packets_received = 0;
PacketNodeIt node_it = received_packets_.begin(); // Latest.
// Lowest timestamp limit, oldest one that should be checked.
int64_t time_limit_ms = (*node_it)->arrival_time_ms - kPacketLossTimeWindowMs;
// Oldest and newest values found within the given time window.
uint16_t oldest_seq_nb = (*node_it)->sequence_number;
uint16_t newest_seq_nb = oldest_seq_nb;
while (node_it != received_packets_.end()) {
if ((*node_it)->arrival_time_ms < time_limit_ms) {
break;
}
uint16_t seq_nb = (*node_it)->sequence_number;
if (IsNewerSequenceNumber(seq_nb, newest_seq_nb)) {
newest_seq_nb = seq_nb;
}
if (IsNewerSequenceNumber(oldest_seq_nb, seq_nb)) {
oldest_seq_nb = seq_nb;
}
++node_it;
++number_packets_received;
}
// Interval width between oldest and newest sequence number.
// There was an overflow if newest_seq_nb < oldest_seq_nb.
int gap = static_cast<uint16_t>(newest_seq_nb - oldest_seq_nb + 1);
return static_cast<float>(gap - number_packets_received) / gap;
}
void LinkedSet::Insert(uint16_t sequence_number,
int64_t send_time_ms,
int64_t arrival_time_ms,
size_t payload_size) {
std::map<uint16_t, PacketNodeIt>::iterator it = map_.find(sequence_number);
if (it != map_.end()) {
PacketNodeIt node_it = it->second;
PacketIdentifierNode* node = *node_it;
node->arrival_time_ms = arrival_time_ms;
if (node_it != list_.begin()) {
list_.erase(node_it);
list_.push_front(node);
map_[sequence_number] = list_.begin();
}
} else {
if (size() == capacity_) {
RemoveTail();
}
UpdateHead(new PacketIdentifierNode(sequence_number, send_time_ms,
arrival_time_ms, payload_size));
}
}
void LinkedSet::RemoveTail() {
map_.erase(list_.back()->sequence_number);
list_.pop_back();
}
void LinkedSet::UpdateHead(PacketIdentifierNode* new_head) {
list_.push_front(new_head);
map_[new_head->sequence_number] = list_.begin();
}
} // namespace bwe
} // namespace testing
} // namespace webrtc

View File

@ -20,6 +20,66 @@ namespace webrtc {
namespace testing {
namespace bwe {
// Holds only essential information about packets to be saved for
// further use, e.g. for calculating packet loss and receiving rate.
struct PacketIdentifierNode {
PacketIdentifierNode(uint16_t sequence_number,
int64_t send_time_ms,
int64_t arrival_time_ms,
size_t payload_size)
: sequence_number(sequence_number),
send_time_ms(send_time_ms),
arrival_time_ms(arrival_time_ms),
payload_size(payload_size) {}
uint16_t sequence_number;
int64_t send_time_ms;
int64_t arrival_time_ms;
size_t payload_size;
};
typedef std::list<PacketIdentifierNode*>::iterator PacketNodeIt;
// FIFO implementation for a limited capacity set.
// Used for keeping the latest arrived packets while avoiding duplicates.
// Allows efficient insertion, deletion and search.
class LinkedSet {
public:
explicit LinkedSet(int capacity) : capacity_(capacity) {}
// If the arriving packet (identified by its sequence number) is already
// in the LinkedSet, move its Node to the head of the list. Else, create
// a PacketIdentifierNode n_ and then UpdateHead(n_), calling RemoveTail()
// if the LinkedSet reached its maximum capacity.
void Insert(uint16_t sequence_number,
int64_t send_time_ms,
int64_t arrival_time_ms,
size_t payload_size);
PacketNodeIt begin() { return list_.begin(); }
PacketNodeIt end() { return list_.end(); }
bool empty() { return list_.empty(); }
size_t size() { return list_.size(); }
// Gets the latest arrived sequence number.
uint16_t find_max() { return map_.rbegin()->first; }
// Gets the first arrived sequence number still saved in the LinkedSet.
uint16_t find_min() { return map_.begin()->first; }
// Gets the lowest saved sequence number that is >= than the input key.
uint16_t lower_bound(uint16_t key) { return map_.lower_bound(key)->first; }
// Gets the highest saved sequence number that is <= than the input key.
uint16_t upper_bound(uint16_t key) { return map_.upper_bound(key)->first; }
size_t capacity() { return capacity_; }
private:
// Pop oldest element from the back of the list and remove it from the map.
void RemoveTail();
// Add new element to the front of the list and insert it in the map.
void UpdateHead(PacketIdentifierNode* new_head);
size_t capacity_;
std::map<uint16_t, PacketNodeIt> map_;
std::list<PacketIdentifierNode*> list_;
};
const int kMinBitrateKbps = 150;
const int kMaxBitrateKbps = 3000;
@ -38,15 +98,23 @@ class BweSender : public Module {
class BweReceiver {
public:
explicit BweReceiver(int flow_id) : flow_id_(flow_id) {}
explicit BweReceiver(int flow_id);
virtual ~BweReceiver() {}
virtual void ReceivePacket(int64_t arrival_time_ms,
const MediaPacket& media_packet) {}
virtual FeedbackPacket* GetFeedback(int64_t now_ms) { return NULL; }
float GlobalPacketLossRatio();
float RecentPacketLossRatio();
size_t GetSetCapacity() { return received_packets_.capacity(); }
static const int64_t kPacketLossTimeWindowMs = 500;
protected:
int flow_id_;
// Deals with packets sent more than once.
LinkedSet received_packets_;
};
enum BandwidthEstimatorType {

View File

@ -28,10 +28,9 @@ namespace testing {
namespace bwe {
const int NadaBweReceiver::kMedian;
const int64_t NadaBweReceiver::kPacketLossTimeWindowMs;
const int64_t NadaBweReceiver::kReceivingRateTimeWindowMs;
const int NadaBweSender::kMinRefRateKbps;
const int NadaBweSender::kMaxRefRateKbps;
const int64_t NadaBweReceiver::kReceivingRateTimeWindowMs;
NadaBweReceiver::NadaBweReceiver(int flow_id)
: BweReceiver(flow_id),
@ -84,9 +83,9 @@ void NadaBweReceiver::ReceivePacket(int64_t arrival_time_ms,
est_queuing_delay_signal_ms_ = 0;
}
received_packets_->Insert(media_packet.sequence_number(),
media_packet.send_time_ms(), arrival_time_ms,
media_packet.payload_size());
received_packets_.Insert(media_packet.sequence_number(),
media_packet.send_time_ms(), arrival_time_ms,
media_packet.payload_size());
}
FeedbackPacket* NadaBweReceiver::GetFeedback(int64_t now_ms) {
@ -110,7 +109,7 @@ FeedbackPacket* NadaBweReceiver::GetFeedback(int64_t now_ms) {
last_feedback_ms_ = now_ms;
last_congestion_signal_ms_ = congestion_signal_ms;
PacketIdentifierNode* latest = *(received_packets_->begin());
PacketIdentifierNode* latest = *(received_packets_.begin());
int64_t corrected_send_time_ms =
latest->send_time_ms + now_ms - latest->arrival_time_ms;
@ -122,83 +121,22 @@ FeedbackPacket* NadaBweReceiver::GetFeedback(int64_t now_ms) {
corrected_send_time_ms);
}
float NadaBweReceiver::GlobalPacketLossRatio() {
if (received_packets_->empty()) {
return 0.0f;
}
// Possibly there are packets missing.
const uint16_t kMaxGap = 1.5 * kSetCapacity;
uint16_t min = received_packets_->find_min();
uint16_t max = received_packets_->find_max();
int gap;
if (max - min < kMaxGap) {
gap = max - min + 1;
} else { // There was an overflow.
max = received_packets_->upper_bound(kMaxGap);
min = received_packets_->lower_bound(0xFFFF - kMaxGap);
gap = max + (0xFFFF - min) + 2;
}
return static_cast<float>(received_packets_->size()) / gap;
}
// Go through a fixed time window of most recent packets received and
// counts packets missing to obtain the packet loss ratio. If an unordered
// packet falls out of the timewindow it will be counted as missing.
// E.g.: for a timewindow covering 5 packets of the following arrival sequence
// {10 7 9 5 6} 8 3 2 4 1, the output will be 1/6 (#8 is considered as missing).
float NadaBweReceiver::RecentPacketLossRatio() {
if (received_packets_->empty()) {
return 0.0f;
}
int number_packets_received = 0;
PacketNodeIt node_it = received_packets_->begin(); // Latest.
// Lowest timestamp limit, oldest one that should be checked.
int64_t time_limit_ms = (*node_it)->arrival_time_ms - kPacketLossTimeWindowMs;
// Oldest and newest values found within the given time window.
uint16_t oldest_seq_nb = (*node_it)->sequence_number;
uint16_t newest_seq_nb = oldest_seq_nb;
while (node_it != received_packets_->end()) {
if ((*node_it)->arrival_time_ms < time_limit_ms) {
break;
}
uint16_t seq_nb = (*node_it)->sequence_number;
if (IsNewerSequenceNumber(seq_nb, newest_seq_nb)) {
newest_seq_nb = seq_nb;
}
if (IsNewerSequenceNumber(oldest_seq_nb, seq_nb)) {
oldest_seq_nb = seq_nb;
}
++node_it;
++number_packets_received;
}
// Interval width between oldest and newest sequence number.
// There was an overflow if newest_seq_nb < oldest_seq_nb.
int gap = static_cast<uint16_t>(newest_seq_nb - oldest_seq_nb + 1);
return static_cast<float>(gap - number_packets_received) / gap;
}
// For a given time window, compute the receiving speed rate in kbps.
// As described below, three cases are considered depending on the number of
// packets received.
size_t NadaBweReceiver::RecentReceivingRate() {
// If the receiver didn't receive any packet, return 0.
if (received_packets_->empty()) {
if (received_packets_.empty()) {
return 0.0f;
}
size_t total_size = 0;
int number_packets = 0;
PacketNodeIt node_it = received_packets_->begin();
PacketNodeIt node_it = received_packets_.begin();
int64_t last_time_ms = (*node_it)->arrival_time_ms;
int64_t start_time_ms = last_time_ms;
PacketNodeIt end = received_packets_->end();
PacketNodeIt end = received_packets_.end();
// Stops after including the first packet out of the timeWindow.
// Ameliorates results when there are wide gaps between packets.
@ -218,13 +156,14 @@ size_t NadaBweReceiver::RecentReceivingRate() {
// If the receiver received a single packet, return its size*8/timeWindow.
if (number_packets == 1) {
corrected_time_ms = kReceivingRateTimeWindowMs;
} else {
// If the receiver received multiple packets, use as time interval the gap
// between first and last packet falling in the timeWindow corrected by the
// factor number_packets/(number_packets-1).
// E.g: Let timeWindow = 500ms, payload_size = 500bytes, number_packets=2,
// packets received at t1(0ms) and t2(499 or 501ms). This prevent the
// function from returning ~2*8, sending instead a more likely ~1*8 kbps.
}
// If the receiver received multiple packets, use as time interval the gap
// between first and last packet falling in the timeWindow corrected by the
// factor number_packets/(number_packets-1).
// E.g: Let timeWindow = 500ms, payload_size = 500 bytes, number_packets = 2,
// packets received at t1(0ms) and t2(499 or 501ms). This prevent the function
// from returning ~2*8, sending instead a more likely ~1*8 kbps.
else {
corrected_time_ms = (number_packets * (start_time_ms - last_time_ms)) /
(number_packets - 1);
}
@ -383,37 +322,6 @@ void NadaBweSender::GradualRateUpdate(const NadaFeedback& fb,
bitrate_kbps_ = bitrate_kbps_ + smoothing_factor * original_increase;
}
void LinkedSet::Insert(uint16_t sequence_number,
int64_t send_time_ms,
int64_t arrival_time_ms,
size_t payload_size) {
std::map<uint16_t, PacketNodeIt>::iterator it = map_.find(sequence_number);
if (it != map_.end()) {
PacketNodeIt node_it = it->second;
PacketIdentifierNode* node = *node_it;
node->arrival_time_ms = arrival_time_ms;
if (node_it != list_.begin()) {
list_.erase(node_it);
list_.push_front(node);
map_[sequence_number] = list_.begin();
}
} else {
if (size() == capacity_) {
RemoveTail();
}
UpdateHead(new PacketIdentifierNode(sequence_number, send_time_ms,
arrival_time_ms, payload_size));
}
}
void LinkedSet::RemoveTail() {
map_.erase(list_.back()->sequence_number);
list_.pop_back();
}
void LinkedSet::UpdateHead(PacketIdentifierNode* new_head) {
list_.push_front(new_head);
map_[new_head->sequence_number] = list_.begin();
}
} // namespace bwe
} // namespace testing
} // namespace webrtc

View File

@ -31,65 +31,6 @@ class ReceiveStatistics;
namespace testing {
namespace bwe {
// Holds only essential information about packets to be saved for
// further use, e.g. for calculating packet loss and receiving rate.
struct PacketIdentifierNode {
PacketIdentifierNode(uint16_t sequence_number,
int64_t send_time_ms,
int64_t arrival_time_ms,
size_t payload_size)
: sequence_number(sequence_number),
send_time_ms(send_time_ms),
arrival_time_ms(arrival_time_ms),
payload_size(payload_size) {}
uint16_t sequence_number;
int64_t send_time_ms;
int64_t arrival_time_ms;
size_t payload_size;
};
typedef std::list<PacketIdentifierNode*>::iterator PacketNodeIt;
// FIFO implementation for a limited capacity set.
// Used for keeping the latest arrived packets while avoiding duplicates.
// Allows efficient insertion, deletion and search.
class LinkedSet {
public:
explicit LinkedSet(size_t capacity) : capacity_(capacity) {}
// If the arriving packet (identified by its sequence number) is already
// in the LinkedSet, move its Node to the head of the list. Else, create
// a PacketIdentifierNode n_ and then UpdateHead(n_), calling RemoveTail()
// if the LinkedSet reached its maximum capacity.
void Insert(uint16_t sequence_number,
int64_t send_time_ms,
int64_t arrival_time_ms,
size_t payload_size);
PacketNodeIt begin() { return list_.begin(); }
PacketNodeIt end() { return list_.end(); }
bool empty() { return list_.empty(); }
size_t size() { return list_.size(); }
// Gets the latest arrived sequence number.
uint16_t find_max() { return map_.rbegin()->first; }
// Gets the first arrived sequence number still saved in the LinkedSet.
uint16_t find_min() { return map_.begin()->first; }
// Gets the lowest saved sequence number that is >= than the input key.
uint16_t lower_bound(uint16_t key) { return map_.lower_bound(key)->first; }
// Gets the highest saved sequence number that is <= than the input key.
uint16_t upper_bound(uint16_t key) { return map_.upper_bound(key)->first; }
private:
// Pop oldest element from the back of the list and remove it from the map.
void RemoveTail();
// Add new element to the front of the list and insert it in the map.
void UpdateHead(PacketIdentifierNode* new_head);
size_t capacity_;
std::map<uint16_t, PacketNodeIt> map_;
std::list<PacketIdentifierNode*> list_;
};
class NadaBweReceiver : public BweReceiver {
public:
explicit NadaBweReceiver(int flow_id);
@ -98,20 +39,13 @@ class NadaBweReceiver : public BweReceiver {
void ReceivePacket(int64_t arrival_time_ms,
const MediaPacket& media_packet) override;
FeedbackPacket* GetFeedback(int64_t now_ms) override;
float GlobalPacketLossRatio();
float RecentPacketLossRatio();
size_t RecentReceivingRate();
static int64_t MedianFilter(int64_t* v, int size);
static int64_t ExponentialSmoothingFilter(int64_t new_value,
int64_t last_smoothed_value,
float alpha);
// With the assumption that packet loss is lower than 97%, the max gap
// between elements in the set is lower than 0x8000, hence we have a
// total order in the set. For (x,y,z) subset of the LinkedSet,
// (x<=y and y<=z) ==> x<=z so the set can be sorted.
static const int kSetCapacity = 1000;
static const int64_t kPacketLossTimeWindowMs = 500;
static const int64_t kReceivingRateTimeWindowMs = 500;
private:
@ -125,8 +59,6 @@ class NadaBweReceiver : public BweReceiver {
int64_t exp_smoothed_delay_ms_; // Referred as d_hat_n.
int64_t est_queuing_delay_signal_ms_; // Referred as d_tilde_n.
// Deals with packets sent more than once.
LinkedSet* received_packets_ = new LinkedSet(kSetCapacity);
static const int kMedian = 5; // Used for k-points Median Filter.
int64_t last_delays_ms_[kMedian]; // Used for Median Filter.
};

View File

@ -435,7 +435,7 @@ TEST_F(NadaReceiverSideTest, PacketLossSinglePacket) {
TEST_F(NadaReceiverSideTest, PacketLossContiguousPackets) {
const int64_t kTimeWindowMs = NadaBweReceiver::kPacketLossTimeWindowMs;
const int kSetCapacity = NadaBweReceiver::kSetCapacity;
size_t set_capacity = nada_receiver_.GetSetCapacity();
for (int i = 0; i < 10; ++i) {
uint16_t sequence_number = static_cast<uint16_t>(i);
@ -465,7 +465,7 @@ TEST_F(NadaReceiverSideTest, PacketLossContiguousPackets) {
EXPECT_EQ(nada_receiver_.RecentPacketLossRatio(), 0.0f);
// Should handle set overflow.
for (int i = 0; i < kSetCapacity * 1.5; ++i) {
for (int i = 0; i < set_capacity * 1.5; ++i) {
uint16_t sequence_number = static_cast<uint16_t>(i);
const MediaPacket media_packet(kFlowId, 0, 0, sequence_number);
// Only the packets sent in this for loop will be considered.
@ -503,11 +503,11 @@ TEST_F(NadaReceiverSideTest, PacketLossDuplicatedPackets) {
}
TEST_F(NadaReceiverSideTest, PacketLossLakingPackets) {
const int kSetCapacity = NadaBweReceiver::kSetCapacity;
EXPECT_LT(kSetCapacity, 0xFFFF);
size_t set_capacity = nada_receiver_.GetSetCapacity();
EXPECT_LT(set_capacity, static_cast<size_t>(0xFFFF));
// Missing every other packet.
for (int i = 0; i < kSetCapacity; ++i) {
for (size_t i = 0; i < set_capacity; ++i) {
if ((i & 1) == 0) { // Only even sequence numbers.
uint16_t sequence_number = static_cast<uint16_t>(i);
const MediaPacket media_packet(kFlowId, 0, 0, sequence_number);
@ -519,12 +519,12 @@ TEST_F(NadaReceiverSideTest, PacketLossLakingPackets) {
}
TEST_F(NadaReceiverSideTest, PacketLossLakingFewPackets) {
const int kSetCapacity = NadaBweReceiver::kSetCapacity;
EXPECT_LT(kSetCapacity, 0xFFFF);
size_t set_capacity = nada_receiver_.GetSetCapacity();
EXPECT_LT(set_capacity, static_cast<size_t>(0xFFFF));
const int kPeriod = 100;
// Missing one for each kPeriod packets.
for (int i = 0; i < kSetCapacity; ++i) {
for (size_t i = 0; i < set_capacity; ++i) {
if ((i % kPeriod) != 0) {
uint16_t sequence_number = static_cast<uint16_t>(i);
const MediaPacket media_packet(kFlowId, 0, 0, sequence_number);
@ -557,16 +557,16 @@ TEST_F(NadaReceiverSideTest, PacketLossWideGap) {
// Packets arriving unordered should not be counted as losted.
TEST_F(NadaReceiverSideTest, PacketLossUnorderedPackets) {
const int kNumPackets = NadaBweReceiver::kSetCapacity / 2;
int num_packets = nada_receiver_.GetSetCapacity() / 2;
std::vector<uint16_t> sequence_numbers;
for (int i = 0; i < kNumPackets; ++i) {
for (int i = 0; i < num_packets; ++i) {
sequence_numbers.push_back(static_cast<uint16_t>(i + 1));
}
random_shuffle(sequence_numbers.begin(), sequence_numbers.end());
for (int i = 0; i < kNumPackets; ++i) {
for (int i = 0; i < num_packets; ++i) {
const MediaPacket media_packet(kFlowId, 0, 0, sequence_numbers[i]);
// Arrival time = 0, all packets will be considered.
nada_receiver_.ReceivePacket(0, media_packet);

View File

@ -99,6 +99,10 @@ void RembReceiver::ReceivePacket(int64_t arrival_time_ms,
media_packet.header());
clock_.AdvanceTimeMilliseconds(arrival_time_ms - clock_.TimeInMilliseconds());
ASSERT_TRUE(arrival_time_ms == clock_.TimeInMilliseconds());
received_packets_.Insert(media_packet.sequence_number(),
media_packet.send_time_ms(), arrival_time_ms,
media_packet.payload_size());
}
FeedbackPacket* RembReceiver::GetFeedback(int64_t now_ms) {

View File

@ -127,6 +127,10 @@ void SendSideBweReceiver::ReceivePacket(int64_t arrival_time_ms,
packet_feedback_vector_.push_back(PacketInfo(
arrival_time_ms, media_packet.sender_timestamp_us() / 1000,
media_packet.header().sequenceNumber, media_packet.payload_size()));
received_packets_.Insert(media_packet.sequence_number(),
media_packet.send_time_ms(), arrival_time_ms,
media_packet.payload_size());
}
FeedbackPacket* SendSideBweReceiver::GetFeedback(int64_t now_ms) {

View File

@ -35,6 +35,10 @@ void TcpBweReceiver::ReceivePacket(int64_t arrival_time_ms,
const MediaPacket& media_packet) {
latest_owd_ms_ = arrival_time_ms - media_packet.sender_timestamp_us() / 1000;
acks_.push_back(media_packet.header().sequenceNumber);
received_packets_.Insert(media_packet.sequence_number(),
media_packet.send_time_ms(), arrival_time_ms,
media_packet.payload_size());
}
FeedbackPacket* TcpBweReceiver::GetFeedback(int64_t now_ms) {

View File

@ -10,6 +10,7 @@
#include "webrtc/modules/remote_bitrate_estimator/test/packet_receiver.h"
#include <math.h>
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
@ -31,13 +32,32 @@ PacketReceiver::PacketReceiver(PacketProcessorListener* listener,
bool plot_bwe)
: PacketProcessor(listener, flow_id, kReceiver),
delay_log_prefix_(),
metric_log_prefix_(),
packet_loss_log_prefix_(),
last_delay_plot_ms_(0),
last_metric_plot_ms_(0),
last_packet_loss_plot_ms_(0),
plot_delay_(plot_delay),
bwe_receiver_(CreateBweReceiver(bwe_type, flow_id, plot_bwe)) {
// TODO(magalhaesc) Add separated plot_objective_function and
// plot_packet_loss parameters to the constructor.
plot_objective_function_(plot_delay),
plot_packet_loss_(plot_delay),
bwe_receiver_(CreateBweReceiver(bwe_type, flow_id, plot_bwe)),
total_delay_ms_(0),
total_throughput_(0),
number_packets_(0) {
// Setup the prefix ststd::rings used when logging.
std::stringstream ss;
ss << "Delay_" << flow_id << "#2";
delay_log_prefix_ = ss.str();
std::stringstream ss1;
ss1 << "Delay_" << flow_id << "#2";
delay_log_prefix_ = ss1.str();
std::stringstream ss2;
ss2 << "Objective_function_" << flow_id << "#2";
metric_log_prefix_ = ss2.str();
std::stringstream ss3;
ss3 << "Packet_Loss_" << flow_id << "#2";
packet_loss_log_prefix_ = ss3.str();
}
PacketReceiver::~PacketReceiver() {
@ -61,6 +81,12 @@ void PacketReceiver::RunFor(int64_t time_ms, Packets* in_out) {
int64_t send_time_ms = (media_packet->creation_time_us() + 500) / 1000;
delay_stats_.Push(arrival_time_ms - send_time_ms);
PlotDelay(arrival_time_ms, send_time_ms);
PlotObjectiveFunction(arrival_time_ms);
PlotPacketLoss(arrival_time_ms);
total_delay_ms_ += arrival_time_ms - send_time_ms;
total_throughput_ += media_packet->payload_size();
++number_packets_;
bwe_receiver_->ReceivePacket(arrival_time_ms, *media_packet);
FeedbackPacket* fb = bwe_receiver_->GetFeedback(arrival_time_ms);
@ -87,6 +113,37 @@ void PacketReceiver::PlotDelay(int64_t arrival_time_ms, int64_t send_time_ms) {
}
}
double PacketReceiver::ObjectiveFunction() {
const double kDelta = 1.0; // Delay penalty factor.
double throughput_metric = log(static_cast<double>(total_throughput_));
double delay_penalty = kDelta * log(static_cast<double>(total_delay_ms_));
return throughput_metric - delay_penalty;
}
void PacketReceiver::PlotObjectiveFunction(int64_t arrival_time_ms) {
static const int kMetricPlotIntervalMs = 1000;
if (!plot_objective_function_) {
return;
}
if (arrival_time_ms - last_metric_plot_ms_ > kMetricPlotIntervalMs) {
BWE_TEST_LOGGING_PLOT(1, metric_log_prefix_, arrival_time_ms,
ObjectiveFunction());
last_metric_plot_ms_ = arrival_time_ms;
}
}
void PacketReceiver::PlotPacketLoss(int64_t arrival_time_ms) {
static const int kPacketLossPlotIntervalMs = 500;
if (!plot_packet_loss_) {
return;
}
if (arrival_time_ms - last_packet_loss_plot_ms_ > kPacketLossPlotIntervalMs) {
BWE_TEST_LOGGING_PLOT(2, packet_loss_log_prefix_, arrival_time_ms,
bwe_receiver_->RecentPacketLossRatio());
last_packet_loss_plot_ms_ = arrival_time_ms;
}
}
Stats<double> PacketReceiver::GetDelayStats() const {
return delay_stats_;
}

View File

@ -40,14 +40,27 @@ class PacketReceiver : public PacketProcessor {
protected:
void PlotDelay(int64_t arrival_time_ms, int64_t send_time_ms);
void PlotObjectiveFunction(int64_t arrival_time_ms);
void PlotPacketLoss(int64_t arrival_time_ms);
double ObjectiveFunction();
int64_t now_ms_;
std::string delay_log_prefix_;
std::string metric_log_prefix_;
std::string packet_loss_log_prefix_;
int64_t last_delay_plot_ms_;
int64_t last_metric_plot_ms_;
int64_t last_packet_loss_plot_ms_;
bool plot_delay_;
bool plot_objective_function_;
bool plot_packet_loss_;
Stats<double> delay_stats_;
rtc::scoped_ptr<BweReceiver> bwe_receiver_;
int64_t total_delay_ms_;
size_t total_throughput_;
int number_packets_;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(PacketReceiver);
};