Revert "Omit calls to set composing region when pasting image."
[chromium-blink-merge.git] / media / cast / test / cast_benchmarks.cc
blobbea587e2fe173c7eefb9a966c35fada2889c8a83
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).
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
24 #include <math.h>
25 #include <stdint.h>
27 #include <map>
28 #include <vector>
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/memory/weak_ptr.h"
36 #include "base/run_loop.h"
37 #include "base/stl_util.h"
38 #include "base/strings/string_number_conversions.h"
39 #include "base/strings/stringprintf.h"
40 #include "base/test/simple_test_tick_clock.h"
41 #include "base/threading/thread.h"
42 #include "base/time/tick_clock.h"
43 #include "media/base/audio_bus.h"
44 #include "media/base/video_frame.h"
45 #include "media/cast/cast_config.h"
46 #include "media/cast/cast_environment.h"
47 #include "media/cast/cast_receiver.h"
48 #include "media/cast/cast_sender.h"
49 #include "media/cast/logging/simple_event_subscriber.h"
50 #include "media/cast/net/cast_transport_config.h"
51 #include "media/cast/net/cast_transport_defines.h"
52 #include "media/cast/net/cast_transport_sender.h"
53 #include "media/cast/net/cast_transport_sender_impl.h"
54 #include "media/cast/test/fake_single_thread_task_runner.h"
55 #include "media/cast/test/loopback_transport.h"
56 #include "media/cast/test/skewed_single_thread_task_runner.h"
57 #include "media/cast/test/skewed_tick_clock.h"
58 #include "media/cast/test/utility/audio_utility.h"
59 #include "media/cast/test/utility/default_config.h"
60 #include "media/cast/test/utility/test_util.h"
61 #include "media/cast/test/utility/udp_proxy.h"
62 #include "media/cast/test/utility/video_utility.h"
63 #include "testing/gtest/include/gtest/gtest.h"
65 namespace media {
66 namespace cast {
68 namespace {
70 static const int64 kStartMillisecond = INT64_C(1245);
71 static const int kTargetPlayoutDelayMs = 400;
73 void UpdateCastTransportStatus(CastTransportStatus status) {
74 bool result = (status == TRANSPORT_AUDIO_INITIALIZED ||
75 status == TRANSPORT_VIDEO_INITIALIZED);
76 EXPECT_TRUE(result);
79 void ExpectVideoSuccess(OperationalStatus status) {
80 EXPECT_EQ(STATUS_INITIALIZED, status);
83 void ExpectAudioSuccess(OperationalStatus status) {
84 EXPECT_EQ(STATUS_INITIALIZED, status);
87 void IgnoreRawEvents(const std::vector<PacketEvent>& packet_events,
88 const std::vector<FrameEvent>& frame_events) {
91 } // namespace
93 // Wraps a CastTransportSender and records some statistics about
94 // the data that goes through it.
95 class CastTransportSenderWrapper : public CastTransportSender {
96 public:
97 // Takes ownership of |transport|.
98 void Init(CastTransportSender* transport,
99 uint64* encoded_video_bytes,
100 uint64* encoded_audio_bytes) {
101 transport_.reset(transport);
102 encoded_video_bytes_ = encoded_video_bytes;
103 encoded_audio_bytes_ = encoded_audio_bytes;
106 void InitializeAudio(const CastTransportRtpConfig& config,
107 const RtcpCastMessageCallback& cast_message_cb,
108 const RtcpRttCallback& rtt_cb) final {
109 audio_ssrc_ = config.ssrc;
110 transport_->InitializeAudio(config, cast_message_cb, rtt_cb);
113 void InitializeVideo(const CastTransportRtpConfig& config,
114 const RtcpCastMessageCallback& cast_message_cb,
115 const RtcpRttCallback& rtt_cb) final {
116 video_ssrc_ = config.ssrc;
117 transport_->InitializeVideo(config, cast_message_cb, rtt_cb);
120 void InsertFrame(uint32 ssrc, const EncodedFrame& frame) final {
121 if (ssrc == audio_ssrc_) {
122 *encoded_audio_bytes_ += frame.data.size();
123 } else if (ssrc == video_ssrc_) {
124 *encoded_video_bytes_ += frame.data.size();
126 transport_->InsertFrame(ssrc, frame);
129 void SendSenderReport(uint32 ssrc,
130 base::TimeTicks current_time,
131 uint32 current_time_as_rtp_timestamp) final {
132 transport_->SendSenderReport(ssrc,
133 current_time,
134 current_time_as_rtp_timestamp);
137 void CancelSendingFrames(uint32 ssrc,
138 const std::vector<uint32>& frame_ids) final {
139 transport_->CancelSendingFrames(ssrc, frame_ids);
142 void ResendFrameForKickstart(uint32 ssrc, uint32 frame_id) final {
143 transport_->ResendFrameForKickstart(ssrc, frame_id);
146 PacketReceiverCallback PacketReceiverForTesting() final {
147 return transport_->PacketReceiverForTesting();
150 void AddValidSsrc(uint32 ssrc) final {
151 return transport_->AddValidSsrc(ssrc);
154 void SendRtcpFromRtpReceiver(
155 uint32 ssrc,
156 uint32 sender_ssrc,
157 const RtcpTimeData& time_data,
158 const RtcpCastMessage* cast_message,
159 base::TimeDelta target_delay,
160 const ReceiverRtcpEventSubscriber::RtcpEvents* rtcp_events,
161 const RtpReceiverStatistics* rtp_receiver_statistics) final {
162 return transport_->SendRtcpFromRtpReceiver(ssrc,
163 sender_ssrc,
164 time_data,
165 cast_message,
166 target_delay,
167 rtcp_events,
168 rtp_receiver_statistics);
171 private:
172 scoped_ptr<CastTransportSender> transport_;
173 uint32 audio_ssrc_, video_ssrc_;
174 uint64* encoded_video_bytes_;
175 uint64* encoded_audio_bytes_;
178 struct MeasuringPoint {
179 MeasuringPoint(double bitrate_, double latency_, double percent_packet_drop_)
180 : bitrate(bitrate_),
181 latency(latency_),
182 percent_packet_drop(percent_packet_drop_) {}
183 bool operator<=(const MeasuringPoint& other) const {
184 return bitrate >= other.bitrate && latency <= other.latency &&
185 percent_packet_drop <= other.percent_packet_drop;
187 bool operator>=(const MeasuringPoint& other) const {
188 return bitrate <= other.bitrate && latency >= other.latency &&
189 percent_packet_drop >= other.percent_packet_drop;
192 std::string AsString() const {
193 return base::StringPrintf(
194 "%f Mbit/s %f ms %f %% ", bitrate, latency, percent_packet_drop);
197 double bitrate;
198 double latency;
199 double percent_packet_drop;
202 class RunOneBenchmark {
203 public:
204 RunOneBenchmark()
205 : start_time_(),
206 task_runner_(new test::FakeSingleThreadTaskRunner(&testing_clock_)),
207 testing_clock_sender_(new test::SkewedTickClock(&testing_clock_)),
208 task_runner_sender_(
209 new test::SkewedSingleThreadTaskRunner(task_runner_)),
210 testing_clock_receiver_(new test::SkewedTickClock(&testing_clock_)),
211 task_runner_receiver_(
212 new test::SkewedSingleThreadTaskRunner(task_runner_)),
213 cast_environment_sender_(new CastEnvironment(
214 scoped_ptr<base::TickClock>(testing_clock_sender_).Pass(),
215 task_runner_sender_,
216 task_runner_sender_,
217 task_runner_sender_)),
218 cast_environment_receiver_(new CastEnvironment(
219 scoped_ptr<base::TickClock>(testing_clock_receiver_).Pass(),
220 task_runner_receiver_,
221 task_runner_receiver_,
222 task_runner_receiver_)),
223 receiver_to_sender_(cast_environment_receiver_),
224 sender_to_receiver_(cast_environment_sender_),
225 video_bytes_encoded_(0),
226 audio_bytes_encoded_(0),
227 frames_sent_(0) {
228 testing_clock_.Advance(
229 base::TimeDelta::FromMilliseconds(kStartMillisecond));
232 void Configure(Codec video_codec,
233 Codec audio_codec) {
234 audio_sender_config_ = GetDefaultAudioSenderConfig();
235 audio_sender_config_.min_playout_delay =
236 audio_sender_config_.max_playout_delay =
237 base::TimeDelta::FromMilliseconds(kTargetPlayoutDelayMs);
238 audio_sender_config_.codec = audio_codec;
240 audio_receiver_config_ = GetDefaultAudioReceiverConfig();
241 audio_receiver_config_.rtp_max_delay_ms =
242 audio_sender_config_.max_playout_delay.InMicroseconds();
243 audio_receiver_config_.codec = audio_codec;
245 video_sender_config_ = GetDefaultVideoSenderConfig();
246 video_sender_config_.min_playout_delay =
247 video_sender_config_.max_playout_delay =
248 base::TimeDelta::FromMilliseconds(kTargetPlayoutDelayMs);
249 video_sender_config_.max_bitrate = 4000000;
250 video_sender_config_.min_bitrate = 4000000;
251 video_sender_config_.start_bitrate = 4000000;
252 video_sender_config_.codec = video_codec;
254 video_receiver_config_ = GetDefaultVideoReceiverConfig();
255 video_receiver_config_.rtp_max_delay_ms = kTargetPlayoutDelayMs;
256 video_receiver_config_.codec = video_codec;
258 frame_duration_ = base::TimeDelta::FromSeconds(1) /
259 video_sender_config_.max_frame_rate;
262 void SetSenderClockSkew(double skew, base::TimeDelta offset) {
263 testing_clock_sender_->SetSkew(skew, offset);
264 task_runner_sender_->SetSkew(1.0 / skew);
267 void SetReceiverClockSkew(double skew, base::TimeDelta offset) {
268 testing_clock_receiver_->SetSkew(skew, offset);
269 task_runner_receiver_->SetSkew(1.0 / skew);
272 void Create(const MeasuringPoint& p) {
273 net::IPEndPoint dummy_endpoint;
274 transport_sender_.Init(
275 new CastTransportSenderImpl(
276 NULL,
277 testing_clock_sender_,
278 dummy_endpoint,
279 dummy_endpoint,
280 make_scoped_ptr(new base::DictionaryValue),
281 base::Bind(&UpdateCastTransportStatus),
282 base::Bind(&IgnoreRawEvents),
283 base::TimeDelta::FromSeconds(1),
284 task_runner_sender_,
285 PacketReceiverCallback(),
286 &sender_to_receiver_),
287 &video_bytes_encoded_,
288 &audio_bytes_encoded_);
290 transport_receiver_.reset(
291 new CastTransportSenderImpl(
292 NULL,
293 testing_clock_receiver_,
294 dummy_endpoint,
295 dummy_endpoint,
296 make_scoped_ptr(new base::DictionaryValue),
297 base::Bind(&UpdateCastTransportStatus),
298 base::Bind(&IgnoreRawEvents),
299 base::TimeDelta::FromSeconds(1),
300 task_runner_receiver_,
301 base::Bind(&RunOneBenchmark::ReceivePacket, base::Unretained(this)),
302 &receiver_to_sender_));
304 cast_receiver_ = CastReceiver::Create(cast_environment_receiver_,
305 audio_receiver_config_,
306 video_receiver_config_,
307 transport_receiver_.get());
309 cast_sender_ =
310 CastSender::Create(cast_environment_sender_, &transport_sender_);
312 cast_sender_->InitializeAudio(
313 audio_sender_config_,
314 base::Bind(&ExpectAudioSuccess));
315 cast_sender_->InitializeVideo(
316 video_sender_config_,
317 base::Bind(&ExpectVideoSuccess),
318 CreateDefaultVideoEncodeAcceleratorCallback(),
319 CreateDefaultVideoEncodeMemoryCallback());
321 receiver_to_sender_.Initialize(
322 CreateSimplePipe(p).Pass(),
323 transport_sender_.PacketReceiverForTesting(),
324 task_runner_, &testing_clock_);
325 sender_to_receiver_.Initialize(
326 CreateSimplePipe(p).Pass(),
327 transport_receiver_->PacketReceiverForTesting(),
328 task_runner_, &testing_clock_);
330 task_runner_->RunTasks();
333 void ReceivePacket(scoped_ptr<Packet> packet) {
334 cast_receiver_->ReceivePacket(packet.Pass());
337 virtual ~RunOneBenchmark() {
338 cast_sender_.reset();
339 cast_receiver_.reset();
340 task_runner_->RunTasks();
343 base::TimeDelta VideoTimestamp(int frame_number) {
344 return (frame_number * base::TimeDelta::FromSeconds(1)) /
345 video_sender_config_.max_frame_rate;
348 void SendFakeVideoFrame() {
349 // NB: Blackframe with timestamp
350 cast_sender_->video_frame_input()->InsertRawVideoFrame(
351 media::VideoFrame::CreateColorFrame(gfx::Size(2, 2),
352 0x00, 0x80, 0x80, VideoTimestamp(frames_sent_)),
353 testing_clock_sender_->NowTicks());
354 frames_sent_++;
357 void RunTasks(base::TimeDelta duration) {
358 task_runner_->Sleep(duration);
361 void BasicPlayerGotVideoFrame(
362 const scoped_refptr<media::VideoFrame>& video_frame,
363 const base::TimeTicks& render_time,
364 bool continuous) {
365 video_ticks_.push_back(
366 std::make_pair(testing_clock_receiver_->NowTicks(), render_time));
367 cast_receiver_->RequestDecodedVideoFrame(base::Bind(
368 &RunOneBenchmark::BasicPlayerGotVideoFrame, base::Unretained(this)));
371 void BasicPlayerGotAudioFrame(scoped_ptr<AudioBus> audio_bus,
372 const base::TimeTicks& playout_time,
373 bool is_continuous) {
374 audio_ticks_.push_back(
375 std::make_pair(testing_clock_receiver_->NowTicks(), playout_time));
376 cast_receiver_->RequestDecodedAudioFrame(base::Bind(
377 &RunOneBenchmark::BasicPlayerGotAudioFrame, base::Unretained(this)));
380 void StartBasicPlayer() {
381 cast_receiver_->RequestDecodedVideoFrame(base::Bind(
382 &RunOneBenchmark::BasicPlayerGotVideoFrame, base::Unretained(this)));
383 cast_receiver_->RequestDecodedAudioFrame(base::Bind(
384 &RunOneBenchmark::BasicPlayerGotAudioFrame, base::Unretained(this)));
387 scoped_ptr<test::PacketPipe> CreateSimplePipe(const MeasuringPoint& p) {
388 scoped_ptr<test::PacketPipe> pipe = test::NewBuffer(65536, p.bitrate);
389 pipe->AppendToPipe(
390 test::NewRandomDrop(p.percent_packet_drop / 100.0).Pass());
391 pipe->AppendToPipe(test::NewConstantDelay(p.latency / 1000.0));
392 return pipe.Pass();
395 void Run(const MeasuringPoint& p) {
396 available_bitrate_ = p.bitrate;
397 Configure(CODEC_VIDEO_FAKE, CODEC_AUDIO_PCM16);
398 Create(p);
399 StartBasicPlayer();
401 for (int frame = 0; frame < 1000; frame++) {
402 SendFakeVideoFrame();
403 RunTasks(frame_duration_);
405 RunTasks(100 * frame_duration_); // Empty the pipeline.
406 VLOG(1) << "=============INPUTS============";
407 VLOG(1) << "Bitrate: " << p.bitrate << " mbit/s";
408 VLOG(1) << "Latency: " << p.latency << " ms";
409 VLOG(1) << "Packet drop drop: " << p.percent_packet_drop << "%";
410 VLOG(1) << "=============OUTPUTS============";
411 VLOG(1) << "Frames lost: " << frames_lost();
412 VLOG(1) << "Late frames: " << late_frames();
413 VLOG(1) << "Playout margin: " << frame_playout_buffer().AsString();
414 VLOG(1) << "Video bandwidth used: " << video_bandwidth() << " mbit/s ("
415 << (video_bandwidth() * 100 / desired_video_bitrate()) << "%)";
416 VLOG(1) << "Good run: " << SimpleGood();
419 // Metrics
420 int frames_lost() const { return frames_sent_ - video_ticks_.size(); }
422 int late_frames() const {
423 int frames = 0;
424 // Ignore the first two seconds of video or so.
425 for (size_t i = 60; i < video_ticks_.size(); i++) {
426 if (video_ticks_[i].first > video_ticks_[i].second) {
427 frames++;
430 return frames;
433 test::MeanAndError frame_playout_buffer() const {
434 std::vector<double> values;
435 for (size_t i = 0; i < video_ticks_.size(); i++) {
436 values.push_back(
437 (video_ticks_[i].second - video_ticks_[i].first).InMillisecondsF());
439 return test::MeanAndError(values);
442 // Mbits per second
443 double video_bandwidth() const {
444 double seconds = (frame_duration_.InSecondsF() * frames_sent_);
445 double megabits = video_bytes_encoded_ * 8 / 1000000.0;
446 return megabits / seconds;
449 // Mbits per second
450 double audio_bandwidth() const {
451 double seconds = (frame_duration_.InSecondsF() * frames_sent_);
452 double megabits = audio_bytes_encoded_ * 8 / 1000000.0;
453 return megabits / seconds;
456 double desired_video_bitrate() {
457 return std::min<double>(available_bitrate_,
458 video_sender_config_.max_bitrate / 1000000.0);
461 bool SimpleGood() {
462 return frames_lost() <= 1 && late_frames() <= 1 &&
463 video_bandwidth() > desired_video_bitrate() * 0.8 &&
464 video_bandwidth() < desired_video_bitrate() * 1.2;
467 private:
468 FrameReceiverConfig audio_receiver_config_;
469 FrameReceiverConfig video_receiver_config_;
470 AudioSenderConfig audio_sender_config_;
471 VideoSenderConfig video_sender_config_;
473 base::TimeTicks start_time_;
475 // These run in "test time"
476 base::SimpleTestTickClock testing_clock_;
477 scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
479 // These run on the sender timeline.
480 test::SkewedTickClock* testing_clock_sender_;
481 scoped_refptr<test::SkewedSingleThreadTaskRunner> task_runner_sender_;
483 // These run on the receiver timeline.
484 test::SkewedTickClock* testing_clock_receiver_;
485 scoped_refptr<test::SkewedSingleThreadTaskRunner> task_runner_receiver_;
487 scoped_refptr<CastEnvironment> cast_environment_sender_;
488 scoped_refptr<CastEnvironment> cast_environment_receiver_;
490 LoopBackTransport receiver_to_sender_;
491 LoopBackTransport sender_to_receiver_;
492 CastTransportSenderWrapper transport_sender_;
493 scoped_ptr<CastTransportSender> transport_receiver_;
494 uint64 video_bytes_encoded_;
495 uint64 audio_bytes_encoded_;
497 scoped_ptr<CastReceiver> cast_receiver_;
498 scoped_ptr<CastSender> cast_sender_;
500 int frames_sent_;
501 base::TimeDelta frame_duration_;
502 double available_bitrate_;
503 std::vector<std::pair<base::TimeTicks, base::TimeTicks> > audio_ticks_;
504 std::vector<std::pair<base::TimeTicks, base::TimeTicks> > video_ticks_;
507 enum CacheResult { FOUND_TRUE, FOUND_FALSE, NOT_FOUND };
509 template <class T>
510 class BenchmarkCache {
511 public:
512 CacheResult Lookup(const T& x) {
513 base::AutoLock key(lock_);
514 for (size_t i = 0; i < results_.size(); i++) {
515 if (results_[i].second) {
516 if (x <= results_[i].first) {
517 VLOG(2) << "TRUE because: " << x.AsString()
518 << " <= " << results_[i].first.AsString();
519 return FOUND_TRUE;
521 } else {
522 if (x >= results_[i].first) {
523 VLOG(2) << "FALSE because: " << x.AsString()
524 << " >= " << results_[i].first.AsString();
525 return FOUND_FALSE;
529 return NOT_FOUND;
532 void Add(const T& x, bool result) {
533 base::AutoLock key(lock_);
534 VLOG(2) << "Cache Insert: " << x.AsString() << " = " << result;
535 results_.push_back(std::make_pair(x, result));
538 private:
539 base::Lock lock_;
540 std::vector<std::pair<T, bool> > results_;
543 struct SearchVariable {
544 SearchVariable() : base(0.0), grade(0.0) {}
545 SearchVariable(double b, double g) : base(b), grade(g) {}
546 SearchVariable blend(const SearchVariable& other, double factor) {
547 CHECK_GE(factor, 0);
548 CHECK_LE(factor, 1.0);
549 return SearchVariable(base * (1 - factor) + other.base * factor,
550 grade * (1 - factor) + other.grade * factor);
552 double value(double x) const { return base + grade * x; }
553 double base;
554 double grade;
557 struct SearchVector {
558 SearchVector blend(const SearchVector& other, double factor) {
559 SearchVector ret;
560 ret.bitrate = bitrate.blend(other.bitrate, factor);
561 ret.latency = latency.blend(other.latency, factor);
562 ret.packet_drop = packet_drop.blend(other.packet_drop, factor);
563 return ret;
566 SearchVector average(const SearchVector& other) {
567 return blend(other, 0.5);
570 MeasuringPoint GetMeasuringPoint(double v) const {
571 return MeasuringPoint(
572 bitrate.value(-v), latency.value(v), packet_drop.value(v));
574 std::string AsString(double v) { return GetMeasuringPoint(v).AsString(); }
576 SearchVariable bitrate;
577 SearchVariable latency;
578 SearchVariable packet_drop;
581 class CastBenchmark {
582 public:
583 bool RunOnePoint(const SearchVector& v, double multiplier) {
584 MeasuringPoint p = v.GetMeasuringPoint(multiplier);
585 VLOG(1) << "RUN: v = " << multiplier << " p = " << p.AsString();
586 if (p.bitrate <= 0) {
587 return false;
589 switch (cache_.Lookup(p)) {
590 case FOUND_TRUE:
591 return true;
592 case FOUND_FALSE:
593 return false;
594 case NOT_FOUND:
595 // Keep going
596 break;
598 bool result = true;
599 for (int tries = 0; tries < 3 && result; tries++) {
600 RunOneBenchmark benchmark;
601 benchmark.Run(p);
602 result &= benchmark.SimpleGood();
604 cache_.Add(p, result);
605 return result;
608 void BinarySearch(SearchVector v, double accuracy) {
609 double min = 0.0;
610 double max = 1.0;
611 while (RunOnePoint(v, max)) {
612 min = max;
613 max *= 2;
616 while (max - min > accuracy) {
617 double avg = (min + max) / 2;
618 if (RunOnePoint(v, avg)) {
619 min = avg;
620 } else {
621 max = avg;
625 // Print a data point to stdout.
626 base::AutoLock key(lock_);
627 MeasuringPoint p = v.GetMeasuringPoint(min);
628 fprintf(stdout, "%f %f %f\n", p.bitrate, p.latency, p.percent_packet_drop);
629 fflush(stdout);
632 void SpanningSearch(int max,
633 int x,
634 int y,
635 int skip,
636 SearchVector a,
637 SearchVector b,
638 SearchVector c,
639 double accuracy,
640 std::vector<linked_ptr<base::Thread> >* threads) {
641 static int thread_num = 0;
642 if (x > max) return;
643 if (skip > max) {
644 if (y > x) return;
645 SearchVector ab = a.blend(b, static_cast<double>(x) / max);
646 SearchVector ac = a.blend(c, static_cast<double>(x) / max);
647 SearchVector v = ab.blend(ac, x == y ? 1.0 : static_cast<double>(y) / x);
648 thread_num++;
649 (*threads)[thread_num % threads->size()]->message_loop()->PostTask(
650 FROM_HERE,
651 base::Bind(&CastBenchmark::BinarySearch,
652 base::Unretained(this),
654 accuracy));
655 } else {
656 skip *= 2;
657 SpanningSearch(max, x, y, skip, a, b, c, accuracy, threads);
658 SpanningSearch(max, x + skip, y + skip, skip, a, b, c, accuracy, threads);
659 SpanningSearch(max, x + skip, y, skip, a, b, c, accuracy, threads);
660 SpanningSearch(max, x, y + skip, skip, a, b, c, accuracy, threads);
664 void Run() {
665 // Spanning search.
667 std::vector<linked_ptr<base::Thread> > threads;
668 for (int i = 0; i < 16; i++) {
669 threads.push_back(make_linked_ptr(new base::Thread(
670 base::StringPrintf("cast_bench_thread_%d", i))));
671 threads[i]->Start();
674 if (base::CommandLine::ForCurrentProcess()->HasSwitch("single-run")) {
675 SearchVector a;
676 a.bitrate.base = 100.0;
677 a.bitrate.grade = 1.0;
678 a.latency.grade = 1.0;
679 a.packet_drop.grade = 1.0;
680 threads[0]->message_loop()->PostTask(
681 FROM_HERE,
682 base::Bind(base::IgnoreResult(&CastBenchmark::RunOnePoint),
683 base::Unretained(this),
685 1.0));
686 } else {
687 SearchVector a, b, c;
688 a.bitrate.base = b.bitrate.base = c.bitrate.base = 100.0;
689 a.bitrate.grade = 1.0;
690 b.latency.grade = 1.0;
691 c.packet_drop.grade = 1.0;
693 SpanningSearch(512,
700 0.01,
701 &threads);
704 for (size_t i = 0; i < threads.size(); i++) {
705 threads[i]->Stop();
709 private:
710 BenchmarkCache<MeasuringPoint> cache_;
711 base::Lock lock_;
714 } // namespace cast
715 } // namespace media
717 int main(int argc, char** argv) {
718 base::AtExitManager at_exit;
719 base::CommandLine::Init(argc, argv);
720 media::cast::CastBenchmark benchmark;
721 if (getenv("PROFILE_FILE")) {
722 std::string profile_file(getenv("PROFILE_FILE"));
723 base::debug::StartProfiling(profile_file);
724 benchmark.Run();
725 base::debug::StopProfiling();
726 } else {
727 benchmark.Run();