123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731 |
- // Copyright 2014 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- //
- // This program benchmarks the theoretical throughput of the cast library.
- // It runs using a fake clock, simulated network and fake codecs. This allows
- // tests to run much faster than real time.
- // To run the program, run:
- // $ ./out/Release/cast_benchmarks | tee benchmarkoutput.asc
- // This may take a while, when it is done, you can view the data with
- // meshlab by running:
- // $ meshlab benchmarkoutput.asc
- // After starting meshlab, turn on Render->Show Axis. The red axis will
- // represent bandwidth (in megabits) the blue axis will be packet drop
- // (in percent) and the green axis will be latency (in milliseconds).
- //
- // This program can also be used for profiling. On linux it has
- // built-in support for this. Simply set the environment variable
- // PROFILE_FILE before running it, like so:
- // $ export PROFILE_FILE=cast_benchmark.profile
- // Then after running the program, you can view the profile with:
- // $ pprof ./out/Release/cast_benchmarks $PROFILE_FILE --gv
- #include <math.h>
- #include <stddef.h>
- #include <stdint.h>
- #include <map>
- #include <memory>
- #include <utility>
- #include <vector>
- #include "base/at_exit.h"
- #include "base/bind.h"
- #include "base/callback_helpers.h"
- #include "base/command_line.h"
- #include "base/debug/profiler.h"
- #include "base/logging.h"
- #include "base/memory/ptr_util.h"
- #include "base/memory/raw_ptr.h"
- #include "base/memory/weak_ptr.h"
- #include "base/run_loop.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/stringprintf.h"
- #include "base/task/single_thread_task_runner.h"
- #include "base/test/simple_test_tick_clock.h"
- #include "base/threading/thread.h"
- #include "base/time/tick_clock.h"
- #include "base/time/time.h"
- #include "media/base/audio_bus.h"
- #include "media/base/fake_single_thread_task_runner.h"
- #include "media/base/video_frame.h"
- #include "media/cast/cast_config.h"
- #include "media/cast/cast_environment.h"
- #include "media/cast/cast_sender.h"
- #include "media/cast/common/encoded_frame.h"
- #include "media/cast/logging/simple_event_subscriber.h"
- #include "media/cast/net/cast_transport.h"
- #include "media/cast/net/cast_transport_config.h"
- #include "media/cast/net/cast_transport_defines.h"
- #include "media/cast/net/cast_transport_impl.h"
- #include "media/cast/test/loopback_transport.h"
- #include "media/cast/test/receiver/cast_receiver.h"
- #include "media/cast/test/skewed_single_thread_task_runner.h"
- #include "media/cast/test/skewed_tick_clock.h"
- #include "media/cast/test/utility/audio_utility.h"
- #include "media/cast/test/utility/default_config.h"
- #include "media/cast/test/utility/test_util.h"
- #include "media/cast/test/utility/udp_proxy.h"
- #include "media/cast/test/utility/video_utility.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace media {
- namespace cast {
- namespace {
- static const int64_t kStartMillisecond = INT64_C(1245);
- static const int kTargetPlayoutDelayMs = 400;
- void ExpectVideoSuccess(OperationalStatus status) {
- EXPECT_EQ(STATUS_INITIALIZED, status);
- }
- void ExpectAudioSuccess(OperationalStatus status) {
- EXPECT_EQ(STATUS_INITIALIZED, status);
- }
- } // namespace
- // Wraps a CastTransport and records some statistics about
- // the data that goes through it.
- class CastTransportWrapper : public CastTransport {
- public:
- // Takes ownership of |transport|.
- void Init(CastTransport* transport,
- uint64_t* encoded_video_bytes,
- uint64_t* encoded_audio_bytes) {
- transport_.reset(transport);
- encoded_video_bytes_ = encoded_video_bytes;
- encoded_audio_bytes_ = encoded_audio_bytes;
- }
- void InitializeStream(const CastTransportRtpConfig& config,
- std::unique_ptr<RtcpObserver> rtcp_observer) final {
- if (config.rtp_payload_type <= RtpPayloadType::AUDIO_LAST)
- audio_ssrc_ = config.ssrc;
- else
- video_ssrc_ = config.ssrc;
- transport_->InitializeStream(config, std::move(rtcp_observer));
- }
- void InsertFrame(uint32_t ssrc, const EncodedFrame& frame) final {
- if (ssrc == audio_ssrc_) {
- *encoded_audio_bytes_ += frame.data.size();
- } else if (ssrc == video_ssrc_) {
- *encoded_video_bytes_ += frame.data.size();
- }
- transport_->InsertFrame(ssrc, frame);
- }
- void SendSenderReport(uint32_t ssrc,
- base::TimeTicks current_time,
- RtpTimeTicks current_time_as_rtp_timestamp) final {
- transport_->SendSenderReport(ssrc,
- current_time,
- current_time_as_rtp_timestamp);
- }
- void CancelSendingFrames(uint32_t ssrc,
- const std::vector<FrameId>& frame_ids) final {
- transport_->CancelSendingFrames(ssrc, frame_ids);
- }
- void ResendFrameForKickstart(uint32_t ssrc, FrameId frame_id) final {
- transport_->ResendFrameForKickstart(ssrc, frame_id);
- }
- PacketReceiverCallback PacketReceiverForTesting() final {
- return transport_->PacketReceiverForTesting();
- }
- void AddValidRtpReceiver(uint32_t rtp_sender_ssrc,
- uint32_t rtp_receiver_ssrc) final {
- return transport_->AddValidRtpReceiver(rtp_sender_ssrc, rtp_receiver_ssrc);
- }
- void InitializeRtpReceiverRtcpBuilder(uint32_t rtp_receiver_ssrc,
- const RtcpTimeData& time_data) final {
- transport_->InitializeRtpReceiverRtcpBuilder(rtp_receiver_ssrc, time_data);
- }
- void AddCastFeedback(const RtcpCastMessage& cast_message,
- base::TimeDelta target_delay) final {
- transport_->AddCastFeedback(cast_message, target_delay);
- }
- void AddRtcpEvents(
- const ReceiverRtcpEventSubscriber::RtcpEvents& rtcp_events) final {
- transport_->AddRtcpEvents(rtcp_events);
- }
- void AddRtpReceiverReport(const RtcpReportBlock& rtp_report_block) final {
- transport_->AddRtpReceiverReport(rtp_report_block);
- }
- void AddPli(const RtcpPliMessage& pli_message) final {
- transport_->AddPli(pli_message);
- }
- void SendRtcpFromRtpReceiver() final {
- transport_->SendRtcpFromRtpReceiver();
- }
- void SetOptions(const base::Value::Dict& options) final {}
- private:
- std::unique_ptr<CastTransport> transport_;
- uint32_t audio_ssrc_, video_ssrc_;
- raw_ptr<uint64_t> encoded_video_bytes_;
- raw_ptr<uint64_t> encoded_audio_bytes_;
- };
- struct MeasuringPoint {
- MeasuringPoint(double bitrate_, double latency_, double percent_packet_drop_)
- : bitrate(bitrate_),
- latency(latency_),
- percent_packet_drop(percent_packet_drop_) {}
- bool operator<=(const MeasuringPoint& other) const {
- return bitrate >= other.bitrate && latency <= other.latency &&
- percent_packet_drop <= other.percent_packet_drop;
- }
- bool operator>=(const MeasuringPoint& other) const {
- return bitrate <= other.bitrate && latency >= other.latency &&
- percent_packet_drop >= other.percent_packet_drop;
- }
- std::string AsString() const {
- return base::StringPrintf(
- "%f Mbit/s %f ms %f %% ", bitrate, latency, percent_packet_drop);
- }
- double bitrate;
- double latency;
- double percent_packet_drop;
- };
- class RunOneBenchmark {
- public:
- RunOneBenchmark()
- : start_time_(),
- task_runner_(new FakeSingleThreadTaskRunner(&testing_clock_)),
- testing_clock_sender_(&testing_clock_),
- task_runner_sender_(
- new test::SkewedSingleThreadTaskRunner(task_runner_)),
- testing_clock_receiver_(&testing_clock_),
- task_runner_receiver_(
- new test::SkewedSingleThreadTaskRunner(task_runner_)),
- cast_environment_sender_(new CastEnvironment(&testing_clock_sender_,
- task_runner_sender_,
- task_runner_sender_,
- task_runner_sender_)),
- cast_environment_receiver_(new CastEnvironment(&testing_clock_receiver_,
- task_runner_receiver_,
- task_runner_receiver_,
- task_runner_receiver_)),
- video_bytes_encoded_(0),
- audio_bytes_encoded_(0),
- frames_sent_(0) {
- testing_clock_.Advance(base::Milliseconds(kStartMillisecond));
- }
- void Configure(Codec video_codec,
- Codec audio_codec) {
- audio_sender_config_ = GetDefaultAudioSenderConfig();
- audio_sender_config_.min_playout_delay =
- audio_sender_config_.max_playout_delay =
- base::Milliseconds(kTargetPlayoutDelayMs);
- audio_sender_config_.codec = audio_codec;
- audio_receiver_config_ = GetDefaultAudioReceiverConfig();
- audio_receiver_config_.rtp_max_delay_ms =
- audio_sender_config_.max_playout_delay.InMicroseconds();
- audio_receiver_config_.codec = audio_codec;
- video_sender_config_ = GetDefaultVideoSenderConfig();
- video_sender_config_.min_playout_delay =
- video_sender_config_.max_playout_delay =
- base::Milliseconds(kTargetPlayoutDelayMs);
- video_sender_config_.max_bitrate = 4000000;
- video_sender_config_.min_bitrate = 4000000;
- video_sender_config_.start_bitrate = 4000000;
- video_sender_config_.codec = video_codec;
- video_receiver_config_ = GetDefaultVideoReceiverConfig();
- video_receiver_config_.rtp_max_delay_ms = kTargetPlayoutDelayMs;
- video_receiver_config_.codec = video_codec;
- DCHECK_GT(video_sender_config_.max_frame_rate, 0);
- frame_duration_ = base::Seconds(1.0 / video_sender_config_.max_frame_rate);
- }
- void SetSenderClockSkew(double skew, base::TimeDelta offset) {
- testing_clock_sender_.SetSkew(skew, offset);
- task_runner_sender_->SetSkew(1.0 / skew);
- }
- void SetReceiverClockSkew(double skew, base::TimeDelta offset) {
- testing_clock_receiver_.SetSkew(skew, offset);
- task_runner_receiver_->SetSkew(1.0 / skew);
- }
- void Create(const MeasuringPoint& p);
- void ReceivePacket(std::unique_ptr<Packet> packet) {
- cast_receiver_->ReceivePacket(std::move(packet));
- }
- virtual ~RunOneBenchmark() {
- cast_sender_.reset();
- cast_receiver_.reset();
- task_runner_->RunTasks();
- }
- base::TimeDelta VideoTimestamp(int frame_number) {
- return frame_number *
- base::Seconds(1.0 / video_sender_config_.max_frame_rate);
- }
- void SendFakeVideoFrame() {
- // NB: Blackframe with timestamp
- cast_sender_->video_frame_input()->InsertRawVideoFrame(
- media::VideoFrame::CreateColorFrame(gfx::Size(2, 2), 0x00, 0x80, 0x80,
- VideoTimestamp(frames_sent_)),
- testing_clock_sender_.NowTicks());
- frames_sent_++;
- }
- void RunTasks(base::TimeDelta duration) {
- task_runner_->Sleep(duration);
- }
- void BasicPlayerGotVideoFrame(scoped_refptr<media::VideoFrame> video_frame,
- base::TimeTicks render_time,
- bool continuous) {
- video_ticks_.push_back(
- std::make_pair(testing_clock_receiver_.NowTicks(), render_time));
- cast_receiver_->RequestDecodedVideoFrame(base::BindRepeating(
- &RunOneBenchmark::BasicPlayerGotVideoFrame, base::Unretained(this)));
- }
- void BasicPlayerGotAudioFrame(std::unique_ptr<AudioBus> audio_bus,
- base::TimeTicks playout_time,
- bool is_continuous) {
- audio_ticks_.push_back(
- std::make_pair(testing_clock_receiver_.NowTicks(), playout_time));
- cast_receiver_->RequestDecodedAudioFrame(base::BindRepeating(
- &RunOneBenchmark::BasicPlayerGotAudioFrame, base::Unretained(this)));
- }
- void StartBasicPlayer() {
- cast_receiver_->RequestDecodedVideoFrame(base::BindRepeating(
- &RunOneBenchmark::BasicPlayerGotVideoFrame, base::Unretained(this)));
- cast_receiver_->RequestDecodedAudioFrame(base::BindRepeating(
- &RunOneBenchmark::BasicPlayerGotAudioFrame, base::Unretained(this)));
- }
- std::unique_ptr<test::PacketPipe> CreateSimplePipe(const MeasuringPoint& p) {
- std::unique_ptr<test::PacketPipe> pipe = test::NewBuffer(65536, p.bitrate);
- pipe->AppendToPipe(test::NewRandomDrop(p.percent_packet_drop / 100.0));
- pipe->AppendToPipe(test::NewConstantDelay(p.latency / 1000.0));
- return pipe;
- }
- void Run(const MeasuringPoint& p) {
- available_bitrate_ = p.bitrate;
- Configure(CODEC_VIDEO_FAKE, CODEC_AUDIO_PCM16);
- Create(p);
- StartBasicPlayer();
- for (int frame = 0; frame < 1000; frame++) {
- SendFakeVideoFrame();
- RunTasks(frame_duration_);
- }
- RunTasks(100 * frame_duration_); // Empty the pipeline.
- VLOG(1) << "=============INPUTS============";
- VLOG(1) << "Bitrate: " << p.bitrate << " mbit/s";
- VLOG(1) << "Latency: " << p.latency << " ms";
- VLOG(1) << "Packet drop drop: " << p.percent_packet_drop << "%";
- VLOG(1) << "=============OUTPUTS============";
- VLOG(1) << "Frames lost: " << frames_lost();
- VLOG(1) << "Late frames: " << late_frames();
- VLOG(1) << "Playout margin: " << frame_playout_buffer().AsString();
- VLOG(1) << "Video bandwidth used: " << video_bandwidth() << " mbit/s ("
- << (video_bandwidth() * 100 / desired_video_bitrate()) << "%)";
- VLOG(1) << "Good run: " << SimpleGood();
- }
- // Metrics
- int frames_lost() const { return frames_sent_ - video_ticks_.size(); }
- int late_frames() const {
- int frames = 0;
- // Ignore the first two seconds of video or so.
- for (size_t i = 60; i < video_ticks_.size(); i++) {
- if (video_ticks_[i].first > video_ticks_[i].second) {
- frames++;
- }
- }
- return frames;
- }
- test::MeanAndError frame_playout_buffer() const {
- std::vector<double> values;
- for (size_t i = 0; i < video_ticks_.size(); i++) {
- values.push_back(
- (video_ticks_[i].second - video_ticks_[i].first).InMillisecondsF());
- }
- return test::MeanAndError(values);
- }
- // Mbits per second
- double video_bandwidth() const {
- double seconds = (frame_duration_.InSecondsF() * frames_sent_);
- double megabits = video_bytes_encoded_ * 8 / 1000000.0;
- return megabits / seconds;
- }
- // Mbits per second
- double audio_bandwidth() const {
- double seconds = (frame_duration_.InSecondsF() * frames_sent_);
- double megabits = audio_bytes_encoded_ * 8 / 1000000.0;
- return megabits / seconds;
- }
- double desired_video_bitrate() {
- return std::min<double>(available_bitrate_,
- video_sender_config_.max_bitrate / 1000000.0);
- }
- bool SimpleGood() {
- return frames_lost() <= 1 && late_frames() <= 1 &&
- video_bandwidth() > desired_video_bitrate() * 0.8 &&
- video_bandwidth() < desired_video_bitrate() * 1.2;
- }
- private:
- FrameReceiverConfig audio_receiver_config_;
- FrameReceiverConfig video_receiver_config_;
- FrameSenderConfig audio_sender_config_;
- FrameSenderConfig video_sender_config_;
- base::TimeTicks start_time_;
- // These run in "test time"
- base::SimpleTestTickClock testing_clock_;
- scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;
- // These run on the sender timeline.
- test::SkewedTickClock testing_clock_sender_;
- scoped_refptr<test::SkewedSingleThreadTaskRunner> task_runner_sender_;
- // These run on the receiver timeline.
- test::SkewedTickClock testing_clock_receiver_;
- scoped_refptr<test::SkewedSingleThreadTaskRunner> task_runner_receiver_;
- scoped_refptr<CastEnvironment> cast_environment_sender_;
- scoped_refptr<CastEnvironment> cast_environment_receiver_;
- raw_ptr<LoopBackTransport>
- receiver_to_sender_; // Owned by CastTransportImpl.
- raw_ptr<LoopBackTransport>
- sender_to_receiver_; // Owned by CastTransportImpl.
- CastTransportWrapper transport_sender_;
- std::unique_ptr<CastTransport> transport_receiver_;
- uint64_t video_bytes_encoded_;
- uint64_t audio_bytes_encoded_;
- std::unique_ptr<CastReceiver> cast_receiver_;
- std::unique_ptr<CastSender> cast_sender_;
- int frames_sent_;
- base::TimeDelta frame_duration_;
- double available_bitrate_;
- std::vector<std::pair<base::TimeTicks, base::TimeTicks> > audio_ticks_;
- std::vector<std::pair<base::TimeTicks, base::TimeTicks> > video_ticks_;
- };
- namespace {
- class TransportClient : public CastTransport::Client {
- public:
- explicit TransportClient(RunOneBenchmark* run_one_benchmark)
- : run_one_benchmark_(run_one_benchmark) {}
- TransportClient(const TransportClient&) = delete;
- TransportClient& operator=(const TransportClient&) = delete;
- void OnStatusChanged(CastTransportStatus status) final {
- EXPECT_EQ(TRANSPORT_STREAM_INITIALIZED, status);
- }
- void OnLoggingEventsReceived(
- std::unique_ptr<std::vector<FrameEvent>> frame_events,
- std::unique_ptr<std::vector<PacketEvent>> packet_events) final {}
- void ProcessRtpPacket(std::unique_ptr<Packet> packet) final {
- if (run_one_benchmark_)
- run_one_benchmark_->ReceivePacket(std::move(packet));
- }
- private:
- const raw_ptr<RunOneBenchmark> run_one_benchmark_;
- };
- } // namespace
- void RunOneBenchmark::Create(const MeasuringPoint& p) {
- sender_to_receiver_ = new LoopBackTransport(cast_environment_sender_);
- transport_sender_.Init(
- new CastTransportImpl(&testing_clock_sender_, base::Seconds(1),
- std::make_unique<TransportClient>(nullptr),
- base::WrapUnique(sender_to_receiver_.get()),
- task_runner_sender_),
- &video_bytes_encoded_, &audio_bytes_encoded_);
- receiver_to_sender_ = new LoopBackTransport(cast_environment_receiver_);
- transport_receiver_ = std::make_unique<CastTransportImpl>(
- &testing_clock_receiver_, base::Seconds(1),
- std::make_unique<TransportClient>(this),
- base::WrapUnique(receiver_to_sender_.get()), task_runner_receiver_);
- cast_receiver_ =
- CastReceiver::Create(cast_environment_receiver_, audio_receiver_config_,
- video_receiver_config_, transport_receiver_.get());
- cast_sender_ =
- CastSender::Create(cast_environment_sender_, &transport_sender_);
- cast_sender_->InitializeAudio(audio_sender_config_,
- base::BindOnce(&ExpectAudioSuccess));
- cast_sender_->InitializeVideo(video_sender_config_,
- base::BindRepeating(&ExpectVideoSuccess),
- base::DoNothing());
- receiver_to_sender_->Initialize(CreateSimplePipe(p),
- transport_sender_.PacketReceiverForTesting(),
- task_runner_, &testing_clock_);
- sender_to_receiver_->Initialize(
- CreateSimplePipe(p), transport_receiver_->PacketReceiverForTesting(),
- task_runner_, &testing_clock_);
- task_runner_->RunTasks();
- }
- enum CacheResult { FOUND_TRUE, FOUND_FALSE, NOT_FOUND };
- template <class T>
- class BenchmarkCache {
- public:
- CacheResult Lookup(const T& x) {
- base::AutoLock key(lock_);
- for (size_t i = 0; i < results_.size(); i++) {
- if (results_[i].second) {
- if (x <= results_[i].first) {
- VLOG(2) << "TRUE because: " << x.AsString()
- << " <= " << results_[i].first.AsString();
- return FOUND_TRUE;
- }
- } else {
- if (x >= results_[i].first) {
- VLOG(2) << "FALSE because: " << x.AsString()
- << " >= " << results_[i].first.AsString();
- return FOUND_FALSE;
- }
- }
- }
- return NOT_FOUND;
- }
- void Add(const T& x, bool result) {
- base::AutoLock key(lock_);
- VLOG(2) << "Cache Insert: " << x.AsString() << " = " << result;
- results_.push_back(std::make_pair(x, result));
- }
- private:
- base::Lock lock_;
- std::vector<std::pair<T, bool> > results_;
- };
- struct SearchVariable {
- SearchVariable() : base(0.0), grade(0.0) {}
- SearchVariable(double b, double g) : base(b), grade(g) {}
- SearchVariable blend(const SearchVariable& other, double factor) {
- CHECK_GE(factor, 0);
- CHECK_LE(factor, 1.0);
- return SearchVariable(base * (1 - factor) + other.base * factor,
- grade * (1 - factor) + other.grade * factor);
- }
- double value(double x) const { return base + grade * x; }
- double base;
- double grade;
- };
- struct SearchVector {
- SearchVector blend(const SearchVector& other, double factor) {
- SearchVector ret;
- ret.bitrate = bitrate.blend(other.bitrate, factor);
- ret.latency = latency.blend(other.latency, factor);
- ret.packet_drop = packet_drop.blend(other.packet_drop, factor);
- return ret;
- }
- SearchVector average(const SearchVector& other) {
- return blend(other, 0.5);
- }
- MeasuringPoint GetMeasuringPoint(double v) const {
- return MeasuringPoint(
- bitrate.value(-v), latency.value(v), packet_drop.value(v));
- }
- std::string AsString(double v) { return GetMeasuringPoint(v).AsString(); }
- SearchVariable bitrate;
- SearchVariable latency;
- SearchVariable packet_drop;
- };
- class CastBenchmark {
- public:
- bool RunOnePoint(const SearchVector& v, double multiplier) {
- MeasuringPoint p = v.GetMeasuringPoint(multiplier);
- VLOG(1) << "RUN: v = " << multiplier << " p = " << p.AsString();
- if (p.bitrate <= 0) {
- return false;
- }
- switch (cache_.Lookup(p)) {
- case FOUND_TRUE:
- return true;
- case FOUND_FALSE:
- return false;
- case NOT_FOUND:
- // Keep going
- break;
- }
- bool result = true;
- for (int tries = 0; tries < 3 && result; tries++) {
- RunOneBenchmark benchmark;
- benchmark.Run(p);
- result &= benchmark.SimpleGood();
- }
- cache_.Add(p, result);
- return result;
- }
- void BinarySearch(SearchVector v, double accuracy) {
- double min = 0.0;
- double max = 1.0;
- while (RunOnePoint(v, max)) {
- min = max;
- max *= 2;
- }
- while (max - min > accuracy) {
- double avg = (min + max) / 2;
- if (RunOnePoint(v, avg)) {
- min = avg;
- } else {
- max = avg;
- }
- }
- // Print a data point to stdout.
- base::AutoLock key(lock_);
- MeasuringPoint p = v.GetMeasuringPoint(min);
- fprintf(stdout, "%f %f %f\n", p.bitrate, p.latency, p.percent_packet_drop);
- fflush(stdout);
- }
- void SpanningSearch(int max,
- int x,
- int y,
- int skip,
- SearchVector a,
- SearchVector b,
- SearchVector c,
- double accuracy,
- std::vector<std::unique_ptr<base::Thread>>* threads) {
- static int thread_num = 0;
- if (x > max) return;
- if (skip > max) {
- if (y > x) return;
- SearchVector ab = a.blend(b, static_cast<double>(x) / max);
- SearchVector ac = a.blend(c, static_cast<double>(x) / max);
- SearchVector v = ab.blend(ac, x == y ? 1.0 : static_cast<double>(y) / x);
- thread_num++;
- (*threads)[thread_num % threads->size()]->task_runner()->PostTask(
- FROM_HERE, base::BindOnce(&CastBenchmark::BinarySearch,
- base::Unretained(this), v, accuracy));
- } else {
- skip *= 2;
- SpanningSearch(max, x, y, skip, a, b, c, accuracy, threads);
- SpanningSearch(max, x + skip, y + skip, skip, a, b, c, accuracy, threads);
- SpanningSearch(max, x + skip, y, skip, a, b, c, accuracy, threads);
- SpanningSearch(max, x, y + skip, skip, a, b, c, accuracy, threads);
- }
- }
- void Run() {
- // Spanning search.
- std::vector<std::unique_ptr<base::Thread>> threads;
- for (int i = 0; i < 16; i++) {
- threads.push_back(std::make_unique<base::Thread>(
- base::StringPrintf("cast_bench_thread_%d", i)));
- threads[i]->Start();
- }
- if (base::CommandLine::ForCurrentProcess()->HasSwitch("single-run")) {
- SearchVector a;
- a.bitrate.base = 100.0;
- a.bitrate.grade = 1.0;
- a.latency.grade = 1.0;
- a.packet_drop.grade = 1.0;
- threads[0]->task_runner()->PostTask(
- FROM_HERE,
- base::BindOnce(base::IgnoreResult(&CastBenchmark::RunOnePoint),
- base::Unretained(this), a, 1.0));
- } else {
- SearchVector a, b, c;
- a.bitrate.base = b.bitrate.base = c.bitrate.base = 100.0;
- a.bitrate.grade = 1.0;
- b.latency.grade = 1.0;
- c.packet_drop.grade = 1.0;
- SpanningSearch(512,
- 0,
- 0,
- 1,
- a,
- b,
- c,
- 0.01,
- &threads);
- }
- for (size_t i = 0; i < threads.size(); i++) {
- threads[i]->Stop();
- }
- }
- private:
- BenchmarkCache<MeasuringPoint> cache_;
- base::Lock lock_;
- };
- } // namespace cast
- } // namespace media
- int main(int argc, char** argv) {
- base::AtExitManager at_exit;
- base::CommandLine::Init(argc, argv);
- media::cast::CastBenchmark benchmark;
- if (getenv("PROFILE_FILE")) {
- std::string profile_file(getenv("PROFILE_FILE"));
- base::debug::StartProfiling(profile_file);
- benchmark.Run();
- base::debug::StopProfiling();
- } else {
- benchmark.Run();
- }
- }
|