Bug 1540573 - P4. Use larger MediaCache sizes when on cellular connection. r=jya

Differential Revision: https://phabricator.services.mozilla.com/D26233

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Chris Pearce 2019-05-01 23:48:13 +00:00
Родитель 8ad76b6460
Коммит 217bd1680c
6 изменённых файлов: 102 добавлений и 39 удалений

Просмотреть файл

@ -125,11 +125,9 @@ void FileBlockCache::Flush() {
}));
}
int32_t FileBlockCache::GetMaxBlocks() const {
size_t FileBlockCache::GetMaxBlocks(size_t aCacheSizeInKB) const {
// We look up the cache size every time. This means dynamic changes
// to the pref are applied.
const uint32_t cacheSizeKb =
std::min(StaticPrefs::MediaCacheSize(), uint32_t(INT32_MAX) * 2);
// Ensure we can divide BLOCK_SIZE by 1024.
static_assert(MediaCacheStream::BLOCK_SIZE % 1024 == 0,
"BLOCK_SIZE should be a multiple of 1024");
@ -140,14 +138,13 @@ int32_t FileBlockCache::GetMaxBlocks() const {
static_assert(MediaCacheStream::BLOCK_SIZE / 1024 <= int64_t(UINT32_MAX),
"BLOCK_SIZE / 1024 should be at most UINT32_MAX");
// Since BLOCK_SIZE is a strict multiple of 1024,
// cacheSizeKb * 1024 / BLOCK_SIZE == cacheSizeKb / (BLOCK_SIZE / 1024),
// but the latter formula avoids a potential overflow from `* 1024`.
// aCacheSizeInKB * 1024 / BLOCK_SIZE == aCacheSizeInKB / (BLOCK_SIZE /
// 1024), but the latter formula avoids a potential overflow from `* 1024`.
// And because BLOCK_SIZE/1024 is at least 2, the maximum cache size
// INT32_MAX*2 will give a maxBlocks that can fit in an int32_t.
constexpr uint32_t blockSizeKb =
uint32_t(MediaCacheStream::BLOCK_SIZE / 1024);
const int32_t maxBlocks = int32_t(cacheSizeKb / blockSizeKb);
return std::max(maxBlocks, int32_t(1));
constexpr size_t blockSizeKb = size_t(MediaCacheStream::BLOCK_SIZE / 1024);
const size_t maxBlocks = aCacheSizeInKB / blockSizeKb;
return std::max(maxBlocks, size_t(1));
}
FileBlockCache::FileBlockCache()

Просмотреть файл

@ -68,7 +68,7 @@ class FileBlockCache : public MediaBlockCacheBase {
// Maximum number of blocks allowed in this block cache.
// Calculated from "media.cache_size" pref.
int32_t GetMaxBlocks() const override;
size_t GetMaxBlocks(size_t aCacheSizeInKB) const override;
// Can be called on any thread. This defers to a non-main thread.
nsresult WriteBlock(uint32_t aBlockIndex, Span<const uint8_t> aData1,

Просмотреть файл

@ -56,7 +56,7 @@ class MediaBlockCacheBase {
// Maximum number of blocks expected in this block cache. (But allow overflow
// to accomodate incoming traffic before MediaCache can handle it.)
virtual int32_t GetMaxBlocks() const = 0;
virtual size_t GetMaxBlocks(size_t aCacheSizeInKiB) const = 0;
// Can be called on any thread. This defers to a non-main thread.
virtual nsresult WriteBlock(uint32_t aBlockIndex, Span<const uint8_t> aData1,

Просмотреть файл

@ -11,6 +11,7 @@
#include "MediaBlockCacheBase.h"
#include "MediaResource.h"
#include "MemoryBlockCache.h"
#include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/ErrorNames.h"
@ -23,12 +24,14 @@
#include "mozilla/SystemGroup.h"
#include "mozilla/Telemetry.h"
#include "nsContentUtils.h"
#include "nsINetworkLinkService.h"
#include "nsIObserverService.h"
#include "nsIPrincipal.h"
#include "nsPrintfCString.h"
#include "nsProxyRelease.h"
#include "nsThreadUtils.h"
#include "prio.h"
#include "VideoUtils.h"
#include <algorithm>
namespace mozilla {
@ -114,7 +117,6 @@ void MediaCacheFlusher::RegisterMediaCache(MediaCache* aMediaCache) {
if (!gMediaCacheFlusher) {
gMediaCacheFlusher = new MediaCacheFlusher();
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (observerService) {
@ -122,6 +124,10 @@ void MediaCacheFlusher::RegisterMediaCache(MediaCache* aMediaCache) {
true);
observerService->AddObserver(gMediaCacheFlusher,
"cacheservice:empty-cache", true);
observerService->AddObserver(
gMediaCacheFlusher, "contentchild:network-link-type-changed", true);
observerService->AddObserver(gMediaCacheFlusher,
NS_NETWORK_LINK_TYPE_TOPIC, true);
}
}
@ -242,6 +248,10 @@ class MediaCache {
return mMonitor;
}
// Updates the cache size, readahead limit, and resume threshold, based on
// whether we're on a cellular connection or not. Main thread only.
static void UpdateGeometryStatics();
/**
* An iterator that makes it easy to iterate through all streams that
* have a given resource ID and are not closed.
@ -282,6 +292,7 @@ class MediaCache {
NS_ASSERTION(NS_IsMainThread(), "Only construct MediaCache on main thread");
MOZ_COUNT_CTOR(MediaCache);
MediaCacheFlusher::RegisterMediaCache(this);
UpdateGeometryStatics();
}
~MediaCache() {
@ -313,6 +324,21 @@ class MediaCache {
MOZ_COUNT_DTOR(MediaCache);
}
static size_t CacheSize() {
MOZ_ASSERT(sThread->IsOnCurrentThread());
return sCacheSizeInKB;
}
static size_t ReadaheadLimit() {
MOZ_ASSERT(sThread->IsOnCurrentThread());
return sReadaheadLimit;
}
static size_t ResumeThreshold() {
MOZ_ASSERT(sThread->IsOnCurrentThread());
return sResumeThreshold;
}
// Find a free or reusable block and return its index. If there are no
// free blocks and no reusable blocks, add a new block to the cache
// and return it. Can return -1 on OOM.
@ -451,6 +477,11 @@ class MediaCache {
// to access sThread on all threads.
static bool sThreadInit;
// Accesson MediaCache thread only.
static size_t sCacheSizeInKB;
static size_t sReadaheadLimit;
static size_t sResumeThreshold;
private:
// Used by MediaCacheStream::GetDebugInfo() only for debugging.
// Don't add new callers to this function.
@ -470,6 +501,37 @@ StaticRefPtr<nsIThread> MediaCache::sThread;
/* static */
bool MediaCache::sThreadInit = false;
/* static */ size_t MediaCache::sCacheSizeInKB = 0;
/* static */ size_t MediaCache::sReadaheadLimit = 0;
/* static */ size_t MediaCache::sResumeThreshold = 0;
void MediaCache::UpdateGeometryStatics() {
NS_ASSERTION(NS_IsMainThread(),
"Only call on main thread"); // JNI required on Android...
bool cacheAggressively = !OnCellularConnection();
LOG("MediaCache::UpdateGeometryStatics() cacheAggressively=%d",
cacheAggressively);
// Read the prefs on the main thread, and post their value to the MediaCache
// thread. This ensures the values are synchronized.
uint32_t cacheSize = 0, readaheadLimit = 0, resumeThreshold = 0;
if (cacheAggressively) {
cacheSize = StaticPrefs::MediaCacheSize();
readaheadLimit = StaticPrefs::MediaCacheReadaheadLimit();
resumeThreshold = StaticPrefs::MediaCacheResumeThreshold();
} else {
cacheSize = StaticPrefs::MediaCacheCellularSize();
readaheadLimit = StaticPrefs::MediaCacheCellularReadaheadLimit();
resumeThreshold = StaticPrefs::MediaCacheCellularResumeThreshold();
}
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction("MediaCache::UpdateGeometryStatics", [=]() {
sCacheSizeInKB = cacheSize;
sReadaheadLimit = readaheadLimit;
sResumeThreshold = resumeThreshold;
});
sThread->Dispatch(r.forget());
}
NS_IMETHODIMP
MediaCacheFlusher::Observe(nsISupports* aSubject, char const* aTopic,
char16_t const* aData) {
@ -487,6 +549,10 @@ MediaCacheFlusher::Observe(nsISupports* aSubject, char const* aTopic,
}
return NS_OK;
}
if (strcmp(aTopic, "contentchild:network-link-type-changed") == 0 ||
strcmp(aTopic, NS_NETWORK_LINK_TYPE_TOPIC) == 0) {
MediaCache::UpdateGeometryStatics();
}
return NS_OK;
}
@ -827,7 +893,8 @@ int32_t MediaCache::FindBlockForIncomingData(AutoLock& aLock, TimeStamp aNow,
// b) the data we're going to store in the free block is not higher
// priority than the data already stored in the free block.
// The latter can lead us to go over the cache limit a bit.
if ((mIndex.Length() < uint32_t(mBlockCache->GetMaxBlocks()) ||
if ((mIndex.Length() <
uint32_t(mBlockCache->GetMaxBlocks(MediaCache::CacheSize())) ||
blockIndex < 0 ||
PredictNextUseForIncomingData(aLock, aStream) >=
PredictNextUse(aLock, aNow, blockIndex))) {
@ -1155,7 +1222,7 @@ void MediaCache::Update() {
mInUpdate = true;
#endif
int32_t maxBlocks = mBlockCache->GetMaxBlocks();
int32_t maxBlocks = mBlockCache->GetMaxBlocks(MediaCache::CacheSize());
TimeStamp now = TimeStamp::Now();
int32_t freeBlockCount = mFreeBlocks.GetCount();
@ -1276,8 +1343,8 @@ void MediaCache::Update() {
}
}
int32_t resumeThreshold = StaticPrefs::MediaCacheResumeThreshold();
int32_t readaheadLimit = StaticPrefs::MediaCacheReadaheadLimit();
int32_t resumeThreshold = MediaCache::ResumeThreshold();
int32_t readaheadLimit = MediaCache::ReadaheadLimit();
for (uint32_t i = 0; i < mStreams.Length(); ++i) {
actions.AppendElement(StreamAction{});

Просмотреть файл

@ -45,7 +45,7 @@ class MemoryBlockCache : public MediaBlockCacheBase {
// Maximum number of blocks allowed in this block cache.
// Based on initial content length, and minimum usable block cache.
int32_t GetMaxBlocks() const override { return mMaxBlocks; }
size_t GetMaxBlocks(size_t) const override { return mMaxBlocks; }
// Can be called on any thread.
virtual nsresult WriteBlock(uint32_t aBlockIndex, Span<const uint8_t> aData1,
@ -73,7 +73,7 @@ class MemoryBlockCache : public MediaBlockCacheBase {
const size_t mInitialContentLength;
// Maximum number of blocks that this MemoryBlockCache expects.
const int32_t mMaxBlocks;
const size_t mMaxBlocks;
// Mutex which controls access to all members below.
Mutex mMutex;

Просмотреть файл

@ -1441,17 +1441,18 @@ VARCACHE_PREF(
// reviewer had an unshakeable preference for that.
// File-backed MediaCache size.
#ifdef ANDROID
# define PREF_VALUE 32768 // Measured in KiB
#else
# define PREF_VALUE 512000 // Measured in KiB
#endif
VARCACHE_PREF(
"media.cache_size",
MediaCacheSize,
RelaxedAtomicUint32, PREF_VALUE
uint32_t, 512000 // Measured in KiB
)
// Size of file backed MediaCache while on a connection which is cellular (3G, etc),
// and thus assumed to be "expensive".
VARCACHE_PREF(
"media.cache_size.cellular",
MediaCacheCellularSize,
uint32_t, 32768 // Measured in KiB
)
#undef PREF_VALUE
// If a resource is known to be smaller than this size (in kilobytes), a
// memory-backed MediaCache may be used; otherwise the (single shared global)
@ -1480,32 +1481,30 @@ VARCACHE_PREF(
// When a network connection is suspended, don't resume it until the amount of
// buffered data falls below this threshold (in seconds).
#ifdef ANDROID
# define PREF_VALUE 10 // Use a smaller limit to save battery.
#else
# define PREF_VALUE 30
#endif
VARCACHE_PREF(
"media.cache_resume_threshold",
MediaCacheResumeThreshold,
RelaxedAtomicInt32, PREF_VALUE
uint32_t, 30
)
VARCACHE_PREF(
"media.cache_resume_threshold.cellular",
MediaCacheCellularResumeThreshold,
uint32_t, 10
)
#undef PREF_VALUE
// Stop reading ahead when our buffered data is this many seconds ahead of the
// current playback position. This limit can stop us from using arbitrary
// amounts of network bandwidth prefetching huge videos.
#ifdef ANDROID
# define PREF_VALUE 30 // Use a smaller limit to save battery.
#else
# define PREF_VALUE 60
#endif
VARCACHE_PREF(
"media.cache_readahead_limit",
MediaCacheReadaheadLimit,
RelaxedAtomicInt32, PREF_VALUE
uint32_t, 60
)
VARCACHE_PREF(
"media.cache_readahead_limit.cellular",
MediaCacheCellularReadaheadLimit,
uint32_t, 30
)
#undef PREF_VALUE
// AudioSink
VARCACHE_PREF(