Home | History | Annotate | Download | only in test
      1 /*
      2  *  Copyright (c) 2013 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 
     11 #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test.h"
     12 
     13 #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_baselinefile.h"
     14 #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h"
     15 #include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
     16 #include "webrtc/system_wrappers/interface/clock.h"
     17 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
     18 
     19 using std::string;
     20 using std::vector;
     21 
     22 namespace webrtc {
     23 namespace testing {
     24 namespace bwe {
     25 
     26 class TestedEstimator : public RemoteBitrateObserver {
     27  public:
     28   static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
     29   static const int kDelayPlotIntervalMs = 100;
     30 
     31   TestedEstimator(const string& test_name,
     32                   const BweTestConfig::EstimatorConfig& config)
     33       : debug_name_(config.debug_name),
     34         delay_log_prefix_(),
     35         estimate_log_prefix_(),
     36         last_delay_plot_ms_(0),
     37         plot_delay_(config.plot_delay),
     38         plot_estimate_(config.plot_estimate),
     39         clock_(0),
     40         stats_(),
     41         latest_estimate_bps_(-1),
     42         estimator_(config.estimator_factory->Create(
     43             this, &clock_, config.control_type,
     44             kRemoteBitrateEstimatorMinBitrateBps)),
     45         baseline_(BaseLineFileInterface::Create(test_name + "_" + debug_name_,
     46                                                 config.update_baseline)) {
     47     assert(estimator_.get());
     48     assert(baseline_.get());
     49     // Setup the prefix strings used when logging.
     50     std::stringstream ss;
     51     ss << "Delay_" << config.flow_id << "#2";
     52     delay_log_prefix_ = ss.str();
     53     ss.str("");
     54     ss << "Estimate_" << config.flow_id << "#1";
     55     estimate_log_prefix_ = ss.str();
     56     // Default RTT in RemoteRateControl is 200 ms ; 50 ms is more realistic.
     57     estimator_->OnRttUpdate(50);
     58   }
     59 
     60   void EatPacket(const Packet& packet) {
     61     BWE_TEST_LOGGING_CONTEXT(debug_name_);
     62 
     63     latest_estimate_bps_ = -1;
     64 
     65     // We're treating the send time (from previous filter) as the arrival
     66     // time once packet reaches the estimator.
     67     int64_t packet_time_ms = (packet.send_time_us() + 500) / 1000;
     68     BWE_TEST_LOGGING_TIME(packet_time_ms);
     69     if (plot_delay_) {
     70       if (clock_.TimeInMilliseconds() - last_delay_plot_ms_ >
     71           kDelayPlotIntervalMs) {
     72         BWE_TEST_LOGGING_PLOT(delay_log_prefix_, clock_.TimeInMilliseconds(),
     73                               packet_time_ms -
     74                               (packet.creation_time_us() + 500) / 1000);
     75         last_delay_plot_ms_ = clock_.TimeInMilliseconds();
     76       }
     77     }
     78 
     79     int64_t step_ms = std::max(estimator_->TimeUntilNextProcess(), 0);
     80     while ((clock_.TimeInMilliseconds() + step_ms) < packet_time_ms) {
     81       clock_.AdvanceTimeMilliseconds(step_ms);
     82       estimator_->Process();
     83       step_ms = std::max(estimator_->TimeUntilNextProcess(), 0);
     84     }
     85     estimator_->IncomingPacket(packet_time_ms, packet.payload_size(),
     86                                packet.header());
     87     clock_.AdvanceTimeMilliseconds(packet_time_ms -
     88                                    clock_.TimeInMilliseconds());
     89     ASSERT_TRUE(packet_time_ms == clock_.TimeInMilliseconds());
     90   }
     91 
     92   bool CheckEstimate(PacketSender::Feedback* feedback) {
     93     assert(feedback);
     94     BWE_TEST_LOGGING_CONTEXT(debug_name_);
     95     uint32_t estimated_bps = 0;
     96     if (LatestEstimate(&estimated_bps)) {
     97       feedback->estimated_bps = estimated_bps;
     98       baseline_->Estimate(clock_.TimeInMilliseconds(), estimated_bps);
     99 
    100       double estimated_kbps = static_cast<double>(estimated_bps) / 1000.0;
    101       stats_.Push(estimated_kbps);
    102       if (plot_estimate_) {
    103         BWE_TEST_LOGGING_PLOT(estimate_log_prefix_, clock_.TimeInMilliseconds(),
    104                               estimated_kbps);
    105       }
    106       return true;
    107     }
    108     return false;
    109   }
    110 
    111   void LogStats() {
    112     BWE_TEST_LOGGING_CONTEXT(debug_name_);
    113     BWE_TEST_LOGGING_CONTEXT("Mean");
    114     stats_.Log("kbps");
    115   }
    116 
    117   void VerifyOrWriteBaseline() {
    118     EXPECT_TRUE(baseline_->VerifyOrWrite());
    119   }
    120 
    121   virtual void OnReceiveBitrateChanged(const vector<unsigned int>& ssrcs,
    122                                        unsigned int bitrate) {
    123   }
    124 
    125  private:
    126   bool LatestEstimate(uint32_t* estimate_bps) {
    127     if (latest_estimate_bps_ < 0) {
    128       vector<unsigned int> ssrcs;
    129       unsigned int bps = 0;
    130       if (!estimator_->LatestEstimate(&ssrcs, &bps)) {
    131         return false;
    132       }
    133       latest_estimate_bps_ = bps;
    134     }
    135     *estimate_bps = latest_estimate_bps_;
    136     return true;
    137   }
    138 
    139   string debug_name_;
    140   string delay_log_prefix_;
    141   string estimate_log_prefix_;
    142   int64_t last_delay_plot_ms_;
    143   bool plot_delay_;
    144   bool plot_estimate_;
    145   SimulatedClock clock_;
    146   Stats<double> stats_;
    147   int64_t latest_estimate_bps_;
    148   scoped_ptr<RemoteBitrateEstimator> estimator_;
    149   scoped_ptr<BaseLineFileInterface> baseline_;
    150 
    151   DISALLOW_IMPLICIT_CONSTRUCTORS(TestedEstimator);
    152 };
    153 
    154 class PacketProcessorRunner {
    155  public:
    156   explicit PacketProcessorRunner(PacketProcessor* processor)
    157       : processor_(processor) {}
    158 
    159   bool HasProcessor(const PacketProcessor* processor) const {
    160     return processor == processor_;
    161   }
    162 
    163   void RunFor(int64_t time_ms, int64_t time_now_ms, Packets* in_out) {
    164     Packets to_process;
    165     FindPacketsToProcess(processor_->flow_ids(), in_out, &to_process);
    166     processor_->RunFor(time_ms, &to_process);
    167     QueuePackets(&to_process, time_now_ms * 1000);
    168     if (!to_process.empty()) {
    169       processor_->Plot((to_process.back().send_time_us() + 500) / 1000);
    170     }
    171     in_out->merge(to_process);
    172   }
    173 
    174  private:
    175   void FindPacketsToProcess(const FlowIds& flow_ids, Packets* in,
    176                             Packets* out) {
    177     assert(out->empty());
    178     for (Packets::iterator it = in->begin(); it != in->end();) {
    179       // TODO(holmer): Further optimize this by looking for consecutive flow ids
    180       // in the packet list and only doing the binary search + splice once for a
    181       // sequence.
    182       if (std::binary_search(flow_ids.begin(), flow_ids.end(), it->flow_id())) {
    183         Packets::iterator next = it;
    184         ++next;
    185         out->splice(out->end(), *in, it);
    186         it = next;
    187       } else {
    188         ++it;
    189       }
    190     }
    191   }
    192 
    193   void QueuePackets(Packets* batch, int64_t end_of_batch_time_us) {
    194     queue_.merge(*batch);
    195     if (queue_.empty()) {
    196       return;
    197     }
    198     Packets::iterator it = queue_.begin();
    199     for (; it != queue_.end(); ++it) {
    200       if (it->send_time_us() > end_of_batch_time_us) {
    201         break;
    202       }
    203     }
    204     Packets to_transfer;
    205     to_transfer.splice(to_transfer.begin(), queue_, queue_.begin(), it);
    206     batch->merge(to_transfer);
    207   }
    208 
    209   PacketProcessor* processor_;
    210   Packets queue_;
    211 };
    212 
    213 BweTest::BweTest()
    214     : run_time_ms_(0),
    215       time_now_ms_(-1),
    216       simulation_interval_ms_(-1),
    217       estimators_(),
    218       processors_() {
    219 }
    220 
    221 BweTest::~BweTest() {
    222   BWE_TEST_LOGGING_GLOBAL_ENABLE(true);
    223   for (EstimatorMap::iterator it = estimators_.begin(); it != estimators_.end();
    224       ++it) {
    225     it->second->VerifyOrWriteBaseline();
    226     it->second->LogStats();
    227   }
    228   BWE_TEST_LOGGING_GLOBAL_CONTEXT("");
    229 
    230   for (EstimatorMap::iterator it = estimators_.begin();
    231        it != estimators_.end(); ++it) {
    232     delete it->second;
    233   }
    234 }
    235 
    236 void BweTest::SetupTestFromConfig(const BweTestConfig& config) {
    237   const ::testing::TestInfo* const test_info =
    238       ::testing::UnitTest::GetInstance()->current_test_info();
    239   string test_name =
    240       string(test_info->test_case_name()) + "_" + string(test_info->name());
    241   BWE_TEST_LOGGING_GLOBAL_CONTEXT(test_name);
    242   for (vector<BweTestConfig::EstimatorConfig>::const_iterator it =
    243        config.estimator_configs.begin(); it != config.estimator_configs.end();
    244        ++it) {
    245     estimators_.insert(std::make_pair(it->flow_id, new TestedEstimator(
    246         test_name, *it)));
    247   }
    248   BWE_TEST_LOGGING_GLOBAL_ENABLE(false);
    249 }
    250 
    251 void BweTest::AddPacketProcessor(PacketProcessor* processor, bool is_sender) {
    252   assert(processor);
    253   processors_.push_back(PacketProcessorRunner(processor));
    254   if (is_sender) {
    255     senders_.push_back(static_cast<PacketSender*>(processor));
    256   }
    257   const FlowIds& flow_ids = processor->flow_ids();
    258   for (size_t i = 0; i < flow_ids.size(); ++i) {
    259     assert(estimators_.count(flow_ids[i]) == 1);
    260   }
    261 }
    262 
    263 void BweTest::RemovePacketProcessor(
    264     PacketProcessor* processor) {
    265   for (vector<PacketProcessorRunner>::iterator it = processors_.begin();
    266        it != processors_.end(); ++it) {
    267     if (it->HasProcessor(processor)) {
    268       processors_.erase(it);
    269       return;
    270     }
    271   }
    272   assert(false);
    273 }
    274 
    275 void BweTest::VerboseLogging(bool enable) {
    276   BWE_TEST_LOGGING_GLOBAL_ENABLE(enable);
    277 }
    278 
    279 void BweTest::GiveFeedbackToAffectedSenders(int flow_id,
    280                                             TestedEstimator* estimator) {
    281   std::list<PacketSender*> affected_senders;
    282   for (std::vector<PacketSender*>::iterator psit =
    283        senders_.begin(); psit != senders_.end(); ++psit) {
    284     const FlowIds& flow_ids = (*psit)->flow_ids();
    285     if (std::binary_search(flow_ids.begin(), flow_ids.end(), flow_id)) {
    286       affected_senders.push_back(*psit);
    287     }
    288   }
    289   PacketSender::Feedback feedback = {0};
    290   if (estimator->CheckEstimate(&feedback) && !affected_senders.empty()) {
    291     // Allocate the bitrate evenly between the senders.
    292     feedback.estimated_bps /= affected_senders.size();
    293     for (std::list<PacketSender*>::iterator psit = affected_senders.begin();
    294         psit != affected_senders.end(); ++psit) {
    295       (*psit)->GiveFeedback(feedback);
    296     }
    297   }
    298 }
    299 
    300 void BweTest::RunFor(int64_t time_ms) {
    301   // Set simulation interval from first packet sender.
    302   // TODO(holmer): Support different feedback intervals for different flows.
    303   if (!senders_.empty()) {
    304     simulation_interval_ms_ = senders_[0]->GetFeedbackIntervalMs();
    305   }
    306   assert(simulation_interval_ms_ > 0);
    307   if (time_now_ms_ == -1) {
    308     time_now_ms_ = simulation_interval_ms_;
    309   }
    310   for (run_time_ms_ += time_ms;
    311        time_now_ms_ <= run_time_ms_ - simulation_interval_ms_;
    312        time_now_ms_ += simulation_interval_ms_) {
    313     Packets packets;
    314     for (vector<PacketProcessorRunner>::iterator it =
    315          processors_.begin(); it != processors_.end(); ++it) {
    316       it->RunFor(simulation_interval_ms_, time_now_ms_, &packets);
    317     }
    318 
    319     // Verify packets are in order between batches.
    320     if (!packets.empty()) {
    321       if (!previous_packets_.empty()) {
    322         packets.splice(packets.begin(), previous_packets_,
    323                        --previous_packets_.end());
    324         ASSERT_TRUE(IsTimeSorted(packets));
    325         packets.erase(packets.begin());
    326       }
    327       ASSERT_LE(packets.front().send_time_us(), time_now_ms_ * 1000);
    328       ASSERT_LE(packets.back().send_time_us(), time_now_ms_ * 1000);
    329     } else {
    330       ASSERT_TRUE(IsTimeSorted(packets));
    331     }
    332 
    333     for (PacketsConstIt it = packets.begin(); it != packets.end(); ++it) {
    334       EstimatorMap::iterator est_it = estimators_.find(it->flow_id());
    335       ASSERT_TRUE(est_it != estimators_.end());
    336       est_it->second->EatPacket(*it);
    337     }
    338 
    339     for (EstimatorMap::iterator est_it = estimators_.begin();
    340          est_it != estimators_.end(); ++est_it) {
    341       GiveFeedbackToAffectedSenders(est_it->first, est_it->second);
    342     }
    343   }
    344 }
    345 
    346 string BweTest::GetTestName() const {
    347   const ::testing::TestInfo* const test_info =
    348       ::testing::UnitTest::GetInstance()->current_test_info();
    349   return string(test_info->name());
    350 }
    351 }  // namespace bwe
    352 }  // namespace testing
    353 }  // namespace webrtc
    354