fune/toolkit/components/perfmonitoring/PerformanceUtils.cpp
Tarek Ziadé 48840088a2 Bug 1519861 - Improve mozilla::GetTabSizes - r=smaug
Introduces a generation number in dom::base::Document as well
as a cached version of TabSizes we can Get and Set.
When the document is changed, the cache is invalidated.

This change improves about:performance speed by avoiding
a heavy recursive call on big DOM trees via GetTabSizes() calls.
If the page does not change, the cached values are returned.

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

--HG--
extra : moz-landing-system : lando
2019-02-25 16:39:46 +00:00

141 lines
4.8 KiB
C++

/* -*- 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 "nsThreadUtils.h"
#include "mozilla/PerformanceUtils.h"
#include "mozilla/dom/DocGroup.h"
#include "mozilla/dom/TabChild.h"
#include "mozilla/dom/WorkerDebugger.h"
#include "mozilla/dom/WorkerDebuggerManager.h"
#include "MediaDecoder.h"
#include "XPCJSMemoryReporter.h"
#include "jsfriendapi.h"
#include "js/MemoryMetrics.h"
#include "nsWindowMemoryReporter.h"
#include "nsDOMWindowList.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());
}
// collecting ReportPerformanceInfo from all DocGroup instances
LinkedList<TabGroup>* tabGroups = TabGroup::GetTabGroupList();
// if GetTabGroupList() returns null, we don't have any tab group
if (tabGroups) {
// Per Bug 1519038, we want to collect DocGroup objects
// and use them outside the iterator, to avoid a read-write conflict.
nsTArray<RefPtr<DocGroup>> docGroups;
for (TabGroup* tabGroup = tabGroups->getFirst(); tabGroup;
tabGroup =
static_cast<LinkedListElement<TabGroup>*>(tabGroup)->getNext()) {
for (auto iter = tabGroup->Iter(); !iter.Done(); iter.Next()) {
docGroups.AppendElement(iter.Get()->mDocGroup);
}
}
for (DocGroup* docGroup : docGroups) {
promises.AppendElement(docGroup->ReportPerformanceInfo());
}
}
return promises;
}
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;
}
nsresult GetTabSizes(nsGlobalWindowOuter* aWindow, nsTabSizes* aSizes) {
// Add the window (and inner window) sizes. Might be cached.
AddWindowTabSizes(aWindow, aSizes);
nsDOMWindowList* frames = aWindow->GetFrames();
uint32_t length = frames->GetLength();
// Measure this window's descendents.
for (uint32_t i = 0; i < length; i++) {
nsCOMPtr<nsPIDOMWindowOuter> child = frames->IndexedGetter(i);
NS_ENSURE_STATE(child);
nsGlobalWindowOuter* childWin = nsGlobalWindowOuter::Cast(child);
nsresult rv = GetTabSizes(childWin, aSizes);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
RefPtr<MemoryPromise> CollectMemoryInfo(
const nsCOMPtr<nsPIDOMWindowOuter>& aWindow,
const RefPtr<AbstractThread>& aEventTarget) {
// Getting Dom sizes. -- XXX should we reimplement GetTabSizes to async here ?
nsGlobalWindowOuter* window = nsGlobalWindowOuter::Cast(aWindow);
nsTabSizes sizes;
nsresult rv = GetTabSizes(window, &sizes);
if (NS_FAILED(rv)) {
return MemoryPromise::CreateAndReject(rv, __func__);
}
// Getting GC Heap Usage
JSObject* obj = window->GetGlobalJSObject();
uint64_t GCHeapUsage = 0;
if (obj != nullptr) {
GCHeapUsage = js::GetGCHeapUsageForObjectZone(obj);
}
// Getting Media sizes.
return GetMediaMemorySizes()->Then(
aEventTarget, __func__,
[GCHeapUsage, sizes](const MediaMemoryInfo& media) {
return MemoryPromise::CreateAndResolve(
PerformanceMemoryInfo(media, sizes.mDom, sizes.mStyle, sizes.mOther,
GCHeapUsage),
__func__);
},
[](const nsresult rv) {
return MemoryPromise::CreateAndReject(rv, __func__);
});
}
} // namespace mozilla