Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: trunk/src/media/cast/test/cast_benchmarks.cc

Issue 328313002: Revert 276603 "Cast: Synthetic benchmark tool." (Closed) Base URL: svn://svn.chromium.org/chrome/
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/test/fake_single_thread_task_runner.h"
49 #include "media/cast/test/skewed_single_thread_task_runner.h"
50 #include "media/cast/test/skewed_tick_clock.h"
51 #include "media/cast/test/utility/audio_utility.h"
52 #include "media/cast/test/utility/default_config.h"
53 #include "media/cast/test/utility/test_util.h"
54 #include "media/cast/test/utility/udp_proxy.h"
55 #include "media/cast/test/utility/video_utility.h"
56 #include "media/cast/transport/cast_transport_config.h"
57 #include "media/cast/transport/cast_transport_defines.h"
58 #include "media/cast/transport/cast_transport_sender.h"
59 #include "media/cast/transport/cast_transport_sender_impl.h"
60 #include "testing/gtest/include/gtest/gtest.h"
61
62 namespace media {
63 namespace cast {
64
65 namespace {
66
67 static const int64 kStartMillisecond = INT64_C(1245);
68 static const int kAudioChannels = 2;
69 static const int kVideoHdWidth = 1280;
70 static const int kVideoHdHeight = 720;
71 static const int kTargetDelay = 300;
72
73 // The tests are commonly implemented with |kFrameTimerMs| RunTask function;
74 // a normal video is 30 fps hence the 33 ms between frames.
75 static const int kFrameTimerMs = 33;
76
77 void UpdateCastTransportStatus(transport::CastTransportStatus status) {
78 bool result = (status == transport::TRANSPORT_AUDIO_INITIALIZED ||
79 status == transport::TRANSPORT_VIDEO_INITIALIZED);
80 EXPECT_TRUE(result);
81 }
82
83 void AudioInitializationStatus(CastInitializationStatus status) {
84 EXPECT_EQ(STATUS_AUDIO_INITIALIZED, status);
85 }
86
87 void VideoInitializationStatus(CastInitializationStatus status) {
88 EXPECT_EQ(STATUS_VIDEO_INITIALIZED, status);
89 }
90
91 void IgnoreRawEvents(const std::vector<PacketEvent>& packet_events) {
92 }
93
94 } // namespace
95
96 // Shim that turns forwards packets from a test::PacketPipe to a
97 // PacketReceiverCallback.
98 class LoopBackPacketPipe : public test::PacketPipe {
99 public:
100 LoopBackPacketPipe(const transport::PacketReceiverCallback& packet_receiver)
101 : packet_receiver_(packet_receiver) {}
102
103 virtual ~LoopBackPacketPipe() {}
104
105 // PacketPipe implementations.
106 virtual void Send(scoped_ptr<transport::Packet> packet) OVERRIDE {
107 packet_receiver_.Run(packet.Pass());
108 }
109
110 private:
111 transport::PacketReceiverCallback packet_receiver_;
112 };
113
114 // Class that sends the packet direct from sender into the receiver with the
115 // ability to drop packets between the two.
116 // TODO(hubbe): Break this out and share code with end2end_unittest.cc
117 class LoopBackTransport : public transport::PacketSender {
118 public:
119 explicit LoopBackTransport(scoped_refptr<CastEnvironment> cast_environment)
120 : cast_environment_(cast_environment) {}
121
122 void SetPacketReceiver(
123 const transport::PacketReceiverCallback& packet_receiver,
124 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
125 base::TickClock* clock) {
126 scoped_ptr<test::PacketPipe> loopback_pipe(
127 new LoopBackPacketPipe(packet_receiver));
128 if (packet_pipe_) {
129 packet_pipe_->AppendToPipe(loopback_pipe.Pass());
130 } else {
131 packet_pipe_ = loopback_pipe.Pass();
132 }
133 packet_pipe_->InitOnIOThread(task_runner, clock);
134 }
135
136 virtual bool SendPacket(transport::PacketRef packet,
137 const base::Closure& cb) OVERRIDE {
138 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
139 scoped_ptr<Packet> packet_copy(new Packet(packet->data));
140 packet_pipe_->Send(packet_copy.Pass());
141 return true;
142 }
143
144 void SetPacketPipe(scoped_ptr<test::PacketPipe> pipe) {
145 // Append the loopback pipe to the end.
146 pipe->AppendToPipe(packet_pipe_.Pass());
147 packet_pipe_ = pipe.Pass();
148 }
149
150 private:
151 scoped_refptr<CastEnvironment> cast_environment_;
152 scoped_ptr<test::PacketPipe> packet_pipe_;
153 };
154
155 // Wraps a CastTransportSender and records some statistics about
156 // the data that goes through it.
157 class CastTransportSenderWrapper : public transport::CastTransportSender {
158 public:
159 // Takes ownership of |transport|.
160 void Init(CastTransportSender* transport,
161 uint64* encoded_video_bytes,
162 uint64* encoded_audio_bytes) {
163 transport_.reset(transport);
164 encoded_video_bytes_ = encoded_video_bytes;
165 encoded_audio_bytes_ = encoded_audio_bytes;
166 }
167
168 virtual void InitializeAudio(
169 const transport::CastTransportAudioConfig& config) OVERRIDE {
170 transport_->InitializeAudio(config);
171 }
172
173 virtual void InitializeVideo(
174 const transport::CastTransportVideoConfig& config) OVERRIDE {
175 transport_->InitializeVideo(config);
176 }
177
178 virtual void SetPacketReceiver(
179 const transport::PacketReceiverCallback& packet_receiver) OVERRIDE {
180 transport_->SetPacketReceiver(packet_receiver);
181 }
182
183 virtual void InsertCodedAudioFrame(
184 const transport::EncodedFrame& audio_frame) OVERRIDE {
185 *encoded_audio_bytes_ += audio_frame.data.size();
186 transport_->InsertCodedAudioFrame(audio_frame);
187 }
188
189 virtual void InsertCodedVideoFrame(
190 const transport::EncodedFrame& video_frame) OVERRIDE {
191 *encoded_video_bytes_ += video_frame.data.size();
192 transport_->InsertCodedVideoFrame(video_frame);
193 }
194
195 virtual void SendRtcpFromRtpSender(uint32 packet_type_flags,
196 uint32 ntp_seconds,
197 uint32 ntp_fraction,
198 uint32 rtp_timestamp,
199 const transport::RtcpDlrrReportBlock& dlrr,
200 uint32 sending_ssrc,
201 const std::string& c_name) OVERRIDE {
202 transport_->SendRtcpFromRtpSender(packet_type_flags,
203 ntp_seconds,
204 ntp_fraction,
205 rtp_timestamp,
206 dlrr,
207 sending_ssrc,
208 c_name);
209 }
210
211 // Retransmission request.
212 virtual void ResendPackets(
213 bool is_audio,
214 const MissingFramesAndPacketsMap& missing_packets) OVERRIDE {
215 transport_->ResendPackets(is_audio, missing_packets);
216 }
217
218 private:
219 scoped_ptr<transport::CastTransportSender> transport_;
220 uint64* encoded_video_bytes_;
221 uint64* encoded_audio_bytes_;
222 };
223
224 struct MeasuringPoint {
225 MeasuringPoint(double bitrate_, double latency_, double percent_packet_drop_)
226 : bitrate(bitrate_),
227 latency(latency_),
228 percent_packet_drop(percent_packet_drop_) {}
229 bool operator<=(const MeasuringPoint& other) const {
230 return bitrate >= other.bitrate && latency <= other.latency &&
231 percent_packet_drop <= other.percent_packet_drop;
232 }
233 bool operator>=(const MeasuringPoint& other) const {
234 return bitrate <= other.bitrate && latency >= other.latency &&
235 percent_packet_drop >= other.percent_packet_drop;
236 }
237
238 std::string AsString() const {
239 return base::StringPrintf(
240 "%f Mbit/s %f ms %f %% ", bitrate, latency, percent_packet_drop);
241 }
242
243 double bitrate;
244 double latency;
245 double percent_packet_drop;
246 };
247
248 class RunOneBenchmark {
249 public:
250 RunOneBenchmark()
251 : start_time_(),
252 task_runner_(new test::FakeSingleThreadTaskRunner(&testing_clock_)),
253 testing_clock_sender_(new test::SkewedTickClock(&testing_clock_)),
254 task_runner_sender_(
255 new test::SkewedSingleThreadTaskRunner(task_runner_)),
256 testing_clock_receiver_(new test::SkewedTickClock(&testing_clock_)),
257 task_runner_receiver_(
258 new test::SkewedSingleThreadTaskRunner(task_runner_)),
259 cast_environment_sender_(new CastEnvironment(
260 scoped_ptr<base::TickClock>(testing_clock_sender_).Pass(),
261 task_runner_sender_,
262 task_runner_sender_,
263 task_runner_sender_)),
264 cast_environment_receiver_(new CastEnvironment(
265 scoped_ptr<base::TickClock>(testing_clock_receiver_).Pass(),
266 task_runner_receiver_,
267 task_runner_receiver_,
268 task_runner_receiver_)),
269 receiver_to_sender_(cast_environment_receiver_),
270 sender_to_receiver_(cast_environment_sender_),
271 video_bytes_encoded_(0),
272 audio_bytes_encoded_(0),
273 frames_sent_(0) {
274 testing_clock_.Advance(
275 base::TimeDelta::FromMilliseconds(kStartMillisecond));
276 }
277
278 void Configure(transport::VideoCodec video_codec,
279 transport::AudioCodec audio_codec,
280 int audio_sampling_frequency,
281 int max_number_of_video_buffers_used) {
282 audio_sender_config_.rtp_config.ssrc = 1;
283 audio_sender_config_.incoming_feedback_ssrc = 2;
284 audio_sender_config_.rtp_config.payload_type = 96;
285 audio_sender_config_.use_external_encoder = false;
286 audio_sender_config_.frequency = audio_sampling_frequency;
287 audio_sender_config_.channels = kAudioChannels;
288 audio_sender_config_.bitrate = kDefaultAudioEncoderBitrate;
289 audio_sender_config_.codec = audio_codec;
290 audio_sender_config_.rtp_config.max_delay_ms = kTargetDelay;
291
292 audio_receiver_config_.feedback_ssrc =
293 audio_sender_config_.incoming_feedback_ssrc;
294 audio_receiver_config_.incoming_ssrc = audio_sender_config_.rtp_config.ssrc;
295 audio_receiver_config_.rtp_payload_type =
296 audio_sender_config_.rtp_config.payload_type;
297 audio_receiver_config_.frequency = audio_sender_config_.frequency;
298 audio_receiver_config_.channels = kAudioChannels;
299 audio_receiver_config_.max_frame_rate = 100;
300 audio_receiver_config_.codec.audio = audio_sender_config_.codec;
301 audio_receiver_config_.rtp_max_delay_ms = kTargetDelay;
302
303 video_sender_config_.rtp_config.ssrc = 3;
304 video_sender_config_.incoming_feedback_ssrc = 4;
305 video_sender_config_.rtp_config.payload_type = 97;
306 video_sender_config_.use_external_encoder = false;
307 video_sender_config_.width = kVideoHdWidth;
308 video_sender_config_.height = kVideoHdHeight;
309 #if 0
310 video_sender_config_.max_bitrate = 10000000; // 10Mbit max
311 video_sender_config_.min_bitrate = 1000000; // 1Mbit min
312 video_sender_config_.start_bitrate = 1000000; // 1Mbit start
313 #else
314 video_sender_config_.max_bitrate = 4000000; // 4Mbit all the time
315 video_sender_config_.min_bitrate = 4000000;
316 video_sender_config_.start_bitrate = 4000000;
317 #endif
318 video_sender_config_.max_qp = 56;
319 video_sender_config_.min_qp = 4;
320 video_sender_config_.max_frame_rate = 30;
321 video_sender_config_.max_number_of_video_buffers_used =
322 max_number_of_video_buffers_used;
323 video_sender_config_.codec = video_codec;
324 video_sender_config_.rtp_config.max_delay_ms = kTargetDelay;
325
326 video_receiver_config_.feedback_ssrc =
327 video_sender_config_.incoming_feedback_ssrc;
328 video_receiver_config_.incoming_ssrc = video_sender_config_.rtp_config.ssrc;
329 video_receiver_config_.rtp_payload_type =
330 video_sender_config_.rtp_config.payload_type;
331 video_receiver_config_.codec.video = video_sender_config_.codec;
332 video_receiver_config_.frequency = kVideoFrequency;
333 video_receiver_config_.channels = 1;
334 video_receiver_config_.max_frame_rate = 100;
335 video_receiver_config_.rtp_max_delay_ms = kTargetDelay;
336 }
337
338 void SetSenderClockSkew(double skew, base::TimeDelta offset) {
339 testing_clock_sender_->SetSkew(skew, offset);
340 task_runner_sender_->SetSkew(1.0 / skew);
341 }
342
343 void SetReceiverClockSkew(double skew, base::TimeDelta offset) {
344 testing_clock_receiver_->SetSkew(skew, offset);
345 task_runner_receiver_->SetSkew(1.0 / skew);
346 }
347
348 void Create() {
349 cast_receiver_ = CastReceiver::Create(cast_environment_receiver_,
350 audio_receiver_config_,
351 video_receiver_config_,
352 &receiver_to_sender_);
353 net::IPEndPoint dummy_endpoint;
354 transport_sender_.Init(new transport::CastTransportSenderImpl(
355 NULL,
356 testing_clock_sender_,
357 dummy_endpoint,
358 base::Bind(&UpdateCastTransportStatus),
359 base::Bind(&IgnoreRawEvents),
360 base::TimeDelta::FromSeconds(1),
361 task_runner_sender_,
362 &sender_to_receiver_),
363 &video_bytes_encoded_,
364 &audio_bytes_encoded_);
365
366 cast_sender_ =
367 CastSender::Create(cast_environment_sender_, &transport_sender_);
368
369 // Initializing audio and video senders.
370 cast_sender_->InitializeAudio(audio_sender_config_,
371 base::Bind(&AudioInitializationStatus));
372 cast_sender_->InitializeVideo(video_sender_config_,
373 base::Bind(&VideoInitializationStatus),
374 CreateDefaultVideoEncodeAcceleratorCallback(),
375 CreateDefaultVideoEncodeMemoryCallback());
376
377 receiver_to_sender_.SetPacketReceiver(
378 cast_sender_->packet_receiver(), task_runner_, &testing_clock_);
379 sender_to_receiver_.SetPacketReceiver(
380 cast_receiver_->packet_receiver(), task_runner_, &testing_clock_);
381 }
382
383 virtual ~RunOneBenchmark() {
384 cast_sender_.reset();
385 cast_receiver_.reset();
386 task_runner_->RunTasks();
387 }
388
389 void SendFakeVideoFrame() {
390 frames_sent_++;
391 cast_sender_->video_frame_input()->InsertRawVideoFrame(
392 media::VideoFrame::CreateBlackFrame(gfx::Size(2, 2)),
393 testing_clock_sender_->NowTicks());
394 }
395
396 void RunTasks(int ms) {
397 task_runner_->Sleep(base::TimeDelta::FromMilliseconds(ms));
398 }
399
400 void BasicPlayerGotVideoFrame(
401 const scoped_refptr<media::VideoFrame>& video_frame,
402 const base::TimeTicks& render_time,
403 bool continuous) {
404 video_ticks_.push_back(
405 std::make_pair(testing_clock_receiver_->NowTicks(), render_time));
406 cast_receiver_->RequestDecodedVideoFrame(base::Bind(
407 &RunOneBenchmark::BasicPlayerGotVideoFrame, base::Unretained(this)));
408 }
409
410 void BasicPlayerGotAudioFrame(scoped_ptr<AudioBus> audio_bus,
411 const base::TimeTicks& playout_time,
412 bool is_continuous) {
413 audio_ticks_.push_back(
414 std::make_pair(testing_clock_receiver_->NowTicks(), playout_time));
415 cast_receiver_->RequestDecodedAudioFrame(base::Bind(
416 &RunOneBenchmark::BasicPlayerGotAudioFrame, base::Unretained(this)));
417 }
418
419 void StartBasicPlayer() {
420 cast_receiver_->RequestDecodedVideoFrame(base::Bind(
421 &RunOneBenchmark::BasicPlayerGotVideoFrame, base::Unretained(this)));
422 cast_receiver_->RequestDecodedAudioFrame(base::Bind(
423 &RunOneBenchmark::BasicPlayerGotAudioFrame, base::Unretained(this)));
424 }
425
426 scoped_ptr<test::PacketPipe> CreateSimplePipe(const MeasuringPoint& p) {
427 scoped_ptr<test::PacketPipe> pipe = test::NewBuffer(65536, p.bitrate);
428 pipe->AppendToPipe(
429 test::NewRandomDrop(p.percent_packet_drop / 100.0).Pass());
430 pipe->AppendToPipe(test::NewConstantDelay(p.latency / 1000.0));
431 return pipe.Pass();
432 }
433
434 void Run(const MeasuringPoint& p) {
435 available_bitrate_ = p.bitrate;
436 Configure(transport::kFakeSoftwareVideo, transport::kPcm16, 32000, 1);
437 receiver_to_sender_.SetPacketPipe(CreateSimplePipe(p).Pass());
438 sender_to_receiver_.SetPacketPipe(CreateSimplePipe(p).Pass());
439 Create();
440 StartBasicPlayer();
441
442 for (int frame = 0; frame < 1000; frame++) {
443 SendFakeVideoFrame();
444 RunTasks(kFrameTimerMs);
445 }
446 RunTasks(100 * kFrameTimerMs); // Empty the pipeline.
447 VLOG(1) << "=============INPUTS============";
448 VLOG(1) << "Bitrate: " << p.bitrate << " mbit/s";
449 VLOG(1) << "Latency: " << p.latency << " ms";
450 VLOG(1) << "Packet drop drop: " << p.percent_packet_drop << "%";
451 VLOG(1) << "=============OUTPUTS============";
452 VLOG(1) << "Frames lost: " << frames_lost();
453 VLOG(1) << "Late frames: " << late_frames();
454 VLOG(1) << "Playout margin: " << frame_playout_buffer().AsString();
455 VLOG(1) << "Video bandwidth used: " << video_bandwidth() << " mbit/s ("
456 << (video_bandwidth() * 100 / desired_video_bitrate()) << "%)";
457 VLOG(1) << "Good run: " << SimpleGood();
458 }
459
460 // Metrics
461 int frames_lost() const { return frames_sent_ - video_ticks_.size(); }
462
463 int late_frames() const {
464 int frames = 0;
465 // Ignore the first two seconds of video or so.
466 for (size_t i = 60; i < video_ticks_.size(); i++) {
467 if (video_ticks_[i].first > video_ticks_[i].second) {
468 frames++;
469 }
470 }
471 return frames;
472 }
473
474 test::MeanAndError frame_playout_buffer() const {
475 std::vector<double> values;
476 for (size_t i = 0; i < video_ticks_.size(); i++) {
477 values.push_back(
478 (video_ticks_[i].second - video_ticks_[i].first).InMillisecondsF());
479 }
480 return test::MeanAndError(values);
481 }
482
483 // Mbits per second
484 double video_bandwidth() const {
485 double seconds = (kFrameTimerMs * frames_sent_ / 1000.0);
486 double megabits = video_bytes_encoded_ * 8 / 1000000.0;
487 return megabits / seconds;
488 }
489
490 // Mbits per second
491 double audio_bandwidth() const {
492 double seconds = (kFrameTimerMs * frames_sent_ / 1000.0);
493 double megabits = audio_bytes_encoded_ * 8 / 1000000.0;
494 return megabits / seconds;
495 }
496
497 double desired_video_bitrate() {
498 return std::min<double>(available_bitrate_,
499 video_sender_config_.max_bitrate / 1000000.0);
500 }
501
502 bool SimpleGood() {
503 return frames_lost() <= 1 && late_frames() <= 1 &&
504 video_bandwidth() > desired_video_bitrate() * 0.8 &&
505 video_bandwidth() < desired_video_bitrate() * 1.2;
506 }
507
508 private:
509 FrameReceiverConfig audio_receiver_config_;
510 FrameReceiverConfig video_receiver_config_;
511 AudioSenderConfig audio_sender_config_;
512 VideoSenderConfig video_sender_config_;
513
514 base::TimeTicks start_time_;
515
516 // These run in "test time"
517 base::SimpleTestTickClock testing_clock_;
518 scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
519
520 // These run on the sender timeline.
521 test::SkewedTickClock* testing_clock_sender_;
522 scoped_refptr<test::SkewedSingleThreadTaskRunner> task_runner_sender_;
523
524 // These run on the receiver timeline.
525 test::SkewedTickClock* testing_clock_receiver_;
526 scoped_refptr<test::SkewedSingleThreadTaskRunner> task_runner_receiver_;
527
528 scoped_refptr<CastEnvironment> cast_environment_sender_;
529 scoped_refptr<CastEnvironment> cast_environment_receiver_;
530
531 LoopBackTransport receiver_to_sender_;
532 LoopBackTransport sender_to_receiver_;
533 CastTransportSenderWrapper transport_sender_;
534 uint64 video_bytes_encoded_;
535 uint64 audio_bytes_encoded_;
536
537 scoped_ptr<CastReceiver> cast_receiver_;
538 scoped_ptr<CastSender> cast_sender_;
539
540 int frames_sent_;
541 double available_bitrate_;
542 std::vector<std::pair<base::TimeTicks, base::TimeTicks> > audio_ticks_;
543 std::vector<std::pair<base::TimeTicks, base::TimeTicks> > video_ticks_;
544 };
545
546 enum CacheResult { FOUND_TRUE, FOUND_FALSE, NOT_FOUND };
547
548 template <class T>
549 class BenchmarkCache {
550 public:
551 CacheResult Lookup(const T& x) {
552 base::AutoLock key(lock_);
553 for (size_t i = 0; i < results_.size(); i++) {
554 if (results_[i].second) {
555 if (x <= results_[i].first) {
556 VLOG(2) << "TRUE because: " << x.AsString()
557 << " <= " << results_[i].first.AsString();
558 return FOUND_TRUE;
559 }
560 } else {
561 if (x >= results_[i].first) {
562 VLOG(2) << "FALSE because: " << x.AsString()
563 << " >= " << results_[i].first.AsString();
564 return FOUND_FALSE;
565 }
566 }
567 }
568 return NOT_FOUND;
569 }
570
571 void Add(const T& x, bool result) {
572 base::AutoLock key(lock_);
573 VLOG(2) << "Cache Insert: " << x.AsString() << " = " << result;
574 results_.push_back(std::make_pair(x, result));
575 }
576
577 private:
578 base::Lock lock_;
579 std::vector<std::pair<T, bool> > results_;
580 };
581
582 struct SearchVariable {
583 SearchVariable() : base(0.0), grade(0.0) {}
584 SearchVariable(double b, double g) : base(b), grade(g) {}
585 SearchVariable blend(const SearchVariable& other, double factor) {
586 CHECK_GE(factor, 0);
587 CHECK_LE(factor, 1.0);
588 return SearchVariable(base * (1 - factor) + other.base * factor,
589 grade * (1 - factor) + other.grade * factor);
590 }
591 double value(double x) const { return base + grade * x; }
592 double base;
593 double grade;
594 };
595
596 struct SearchVector {
597 SearchVector blend(const SearchVector& other, double factor) {
598 SearchVector ret;
599 ret.bitrate = bitrate.blend(other.bitrate, factor);
600 ret.latency = latency.blend(other.latency, factor);
601 ret.packet_drop = packet_drop.blend(other.packet_drop, factor);
602 return ret;
603 }
604
605 SearchVector average(const SearchVector& other) {
606 return blend(other, 0.5);
607 }
608
609 MeasuringPoint GetMeasuringPoint(double v) const {
610 return MeasuringPoint(
611 bitrate.value(-v), latency.value(v), packet_drop.value(v));
612 }
613 std::string AsString(double v) { return GetMeasuringPoint(v).AsString(); }
614
615 SearchVariable bitrate;
616 SearchVariable latency;
617 SearchVariable packet_drop;
618 };
619
620 class CastBenchmark {
621 public:
622 bool RunOnePoint(const SearchVector& v, double multiplier) {
623 MeasuringPoint p = v.GetMeasuringPoint(multiplier);
624 VLOG(1) << "RUN: v = " << multiplier << " p = " << p.AsString();
625 if (p.bitrate <= 0) {
626 return false;
627 }
628 switch (cache_.Lookup(p)) {
629 case FOUND_TRUE:
630 return true;
631 case FOUND_FALSE:
632 return false;
633 case NOT_FOUND:
634 // Keep going
635 break;
636 }
637 bool result = true;
638 for (int tries = 0; tries < 3 && result; tries++) {
639 RunOneBenchmark benchmark;
640 benchmark.Run(p);
641 result &= benchmark.SimpleGood();
642 }
643 cache_.Add(p, result);
644 return result;
645 }
646
647 void BinarySearch(SearchVector v, double accuracy) {
648 double min = 0.0;
649 double max = 1.0;
650 while (RunOnePoint(v, max)) {
651 min = max;
652 max *= 2;
653 }
654
655 while (max - min > accuracy) {
656 double avg = (min + max) / 2;
657 if (RunOnePoint(v, avg)) {
658 min = avg;
659 } else {
660 max = avg;
661 }
662 }
663
664 // Print a data point to stdout.
665 base::AutoLock key(lock_);
666 MeasuringPoint p = v.GetMeasuringPoint(min);
667 fprintf(stdout, "%f %f %f\n", p.bitrate, p.latency, p.percent_packet_drop);
668 fflush(stdout);
669 }
670
671 void SpanningSearch(int max,
672 int x,
673 int y,
674 int skip,
675 SearchVector a,
676 SearchVector b,
677 SearchVector c,
678 double accuracy,
679 std::vector<linked_ptr<base::Thread> >* threads) {
680 static int thread_num = 0;
681 if (x > max) return;
682 if (skip > max) {
683 if (y > x) return;
684 SearchVector ab = a.blend(b, static_cast<double>(x) / max);
685 SearchVector ac = a.blend(c, static_cast<double>(x) / max);
686 SearchVector v = ab.blend(ac, x == y ? 1.0 : static_cast<double>(y) / x);
687 thread_num++;
688 (*threads)[thread_num % threads->size()]->message_loop()->PostTask(
689 FROM_HERE,
690 base::Bind(&CastBenchmark::BinarySearch,
691 base::Unretained(this),
692 v,
693 accuracy));
694 } else {
695 skip *= 2;
696 SpanningSearch(max, x, y, skip, a, b, c, accuracy, threads);
697 SpanningSearch(max, x + skip, y + skip, skip, a, b, c, accuracy, threads);
698 SpanningSearch(max, x + skip, y, skip, a, b, c, accuracy, threads);
699 SpanningSearch(max, x, y + skip, skip, a, b, c, accuracy, threads);
700 }
701 }
702
703 void Run() {
704 // Spanning search.
705
706 std::vector<linked_ptr<base::Thread> > threads;
707 for (size_t i = 0; i < 16; i++) {
708 threads.push_back(make_linked_ptr(new base::Thread(
709 base::StringPrintf("cast_bench_thread_%lu", i))));
710 threads[i]->Start();
711 }
712
713 if (CommandLine::ForCurrentProcess()->HasSwitch("single-run")) {
714 SearchVector a;
715 a.bitrate.base = 100.0;
716 a.bitrate.grade = 1.0;
717 a.latency.grade = 1.0;
718 a.packet_drop.grade = 1.0;
719 threads[0]->message_loop()->PostTask(
720 FROM_HERE,
721 base::Bind(base::IgnoreResult(&CastBenchmark::RunOnePoint),
722 base::Unretained(this),
723 a,
724 1.0));
725 } else {
726 SearchVector a, b, c;
727 a.bitrate.base = b.bitrate.base = c.bitrate.base = 100.0;
728 a.bitrate.grade = 1.0;
729 b.latency.grade = 1.0;
730 c.packet_drop.grade = 1.0;
731
732 SpanningSearch(512,
733 0,
734 0,
735 1,
736 a,
737 b,
738 c,
739 0.01,
740 &threads);
741 }
742
743 for (size_t i = 0; i < threads.size(); i++) {
744 threads[i]->Stop();
745 }
746 }
747
748 private:
749 BenchmarkCache<MeasuringPoint> cache_;
750 base::Lock lock_;
751 };
752
753 } // namespace cast
754 } // namespace media
755
756 int main(int argc, char** argv) {
757 base::AtExitManager at_exit;
758 CommandLine::Init(argc, argv);
759 media::cast::CastBenchmark benchmark;
760 if (getenv("PROFILE_FILE")) {
761 std::string profile_file(getenv("PROFILE_FILE"));
762 base::debug::StartProfiling(profile_file);
763 benchmark.Run();
764 base::debug::StopProfiling();
765 } else {
766 benchmark.Run();
767 }
768 }
OLDNEW
« no previous file with comments | « trunk/src/media/cast/receiver/video_decoder.cc ('k') | trunk/src/media/cast/test/fake_single_thread_task_runner.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698