From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- dom/media/Benchmark.cpp | 332 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 332 insertions(+) create mode 100644 dom/media/Benchmark.cpp (limited to 'dom/media/Benchmark.cpp') diff --git a/dom/media/Benchmark.cpp b/dom/media/Benchmark.cpp new file mode 100644 index 000000000..a4761f1b1 --- /dev/null +++ b/dom/media/Benchmark.cpp @@ -0,0 +1,332 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "Benchmark.h" +#include "BufferMediaResource.h" +#include "MediaData.h" +#include "MediaPrefs.h" +#include "PDMFactory.h" +#include "WebMDemuxer.h" +#include "mozilla/Preferences.h" +#include "mozilla/Telemetry.h" +#include "mozilla/dom/ContentChild.h" + +#ifndef MOZ_WIDGET_ANDROID +#include "WebMSample.h" +#endif + +namespace mozilla { + +// Update this version number to force re-running the benchmark. Such as when +// an improvement to FFVP9 or LIBVPX is deemed worthwhile. +const uint32_t VP9Benchmark::sBenchmarkVersionID = 1; + +const char* VP9Benchmark::sBenchmarkFpsPref = "media.benchmark.vp9.fps"; +const char* VP9Benchmark::sBenchmarkFpsVersionCheck = "media.benchmark.vp9.versioncheck"; +bool VP9Benchmark::sHasRunTest = false; + +// static +bool +VP9Benchmark::IsVP9DecodeFast() +{ + MOZ_ASSERT(NS_IsMainThread()); + +#ifdef MOZ_WIDGET_ANDROID + return false; +#else + bool hasPref = Preferences::HasUserValue(sBenchmarkFpsPref); + uint32_t hadRecentUpdate = Preferences::GetUint(sBenchmarkFpsVersionCheck, 0U); + + if (!sHasRunTest && (!hasPref || hadRecentUpdate != sBenchmarkVersionID)) { + sHasRunTest = true; + + RefPtr demuxer = + new WebMDemuxer(new BufferMediaResource(sWebMSample, sizeof(sWebMSample), nullptr, + NS_LITERAL_CSTRING("video/webm"))); + RefPtr estimiser = + new Benchmark(demuxer, + { + Preferences::GetInt("media.benchmark.frames", 300), // frames to measure + 1, // start benchmarking after decoding this frame. + 8, // loop after decoding that many frames. + TimeDuration::FromMilliseconds( + Preferences::GetUint("media.benchmark.timeout", 1000)) + }); + estimiser->Run()->Then( + AbstractThread::MainThread(), __func__, + [](uint32_t aDecodeFps) { + if (XRE_IsContentProcess()) { + dom::ContentChild* contentChild = dom::ContentChild::GetSingleton(); + if (contentChild) { + contentChild->SendNotifyBenchmarkResult(NS_LITERAL_STRING("VP9"), + aDecodeFps); + } + } else { + Preferences::SetUint(sBenchmarkFpsPref, aDecodeFps); + Preferences::SetUint(sBenchmarkFpsVersionCheck, sBenchmarkVersionID); + } + Telemetry::Accumulate(Telemetry::ID::VIDEO_VP9_BENCHMARK_FPS, aDecodeFps); + }, + []() { }); + } + + if (!hasPref) { + return false; + } + + uint32_t decodeFps = Preferences::GetUint(sBenchmarkFpsPref); + uint32_t threshold = + Preferences::GetUint("media.benchmark.vp9.threshold", 150); + + return decodeFps >= threshold; +#endif +} + +Benchmark::Benchmark(MediaDataDemuxer* aDemuxer, const Parameters& aParameters) + : QueueObject(AbstractThread::GetCurrent()) + , mParameters(aParameters) + , mKeepAliveUntilComplete(this) + , mPlaybackState(this, aDemuxer) +{ + MOZ_COUNT_CTOR(Benchmark); + MOZ_ASSERT(Thread(), "Must be run in task queue"); +} + +Benchmark::~Benchmark() +{ + MOZ_COUNT_DTOR(Benchmark); +} + +RefPtr +Benchmark::Run() +{ + MOZ_ASSERT(OnThread()); + + RefPtr p = mPromise.Ensure(__func__); + RefPtr self = this; + mPlaybackState.Dispatch( + NS_NewRunnableFunction([self]() { self->mPlaybackState.DemuxSamples(); })); + return p; +} + +void +Benchmark::ReturnResult(uint32_t aDecodeFps) +{ + MOZ_ASSERT(OnThread()); + + mPromise.ResolveIfExists(aDecodeFps, __func__); +} + +void +Benchmark::Dispose() +{ + MOZ_ASSERT(OnThread()); + + mKeepAliveUntilComplete = nullptr; + mPromise.RejectIfExists(false, __func__); +} + +void +Benchmark::Init() +{ + MOZ_ASSERT(NS_IsMainThread()); + + MediaPrefs::GetSingleton(); +} + +BenchmarkPlayback::BenchmarkPlayback(Benchmark* aMainThreadState, + MediaDataDemuxer* aDemuxer) + : QueueObject(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK))) + , mMainThreadState(aMainThreadState) + , mDecoderTaskQueue(new TaskQueue(GetMediaThreadPool( + MediaThreadType::PLATFORM_DECODER))) + , mDemuxer(aDemuxer) + , mSampleIndex(0) + , mFrameCount(0) + , mFinished(false) +{ + MOZ_ASSERT(static_cast(mMainThreadState)->OnThread()); +} + +void +BenchmarkPlayback::DemuxSamples() +{ + MOZ_ASSERT(OnThread()); + + RefPtr ref(mMainThreadState); + mDemuxer->Init()->Then( + Thread(), __func__, + [this, ref](nsresult aResult) { + MOZ_ASSERT(OnThread()); + mTrackDemuxer = + mDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0); + if (!mTrackDemuxer) { + MainThreadShutdown(); + return; + } + DemuxNextSample(); + }, + [this, ref](const MediaResult& aError) { MainThreadShutdown(); }); +} + +void +BenchmarkPlayback::DemuxNextSample() +{ + MOZ_ASSERT(OnThread()); + + RefPtr ref(mMainThreadState); + RefPtr promise = mTrackDemuxer->GetSamples(); + promise->Then( + Thread(), __func__, + [this, ref](RefPtr aHolder) { + mSamples.AppendElements(Move(aHolder->mSamples)); + if (ref->mParameters.mStopAtFrame && + mSamples.Length() == (size_t)ref->mParameters.mStopAtFrame.ref()) { + InitDecoder(Move(*mTrackDemuxer->GetInfo())); + } else { + Dispatch(NS_NewRunnableFunction([this, ref]() { DemuxNextSample(); })); + } + }, + [this, ref](const MediaResult& aError) { + switch (aError.Code()) { + case NS_ERROR_DOM_MEDIA_END_OF_STREAM: + InitDecoder(Move(*mTrackDemuxer->GetInfo())); + break; + default: + MainThreadShutdown(); + } + }); +} + +void +BenchmarkPlayback::InitDecoder(TrackInfo&& aInfo) +{ + MOZ_ASSERT(OnThread()); + + RefPtr platform = new PDMFactory(); + mDecoder = platform->CreateDecoder({ aInfo, mDecoderTaskQueue, reinterpret_cast(this) }); + if (!mDecoder) { + MainThreadShutdown(); + return; + } + RefPtr ref(mMainThreadState); + mDecoder->Init()->Then( + Thread(), __func__, + [this, ref](TrackInfo::TrackType aTrackType) { + InputExhausted(); + }, + [this, ref](MediaResult aError) { + MainThreadShutdown(); + }); +} + +void +BenchmarkPlayback::MainThreadShutdown() +{ + MOZ_ASSERT(OnThread()); + + if (mFinished) { + // Nothing more to do. + return; + } + mFinished = true; + + if (mDecoder) { + mDecoder->Flush(); + mDecoder->Shutdown(); + mDecoder = nullptr; + } + + mDecoderTaskQueue->BeginShutdown(); + mDecoderTaskQueue->AwaitShutdownAndIdle(); + mDecoderTaskQueue = nullptr; + + if (mTrackDemuxer) { + mTrackDemuxer->Reset(); + mTrackDemuxer->BreakCycles(); + mTrackDemuxer = nullptr; + } + + RefPtr ref(mMainThreadState); + Thread()->AsTaskQueue()->BeginShutdown()->Then( + ref->Thread(), __func__, + [ref]() { ref->Dispose(); }, + []() { MOZ_CRASH("not reached"); }); +} + +void +BenchmarkPlayback::Output(MediaData* aData) +{ + RefPtr ref(mMainThreadState); + Dispatch(NS_NewRunnableFunction([this, ref]() { + mFrameCount++; + if (mFrameCount == ref->mParameters.mStartupFrame) { + mDecodeStartTime = TimeStamp::Now(); + } + int32_t frames = mFrameCount - ref->mParameters.mStartupFrame; + TimeDuration elapsedTime = TimeStamp::Now() - mDecodeStartTime; + if (!mFinished && + (frames == ref->mParameters.mFramesToMeasure || + elapsedTime >= ref->mParameters.mTimeout)) { + uint32_t decodeFps = frames / elapsedTime.ToSeconds(); + MainThreadShutdown(); + ref->Dispatch(NS_NewRunnableFunction([ref, decodeFps]() { + ref->ReturnResult(decodeFps); + })); + } + })); +} + +void +BenchmarkPlayback::Error(const MediaResult& aError) +{ + RefPtr ref(mMainThreadState); + Dispatch(NS_NewRunnableFunction([this, ref]() { MainThreadShutdown(); })); +} + +void +BenchmarkPlayback::InputExhausted() +{ + RefPtr ref(mMainThreadState); + Dispatch(NS_NewRunnableFunction([this, ref]() { + MOZ_ASSERT(OnThread()); + if (mFinished || mSampleIndex >= mSamples.Length()) { + return; + } + mDecoder->Input(mSamples[mSampleIndex]); + mSampleIndex++; + if (mSampleIndex == mSamples.Length()) { + if (ref->mParameters.mStopAtFrame) { + mSampleIndex = 0; + } else { + mDecoder->Drain(); + } + } + })); +} + +void +BenchmarkPlayback::DrainComplete() +{ + RefPtr ref(mMainThreadState); + Dispatch(NS_NewRunnableFunction([this, ref]() { + int32_t frames = mFrameCount - ref->mParameters.mStartupFrame; + TimeDuration elapsedTime = TimeStamp::Now() - mDecodeStartTime; + uint32_t decodeFps = frames / elapsedTime.ToSeconds(); + MainThreadShutdown(); + ref->Dispatch(NS_NewRunnableFunction([ref, decodeFps]() { + ref->ReturnResult(decodeFps); + })); + })); +} + +bool +BenchmarkPlayback::OnReaderTaskQueue() +{ + return OnThread(); +} + +} -- cgit v1.2.3