cast_benchmarks.cc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  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. #include <math.h>
  24. #include <stddef.h>
  25. #include <stdint.h>
  26. #include <map>
  27. #include <memory>
  28. #include <utility>
  29. #include <vector>
  30. #include "base/at_exit.h"
  31. #include "base/bind.h"
  32. #include "base/callback_helpers.h"
  33. #include "base/command_line.h"
  34. #include "base/debug/profiler.h"
  35. #include "base/logging.h"
  36. #include "base/memory/ptr_util.h"
  37. #include "base/memory/raw_ptr.h"
  38. #include "base/memory/weak_ptr.h"
  39. #include "base/run_loop.h"
  40. #include "base/strings/string_number_conversions.h"
  41. #include "base/strings/stringprintf.h"
  42. #include "base/task/single_thread_task_runner.h"
  43. #include "base/test/simple_test_tick_clock.h"
  44. #include "base/threading/thread.h"
  45. #include "base/time/tick_clock.h"
  46. #include "base/time/time.h"
  47. #include "media/base/audio_bus.h"
  48. #include "media/base/fake_single_thread_task_runner.h"
  49. #include "media/base/video_frame.h"
  50. #include "media/cast/cast_config.h"
  51. #include "media/cast/cast_environment.h"
  52. #include "media/cast/cast_sender.h"
  53. #include "media/cast/common/encoded_frame.h"
  54. #include "media/cast/logging/simple_event_subscriber.h"
  55. #include "media/cast/net/cast_transport.h"
  56. #include "media/cast/net/cast_transport_config.h"
  57. #include "media/cast/net/cast_transport_defines.h"
  58. #include "media/cast/net/cast_transport_impl.h"
  59. #include "media/cast/test/loopback_transport.h"
  60. #include "media/cast/test/receiver/cast_receiver.h"
  61. #include "media/cast/test/skewed_single_thread_task_runner.h"
  62. #include "media/cast/test/skewed_tick_clock.h"
  63. #include "media/cast/test/utility/audio_utility.h"
  64. #include "media/cast/test/utility/default_config.h"
  65. #include "media/cast/test/utility/test_util.h"
  66. #include "media/cast/test/utility/udp_proxy.h"
  67. #include "media/cast/test/utility/video_utility.h"
  68. #include "testing/gtest/include/gtest/gtest.h"
  69. namespace media {
  70. namespace cast {
  71. namespace {
  72. static const int64_t kStartMillisecond = INT64_C(1245);
  73. static const int kTargetPlayoutDelayMs = 400;
  74. void ExpectVideoSuccess(OperationalStatus status) {
  75. EXPECT_EQ(STATUS_INITIALIZED, status);
  76. }
  77. void ExpectAudioSuccess(OperationalStatus status) {
  78. EXPECT_EQ(STATUS_INITIALIZED, status);
  79. }
  80. } // namespace
  81. // Wraps a CastTransport and records some statistics about
  82. // the data that goes through it.
  83. class CastTransportWrapper : public CastTransport {
  84. public:
  85. // Takes ownership of |transport|.
  86. void Init(CastTransport* transport,
  87. uint64_t* encoded_video_bytes,
  88. uint64_t* encoded_audio_bytes) {
  89. transport_.reset(transport);
  90. encoded_video_bytes_ = encoded_video_bytes;
  91. encoded_audio_bytes_ = encoded_audio_bytes;
  92. }
  93. void InitializeStream(const CastTransportRtpConfig& config,
  94. std::unique_ptr<RtcpObserver> rtcp_observer) final {
  95. if (config.rtp_payload_type <= RtpPayloadType::AUDIO_LAST)
  96. audio_ssrc_ = config.ssrc;
  97. else
  98. video_ssrc_ = config.ssrc;
  99. transport_->InitializeStream(config, std::move(rtcp_observer));
  100. }
  101. void InsertFrame(uint32_t ssrc, const EncodedFrame& frame) final {
  102. if (ssrc == audio_ssrc_) {
  103. *encoded_audio_bytes_ += frame.data.size();
  104. } else if (ssrc == video_ssrc_) {
  105. *encoded_video_bytes_ += frame.data.size();
  106. }
  107. transport_->InsertFrame(ssrc, frame);
  108. }
  109. void SendSenderReport(uint32_t ssrc,
  110. base::TimeTicks current_time,
  111. RtpTimeTicks current_time_as_rtp_timestamp) final {
  112. transport_->SendSenderReport(ssrc,
  113. current_time,
  114. current_time_as_rtp_timestamp);
  115. }
  116. void CancelSendingFrames(uint32_t ssrc,
  117. const std::vector<FrameId>& frame_ids) final {
  118. transport_->CancelSendingFrames(ssrc, frame_ids);
  119. }
  120. void ResendFrameForKickstart(uint32_t ssrc, FrameId frame_id) final {
  121. transport_->ResendFrameForKickstart(ssrc, frame_id);
  122. }
  123. PacketReceiverCallback PacketReceiverForTesting() final {
  124. return transport_->PacketReceiverForTesting();
  125. }
  126. void AddValidRtpReceiver(uint32_t rtp_sender_ssrc,
  127. uint32_t rtp_receiver_ssrc) final {
  128. return transport_->AddValidRtpReceiver(rtp_sender_ssrc, rtp_receiver_ssrc);
  129. }
  130. void InitializeRtpReceiverRtcpBuilder(uint32_t rtp_receiver_ssrc,
  131. const RtcpTimeData& time_data) final {
  132. transport_->InitializeRtpReceiverRtcpBuilder(rtp_receiver_ssrc, time_data);
  133. }
  134. void AddCastFeedback(const RtcpCastMessage& cast_message,
  135. base::TimeDelta target_delay) final {
  136. transport_->AddCastFeedback(cast_message, target_delay);
  137. }
  138. void AddRtcpEvents(
  139. const ReceiverRtcpEventSubscriber::RtcpEvents& rtcp_events) final {
  140. transport_->AddRtcpEvents(rtcp_events);
  141. }
  142. void AddRtpReceiverReport(const RtcpReportBlock& rtp_report_block) final {
  143. transport_->AddRtpReceiverReport(rtp_report_block);
  144. }
  145. void AddPli(const RtcpPliMessage& pli_message) final {
  146. transport_->AddPli(pli_message);
  147. }
  148. void SendRtcpFromRtpReceiver() final {
  149. transport_->SendRtcpFromRtpReceiver();
  150. }
  151. void SetOptions(const base::Value::Dict& options) final {}
  152. private:
  153. std::unique_ptr<CastTransport> transport_;
  154. uint32_t audio_ssrc_, video_ssrc_;
  155. raw_ptr<uint64_t> encoded_video_bytes_;
  156. raw_ptr<uint64_t> encoded_audio_bytes_;
  157. };
  158. struct MeasuringPoint {
  159. MeasuringPoint(double bitrate_, double latency_, double percent_packet_drop_)
  160. : bitrate(bitrate_),
  161. latency(latency_),
  162. percent_packet_drop(percent_packet_drop_) {}
  163. bool operator<=(const MeasuringPoint& other) const {
  164. return bitrate >= other.bitrate && latency <= other.latency &&
  165. percent_packet_drop <= other.percent_packet_drop;
  166. }
  167. bool operator>=(const MeasuringPoint& other) const {
  168. return bitrate <= other.bitrate && latency >= other.latency &&
  169. percent_packet_drop >= other.percent_packet_drop;
  170. }
  171. std::string AsString() const {
  172. return base::StringPrintf(
  173. "%f Mbit/s %f ms %f %% ", bitrate, latency, percent_packet_drop);
  174. }
  175. double bitrate;
  176. double latency;
  177. double percent_packet_drop;
  178. };
  179. class RunOneBenchmark {
  180. public:
  181. RunOneBenchmark()
  182. : start_time_(),
  183. task_runner_(new FakeSingleThreadTaskRunner(&testing_clock_)),
  184. testing_clock_sender_(&testing_clock_),
  185. task_runner_sender_(
  186. new test::SkewedSingleThreadTaskRunner(task_runner_)),
  187. testing_clock_receiver_(&testing_clock_),
  188. task_runner_receiver_(
  189. new test::SkewedSingleThreadTaskRunner(task_runner_)),
  190. cast_environment_sender_(new CastEnvironment(&testing_clock_sender_,
  191. task_runner_sender_,
  192. task_runner_sender_,
  193. task_runner_sender_)),
  194. cast_environment_receiver_(new CastEnvironment(&testing_clock_receiver_,
  195. task_runner_receiver_,
  196. task_runner_receiver_,
  197. task_runner_receiver_)),
  198. video_bytes_encoded_(0),
  199. audio_bytes_encoded_(0),
  200. frames_sent_(0) {
  201. testing_clock_.Advance(base::Milliseconds(kStartMillisecond));
  202. }
  203. void Configure(Codec video_codec,
  204. Codec audio_codec) {
  205. audio_sender_config_ = GetDefaultAudioSenderConfig();
  206. audio_sender_config_.min_playout_delay =
  207. audio_sender_config_.max_playout_delay =
  208. base::Milliseconds(kTargetPlayoutDelayMs);
  209. audio_sender_config_.codec = audio_codec;
  210. audio_receiver_config_ = GetDefaultAudioReceiverConfig();
  211. audio_receiver_config_.rtp_max_delay_ms =
  212. audio_sender_config_.max_playout_delay.InMicroseconds();
  213. audio_receiver_config_.codec = audio_codec;
  214. video_sender_config_ = GetDefaultVideoSenderConfig();
  215. video_sender_config_.min_playout_delay =
  216. video_sender_config_.max_playout_delay =
  217. base::Milliseconds(kTargetPlayoutDelayMs);
  218. video_sender_config_.max_bitrate = 4000000;
  219. video_sender_config_.min_bitrate = 4000000;
  220. video_sender_config_.start_bitrate = 4000000;
  221. video_sender_config_.codec = video_codec;
  222. video_receiver_config_ = GetDefaultVideoReceiverConfig();
  223. video_receiver_config_.rtp_max_delay_ms = kTargetPlayoutDelayMs;
  224. video_receiver_config_.codec = video_codec;
  225. DCHECK_GT(video_sender_config_.max_frame_rate, 0);
  226. frame_duration_ = base::Seconds(1.0 / video_sender_config_.max_frame_rate);
  227. }
  228. void SetSenderClockSkew(double skew, base::TimeDelta offset) {
  229. testing_clock_sender_.SetSkew(skew, offset);
  230. task_runner_sender_->SetSkew(1.0 / skew);
  231. }
  232. void SetReceiverClockSkew(double skew, base::TimeDelta offset) {
  233. testing_clock_receiver_.SetSkew(skew, offset);
  234. task_runner_receiver_->SetSkew(1.0 / skew);
  235. }
  236. void Create(const MeasuringPoint& p);
  237. void ReceivePacket(std::unique_ptr<Packet> packet) {
  238. cast_receiver_->ReceivePacket(std::move(packet));
  239. }
  240. virtual ~RunOneBenchmark() {
  241. cast_sender_.reset();
  242. cast_receiver_.reset();
  243. task_runner_->RunTasks();
  244. }
  245. base::TimeDelta VideoTimestamp(int frame_number) {
  246. return frame_number *
  247. base::Seconds(1.0 / video_sender_config_.max_frame_rate);
  248. }
  249. void SendFakeVideoFrame() {
  250. // NB: Blackframe with timestamp
  251. cast_sender_->video_frame_input()->InsertRawVideoFrame(
  252. media::VideoFrame::CreateColorFrame(gfx::Size(2, 2), 0x00, 0x80, 0x80,
  253. VideoTimestamp(frames_sent_)),
  254. testing_clock_sender_.NowTicks());
  255. frames_sent_++;
  256. }
  257. void RunTasks(base::TimeDelta duration) {
  258. task_runner_->Sleep(duration);
  259. }
  260. void BasicPlayerGotVideoFrame(scoped_refptr<media::VideoFrame> video_frame,
  261. base::TimeTicks render_time,
  262. bool continuous) {
  263. video_ticks_.push_back(
  264. std::make_pair(testing_clock_receiver_.NowTicks(), render_time));
  265. cast_receiver_->RequestDecodedVideoFrame(base::BindRepeating(
  266. &RunOneBenchmark::BasicPlayerGotVideoFrame, base::Unretained(this)));
  267. }
  268. void BasicPlayerGotAudioFrame(std::unique_ptr<AudioBus> audio_bus,
  269. base::TimeTicks playout_time,
  270. bool is_continuous) {
  271. audio_ticks_.push_back(
  272. std::make_pair(testing_clock_receiver_.NowTicks(), playout_time));
  273. cast_receiver_->RequestDecodedAudioFrame(base::BindRepeating(
  274. &RunOneBenchmark::BasicPlayerGotAudioFrame, base::Unretained(this)));
  275. }
  276. void StartBasicPlayer() {
  277. cast_receiver_->RequestDecodedVideoFrame(base::BindRepeating(
  278. &RunOneBenchmark::BasicPlayerGotVideoFrame, base::Unretained(this)));
  279. cast_receiver_->RequestDecodedAudioFrame(base::BindRepeating(
  280. &RunOneBenchmark::BasicPlayerGotAudioFrame, base::Unretained(this)));
  281. }
  282. std::unique_ptr<test::PacketPipe> CreateSimplePipe(const MeasuringPoint& p) {
  283. std::unique_ptr<test::PacketPipe> pipe = test::NewBuffer(65536, p.bitrate);
  284. pipe->AppendToPipe(test::NewRandomDrop(p.percent_packet_drop / 100.0));
  285. pipe->AppendToPipe(test::NewConstantDelay(p.latency / 1000.0));
  286. return pipe;
  287. }
  288. void Run(const MeasuringPoint& p) {
  289. available_bitrate_ = p.bitrate;
  290. Configure(CODEC_VIDEO_FAKE, CODEC_AUDIO_PCM16);
  291. Create(p);
  292. StartBasicPlayer();
  293. for (int frame = 0; frame < 1000; frame++) {
  294. SendFakeVideoFrame();
  295. RunTasks(frame_duration_);
  296. }
  297. RunTasks(100 * frame_duration_); // Empty the pipeline.
  298. VLOG(1) << "=============INPUTS============";
  299. VLOG(1) << "Bitrate: " << p.bitrate << " mbit/s";
  300. VLOG(1) << "Latency: " << p.latency << " ms";
  301. VLOG(1) << "Packet drop drop: " << p.percent_packet_drop << "%";
  302. VLOG(1) << "=============OUTPUTS============";
  303. VLOG(1) << "Frames lost: " << frames_lost();
  304. VLOG(1) << "Late frames: " << late_frames();
  305. VLOG(1) << "Playout margin: " << frame_playout_buffer().AsString();
  306. VLOG(1) << "Video bandwidth used: " << video_bandwidth() << " mbit/s ("
  307. << (video_bandwidth() * 100 / desired_video_bitrate()) << "%)";
  308. VLOG(1) << "Good run: " << SimpleGood();
  309. }
  310. // Metrics
  311. int frames_lost() const { return frames_sent_ - video_ticks_.size(); }
  312. int late_frames() const {
  313. int frames = 0;
  314. // Ignore the first two seconds of video or so.
  315. for (size_t i = 60; i < video_ticks_.size(); i++) {
  316. if (video_ticks_[i].first > video_ticks_[i].second) {
  317. frames++;
  318. }
  319. }
  320. return frames;
  321. }
  322. test::MeanAndError frame_playout_buffer() const {
  323. std::vector<double> values;
  324. for (size_t i = 0; i < video_ticks_.size(); i++) {
  325. values.push_back(
  326. (video_ticks_[i].second - video_ticks_[i].first).InMillisecondsF());
  327. }
  328. return test::MeanAndError(values);
  329. }
  330. // Mbits per second
  331. double video_bandwidth() const {
  332. double seconds = (frame_duration_.InSecondsF() * frames_sent_);
  333. double megabits = video_bytes_encoded_ * 8 / 1000000.0;
  334. return megabits / seconds;
  335. }
  336. // Mbits per second
  337. double audio_bandwidth() const {
  338. double seconds = (frame_duration_.InSecondsF() * frames_sent_);
  339. double megabits = audio_bytes_encoded_ * 8 / 1000000.0;
  340. return megabits / seconds;
  341. }
  342. double desired_video_bitrate() {
  343. return std::min<double>(available_bitrate_,
  344. video_sender_config_.max_bitrate / 1000000.0);
  345. }
  346. bool SimpleGood() {
  347. return frames_lost() <= 1 && late_frames() <= 1 &&
  348. video_bandwidth() > desired_video_bitrate() * 0.8 &&
  349. video_bandwidth() < desired_video_bitrate() * 1.2;
  350. }
  351. private:
  352. FrameReceiverConfig audio_receiver_config_;
  353. FrameReceiverConfig video_receiver_config_;
  354. FrameSenderConfig audio_sender_config_;
  355. FrameSenderConfig video_sender_config_;
  356. base::TimeTicks start_time_;
  357. // These run in "test time"
  358. base::SimpleTestTickClock testing_clock_;
  359. scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;
  360. // These run on the sender timeline.
  361. test::SkewedTickClock testing_clock_sender_;
  362. scoped_refptr<test::SkewedSingleThreadTaskRunner> task_runner_sender_;
  363. // These run on the receiver timeline.
  364. test::SkewedTickClock testing_clock_receiver_;
  365. scoped_refptr<test::SkewedSingleThreadTaskRunner> task_runner_receiver_;
  366. scoped_refptr<CastEnvironment> cast_environment_sender_;
  367. scoped_refptr<CastEnvironment> cast_environment_receiver_;
  368. raw_ptr<LoopBackTransport>
  369. receiver_to_sender_; // Owned by CastTransportImpl.
  370. raw_ptr<LoopBackTransport>
  371. sender_to_receiver_; // Owned by CastTransportImpl.
  372. CastTransportWrapper transport_sender_;
  373. std::unique_ptr<CastTransport> transport_receiver_;
  374. uint64_t video_bytes_encoded_;
  375. uint64_t audio_bytes_encoded_;
  376. std::unique_ptr<CastReceiver> cast_receiver_;
  377. std::unique_ptr<CastSender> cast_sender_;
  378. int frames_sent_;
  379. base::TimeDelta frame_duration_;
  380. double available_bitrate_;
  381. std::vector<std::pair<base::TimeTicks, base::TimeTicks> > audio_ticks_;
  382. std::vector<std::pair<base::TimeTicks, base::TimeTicks> > video_ticks_;
  383. };
  384. namespace {
  385. class TransportClient : public CastTransport::Client {
  386. public:
  387. explicit TransportClient(RunOneBenchmark* run_one_benchmark)
  388. : run_one_benchmark_(run_one_benchmark) {}
  389. TransportClient(const TransportClient&) = delete;
  390. TransportClient& operator=(const TransportClient&) = delete;
  391. void OnStatusChanged(CastTransportStatus status) final {
  392. EXPECT_EQ(TRANSPORT_STREAM_INITIALIZED, status);
  393. }
  394. void OnLoggingEventsReceived(
  395. std::unique_ptr<std::vector<FrameEvent>> frame_events,
  396. std::unique_ptr<std::vector<PacketEvent>> packet_events) final {}
  397. void ProcessRtpPacket(std::unique_ptr<Packet> packet) final {
  398. if (run_one_benchmark_)
  399. run_one_benchmark_->ReceivePacket(std::move(packet));
  400. }
  401. private:
  402. const raw_ptr<RunOneBenchmark> run_one_benchmark_;
  403. };
  404. } // namespace
  405. void RunOneBenchmark::Create(const MeasuringPoint& p) {
  406. sender_to_receiver_ = new LoopBackTransport(cast_environment_sender_);
  407. transport_sender_.Init(
  408. new CastTransportImpl(&testing_clock_sender_, base::Seconds(1),
  409. std::make_unique<TransportClient>(nullptr),
  410. base::WrapUnique(sender_to_receiver_.get()),
  411. task_runner_sender_),
  412. &video_bytes_encoded_, &audio_bytes_encoded_);
  413. receiver_to_sender_ = new LoopBackTransport(cast_environment_receiver_);
  414. transport_receiver_ = std::make_unique<CastTransportImpl>(
  415. &testing_clock_receiver_, base::Seconds(1),
  416. std::make_unique<TransportClient>(this),
  417. base::WrapUnique(receiver_to_sender_.get()), task_runner_receiver_);
  418. cast_receiver_ =
  419. CastReceiver::Create(cast_environment_receiver_, audio_receiver_config_,
  420. video_receiver_config_, transport_receiver_.get());
  421. cast_sender_ =
  422. CastSender::Create(cast_environment_sender_, &transport_sender_);
  423. cast_sender_->InitializeAudio(audio_sender_config_,
  424. base::BindOnce(&ExpectAudioSuccess));
  425. cast_sender_->InitializeVideo(video_sender_config_,
  426. base::BindRepeating(&ExpectVideoSuccess),
  427. base::DoNothing());
  428. receiver_to_sender_->Initialize(CreateSimplePipe(p),
  429. transport_sender_.PacketReceiverForTesting(),
  430. task_runner_, &testing_clock_);
  431. sender_to_receiver_->Initialize(
  432. CreateSimplePipe(p), transport_receiver_->PacketReceiverForTesting(),
  433. task_runner_, &testing_clock_);
  434. task_runner_->RunTasks();
  435. }
  436. enum CacheResult { FOUND_TRUE, FOUND_FALSE, NOT_FOUND };
  437. template <class T>
  438. class BenchmarkCache {
  439. public:
  440. CacheResult Lookup(const T& x) {
  441. base::AutoLock key(lock_);
  442. for (size_t i = 0; i < results_.size(); i++) {
  443. if (results_[i].second) {
  444. if (x <= results_[i].first) {
  445. VLOG(2) << "TRUE because: " << x.AsString()
  446. << " <= " << results_[i].first.AsString();
  447. return FOUND_TRUE;
  448. }
  449. } else {
  450. if (x >= results_[i].first) {
  451. VLOG(2) << "FALSE because: " << x.AsString()
  452. << " >= " << results_[i].first.AsString();
  453. return FOUND_FALSE;
  454. }
  455. }
  456. }
  457. return NOT_FOUND;
  458. }
  459. void Add(const T& x, bool result) {
  460. base::AutoLock key(lock_);
  461. VLOG(2) << "Cache Insert: " << x.AsString() << " = " << result;
  462. results_.push_back(std::make_pair(x, result));
  463. }
  464. private:
  465. base::Lock lock_;
  466. std::vector<std::pair<T, bool> > results_;
  467. };
  468. struct SearchVariable {
  469. SearchVariable() : base(0.0), grade(0.0) {}
  470. SearchVariable(double b, double g) : base(b), grade(g) {}
  471. SearchVariable blend(const SearchVariable& other, double factor) {
  472. CHECK_GE(factor, 0);
  473. CHECK_LE(factor, 1.0);
  474. return SearchVariable(base * (1 - factor) + other.base * factor,
  475. grade * (1 - factor) + other.grade * factor);
  476. }
  477. double value(double x) const { return base + grade * x; }
  478. double base;
  479. double grade;
  480. };
  481. struct SearchVector {
  482. SearchVector blend(const SearchVector& other, double factor) {
  483. SearchVector ret;
  484. ret.bitrate = bitrate.blend(other.bitrate, factor);
  485. ret.latency = latency.blend(other.latency, factor);
  486. ret.packet_drop = packet_drop.blend(other.packet_drop, factor);
  487. return ret;
  488. }
  489. SearchVector average(const SearchVector& other) {
  490. return blend(other, 0.5);
  491. }
  492. MeasuringPoint GetMeasuringPoint(double v) const {
  493. return MeasuringPoint(
  494. bitrate.value(-v), latency.value(v), packet_drop.value(v));
  495. }
  496. std::string AsString(double v) { return GetMeasuringPoint(v).AsString(); }
  497. SearchVariable bitrate;
  498. SearchVariable latency;
  499. SearchVariable packet_drop;
  500. };
  501. class CastBenchmark {
  502. public:
  503. bool RunOnePoint(const SearchVector& v, double multiplier) {
  504. MeasuringPoint p = v.GetMeasuringPoint(multiplier);
  505. VLOG(1) << "RUN: v = " << multiplier << " p = " << p.AsString();
  506. if (p.bitrate <= 0) {
  507. return false;
  508. }
  509. switch (cache_.Lookup(p)) {
  510. case FOUND_TRUE:
  511. return true;
  512. case FOUND_FALSE:
  513. return false;
  514. case NOT_FOUND:
  515. // Keep going
  516. break;
  517. }
  518. bool result = true;
  519. for (int tries = 0; tries < 3 && result; tries++) {
  520. RunOneBenchmark benchmark;
  521. benchmark.Run(p);
  522. result &= benchmark.SimpleGood();
  523. }
  524. cache_.Add(p, result);
  525. return result;
  526. }
  527. void BinarySearch(SearchVector v, double accuracy) {
  528. double min = 0.0;
  529. double max = 1.0;
  530. while (RunOnePoint(v, max)) {
  531. min = max;
  532. max *= 2;
  533. }
  534. while (max - min > accuracy) {
  535. double avg = (min + max) / 2;
  536. if (RunOnePoint(v, avg)) {
  537. min = avg;
  538. } else {
  539. max = avg;
  540. }
  541. }
  542. // Print a data point to stdout.
  543. base::AutoLock key(lock_);
  544. MeasuringPoint p = v.GetMeasuringPoint(min);
  545. fprintf(stdout, "%f %f %f\n", p.bitrate, p.latency, p.percent_packet_drop);
  546. fflush(stdout);
  547. }
  548. void SpanningSearch(int max,
  549. int x,
  550. int y,
  551. int skip,
  552. SearchVector a,
  553. SearchVector b,
  554. SearchVector c,
  555. double accuracy,
  556. std::vector<std::unique_ptr<base::Thread>>* threads) {
  557. static int thread_num = 0;
  558. if (x > max) return;
  559. if (skip > max) {
  560. if (y > x) return;
  561. SearchVector ab = a.blend(b, static_cast<double>(x) / max);
  562. SearchVector ac = a.blend(c, static_cast<double>(x) / max);
  563. SearchVector v = ab.blend(ac, x == y ? 1.0 : static_cast<double>(y) / x);
  564. thread_num++;
  565. (*threads)[thread_num % threads->size()]->task_runner()->PostTask(
  566. FROM_HERE, base::BindOnce(&CastBenchmark::BinarySearch,
  567. base::Unretained(this), v, accuracy));
  568. } else {
  569. skip *= 2;
  570. SpanningSearch(max, x, y, skip, a, b, c, accuracy, threads);
  571. SpanningSearch(max, x + skip, y + skip, skip, a, b, c, accuracy, threads);
  572. SpanningSearch(max, x + skip, y, skip, a, b, c, accuracy, threads);
  573. SpanningSearch(max, x, y + skip, skip, a, b, c, accuracy, threads);
  574. }
  575. }
  576. void Run() {
  577. // Spanning search.
  578. std::vector<std::unique_ptr<base::Thread>> threads;
  579. for (int i = 0; i < 16; i++) {
  580. threads.push_back(std::make_unique<base::Thread>(
  581. base::StringPrintf("cast_bench_thread_%d", i)));
  582. threads[i]->Start();
  583. }
  584. if (base::CommandLine::ForCurrentProcess()->HasSwitch("single-run")) {
  585. SearchVector a;
  586. a.bitrate.base = 100.0;
  587. a.bitrate.grade = 1.0;
  588. a.latency.grade = 1.0;
  589. a.packet_drop.grade = 1.0;
  590. threads[0]->task_runner()->PostTask(
  591. FROM_HERE,
  592. base::BindOnce(base::IgnoreResult(&CastBenchmark::RunOnePoint),
  593. base::Unretained(this), a, 1.0));
  594. } else {
  595. SearchVector a, b, c;
  596. a.bitrate.base = b.bitrate.base = c.bitrate.base = 100.0;
  597. a.bitrate.grade = 1.0;
  598. b.latency.grade = 1.0;
  599. c.packet_drop.grade = 1.0;
  600. SpanningSearch(512,
  601. 0,
  602. 0,
  603. 1,
  604. a,
  605. b,
  606. c,
  607. 0.01,
  608. &threads);
  609. }
  610. for (size_t i = 0; i < threads.size(); i++) {
  611. threads[i]->Stop();
  612. }
  613. }
  614. private:
  615. BenchmarkCache<MeasuringPoint> cache_;
  616. base::Lock lock_;
  617. };
  618. } // namespace cast
  619. } // namespace media
  620. int main(int argc, char** argv) {
  621. base::AtExitManager at_exit;
  622. base::CommandLine::Init(argc, argv);
  623. media::cast::CastBenchmark benchmark;
  624. if (getenv("PROFILE_FILE")) {
  625. std::string profile_file(getenv("PROFILE_FILE"));
  626. base::debug::StartProfiling(profile_file);
  627. benchmark.Run();
  628. base::debug::StopProfiling();
  629. } else {
  630. benchmark.Run();
  631. }
  632. }