Home | History | Annotate | Download | only in test
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 //
      5 // This program benchmarks the theoretical throughput of the cast library.
      6 // It runs using a fake clock, simulated network and fake codecs. This allows
      7 // tests to run much faster than real time.
      8 // To run the program, run:
      9 // $ ./out/Release/cast_benchmarks | tee benchmarkoutput.asc
     10 // This may take a while, when it is done, you can view the data with
     11 // meshlab by running:
     12 // $ meshlab benchmarkoutput.asc
     13 // After starting meshlab, turn on Render->Show Axis. The red axis will
     14 // represent bandwidth (in megabits) the blue axis will be packet drop
     15 // (in percent) and the green axis will be latency (in milliseconds).
     16 //
     17 // This program can also be used for profiling. On linux it has
     18 // built-in support for this. Simply set the environment variable
     19 // PROFILE_FILE before running it, like so:
     20 // $ export PROFILE_FILE=cast_benchmark.profile
     21 // Then after running the program, you can view the profile with:
     22 // $ pprof ./out/Release/cast_benchmarks $PROFILE_FILE --gv
     23 
     24 #include <math.h>
     25 #include <stdint.h>
     26 
     27 #include <map>
     28 #include <vector>
     29 
     30 #include "base/at_exit.h"
     31 #include "base/bind.h"
     32 #include "base/bind_helpers.h"
     33 #include "base/command_line.h"
     34 #include "base/debug/profiler.h"
     35 #include "base/stl_util.h"
     36 #include "base/strings/string_number_conversions.h"
     37 #include "base/strings/stringprintf.h"
     38 #include "base/test/simple_test_tick_clock.h"
     39 #include "base/threading/thread.h"
     40 #include "base/time/tick_clock.h"
     41 #include "media/base/audio_bus.h"
     42 #include "media/base/video_frame.h"
     43 #include "media/cast/cast_config.h"
     44 #include "media/cast/cast_environment.h"
     45 #include "media/cast/cast_receiver.h"
     46 #include "media/cast/cast_sender.h"
     47 #include "media/cast/logging/simple_event_subscriber.h"
     48 #include "media/cast/net/cast_transport_config.h"
     49 #include "media/cast/net/cast_transport_defines.h"
     50 #include "media/cast/net/cast_transport_sender.h"
     51 #include "media/cast/net/cast_transport_sender_impl.h"
     52 #include "media/cast/test/fake_single_thread_task_runner.h"
     53 #include "media/cast/test/loopback_transport.h"
     54 #include "media/cast/test/skewed_single_thread_task_runner.h"
     55 #include "media/cast/test/skewed_tick_clock.h"
     56 #include "media/cast/test/utility/audio_utility.h"
     57 #include "media/cast/test/utility/default_config.h"
     58 #include "media/cast/test/utility/test_util.h"
     59 #include "media/cast/test/utility/udp_proxy.h"
     60 #include "media/cast/test/utility/video_utility.h"
     61 #include "testing/gtest/include/gtest/gtest.h"
     62 
     63 namespace media {
     64 namespace cast {
     65 
     66 namespace {
     67 
     68 static const int64 kStartMillisecond = INT64_C(1245);
     69 static const int kAudioChannels = 2;
     70 static const int kVideoHdWidth = 1280;
     71 static const int kVideoHdHeight = 720;
     72 static const int kTargetPlayoutDelayMs = 300;
     73 
     74 // The tests are commonly implemented with |kFrameTimerMs| RunTask function;
     75 // a normal video is 30 fps hence the 33 ms between frames.
     76 static const int kFrameTimerMs = 33;
     77 
     78 void UpdateCastTransportStatus(CastTransportStatus status) {
     79   bool result = (status == TRANSPORT_AUDIO_INITIALIZED ||
     80                  status == TRANSPORT_VIDEO_INITIALIZED);
     81   EXPECT_TRUE(result);
     82 }
     83 
     84 void AudioInitializationStatus(CastInitializationStatus status) {
     85   EXPECT_EQ(STATUS_AUDIO_INITIALIZED, status);
     86 }
     87 
     88 void VideoInitializationStatus(CastInitializationStatus status) {
     89   EXPECT_EQ(STATUS_VIDEO_INITIALIZED, status);
     90 }
     91 
     92 void IgnoreRawEvents(const std::vector<PacketEvent>& packet_events,
     93                      const std::vector<FrameEvent>& frame_events) {
     94 }
     95 
     96 }  // namespace
     97 
     98 // Wraps a CastTransportSender and records some statistics about
     99 // the data that goes through it.
    100 class CastTransportSenderWrapper : public CastTransportSender {
    101  public:
    102   // Takes ownership of |transport|.
    103   void Init(CastTransportSender* transport,
    104             uint64* encoded_video_bytes,
    105             uint64* encoded_audio_bytes) {
    106     transport_.reset(transport);
    107     encoded_video_bytes_ = encoded_video_bytes;
    108     encoded_audio_bytes_ = encoded_audio_bytes;
    109   }
    110 
    111   virtual void InitializeAudio(
    112       const CastTransportRtpConfig& config,
    113       const RtcpCastMessageCallback& cast_message_cb,
    114       const RtcpRttCallback& rtt_cb) OVERRIDE {
    115     audio_ssrc_ = config.ssrc;
    116     transport_->InitializeAudio(config, cast_message_cb, rtt_cb);
    117   }
    118 
    119   virtual void InitializeVideo(
    120       const CastTransportRtpConfig& config,
    121       const RtcpCastMessageCallback& cast_message_cb,
    122       const RtcpRttCallback& rtt_cb) OVERRIDE {
    123     video_ssrc_ = config.ssrc;
    124     transport_->InitializeVideo(config, cast_message_cb, rtt_cb);
    125   }
    126 
    127   virtual void InsertFrame(uint32 ssrc,
    128                            const EncodedFrame& frame) OVERRIDE {
    129     if (ssrc == audio_ssrc_) {
    130       *encoded_audio_bytes_ += frame.data.size();
    131     } else if (ssrc == video_ssrc_) {
    132       *encoded_video_bytes_ += frame.data.size();
    133     }
    134     transport_->InsertFrame(ssrc, frame);
    135   }
    136 
    137   virtual void SendSenderReport(
    138       uint32 ssrc,
    139       base::TimeTicks current_time,
    140       uint32 current_time_as_rtp_timestamp) OVERRIDE {
    141     transport_->SendSenderReport(ssrc,
    142                                  current_time,
    143                                  current_time_as_rtp_timestamp);
    144   }
    145 
    146   virtual void CancelSendingFrames(
    147       uint32 ssrc,
    148       const std::vector<uint32>& frame_ids) OVERRIDE {
    149     transport_->CancelSendingFrames(ssrc, frame_ids);
    150   }
    151 
    152   virtual void ResendFrameForKickstart(uint32 ssrc,
    153                                        uint32 frame_id) OVERRIDE {
    154     transport_->ResendFrameForKickstart(ssrc, frame_id);
    155   }
    156 
    157   virtual PacketReceiverCallback PacketReceiverForTesting() OVERRIDE {
    158     return transport_->PacketReceiverForTesting();
    159   }
    160 
    161  private:
    162   scoped_ptr<CastTransportSender> transport_;
    163   uint32 audio_ssrc_, video_ssrc_;
    164   uint64* encoded_video_bytes_;
    165   uint64* encoded_audio_bytes_;
    166 };
    167 
    168 struct MeasuringPoint {
    169   MeasuringPoint(double bitrate_, double latency_, double percent_packet_drop_)
    170       : bitrate(bitrate_),
    171         latency(latency_),
    172         percent_packet_drop(percent_packet_drop_) {}
    173   bool operator<=(const MeasuringPoint& other) const {
    174     return bitrate >= other.bitrate && latency <= other.latency &&
    175            percent_packet_drop <= other.percent_packet_drop;
    176   }
    177   bool operator>=(const MeasuringPoint& other) const {
    178     return bitrate <= other.bitrate && latency >= other.latency &&
    179            percent_packet_drop >= other.percent_packet_drop;
    180   }
    181 
    182   std::string AsString() const {
    183     return base::StringPrintf(
    184         "%f Mbit/s %f ms %f %% ", bitrate, latency, percent_packet_drop);
    185   }
    186 
    187   double bitrate;
    188   double latency;
    189   double percent_packet_drop;
    190 };
    191 
    192 class RunOneBenchmark {
    193  public:
    194   RunOneBenchmark()
    195       : start_time_(),
    196         task_runner_(new test::FakeSingleThreadTaskRunner(&testing_clock_)),
    197         testing_clock_sender_(new test::SkewedTickClock(&testing_clock_)),
    198         task_runner_sender_(
    199             new test::SkewedSingleThreadTaskRunner(task_runner_)),
    200         testing_clock_receiver_(new test::SkewedTickClock(&testing_clock_)),
    201         task_runner_receiver_(
    202             new test::SkewedSingleThreadTaskRunner(task_runner_)),
    203         cast_environment_sender_(new CastEnvironment(
    204             scoped_ptr<base::TickClock>(testing_clock_sender_).Pass(),
    205             task_runner_sender_,
    206             task_runner_sender_,
    207             task_runner_sender_)),
    208         cast_environment_receiver_(new CastEnvironment(
    209             scoped_ptr<base::TickClock>(testing_clock_receiver_).Pass(),
    210             task_runner_receiver_,
    211             task_runner_receiver_,
    212             task_runner_receiver_)),
    213         receiver_to_sender_(cast_environment_receiver_),
    214         sender_to_receiver_(cast_environment_sender_),
    215         video_bytes_encoded_(0),
    216         audio_bytes_encoded_(0),
    217         frames_sent_(0) {
    218     testing_clock_.Advance(
    219         base::TimeDelta::FromMilliseconds(kStartMillisecond));
    220   }
    221 
    222   void Configure(Codec video_codec,
    223                  Codec audio_codec,
    224                  int audio_sampling_frequency,
    225                  int max_number_of_video_buffers_used) {
    226     audio_sender_config_.ssrc = 1;
    227     audio_sender_config_.incoming_feedback_ssrc = 2;
    228     audio_sender_config_.max_playout_delay =
    229         base::TimeDelta::FromMilliseconds(kTargetPlayoutDelayMs);
    230     audio_sender_config_.rtp_payload_type = 96;
    231     audio_sender_config_.use_external_encoder = false;
    232     audio_sender_config_.frequency = audio_sampling_frequency;
    233     audio_sender_config_.channels = kAudioChannels;
    234     audio_sender_config_.bitrate = kDefaultAudioEncoderBitrate;
    235     audio_sender_config_.codec = audio_codec;
    236 
    237     audio_receiver_config_.feedback_ssrc =
    238         audio_sender_config_.incoming_feedback_ssrc;
    239     audio_receiver_config_.incoming_ssrc = audio_sender_config_.ssrc;
    240     audio_receiver_config_.rtp_payload_type =
    241         audio_sender_config_.rtp_payload_type;
    242     audio_receiver_config_.frequency = audio_sender_config_.frequency;
    243     audio_receiver_config_.channels = kAudioChannels;
    244     audio_receiver_config_.max_frame_rate = 100;
    245     audio_receiver_config_.codec = audio_sender_config_.codec;
    246     audio_receiver_config_.rtp_max_delay_ms = kTargetPlayoutDelayMs;
    247 
    248     video_sender_config_.ssrc = 3;
    249     video_sender_config_.incoming_feedback_ssrc = 4;
    250     video_sender_config_.max_playout_delay =
    251         base::TimeDelta::FromMilliseconds(kTargetPlayoutDelayMs);
    252     video_sender_config_.rtp_payload_type = 97;
    253     video_sender_config_.use_external_encoder = false;
    254     video_sender_config_.width = kVideoHdWidth;
    255     video_sender_config_.height = kVideoHdHeight;
    256 #if 0
    257     video_sender_config_.max_bitrate = 10000000;  // 10Mbit max
    258     video_sender_config_.min_bitrate = 1000000;   // 1Mbit min
    259     video_sender_config_.start_bitrate = 1000000; // 1Mbit start
    260 #else
    261     video_sender_config_.max_bitrate = 4000000;  // 4Mbit all the time
    262     video_sender_config_.min_bitrate = 4000000;
    263     video_sender_config_.start_bitrate = 4000000;
    264 #endif
    265     video_sender_config_.max_qp = 56;
    266     video_sender_config_.min_qp = 4;
    267     video_sender_config_.max_frame_rate = 30;
    268     video_sender_config_.max_number_of_video_buffers_used =
    269         max_number_of_video_buffers_used;
    270     video_sender_config_.codec = video_codec;
    271 
    272     video_receiver_config_.feedback_ssrc =
    273         video_sender_config_.incoming_feedback_ssrc;
    274     video_receiver_config_.incoming_ssrc = video_sender_config_.ssrc;
    275     video_receiver_config_.rtp_payload_type =
    276         video_sender_config_.rtp_payload_type;
    277     video_receiver_config_.codec = video_sender_config_.codec;
    278     video_receiver_config_.frequency = kVideoFrequency;
    279     video_receiver_config_.channels = 1;
    280     video_receiver_config_.max_frame_rate = 100;
    281     video_receiver_config_.rtp_max_delay_ms = kTargetPlayoutDelayMs;
    282   }
    283 
    284   void SetSenderClockSkew(double skew, base::TimeDelta offset) {
    285     testing_clock_sender_->SetSkew(skew, offset);
    286     task_runner_sender_->SetSkew(1.0 / skew);
    287   }
    288 
    289   void SetReceiverClockSkew(double skew, base::TimeDelta offset) {
    290     testing_clock_receiver_->SetSkew(skew, offset);
    291     task_runner_receiver_->SetSkew(1.0 / skew);
    292   }
    293 
    294   void Create(const MeasuringPoint& p) {
    295     cast_receiver_ = CastReceiver::Create(cast_environment_receiver_,
    296                                           audio_receiver_config_,
    297                                           video_receiver_config_,
    298                                           &receiver_to_sender_);
    299     net::IPEndPoint dummy_endpoint;
    300     transport_sender_.Init(
    301         new CastTransportSenderImpl(
    302             NULL,
    303             testing_clock_sender_,
    304             dummy_endpoint,
    305             make_scoped_ptr(new base::DictionaryValue),
    306             base::Bind(&UpdateCastTransportStatus),
    307             base::Bind(&IgnoreRawEvents),
    308             base::TimeDelta::FromSeconds(1),
    309             task_runner_sender_,
    310             &sender_to_receiver_),
    311         &video_bytes_encoded_,
    312         &audio_bytes_encoded_);
    313 
    314     cast_sender_ =
    315         CastSender::Create(cast_environment_sender_, &transport_sender_);
    316 
    317     // Initializing audio and video senders.
    318     cast_sender_->InitializeAudio(audio_sender_config_,
    319                                   base::Bind(&AudioInitializationStatus));
    320     cast_sender_->InitializeVideo(video_sender_config_,
    321                                   base::Bind(&VideoInitializationStatus),
    322                                   CreateDefaultVideoEncodeAcceleratorCallback(),
    323                                   CreateDefaultVideoEncodeMemoryCallback());
    324 
    325     receiver_to_sender_.Initialize(
    326         CreateSimplePipe(p).Pass(),
    327         transport_sender_.PacketReceiverForTesting(),
    328         task_runner_, &testing_clock_);
    329     sender_to_receiver_.Initialize(
    330         CreateSimplePipe(p).Pass(), cast_receiver_->packet_receiver(),
    331         task_runner_, &testing_clock_);
    332   }
    333 
    334   virtual ~RunOneBenchmark() {
    335     cast_sender_.reset();
    336     cast_receiver_.reset();
    337     task_runner_->RunTasks();
    338   }
    339 
    340   void SendFakeVideoFrame() {
    341     frames_sent_++;
    342     cast_sender_->video_frame_input()->InsertRawVideoFrame(
    343         media::VideoFrame::CreateBlackFrame(gfx::Size(2, 2)),
    344         testing_clock_sender_->NowTicks());
    345   }
    346 
    347   void RunTasks(int ms) {
    348     task_runner_->Sleep(base::TimeDelta::FromMilliseconds(ms));
    349   }
    350 
    351   void BasicPlayerGotVideoFrame(
    352       const scoped_refptr<media::VideoFrame>& video_frame,
    353       const base::TimeTicks& render_time,
    354       bool continuous) {
    355     video_ticks_.push_back(
    356         std::make_pair(testing_clock_receiver_->NowTicks(), render_time));
    357     cast_receiver_->RequestDecodedVideoFrame(base::Bind(
    358         &RunOneBenchmark::BasicPlayerGotVideoFrame, base::Unretained(this)));
    359   }
    360 
    361   void BasicPlayerGotAudioFrame(scoped_ptr<AudioBus> audio_bus,
    362                                 const base::TimeTicks& playout_time,
    363                                 bool is_continuous) {
    364     audio_ticks_.push_back(
    365         std::make_pair(testing_clock_receiver_->NowTicks(), playout_time));
    366     cast_receiver_->RequestDecodedAudioFrame(base::Bind(
    367         &RunOneBenchmark::BasicPlayerGotAudioFrame, base::Unretained(this)));
    368   }
    369 
    370   void StartBasicPlayer() {
    371     cast_receiver_->RequestDecodedVideoFrame(base::Bind(
    372         &RunOneBenchmark::BasicPlayerGotVideoFrame, base::Unretained(this)));
    373     cast_receiver_->RequestDecodedAudioFrame(base::Bind(
    374         &RunOneBenchmark::BasicPlayerGotAudioFrame, base::Unretained(this)));
    375   }
    376 
    377   scoped_ptr<test::PacketPipe> CreateSimplePipe(const MeasuringPoint& p) {
    378     scoped_ptr<test::PacketPipe> pipe = test::NewBuffer(65536, p.bitrate);
    379     pipe->AppendToPipe(
    380         test::NewRandomDrop(p.percent_packet_drop / 100.0).Pass());
    381     pipe->AppendToPipe(test::NewConstantDelay(p.latency / 1000.0));
    382     return pipe.Pass();
    383   }
    384 
    385   void Run(const MeasuringPoint& p) {
    386     available_bitrate_ = p.bitrate;
    387     Configure(
    388         CODEC_VIDEO_FAKE, CODEC_AUDIO_PCM16, 32000, 1);
    389     Create(p);
    390     StartBasicPlayer();
    391 
    392     for (int frame = 0; frame < 1000; frame++) {
    393       SendFakeVideoFrame();
    394       RunTasks(kFrameTimerMs);
    395     }
    396     RunTasks(100 * kFrameTimerMs);  // Empty the pipeline.
    397     VLOG(1) << "=============INPUTS============";
    398     VLOG(1) << "Bitrate: " << p.bitrate << " mbit/s";
    399     VLOG(1) << "Latency: " << p.latency << " ms";
    400     VLOG(1) << "Packet drop drop: " << p.percent_packet_drop << "%";
    401     VLOG(1) << "=============OUTPUTS============";
    402     VLOG(1) << "Frames lost: " << frames_lost();
    403     VLOG(1) << "Late frames: " << late_frames();
    404     VLOG(1) << "Playout margin: " << frame_playout_buffer().AsString();
    405     VLOG(1) << "Video bandwidth used: " << video_bandwidth() << " mbit/s ("
    406             << (video_bandwidth() * 100 / desired_video_bitrate()) << "%)";
    407     VLOG(1) << "Good run: " << SimpleGood();
    408   }
    409 
    410   // Metrics
    411   int frames_lost() const { return frames_sent_ - video_ticks_.size(); }
    412 
    413   int late_frames() const {
    414     int frames = 0;
    415     // Ignore the first two seconds of video or so.
    416     for (size_t i = 60; i < video_ticks_.size(); i++) {
    417       if (video_ticks_[i].first > video_ticks_[i].second) {
    418         frames++;
    419       }
    420     }
    421     return frames;
    422   }
    423 
    424   test::MeanAndError frame_playout_buffer() const {
    425     std::vector<double> values;
    426     for (size_t i = 0; i < video_ticks_.size(); i++) {
    427       values.push_back(
    428           (video_ticks_[i].second - video_ticks_[i].first).InMillisecondsF());
    429     }
    430     return test::MeanAndError(values);
    431   }
    432 
    433   // Mbits per second
    434   double video_bandwidth() const {
    435     double seconds = (kFrameTimerMs * frames_sent_ / 1000.0);
    436     double megabits = video_bytes_encoded_ * 8 / 1000000.0;
    437     return megabits / seconds;
    438   }
    439 
    440   // Mbits per second
    441   double audio_bandwidth() const {
    442     double seconds = (kFrameTimerMs * frames_sent_ / 1000.0);
    443     double megabits = audio_bytes_encoded_ * 8 / 1000000.0;
    444     return megabits / seconds;
    445   }
    446 
    447   double desired_video_bitrate() {
    448     return std::min<double>(available_bitrate_,
    449                             video_sender_config_.max_bitrate / 1000000.0);
    450   }
    451 
    452   bool SimpleGood() {
    453     return frames_lost() <= 1 && late_frames() <= 1 &&
    454            video_bandwidth() > desired_video_bitrate() * 0.8 &&
    455            video_bandwidth() < desired_video_bitrate() * 1.2;
    456   }
    457 
    458  private:
    459   FrameReceiverConfig audio_receiver_config_;
    460   FrameReceiverConfig video_receiver_config_;
    461   AudioSenderConfig audio_sender_config_;
    462   VideoSenderConfig video_sender_config_;
    463 
    464   base::TimeTicks start_time_;
    465 
    466   // These run in "test time"
    467   base::SimpleTestTickClock testing_clock_;
    468   scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
    469 
    470   // These run on the sender timeline.
    471   test::SkewedTickClock* testing_clock_sender_;
    472   scoped_refptr<test::SkewedSingleThreadTaskRunner> task_runner_sender_;
    473 
    474   // These run on the receiver timeline.
    475   test::SkewedTickClock* testing_clock_receiver_;
    476   scoped_refptr<test::SkewedSingleThreadTaskRunner> task_runner_receiver_;
    477 
    478   scoped_refptr<CastEnvironment> cast_environment_sender_;
    479   scoped_refptr<CastEnvironment> cast_environment_receiver_;
    480 
    481   LoopBackTransport receiver_to_sender_;
    482   LoopBackTransport sender_to_receiver_;
    483   CastTransportSenderWrapper transport_sender_;
    484   uint64 video_bytes_encoded_;
    485   uint64 audio_bytes_encoded_;
    486 
    487   scoped_ptr<CastReceiver> cast_receiver_;
    488   scoped_ptr<CastSender> cast_sender_;
    489 
    490   int frames_sent_;
    491   double available_bitrate_;
    492   std::vector<std::pair<base::TimeTicks, base::TimeTicks> > audio_ticks_;
    493   std::vector<std::pair<base::TimeTicks, base::TimeTicks> > video_ticks_;
    494 };
    495 
    496 enum CacheResult { FOUND_TRUE, FOUND_FALSE, NOT_FOUND };
    497 
    498 template <class T>
    499 class BenchmarkCache {
    500  public:
    501   CacheResult Lookup(const T& x) {
    502     base::AutoLock key(lock_);
    503     for (size_t i = 0; i < results_.size(); i++) {
    504       if (results_[i].second) {
    505         if (x <= results_[i].first) {
    506           VLOG(2) << "TRUE because: " << x.AsString()
    507                   << " <= " << results_[i].first.AsString();
    508           return FOUND_TRUE;
    509         }
    510       } else {
    511         if (x >= results_[i].first) {
    512           VLOG(2) << "FALSE because: " << x.AsString()
    513                   << " >= " << results_[i].first.AsString();
    514           return FOUND_FALSE;
    515         }
    516       }
    517     }
    518     return NOT_FOUND;
    519   }
    520 
    521   void Add(const T& x, bool result) {
    522     base::AutoLock key(lock_);
    523     VLOG(2) << "Cache Insert: " << x.AsString() << " = " << result;
    524     results_.push_back(std::make_pair(x, result));
    525   }
    526 
    527  private:
    528   base::Lock lock_;
    529   std::vector<std::pair<T, bool> > results_;
    530 };
    531 
    532 struct SearchVariable {
    533   SearchVariable() : base(0.0), grade(0.0) {}
    534   SearchVariable(double b, double g) : base(b), grade(g) {}
    535   SearchVariable blend(const SearchVariable& other, double factor) {
    536     CHECK_GE(factor, 0);
    537     CHECK_LE(factor, 1.0);
    538     return SearchVariable(base * (1 - factor) + other.base * factor,
    539                           grade * (1 - factor) + other.grade * factor);
    540   }
    541   double value(double x) const { return base + grade * x; }
    542   double base;
    543   double grade;
    544 };
    545 
    546 struct SearchVector {
    547   SearchVector blend(const SearchVector& other, double factor) {
    548     SearchVector ret;
    549     ret.bitrate = bitrate.blend(other.bitrate, factor);
    550     ret.latency = latency.blend(other.latency, factor);
    551     ret.packet_drop = packet_drop.blend(other.packet_drop, factor);
    552     return ret;
    553   }
    554 
    555   SearchVector average(const SearchVector& other) {
    556     return blend(other, 0.5);
    557   }
    558 
    559   MeasuringPoint GetMeasuringPoint(double v) const {
    560     return MeasuringPoint(
    561         bitrate.value(-v), latency.value(v), packet_drop.value(v));
    562   }
    563   std::string AsString(double v) { return GetMeasuringPoint(v).AsString(); }
    564 
    565   SearchVariable bitrate;
    566   SearchVariable latency;
    567   SearchVariable packet_drop;
    568 };
    569 
    570 class CastBenchmark {
    571  public:
    572   bool RunOnePoint(const SearchVector& v, double multiplier) {
    573     MeasuringPoint p = v.GetMeasuringPoint(multiplier);
    574     VLOG(1) << "RUN: v = " << multiplier << " p = " << p.AsString();
    575     if (p.bitrate <= 0) {
    576       return false;
    577     }
    578     switch (cache_.Lookup(p)) {
    579       case FOUND_TRUE:
    580         return true;
    581       case FOUND_FALSE:
    582         return false;
    583       case NOT_FOUND:
    584         // Keep going
    585         break;
    586     }
    587     bool result = true;
    588     for (int tries = 0; tries < 3 && result; tries++) {
    589       RunOneBenchmark benchmark;
    590       benchmark.Run(p);
    591       result &= benchmark.SimpleGood();
    592     }
    593     cache_.Add(p, result);
    594     return result;
    595   }
    596 
    597   void BinarySearch(SearchVector v, double accuracy) {
    598     double min = 0.0;
    599     double max = 1.0;
    600     while (RunOnePoint(v, max)) {
    601       min = max;
    602       max *= 2;
    603     }
    604 
    605     while (max - min > accuracy) {
    606       double avg = (min + max) / 2;
    607       if (RunOnePoint(v, avg)) {
    608         min = avg;
    609       } else {
    610         max = avg;
    611       }
    612     }
    613 
    614     // Print a data point to stdout.
    615     base::AutoLock key(lock_);
    616     MeasuringPoint p = v.GetMeasuringPoint(min);
    617     fprintf(stdout, "%f %f %f\n", p.bitrate, p.latency, p.percent_packet_drop);
    618     fflush(stdout);
    619   }
    620 
    621   void SpanningSearch(int max,
    622                       int x,
    623                       int y,
    624                       int skip,
    625                       SearchVector a,
    626                       SearchVector b,
    627                       SearchVector c,
    628                       double accuracy,
    629                       std::vector<linked_ptr<base::Thread> >* threads) {
    630     static int thread_num = 0;
    631     if (x > max) return;
    632     if (skip > max) {
    633       if (y > x) return;
    634       SearchVector ab = a.blend(b, static_cast<double>(x) / max);
    635       SearchVector ac = a.blend(c, static_cast<double>(x) / max);
    636       SearchVector v = ab.blend(ac, x == y ? 1.0 : static_cast<double>(y) / x);
    637       thread_num++;
    638       (*threads)[thread_num % threads->size()]->message_loop()->PostTask(
    639           FROM_HERE,
    640           base::Bind(&CastBenchmark::BinarySearch,
    641                      base::Unretained(this),
    642                      v,
    643                      accuracy));
    644     } else {
    645       skip *= 2;
    646       SpanningSearch(max, x, y, skip, a, b, c, accuracy, threads);
    647       SpanningSearch(max, x + skip, y + skip, skip, a, b, c, accuracy, threads);
    648       SpanningSearch(max, x + skip, y, skip, a, b, c, accuracy, threads);
    649       SpanningSearch(max, x, y + skip, skip, a, b, c, accuracy, threads);
    650     }
    651   }
    652 
    653   void Run() {
    654     // Spanning search.
    655 
    656     std::vector<linked_ptr<base::Thread> > threads;
    657     for (int i = 0; i < 16; i++) {
    658       threads.push_back(make_linked_ptr(new base::Thread(
    659           base::StringPrintf("cast_bench_thread_%d", i))));
    660       threads[i]->Start();
    661     }
    662 
    663     if (CommandLine::ForCurrentProcess()->HasSwitch("single-run")) {
    664       SearchVector a;
    665       a.bitrate.base = 100.0;
    666       a.bitrate.grade = 1.0;
    667       a.latency.grade = 1.0;
    668       a.packet_drop.grade = 1.0;
    669       threads[0]->message_loop()->PostTask(
    670           FROM_HERE,
    671           base::Bind(base::IgnoreResult(&CastBenchmark::RunOnePoint),
    672                      base::Unretained(this),
    673                      a,
    674                      1.0));
    675     } else {
    676       SearchVector a, b, c;
    677       a.bitrate.base = b.bitrate.base = c.bitrate.base = 100.0;
    678       a.bitrate.grade = 1.0;
    679       b.latency.grade = 1.0;
    680       c.packet_drop.grade = 1.0;
    681 
    682       SpanningSearch(512,
    683                      0,
    684                      0,
    685                      1,
    686                      a,
    687                      b,
    688                      c,
    689                      0.01,
    690                      &threads);
    691     }
    692 
    693     for (size_t i = 0; i < threads.size(); i++) {
    694       threads[i]->Stop();
    695     }
    696   }
    697 
    698  private:
    699   BenchmarkCache<MeasuringPoint> cache_;
    700   base::Lock lock_;
    701 };
    702 
    703 }  // namespace cast
    704 }  // namespace media
    705 
    706 int main(int argc, char** argv) {
    707   base::AtExitManager at_exit;
    708   CommandLine::Init(argc, argv);
    709   media::cast::CastBenchmark benchmark;
    710   if (getenv("PROFILE_FILE")) {
    711     std::string profile_file(getenv("PROFILE_FILE"));
    712     base::debug::StartProfiling(profile_file);
    713     benchmark.Run();
    714     base::debug::StopProfiling();
    715   } else {
    716     benchmark.Run();
    717   }
    718 }
    719