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