forked from mirrors/gecko-dev
Note that this patch only transforms the use of the nsDataHashtable type alias to a directly equivalent use of nsTHashMap. It does not change the specification of the hash key type to make use of the key class deduction that nsTHashMap allows for in some cases. That can be done in a separate step, but requires more attention. Differential Revision: https://phabricator.services.mozilla.com/D106008
243 lines
7.8 KiB
C++
243 lines
7.8 KiB
C++
/* -*- 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 "DecoderBenchmark.h"
|
|
#include "mozilla/BenchmarkStorageChild.h"
|
|
#include "mozilla/media/MediaUtils.h"
|
|
#include "mozilla/StaticPrefs_media.h"
|
|
|
|
namespace mozilla {
|
|
|
|
void DecoderBenchmark::StoreScore(const nsACString& aDecoderName,
|
|
const nsACString& aKey,
|
|
RefPtr<FrameStatistics> aStats) {
|
|
FrameStatisticsData statsData = aStats->GetFrameStatisticsData();
|
|
uint64_t totalFrames = FrameStatistics::GetTotalFrames(statsData);
|
|
uint64_t droppedFrames = FrameStatistics::GetDroppedFrames(statsData);
|
|
|
|
MOZ_ASSERT(droppedFrames <= totalFrames);
|
|
MOZ_ASSERT(totalFrames >= mLastTotalFrames);
|
|
MOZ_ASSERT(droppedFrames >= mLastDroppedFrames);
|
|
|
|
uint64_t diffTotalFrames = totalFrames - mLastTotalFrames;
|
|
uint64_t diffDroppedFrames = droppedFrames - mLastDroppedFrames;
|
|
|
|
/* Update now in case the method returns at the if check bellow. */
|
|
mLastTotalFrames = totalFrames;
|
|
mLastDroppedFrames = droppedFrames;
|
|
|
|
/* A minimum number of 10 frames is required to store the score. */
|
|
if (diffTotalFrames < 10) {
|
|
return;
|
|
}
|
|
|
|
int32_t percentage =
|
|
100 - 100 * float(diffDroppedFrames) / float(diffTotalFrames);
|
|
|
|
MOZ_ASSERT(percentage >= 0);
|
|
|
|
Put(aDecoderName, aKey, percentage);
|
|
}
|
|
|
|
void DecoderBenchmark::Put(const nsACString& aDecoderName,
|
|
const nsACString& aKey, int32_t aValue) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
const nsCString name(aDecoderName);
|
|
const nsCString key(aKey);
|
|
BenchmarkStorageChild::Instance()->SendPut(name, key, aValue);
|
|
}
|
|
|
|
RefPtr<BenchmarkScorePromise> DecoderBenchmark::GetScore(
|
|
const nsACString& aDecoderName, const nsACString& aKey) {
|
|
if (NS_IsMainThread()) {
|
|
return Get(aDecoderName, aKey);
|
|
}
|
|
|
|
RefPtr<DecoderBenchmark> self = this;
|
|
const nsCString decoderName(aDecoderName);
|
|
const nsCString key(aKey);
|
|
return InvokeAsync(
|
|
GetMainThreadSerialEventTarget(), __func__,
|
|
[self, decoderName, key] { return self->Get(decoderName, key); });
|
|
}
|
|
|
|
RefPtr<BenchmarkScorePromise> DecoderBenchmark::Get(
|
|
const nsACString& aDecoderName, const nsACString& aKey) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
const nsCString name(aDecoderName);
|
|
const nsCString key(aKey);
|
|
return BenchmarkStorageChild::Instance()->SendGet(name, key)->Then(
|
|
GetCurrentSerialEventTarget(), __func__,
|
|
[](int32_t aResult) {
|
|
return BenchmarkScorePromise::CreateAndResolve(aResult, __func__);
|
|
},
|
|
[](ipc::ResponseRejectReason&&) {
|
|
return BenchmarkScorePromise::CreateAndReject(NS_ERROR_FAILURE,
|
|
__func__);
|
|
});
|
|
}
|
|
|
|
/* The key string consists of the video properties resolution, framerate,
|
|
* and bitdepth. There are various levels for each of them. The key is
|
|
* formated by the closest level, for example, a video with width=1920,
|
|
* height=1080, frameRate=24, and bitdepth=8bit will have the key:
|
|
* "ResolutionLevel5-FrameRateLevel1-8bit". */
|
|
|
|
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
|
|
|
|
/* Keep them sorted */
|
|
const uint32_t PixelLevels[] = {
|
|
/* 256x144 =*/36864,
|
|
/* 426x240 =*/102240,
|
|
/* 640x360 =*/230400,
|
|
/* 854x480 =*/409920,
|
|
/* 1280x720 =*/921600,
|
|
/* 1920x1080 =*/2073600,
|
|
/* 2560x1440 =*/3686400,
|
|
/* 3840x2160 =*/8294400,
|
|
};
|
|
const size_t PixelLevelsSize = NELEMS(PixelLevels);
|
|
|
|
const uint32_t FrameRateLevels[] = {
|
|
15, 24, 30, 50, 60,
|
|
};
|
|
const size_t FrameRateLevelsSize = NELEMS(FrameRateLevels);
|
|
|
|
/* static */
|
|
nsCString KeyUtil::FindLevel(const uint32_t aLevels[], const size_t length,
|
|
uint32_t aValue) {
|
|
MOZ_ASSERT(aValue);
|
|
if (aValue <= aLevels[0]) {
|
|
return "Level0"_ns;
|
|
}
|
|
nsAutoCString level("Level");
|
|
size_t lastIndex = length - 1;
|
|
if (aValue >= aLevels[lastIndex]) {
|
|
level.AppendInt(static_cast<uint32_t>(lastIndex));
|
|
return std::move(level);
|
|
}
|
|
for (size_t i = 0; i < lastIndex; ++i) {
|
|
if (aValue >= aLevels[i + 1]) {
|
|
continue;
|
|
}
|
|
if (aValue - aLevels[i] < aLevels[i + 1] - aValue) {
|
|
level.AppendInt(static_cast<uint32_t>(i));
|
|
return std::move(level);
|
|
}
|
|
level.AppendInt(static_cast<uint32_t>(i + 1));
|
|
return std::move(level);
|
|
}
|
|
MOZ_CRASH("Array is not sorted");
|
|
return ""_ns;
|
|
}
|
|
|
|
/* static */
|
|
nsCString KeyUtil::BitDepthToStr(uint8_t aBitDepth) {
|
|
switch (aBitDepth) {
|
|
case 8: // ColorDepth::COLOR_8
|
|
return "-8bit"_ns;
|
|
case 10: // ColorDepth::COLOR_10
|
|
case 12: // ColorDepth::COLOR_12
|
|
case 16: // ColorDepth::COLOR_16
|
|
return "-non8bit"_ns;
|
|
}
|
|
MOZ_ASSERT_UNREACHABLE("invalid color depth value");
|
|
return ""_ns;
|
|
}
|
|
|
|
/* static */
|
|
nsCString KeyUtil::CreateKey(const DecoderBenchmarkInfo& aBenchInfo) {
|
|
nsAutoCString key("Resolution");
|
|
key.Append(FindLevel(PixelLevels, PixelLevelsSize,
|
|
aBenchInfo.mWidth * aBenchInfo.mHeight));
|
|
|
|
key.Append("-FrameRate");
|
|
key.Append(
|
|
FindLevel(FrameRateLevels, FrameRateLevelsSize, aBenchInfo.mFrameRate));
|
|
|
|
key.Append(BitDepthToStr(aBenchInfo.mBitDepth));
|
|
|
|
return std::move(key);
|
|
}
|
|
|
|
void DecoderBenchmark::Store(const DecoderBenchmarkInfo& aBenchInfo,
|
|
RefPtr<FrameStatistics> aStats) {
|
|
if (!XRE_IsContentProcess()) {
|
|
NS_WARNING(
|
|
"Storing a benchmark is only allowed only from the content process.");
|
|
return;
|
|
}
|
|
StoreScore(aBenchInfo.mContentType, KeyUtil::CreateKey(aBenchInfo), aStats);
|
|
}
|
|
|
|
/* static */
|
|
RefPtr<BenchmarkScorePromise> DecoderBenchmark::Get(
|
|
const DecoderBenchmarkInfo& aBenchInfo) {
|
|
if (!XRE_IsContentProcess()) {
|
|
NS_WARNING(
|
|
"Getting a benchmark is only allowed only from the content process.");
|
|
return BenchmarkScorePromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
|
}
|
|
// There is no need for any of the data members to query the database, thus
|
|
// it can be a static method.
|
|
auto bench = MakeRefPtr<DecoderBenchmark>();
|
|
return bench->GetScore(aBenchInfo.mContentType,
|
|
KeyUtil::CreateKey(aBenchInfo));
|
|
}
|
|
|
|
static nsTHashMap<nsCStringHashKey, int32_t> DecoderVersionTable() {
|
|
nsTHashMap<nsCStringHashKey, int32_t> decoderVersionTable;
|
|
|
|
/*
|
|
* For the decoders listed here, the benchmark version number will be checked.
|
|
* If the version number does not exist in the database or is different than
|
|
* the version number listed here, all the benchmark entries for this decoder
|
|
* will be erased. An example of assigning the version number `1` for AV1
|
|
* decoder is:
|
|
*
|
|
* decoderVersionTable.InsertOrUpdate("video/av1"_ns, 1);
|
|
*
|
|
* For the decoders not listed here the `CheckVersion` method exits early, to
|
|
* avoid sending unecessary IPC messages.
|
|
*/
|
|
|
|
return decoderVersionTable;
|
|
}
|
|
|
|
/* static */
|
|
void DecoderBenchmark::CheckVersion(const nsACString& aDecoderName) {
|
|
if (!XRE_IsContentProcess()) {
|
|
NS_WARNING(
|
|
"Checking version is only allowed only from the content process.");
|
|
return;
|
|
}
|
|
|
|
if (!StaticPrefs::media_mediacapabilities_from_database()) {
|
|
return;
|
|
}
|
|
|
|
nsCString name(aDecoderName);
|
|
int32_t version;
|
|
if (!DecoderVersionTable().Get(name, &version)) {
|
|
// A version is not set for that decoder ignore.
|
|
return;
|
|
}
|
|
|
|
if (NS_IsMainThread()) {
|
|
BenchmarkStorageChild::Instance()->SendCheckVersion(name, version);
|
|
return;
|
|
}
|
|
|
|
DebugOnly<nsresult> rv =
|
|
GetMainThreadEventTarget()->Dispatch(NS_NewRunnableFunction(
|
|
"DecoderBenchmark::CheckVersion", [name, version]() {
|
|
BenchmarkStorageChild::Instance()->SendCheckVersion(name, version);
|
|
}));
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
}
|
|
|
|
} // namespace mozilla
|