1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "mozilla/PerformanceUtils.h"
8
9 #include "mozilla/dom/DOMTypes.h"
10 #include "mozilla/dom/DocGroup.h"
11 #include "mozilla/dom/BrowsingContextGroup.h"
12 #include "mozilla/dom/Document.h"
13 #include "mozilla/dom/WorkerDebugger.h"
14 #include "mozilla/dom/WorkerDebuggerManager.h"
15
16 #include "MediaDecoder.h"
17 #include "jsfriendapi.h"
18 #include "nsGlobalWindowOuter.h"
19 #include "nsWindowSizes.h"
20
21 using namespace mozilla;
22 using namespace mozilla::dom;
23
24 namespace mozilla {
25
CollectPerformanceInfo()26 nsTArray<RefPtr<PerformanceInfoPromise>> CollectPerformanceInfo() {
27 nsTArray<RefPtr<PerformanceInfoPromise>> promises;
28
29 // collecting ReportPerformanceInfo from all WorkerDebugger instances
30 RefPtr<mozilla::dom::WorkerDebuggerManager> wdm =
31 WorkerDebuggerManager::GetOrCreate();
32 if (NS_WARN_IF(!wdm)) {
33 return promises;
34 }
35
36 for (uint32_t i = 0; i < wdm->GetDebuggersLength(); i++) {
37 const RefPtr<WorkerDebugger> debugger = wdm->GetDebuggerAt(i);
38 promises.AppendElement(debugger->ReportPerformanceInfo());
39 }
40
41 nsTArray<RefPtr<BrowsingContextGroup>> groups;
42 BrowsingContextGroup::GetAllGroups(groups);
43
44 nsTArray<DocGroup*> docGroups;
45 for (auto& browsingContextGroup : groups) {
46 browsingContextGroup->GetDocGroups(docGroups);
47 }
48
49 for (DocGroup* docGroup : docGroups) {
50 promises.AppendElement(docGroup->ReportPerformanceInfo());
51 }
52
53 return promises;
54 }
55
AddWindowTabSizes(nsGlobalWindowOuter * aWindow,nsTabSizes * aSizes)56 void AddWindowTabSizes(nsGlobalWindowOuter* aWindow, nsTabSizes* aSizes) {
57 Document* document = aWindow->GetDocument();
58 if (document && document->GetCachedSizes(aSizes)) {
59 // We got a cached version
60 return;
61 }
62 // We measure the sizes on a fresh nsTabSizes instance
63 // because we want to cache the value and aSizes might
64 // already have some values from other windows.
65 nsTabSizes sizes;
66
67 // Measure the window.
68 SizeOfState state(moz_malloc_size_of);
69 nsWindowSizes windowSizes(state);
70 aWindow->AddSizeOfIncludingThis(windowSizes);
71 // Measure the inner window, if there is one.
72 nsGlobalWindowInner* inner = aWindow->GetCurrentInnerWindowInternal();
73 if (inner != nullptr) {
74 inner->AddSizeOfIncludingThis(windowSizes);
75 }
76 windowSizes.addToTabSizes(&sizes);
77 if (document) {
78 document->SetCachedSizes(&sizes);
79 }
80 aSizes->mDom += sizes.mDom;
81 aSizes->mStyle += sizes.mStyle;
82 aSizes->mOther += sizes.mOther;
83 }
84
GetTabSizes(BrowsingContext * aContext,nsTabSizes * aSizes)85 nsresult GetTabSizes(BrowsingContext* aContext, nsTabSizes* aSizes) {
86 if (!aContext) {
87 return NS_OK;
88 }
89
90 // Add the window (and inner window) sizes. Might be cached.
91 nsGlobalWindowOuter* window =
92 nsGlobalWindowOuter::Cast(aContext->GetDOMWindow());
93 if (window) {
94 AddWindowTabSizes(window, aSizes);
95 }
96
97 // Measure this window's descendents.
98 for (const auto& child : aContext->Children()) {
99 MOZ_TRY(GetTabSizes(child, aSizes));
100 }
101 return NS_OK;
102 }
103
CollectMemoryInfo(const RefPtr<DocGroup> & aDocGroup,const RefPtr<AbstractThread> & aEventTarget)104 RefPtr<MemoryPromise> CollectMemoryInfo(
105 const RefPtr<DocGroup>& aDocGroup,
106 const RefPtr<AbstractThread>& aEventTarget) {
107 // Getting Dom sizes. -- XXX should we reimplement GetTabSizes to async here ?
108 nsTabSizes sizes;
109
110 for (const auto& document : *aDocGroup) {
111 nsGlobalWindowOuter* window =
112 document ? nsGlobalWindowOuter::Cast(document->GetWindow()) : nullptr;
113 if (window) {
114 AddWindowTabSizes(window, &sizes);
115 }
116 }
117
118 BrowsingContextGroup* group = aDocGroup->GetBrowsingContextGroup();
119 // Getting GC Heap Usage
120 uint64_t GCHeapUsage = 0;
121 JSObject* object = group->GetWrapper();
122 if (object != nullptr) {
123 GCHeapUsage = js::GetGCHeapUsageForObjectZone(object);
124 }
125
126 // Getting Media sizes.
127 return GetMediaMemorySizes()->Then(
128 aEventTarget, __func__,
129 [GCHeapUsage, sizes](const MediaMemoryInfo& media) {
130 return MemoryPromise::CreateAndResolve(
131 PerformanceMemoryInfo(media, sizes.mDom, sizes.mStyle, sizes.mOther,
132 GCHeapUsage),
133 __func__);
134 },
135 [](const nsresult rv) {
136 return MemoryPromise::CreateAndReject(rv, __func__);
137 });
138 }
139
CollectMemoryInfo(const RefPtr<BrowsingContext> & aContext,const RefPtr<AbstractThread> & aEventTarget)140 RefPtr<MemoryPromise> CollectMemoryInfo(
141 const RefPtr<BrowsingContext>& aContext,
142 const RefPtr<AbstractThread>& aEventTarget) {
143 // Getting Dom sizes. -- XXX should we reimplement GetTabSizes to async here ?
144 nsTabSizes sizes;
145 nsresult rv = GetTabSizes(aContext, &sizes);
146 if (NS_FAILED(rv)) {
147 return MemoryPromise::CreateAndReject(rv, __func__);
148 }
149
150 // Getting GC Heap Usage
151 JSObject* obj = aContext->GetWrapper();
152 uint64_t GCHeapUsage = 0;
153 if (obj != nullptr) {
154 GCHeapUsage = js::GetGCHeapUsageForObjectZone(obj);
155 }
156
157 // Getting Media sizes.
158 return GetMediaMemorySizes()->Then(
159 aEventTarget, __func__,
160 [GCHeapUsage, sizes](const MediaMemoryInfo& media) {
161 return MemoryPromise::CreateAndResolve(
162 PerformanceMemoryInfo(media, sizes.mDom, sizes.mStyle, sizes.mOther,
163 GCHeapUsage),
164 __func__);
165 },
166 [](const nsresult rv) {
167 return MemoryPromise::CreateAndReject(rv, __func__);
168 });
169 }
170
171 } // namespace mozilla
172