summaryrefslogtreecommitdiffstats
path: root/dom/media/Benchmark.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /dom/media/Benchmark.cpp
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'dom/media/Benchmark.cpp')
-rw-r--r--dom/media/Benchmark.cpp332
1 files changed, 332 insertions, 0 deletions
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<WebMDemuxer> demuxer =
+ new WebMDemuxer(new BufferMediaResource(sWebMSample, sizeof(sWebMSample), nullptr,
+ NS_LITERAL_CSTRING("video/webm")));
+ RefPtr<Benchmark> 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::BenchmarkPromise>
+Benchmark::Run()
+{
+ MOZ_ASSERT(OnThread());
+
+ RefPtr<BenchmarkPromise> p = mPromise.Ensure(__func__);
+ RefPtr<Benchmark> 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<Benchmark*>(mMainThreadState)->OnThread());
+}
+
+void
+BenchmarkPlayback::DemuxSamples()
+{
+ MOZ_ASSERT(OnThread());
+
+ RefPtr<Benchmark> 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<Benchmark> ref(mMainThreadState);
+ RefPtr<MediaTrackDemuxer::SamplesPromise> promise = mTrackDemuxer->GetSamples();
+ promise->Then(
+ Thread(), __func__,
+ [this, ref](RefPtr<MediaTrackDemuxer::SamplesHolder> 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<PDMFactory> platform = new PDMFactory();
+ mDecoder = platform->CreateDecoder({ aInfo, mDecoderTaskQueue, reinterpret_cast<MediaDataDecoderCallback*>(this) });
+ if (!mDecoder) {
+ MainThreadShutdown();
+ return;
+ }
+ RefPtr<Benchmark> 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<Benchmark> ref(mMainThreadState);
+ Thread()->AsTaskQueue()->BeginShutdown()->Then(
+ ref->Thread(), __func__,
+ [ref]() { ref->Dispose(); },
+ []() { MOZ_CRASH("not reached"); });
+}
+
+void
+BenchmarkPlayback::Output(MediaData* aData)
+{
+ RefPtr<Benchmark> 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<Benchmark> ref(mMainThreadState);
+ Dispatch(NS_NewRunnableFunction([this, ref]() { MainThreadShutdown(); }));
+}
+
+void
+BenchmarkPlayback::InputExhausted()
+{
+ RefPtr<Benchmark> 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<Benchmark> 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();
+}
+
+}