Bug 1377575 - MEDIACACHE_MEMORY_WATERMARK records the MemoryBlockCache memory use watermark - r?cpearce,francois
MozReview-Commit-ID: 1KLofciLxo1
--- a/dom/media/MemoryBlockCache.cpp
+++ b/dom/media/MemoryBlockCache.cpp
@@ -3,16 +3,17 @@
/* 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 "MemoryBlockCache.h"
#include "MediaPrefs.h"
#include "mozilla/Atomics.h"
+#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Logging.h"
#include "mozilla/Telemetry.h"
#include "prsystem.h"
namespace mozilla {
#undef LOG
LazyLogModule gMemoryBlockCacheLog("MemoryBlockCache");
@@ -20,16 +21,109 @@ LazyLogModule gMemoryBlockCacheLog("Memo
MOZ_LOG(gMemoryBlockCacheLog, LogLevel::Debug, ("%p " x, this, ##__VA_ARGS__))
// Combined sizes of all MemoryBlockCache buffers.
// Initialized to 0 by non-local static initialization.
// Increases when a buffer grows (during initialization or unexpected OOB
// writes), decreases when a MemoryBlockCache (with its buffer) is destroyed.
static Atomic<size_t> gCombinedSizes;
+class MemoryBlockCacheTelemetry final
+ : public nsIObserver
+ , public nsSupportsWeakReference
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIOBSERVER
+
+ // To be called when the combined size has grown, so that the watermark may
+ // be updated if needed.
+ // Ensures MemoryBlockCache telemetry will be reported at shutdown.
+ // Returns current watermark.
+ static size_t NotifyCombinedSizeGrown(size_t aNewSize);
+
+private:
+ MemoryBlockCacheTelemetry() {}
+ ~MemoryBlockCacheTelemetry() {}
+
+ // Singleton instance created when a first MediaCache is registered, and
+ // released when the last MediaCache is unregistered.
+ // The observer service will keep a weak reference to it, for notifications.
+ static StaticRefPtr<MemoryBlockCacheTelemetry> gMemoryBlockCacheTelemetry;
+
+ // Watermark for the combined sizes; can only increase when a buffer grows.
+ static Atomic<size_t> gCombinedSizesWatermark;
+};
+
+// Initialized to nullptr by non-local static initialization.
+/* static */ StaticRefPtr<MemoryBlockCacheTelemetry>
+ MemoryBlockCacheTelemetry::gMemoryBlockCacheTelemetry;
+
+// Initialized to 0 by non-local static initialization.
+/* static */ Atomic<size_t> MemoryBlockCacheTelemetry::gCombinedSizesWatermark;
+
+NS_IMPL_ISUPPORTS(MemoryBlockCacheTelemetry,
+ nsIObserver,
+ nsISupportsWeakReference)
+
+/* static */ size_t
+MemoryBlockCacheTelemetry::NotifyCombinedSizeGrown(size_t aNewSize)
+{
+ NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
+
+ // Ensure gMemoryBlockCacheTelemetry exists.
+ if (!gMemoryBlockCacheTelemetry) {
+ gMemoryBlockCacheTelemetry = new MemoryBlockCacheTelemetry();
+
+ nsCOMPtr<nsIObserverService> observerService =
+ mozilla::services::GetObserverService();
+ if (observerService) {
+ observerService->AddObserver(
+ gMemoryBlockCacheTelemetry, "profile-change-teardown", true);
+ }
+
+ // Clearing gMemoryBlockCacheTelemetry when handling
+ // "profile-change-teardown" could run the risk of re-creating it (and then
+ // leaking it) if some MediaCache work happened after that notification.
+ // So instead we just request it to be cleared on final shutdown.
+ ClearOnShutdown(&gMemoryBlockCacheTelemetry);
+ }
+
+ // Update watermark if needed, report current watermark.
+ for (;;) {
+ size_t oldSize = gMemoryBlockCacheTelemetry->gCombinedSizesWatermark;
+ if (aNewSize < oldSize) {
+ return oldSize;
+ }
+ if (gMemoryBlockCacheTelemetry->gCombinedSizesWatermark.compareExchange(
+ oldSize, aNewSize)) {
+ return aNewSize;
+ }
+ }
+}
+
+NS_IMETHODIMP
+MemoryBlockCacheTelemetry::Observe(nsISupports* aSubject,
+ char const* aTopic,
+ char16_t const* aData)
+{
+ NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
+
+ if (strcmp(aTopic, "profile-change-teardown") == 0) {
+ uint32_t watermark = static_cast<uint32_t>(gCombinedSizesWatermark);
+ LOG("MemoryBlockCacheTelemetry::~Observe() "
+ "MEDIACACHE_MEMORY_WATERMARK=%" PRIu32,
+ watermark);
+ Telemetry::Accumulate(Telemetry::HistogramID::MEDIACACHE_MEMORY_WATERMARK,
+ watermark);
+ return NS_OK;
+ }
+ return NS_OK;
+}
+
enum MemoryBlockCacheTelemetryErrors
{
// Don't change order/numbers! Add new values at the end and update
// MEMORYBLOCKCACHE_ERRORS description in Histograms.json.
InitUnderuse = 0,
InitAllocation = 1,
ReadOverrun = 2,
WriteBlockOverflow = 3,
@@ -118,25 +212,28 @@ MemoryBlockCache::EnsureBufferCanContain
if (extraCapacity != 0) {
// Our buffer was given a larger capacity than the requested length, we may
// as well claim that extra capacity, both for our accounting, and to
// possibly bypass some future growths that would fit in this new capacity.
mBuffer.SetLength(capacity);
}
size_t newSizes =
static_cast<size_t>(gCombinedSizes += (extra + extraCapacity));
+ size_t watermark =
+ MemoryBlockCacheTelemetry::NotifyCombinedSizeGrown(newSizes);
LOG("EnsureBufferCanContain(%zu) - buffer size %zu + requested %zu + bonus "
"%zu = %zu; combined "
- "sizes %zu",
+ "sizes %zu, watermark %zu",
aContentLength,
initialLength,
extra,
extraCapacity,
capacity,
- newSizes);
+ newSizes,
+ watermark);
mHasGrown = true;
return true;
}
nsresult
MemoryBlockCache::Init()
{
MutexAutoLock lock(mMutex);
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -8487,16 +8487,26 @@
"alert_emails": ["gsquelart@mozilla.com"],
"bug_numbers": [1366929],
"expires_in_version": "60",
"kind": "linear",
"high": 520000,
"n_buckets": 66,
"description": "Maximum MediaCache buffer size reached, in KB. Recorded at every MediaCache destruction, i.e., whenever there is no more media data to be downloaded or kept for playback."
},
+ "MEDIACACHE_MEMORY_WATERMARK": {
+ "record_in_processes": ["main", "content"],
+ "alert_emails": ["gsquelart@mozilla.com"],
+ "bug_numbers": [1377575],
+ "expires_in_version": "60",
+ "kind": "linear",
+ "high": 520000000,
+ "n_buckets": 66,
+ "description": "Maximum memory-backed-MediaCache memory usage reached, in bytes. Recorded at every Firefox shutdown if memory-backed-MediaCache was used."
+ },
"MEDIACACHE_BLOCKOWNERS_WATERMARK": {
"record_in_processes": ["main", "content"],
"alert_emails": ["gsquelart@mozilla.com"],
"bug_numbers": [1366936],
"expires_in_version": "60",
"kind": "enumerated",
"n_values": 32,
"description": "Maximum number of owners for each MediaCache block. Recorded at every MediaCache destruction, i.e., whenever there is no more media data to be downloaded or kept for playback."