summaryrefslogtreecommitdiffstats
path: root/toolkit/components/perfmonitoring/PerformanceUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/perfmonitoring/PerformanceUtils.cpp')
-rw-r--r--toolkit/components/perfmonitoring/PerformanceUtils.cpp186
1 files changed, 186 insertions, 0 deletions
diff --git a/toolkit/components/perfmonitoring/PerformanceUtils.cpp b/toolkit/components/perfmonitoring/PerformanceUtils.cpp
new file mode 100644
index 0000000000..08ee695854
--- /dev/null
+++ b/toolkit/components/perfmonitoring/PerformanceUtils.cpp
@@ -0,0 +1,186 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "mozilla/PerformanceUtils.h"
+
+#include "mozilla/dom/DOMTypes.h"
+#include "mozilla/dom/DocGroup.h"
+#include "mozilla/dom/BrowsingContextGroup.h"
+#include "mozilla/dom/Document.h"
+#include "mozilla/dom/WorkerDebugger.h"
+#include "mozilla/dom/WorkerDebuggerManager.h"
+
+#include "MediaDecoder.h"
+#include "jsfriendapi.h"
+#include "nsGlobalWindowOuter.h"
+#include "nsWindowSizes.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+namespace mozilla {
+
+nsTArray<RefPtr<PerformanceInfoPromise>> CollectPerformanceInfo() {
+ nsTArray<RefPtr<PerformanceInfoPromise>> promises;
+
+ // collecting ReportPerformanceInfo from all WorkerDebugger instances
+ RefPtr<mozilla::dom::WorkerDebuggerManager> wdm =
+ WorkerDebuggerManager::GetOrCreate();
+ if (NS_WARN_IF(!wdm)) {
+ return promises;
+ }
+
+ for (uint32_t i = 0; i < wdm->GetDebuggersLength(); i++) {
+ const RefPtr<WorkerDebugger> debugger = wdm->GetDebuggerAt(i);
+ promises.AppendElement(debugger->ReportPerformanceInfo());
+ }
+
+ nsTArray<RefPtr<BrowsingContextGroup>> groups;
+ BrowsingContextGroup::GetAllGroups(groups);
+
+ nsTArray<DocGroup*> docGroups;
+ for (auto& browsingContextGroup : groups) {
+ browsingContextGroup->GetDocGroups(docGroups);
+ }
+
+ for (DocGroup* docGroup : docGroups) {
+ promises.AppendElement(docGroup->ReportPerformanceInfo());
+ }
+
+ return promises;
+}
+
+static void AddWindowTabSizes(nsGlobalWindowOuter* aWindow,
+ nsTabSizes* aSizes) {
+ Document* document = aWindow->GetDocument();
+ if (document && document->GetCachedSizes(aSizes)) {
+ // We got a cached version
+ return;
+ }
+ // We measure the sizes on a fresh nsTabSizes instance
+ // because we want to cache the value and aSizes might
+ // already have some values from other windows.
+ nsTabSizes sizes;
+
+ // Measure the window.
+ SizeOfState state(moz_malloc_size_of);
+ nsWindowSizes windowSizes(state);
+ aWindow->AddSizeOfIncludingThis(windowSizes);
+ // Measure the inner window, if there is one.
+ nsGlobalWindowInner* inner = aWindow->GetCurrentInnerWindowInternal();
+ if (inner != nullptr) {
+ inner->AddSizeOfIncludingThis(windowSizes);
+ }
+ windowSizes.addToTabSizes(&sizes);
+ if (document) {
+ document->SetCachedSizes(&sizes);
+ }
+ aSizes->mDom += sizes.mDom;
+ aSizes->mStyle += sizes.mStyle;
+ aSizes->mOther += sizes.mOther;
+}
+
+RefPtr<MemoryPromise> CollectMemoryInfo(
+ const RefPtr<DocGroup>& aDocGroup,
+ const RefPtr<AbstractThread>& aEventTarget) {
+ // Getting Dom sizes.
+ nsTabSizes sizes;
+
+ using WindowSet = mozilla::HashSet<nsGlobalWindowOuter*>;
+ WindowSet windowsVisited;
+ for (const auto& document : *aDocGroup) {
+ nsGlobalWindowOuter* window =
+ document ? nsGlobalWindowOuter::Cast(document->GetWindow()) : nullptr;
+ if (window) {
+ WindowSet::AddPtr p = windowsVisited.lookupForAdd(window);
+ if (!p) {
+ // We have not seen this window before.
+ AddWindowTabSizes(window, &sizes);
+ if (!windowsVisited.add(p, window)) {
+ // OOM. Let us stop counting memory, we may undercount.
+ break;
+ }
+ }
+ }
+ }
+
+ using ZoneSet = mozilla::HashSet<JS::Zone*>;
+ using SharedSet = mozilla::HashSet<void*>;
+ ZoneSet zonesVisited;
+ SharedSet sharedVisited;
+ // Getting JS-related memory usage
+ uint64_t jsMemUsed = 0;
+ nsTArray<RefPtr<MediaMemoryPromise>> mediaMemoryPromises;
+ for (auto* doc : *aDocGroup) {
+ bool unused;
+ nsIGlobalObject* globalObject = doc->GetScriptHandlingObject(unused);
+ if (globalObject) {
+ JSObject* object = globalObject->GetGlobalJSObject();
+ if (object != nullptr) {
+ MOZ_ASSERT(NS_IsMainThread(),
+ "We cannot get the object zone on another thread");
+ JS::Zone* zone = JS::GetObjectZone(object);
+ ZoneSet::AddPtr addZone = zonesVisited.lookupForAdd(zone);
+ if (!addZone) {
+ // We have not checked this zone before.
+ jsMemUsed += js::GetMemoryUsageForZone(zone);
+ if (!zonesVisited.add(addZone, zone)) {
+ // OOM. Let us stop counting memory, we may undercount.
+ break;
+ }
+
+ const js::gc::SharedMemoryMap& shared =
+ js::GetSharedMemoryUsageForZone(zone);
+ for (auto iter = shared.iter(); !iter.done(); iter.next()) {
+ void* sharedMem = iter.get().key();
+ SharedSet::AddPtr addShared = sharedVisited.lookupForAdd(sharedMem);
+ if (addShared) {
+ // We *have* seen this shared memory before.
+
+ // Because shared memory is already included in
+ // js::GetMemoryUsageForZone() above, and we've seen it for a
+ // previous zone, we subtract it here so it's not counted more
+ // than once.
+ jsMemUsed -= iter.get().value().nbytes;
+ } else if (!sharedVisited.add(addShared, sharedMem)) {
+ // As above, abort with an under-estimate.
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ mediaMemoryPromises.AppendElement(GetMediaMemorySizes(doc));
+ }
+
+ // Getting Media sizes.
+ return MediaMemoryPromise::All(aEventTarget, mediaMemoryPromises)
+ ->Then(
+ aEventTarget, __func__,
+ [jsMemUsed, sizes](const nsTArray<MediaMemoryInfo> mediaArray) {
+ size_t audioSize = 0;
+ size_t videoSize = 0;
+ size_t resourcesSize = 0;
+
+ for (auto media : mediaArray) {
+ audioSize += media.audioSize();
+ videoSize += media.videoSize();
+ resourcesSize += media.resourcesSize();
+ }
+
+ return MemoryPromise::CreateAndResolve(
+ PerformanceMemoryInfo(
+ MediaMemoryInfo(audioSize, videoSize, resourcesSize),
+ sizes.mDom, sizes.mStyle, sizes.mOther, jsMemUsed),
+ __func__);
+ },
+ [](const nsresult rv) {
+ return MemoryPromise::CreateAndReject(rv, __func__);
+ });
+}
+
+} // namespace mozilla