mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-31 19:10:36 +00:00
Bug 1836191 - remove ChromeUtils.requestPerformanceMetrics that was only used by about:performance, r=smaug.
Differential Revision: https://phabricator.services.mozilla.com/D179696
This commit is contained in:
parent
d272e36525
commit
58ce18a1c9
@ -1619,8 +1619,6 @@ module.exports = {
|
||||
"dom/tests/browser/browser_localStorage_snapshotting.js",
|
||||
"dom/tests/browser/browser_test_toolbars_visibility.js",
|
||||
"dom/tests/browser/browser_windowProxy_transplant.js",
|
||||
"dom/tests/browser/perfmetrics/browser_test_performance_metrics.js",
|
||||
"dom/tests/browser/perfmetrics/browser_test_unresponsive.js",
|
||||
"dom/tests/mochitest/beacon/file_beaconSafelist.html",
|
||||
"dom/tests/mochitest/beacon/test_beaconOriginHeader.html",
|
||||
"dom/tests/mochitest/beacon/test_beaconPreflightWithCustomContentType.html",
|
||||
|
@ -670,8 +670,6 @@ dom/svg/test/test_style_sheet.html
|
||||
dom/svg/test/test_text_update.html
|
||||
dom/tests/browser/dummy.html
|
||||
dom/tests/browser/image.html
|
||||
dom/tests/browser/perfmetrics/dummy.html
|
||||
dom/tests/browser/perfmetrics/sound.html
|
||||
dom/tests/browser/test_new_window_from_content_child.html
|
||||
dom/tests/mochitest/beacon/test_beaconOriginHeader.html
|
||||
dom/tests/mochitest/beacon/test_beaconRedirect.html
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "mozilla/EventStateManager.h"
|
||||
#include "mozilla/FormAutofillNative.h"
|
||||
#include "mozilla/IntentionalCrash.h"
|
||||
#include "mozilla/PerformanceMetricsCollector.h"
|
||||
#include "mozilla/PerfStats.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/ProcInfo.h"
|
||||
@ -1475,35 +1474,6 @@ bool ChromeUtils::VsyncEnabled(GlobalObject& aGlobal) {
|
||||
return mozilla::gfx::VsyncSource::GetFastestVsyncRate().isSome();
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<Promise> ChromeUtils::RequestPerformanceMetrics(
|
||||
GlobalObject& aGlobal, ErrorResult& aRv) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
// Creating a JS promise
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
MOZ_ASSERT(global);
|
||||
RefPtr<Promise> domPromise = Promise::Create(global, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(domPromise);
|
||||
RefPtr<nsISerialEventTarget> target =
|
||||
global->EventTargetFor(TaskCategory::Performance);
|
||||
|
||||
// requesting metrics, that will be returned into the promise
|
||||
PerformanceMetricsCollector::RequestMetrics()->Then(
|
||||
target, __func__,
|
||||
[domPromise,
|
||||
target](nsTArray<dom::PerformanceInfoDictionary>&& aResults) {
|
||||
domPromise->MaybeResolve(std::move(aResults));
|
||||
},
|
||||
[domPromise](const nsresult& aRv) { domPromise->MaybeReject(aRv); });
|
||||
|
||||
// sending back the promise instance
|
||||
return domPromise.forget();
|
||||
}
|
||||
|
||||
void ChromeUtils::SetPerfStatsCollectionMask(GlobalObject& aGlobal,
|
||||
uint64_t aMask) {
|
||||
PerfStats::SetCollectionMask(static_cast<PerfStats::MetricMask>(aMask));
|
||||
|
@ -189,9 +189,6 @@ class ChromeUtils {
|
||||
|
||||
static void ClearStyleSheetCache(GlobalObject& aGlobal);
|
||||
|
||||
static already_AddRefed<Promise> RequestPerformanceMetrics(
|
||||
GlobalObject& aGlobal, ErrorResult& aRv);
|
||||
|
||||
static void SetPerfStatsCollectionMask(GlobalObject& aGlobal, uint64_t aMask);
|
||||
|
||||
static already_AddRefed<Promise> CollectPerfStats(GlobalObject& aGlobal,
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
|
||||
#include "mozilla/AbstractThread.h"
|
||||
#include "mozilla/PerformanceUtils.h"
|
||||
#include "mozilla/SchedulerGroup.h"
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
@ -235,96 +234,6 @@ DocGroup::~DocGroup() {
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<PerformanceInfoPromise> DocGroup::ReportPerformanceInfo() {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mPerformanceCounter);
|
||||
#if defined(XP_WIN)
|
||||
uint32_t pid = GetCurrentProcessId();
|
||||
#else
|
||||
uint32_t pid = getpid();
|
||||
#endif
|
||||
uint64_t windowID = 0;
|
||||
uint16_t count = 0;
|
||||
uint64_t duration = 0;
|
||||
nsCString host;
|
||||
bool isTopLevel = false;
|
||||
RefPtr<BrowsingContext> top;
|
||||
RefPtr<AbstractThread> mainThread =
|
||||
AbstractMainThreadFor(TaskCategory::Performance);
|
||||
|
||||
for (const auto& document : *this) {
|
||||
if (host.IsEmpty()) {
|
||||
nsCOMPtr<nsIURI> docURI = document->GetDocumentURI();
|
||||
if (!docURI) {
|
||||
continue;
|
||||
}
|
||||
|
||||
docURI->GetHost(host);
|
||||
if (host.IsEmpty()) {
|
||||
host = docURI->GetSpecOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
BrowsingContext* context = document->GetBrowsingContext();
|
||||
if (!context) {
|
||||
continue;
|
||||
}
|
||||
|
||||
top = context->Top();
|
||||
|
||||
if (!top || !top->GetCurrentWindowContext()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
isTopLevel = context->IsTop();
|
||||
windowID = top->GetCurrentWindowContext()->OuterWindowId();
|
||||
break;
|
||||
};
|
||||
|
||||
MOZ_ASSERT(!host.IsEmpty());
|
||||
duration = mPerformanceCounter->GetExecutionDuration();
|
||||
FallibleTArray<CategoryDispatch> items;
|
||||
|
||||
// now that we have the host and window ids, let's look at the perf counters
|
||||
for (uint32_t index = 0; index < (uint32_t)TaskCategory::Count; index++) {
|
||||
TaskCategory category = static_cast<TaskCategory>(index);
|
||||
count = mPerformanceCounter->GetDispatchCount(DispatchCategory(category));
|
||||
CategoryDispatch item = CategoryDispatch(index, count);
|
||||
if (!items.AppendElement(item, fallible)) {
|
||||
NS_ERROR("Could not complete the operation");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isTopLevel && top && top->IsInProcess()) {
|
||||
return PerformanceInfoPromise::CreateAndResolve(
|
||||
PerformanceInfo(host, pid, windowID, duration,
|
||||
mPerformanceCounter->GetID(), false, isTopLevel,
|
||||
PerformanceMemoryInfo(), // Empty memory info
|
||||
items),
|
||||
__func__);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mainThread);
|
||||
RefPtr<DocGroup> self = this;
|
||||
return CollectMemoryInfo(self, mainThread)
|
||||
->Then(
|
||||
mainThread, __func__,
|
||||
[self, host, pid, windowID, duration, isTopLevel,
|
||||
items = std::move(items)](const PerformanceMemoryInfo& aMemoryInfo) {
|
||||
PerformanceInfo info =
|
||||
PerformanceInfo(host, pid, windowID, duration,
|
||||
self->mPerformanceCounter->GetID(), false,
|
||||
isTopLevel, aMemoryInfo, items);
|
||||
|
||||
return PerformanceInfoPromise::CreateAndResolve(std::move(info),
|
||||
__func__);
|
||||
},
|
||||
[self](const nsresult rv) {
|
||||
return PerformanceInfoPromise::CreateAndReject(rv, __func__);
|
||||
});
|
||||
}
|
||||
|
||||
nsresult DocGroup::Dispatch(TaskCategory aCategory,
|
||||
already_AddRefed<nsIRunnable>&& aRunnable) {
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "mozilla/dom/BrowsingContextGroup.h"
|
||||
#include "mozilla/dom/HTMLSlotElement.h"
|
||||
#include "mozilla/PerformanceCounter.h"
|
||||
#include "mozilla/PerformanceTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
class AbstractThread;
|
||||
@ -63,8 +62,6 @@ class DocGroup final {
|
||||
JSExecutionManager* GetExecutionManager() const { return mExecutionManager; }
|
||||
void SetExecutionManager(JSExecutionManager*);
|
||||
|
||||
RefPtr<PerformanceInfoPromise> ReportPerformanceInfo();
|
||||
|
||||
BrowsingContextGroup* GetBrowsingContextGroup() const {
|
||||
return mBrowsingContextGroup;
|
||||
}
|
||||
|
@ -554,12 +554,6 @@ partial namespace ChromeUtils {
|
||||
[Throws]
|
||||
object createError(DOMString message, optional object? stack = null);
|
||||
|
||||
/**
|
||||
* Request performance metrics to the current process & all content processes.
|
||||
*/
|
||||
[NewObject]
|
||||
Promise<sequence<PerformanceInfoDictionary>> requestPerformanceMetrics();
|
||||
|
||||
/**
|
||||
* Set the collection of specific detailed performance timing information.
|
||||
* Selecting 0 for the mask will end existing collection. All metrics that
|
||||
@ -883,42 +877,6 @@ dictionary ParentProcInfoDictionary {
|
||||
WebIDLProcType type = "browser";
|
||||
};
|
||||
|
||||
/**
|
||||
* Dictionaries duplicating IPDL types in dom/ipc/DOMTypes.ipdlh
|
||||
* Used by requestPerformanceMetrics
|
||||
*/
|
||||
dictionary MediaMemoryInfoDictionary {
|
||||
unsigned long long audioSize = 0;
|
||||
unsigned long long videoSize = 0;
|
||||
unsigned long long resourcesSize = 0;
|
||||
};
|
||||
|
||||
dictionary MemoryInfoDictionary {
|
||||
unsigned long long domDom = 0;
|
||||
unsigned long long domStyle = 0;
|
||||
unsigned long long domOther = 0;
|
||||
unsigned long long jsMemUsage = 0;
|
||||
required MediaMemoryInfoDictionary media;
|
||||
};
|
||||
|
||||
dictionary CategoryDispatchDictionary
|
||||
{
|
||||
unsigned short category = 0;
|
||||
unsigned short count = 0;
|
||||
};
|
||||
|
||||
dictionary PerformanceInfoDictionary {
|
||||
ByteString host = "";
|
||||
unsigned long pid = 0;
|
||||
unsigned long long windowId = 0;
|
||||
unsigned long long duration = 0;
|
||||
unsigned long long counterId = 0;
|
||||
boolean isWorker = false;
|
||||
boolean isTopLevel = false;
|
||||
required MemoryInfoDictionary memoryInfo;
|
||||
sequence<CategoryDispatchDictionary> items = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Used by requestIOActivity() to return the number of bytes
|
||||
* that were read (rx) and/or written (tx) for a given location.
|
||||
|
@ -32,8 +32,6 @@
|
||||
#include "mozilla/MemoryTelemetry.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "mozilla/PerfStats.h"
|
||||
#include "mozilla/PerformanceMetricsCollector.h"
|
||||
#include "mozilla/PerformanceUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/ProcessHangMonitorIPC.h"
|
||||
#include "mozilla/RemoteDecoderManagerChild.h"
|
||||
@ -1548,25 +1546,6 @@ mozilla::ipc::IPCResult ContentChild::GetResultForRenderingInitFailure(
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentChild::RecvRequestPerformanceMetrics(
|
||||
const nsID& aID) {
|
||||
RefPtr<ContentChild> self = this;
|
||||
RefPtr<AbstractThread> mainThread = AbstractThread::MainThread();
|
||||
nsTArray<RefPtr<PerformanceInfoPromise>> promises = CollectPerformanceInfo();
|
||||
|
||||
PerformanceInfoPromise::All(mainThread, promises)
|
||||
->Then(
|
||||
mainThread, __func__,
|
||||
[self, aID](const nsTArray<mozilla::dom::PerformanceInfo>& aResult) {
|
||||
self->SendAddPerformanceMetrics(aID, aResult);
|
||||
},
|
||||
[]() { /* silently fails -- the parent times out
|
||||
and proceeds when the data is not coming back */
|
||||
});
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
extern "C" {
|
||||
void CGSShutdownServerConnections();
|
||||
|
@ -166,8 +166,6 @@ class ContentChild final : public PContentChild,
|
||||
Endpoint<PRemoteDecoderManagerChild>&& aVideoManager,
|
||||
nsTArray<uint32_t>&& namespaces);
|
||||
|
||||
mozilla::ipc::IPCResult RecvRequestPerformanceMetrics(const nsID& aID);
|
||||
|
||||
mozilla::ipc::IPCResult RecvReinitRendering(
|
||||
Endpoint<PCompositorManagerChild>&& aCompositor,
|
||||
Endpoint<PImageBridgeChild>&& aImageBridge,
|
||||
|
@ -67,7 +67,6 @@
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "mozilla/PerformanceMetricsCollector.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/ProcessHangMonitor.h"
|
||||
@ -4619,13 +4618,6 @@ mozilla::ipc::IPCResult ContentParent::RecvAddMemoryReport(
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvAddPerformanceMetrics(
|
||||
const nsID& aID, nsTArray<PerformanceInfo>&& aMetrics) {
|
||||
nsresult rv = PerformanceMetricsCollector::DataReceived(aID, aMetrics);
|
||||
Unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
PCycleCollectWithLogsParent* ContentParent::AllocPCycleCollectWithLogsParent(
|
||||
const bool& aDumpAllTraces, const FileDescriptor& aGCLog,
|
||||
const FileDescriptor& aCCLog) {
|
||||
|
@ -895,8 +895,6 @@ class ContentParent final : public PContentParent,
|
||||
Endpoint<mozilla::ipc::PBackgroundStarterParent>&& aEndpoint);
|
||||
|
||||
mozilla::ipc::IPCResult RecvAddMemoryReport(const MemoryReport& aReport);
|
||||
mozilla::ipc::IPCResult RecvAddPerformanceMetrics(
|
||||
const nsID& aID, nsTArray<PerformanceInfo>&& aMetrics);
|
||||
|
||||
bool DeallocPRemoteSpellcheckEngineParent(PRemoteSpellcheckEngineParent*);
|
||||
|
||||
|
@ -153,66 +153,6 @@ struct CreatedWindowInfo
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* PerformanceInfo is used to pass performance info stored
|
||||
* in WorkerPrivate and DocGroup instances, as well as
|
||||
* memory-related information.
|
||||
*
|
||||
* Each (host, pid, windowId) is unique to a given DocGroup or
|
||||
* Worker, and we collect the number of dispatches per Dispatch
|
||||
* category and total execution duration as well as the current
|
||||
* Zone JS Heap usage.
|
||||
*
|
||||
* This IPDL struct reflects the data collected in Performance counters,
|
||||
* in addition of some memory usage information.
|
||||
*
|
||||
* see xpcom/threads/PerformanceCounter.h
|
||||
*/
|
||||
|
||||
struct MediaMemoryInfo {
|
||||
uint64_t audioSize;
|
||||
uint64_t videoSize;
|
||||
uint64_t resourcesSize;
|
||||
};
|
||||
|
||||
struct PerformanceMemoryInfo {
|
||||
MediaMemoryInfo media;
|
||||
uint64_t domDom;
|
||||
uint64_t domStyle;
|
||||
uint64_t domOther;
|
||||
uint64_t jsMemUsage;
|
||||
};
|
||||
|
||||
struct CategoryDispatch
|
||||
{
|
||||
// DispatchCategory value
|
||||
uint16_t category;
|
||||
// Number of dispatch
|
||||
uint16_t count;
|
||||
};
|
||||
|
||||
struct PerformanceInfo
|
||||
{
|
||||
// Host of the document, if any
|
||||
nsCString host;
|
||||
// process id
|
||||
uint32_t pid;
|
||||
// window id
|
||||
uint64_t windowId;
|
||||
// Execution time in microseconds
|
||||
uint64_t duration;
|
||||
// Counter ID (unique across processes)
|
||||
uint64_t counterId;
|
||||
// True if the data is collected in a worker
|
||||
bool isWorker;
|
||||
// True if the document window is the top window
|
||||
bool isTopLevel;
|
||||
// Memory
|
||||
PerformanceMemoryInfo memory;
|
||||
// Counters per category. For workers, a single entry
|
||||
CategoryDispatch[] items;
|
||||
};
|
||||
|
||||
struct DocShellLoadStateInit
|
||||
{
|
||||
nullable nsIURI URI;
|
||||
|
@ -609,8 +609,6 @@ child:
|
||||
FileDescriptor? DMDFile)
|
||||
returns (uint32_t aGeneration);
|
||||
|
||||
async RequestPerformanceMetrics(nsID aID);
|
||||
|
||||
#if defined(XP_WIN)
|
||||
/**
|
||||
* Used by third-party modules telemetry (aka "untrusted modules" telemetry)
|
||||
@ -1639,8 +1637,6 @@ parent:
|
||||
|
||||
async BHRThreadHang(HangDetails aHangDetails);
|
||||
|
||||
async AddPerformanceMetrics(nsID aID, PerformanceInfo[] aMetrics);
|
||||
|
||||
/*
|
||||
* Adds a certificate exception for the given hostname and port.
|
||||
*/
|
||||
|
@ -114,51 +114,10 @@ class MediaMemoryTracker : public nsIMemoryReporter {
|
||||
sUniqueInstance = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static RefPtr<MediaMemoryPromise> GetSizes(dom::Document* aDoc) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
DecodersArray& decoders = Decoders();
|
||||
|
||||
// if we don't have any decoder, we can bail
|
||||
if (decoders.IsEmpty()) {
|
||||
// and release the instance that was created by calling Decoders()
|
||||
sUniqueInstance = nullptr;
|
||||
return MediaMemoryPromise::CreateAndResolve(MediaMemoryInfo(), __func__);
|
||||
}
|
||||
|
||||
RefPtr<MediaDecoder::ResourceSizes> resourceSizes =
|
||||
new MediaDecoder::ResourceSizes(MediaMemoryTracker::MallocSizeOf);
|
||||
|
||||
size_t videoSize = 0;
|
||||
size_t audioSize = 0;
|
||||
|
||||
for (auto&& decoder : decoders) {
|
||||
if (decoder->GetOwner() && decoder->GetOwner()->GetDocument() == aDoc) {
|
||||
videoSize += decoder->SizeOfVideoQueue();
|
||||
audioSize += decoder->SizeOfAudioQueue();
|
||||
decoder->AddSizeOfResources(resourceSizes);
|
||||
}
|
||||
}
|
||||
|
||||
return resourceSizes->Promise()->Then(
|
||||
AbstractThread::MainThread(), __func__,
|
||||
[videoSize, audioSize](size_t resourceSize) {
|
||||
return MediaMemoryPromise::CreateAndResolve(
|
||||
MediaMemoryInfo(videoSize, audioSize, resourceSize), __func__);
|
||||
},
|
||||
[](size_t) {
|
||||
return MediaMemoryPromise::CreateAndReject(NS_ERROR_FAILURE,
|
||||
__func__);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
StaticRefPtr<MediaMemoryTracker> MediaMemoryTracker::sUniqueInstance;
|
||||
|
||||
RefPtr<MediaMemoryPromise> GetMediaMemorySizes(dom::Document* aDoc) {
|
||||
return MediaMemoryTracker::GetSizes(aDoc);
|
||||
}
|
||||
|
||||
LazyLogModule gMediaTimerLog("MediaTimer");
|
||||
|
||||
constexpr TimeUnit MediaDecoder::DEFAULT_NEXT_FRAME_AVAILABLE_BUFFERED;
|
||||
|
@ -36,10 +36,6 @@ class nsIPrincipal;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class MediaMemoryInfo;
|
||||
}
|
||||
|
||||
class AbstractThread;
|
||||
class DOMMediaStream;
|
||||
class DecoderBenchmark;
|
||||
@ -826,11 +822,6 @@ class MediaDecoder : public DecoderDoctorLifeLogger<MediaDecoder> {
|
||||
# endif
|
||||
};
|
||||
|
||||
typedef MozPromise<mozilla::dom::MediaMemoryInfo, nsresult, true>
|
||||
MediaMemoryPromise;
|
||||
|
||||
RefPtr<MediaMemoryPromise> GetMediaMemorySizes(dom::Document* aDoc);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
@ -1,21 +0,0 @@
|
||||
[DEFAULT]
|
||||
prefs =
|
||||
dom.performance.children_results_ipc_timeout=2000
|
||||
|
||||
support-files =
|
||||
dummy.html
|
||||
ping_worker.html
|
||||
ping_worker2.html
|
||||
ping_worker.js
|
||||
setinterval.html
|
||||
settimeout.html
|
||||
shared_worker.js
|
||||
unresponsive.html
|
||||
hello.ogg
|
||||
sound.html
|
||||
|
||||
[browser_test_performance_metrics.js]
|
||||
skip-if = verify
|
||||
|
||||
[browser_test_unresponsive.js]
|
||||
skip-if = true # Bug 1498426
|
@ -1,201 +0,0 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=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/. */
|
||||
|
||||
const ROOT_URL = "http://example.com/browser/dom/tests/browser/perfmetrics";
|
||||
const DUMMY_URL = ROOT_URL + "/dummy.html";
|
||||
const WORKER_URL = ROOT_URL + "/ping_worker.html";
|
||||
const WORKER_URL2 = ROOT_URL + "/ping_worker2.html";
|
||||
const INTERVAL_URL = ROOT_URL + "/setinterval.html";
|
||||
const TIMEOUT_URL = ROOT_URL + "/settimeout.html";
|
||||
const SOUND_URL = ROOT_URL + "/sound.html";
|
||||
const CATEGORY_TIMER = 2;
|
||||
|
||||
add_task(async function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
// Load 3 pages and wait. The 3rd one has a worker
|
||||
let page1 = await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
opening: "about:about",
|
||||
forceNewProcess: false,
|
||||
});
|
||||
|
||||
let page2 = await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
opening: "about:memory",
|
||||
forceNewProcess: false,
|
||||
});
|
||||
|
||||
let page3 = await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
opening: WORKER_URL,
|
||||
});
|
||||
// load a 4th tab with a worker
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: WORKER_URL2 },
|
||||
async function (browser) {
|
||||
// grab events..
|
||||
let workerDuration = 0;
|
||||
let workerTotal = 0;
|
||||
let duration = 0;
|
||||
let total = 0;
|
||||
let isTopLevel = false;
|
||||
let aboutMemoryFound = false;
|
||||
let parentProcessEvent = false;
|
||||
let subFrameIds = [];
|
||||
let topLevelIds = [];
|
||||
let sharedWorker = false;
|
||||
let counterIds = [];
|
||||
let timerCalls = 0;
|
||||
let heapUsage = 0;
|
||||
let mediaMemory = 0;
|
||||
|
||||
function exploreResults(data, filterByWindowId) {
|
||||
for (let entry of data) {
|
||||
if (filterByWindowId && entry.windowId != filterByWindowId) {
|
||||
continue;
|
||||
}
|
||||
if (!counterIds.includes(entry.pid + ":" + entry.counterId)) {
|
||||
counterIds.push(entry.pid + ":" + entry.counterId);
|
||||
}
|
||||
sharedWorker =
|
||||
entry.host.endsWith("shared_worker.js") || sharedWorker;
|
||||
heapUsage += entry.memoryInfo.jsMemUsage;
|
||||
mediaMemory +=
|
||||
entry.memoryInfo.media.audioSize +
|
||||
entry.memoryInfo.media.resourcesSize;
|
||||
Assert.ok(
|
||||
entry.host != "" || entry.windowId != 0,
|
||||
"An entry should have a host or a windowId"
|
||||
);
|
||||
if (
|
||||
entry.windowId != 0 &&
|
||||
!entry.isToplevel &&
|
||||
!entry.isWorker &&
|
||||
!subFrameIds.includes(entry.windowId)
|
||||
) {
|
||||
subFrameIds.push(entry.windowId);
|
||||
}
|
||||
if (entry.isTopLevel && !topLevelIds.includes(entry.windowId)) {
|
||||
topLevelIds.push(entry.windowId);
|
||||
}
|
||||
if (entry.host == "example.com" && entry.isTopLevel) {
|
||||
isTopLevel = true;
|
||||
}
|
||||
if (entry.host == "about:memory") {
|
||||
aboutMemoryFound = true;
|
||||
}
|
||||
if (entry.pid == Services.appinfo.processID) {
|
||||
parentProcessEvent = true;
|
||||
}
|
||||
if (entry.isWorker) {
|
||||
workerDuration += entry.duration;
|
||||
} else {
|
||||
duration += entry.duration;
|
||||
}
|
||||
// let's look at the data we got back
|
||||
for (let item of entry.items) {
|
||||
Assert.ok(
|
||||
item.count > 0,
|
||||
"Categories with an empty count are dropped"
|
||||
);
|
||||
if (entry.isWorker) {
|
||||
workerTotal += item.count;
|
||||
} else {
|
||||
total += item.count;
|
||||
}
|
||||
if (item.category == CATEGORY_TIMER) {
|
||||
timerCalls += item.count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get all metrics via the promise
|
||||
let results = await ChromeUtils.requestPerformanceMetrics();
|
||||
exploreResults(results);
|
||||
|
||||
Assert.greater(workerDuration, 0, "Worker duration should be positive");
|
||||
Assert.greater(workerTotal, 0, "Worker count should be positive");
|
||||
Assert.greater(duration, 0, "Duration should be positive");
|
||||
Assert.greater(total, 0, "Should get a positive count");
|
||||
Assert.ok(parentProcessEvent, "parent process sent back some events");
|
||||
Assert.ok(isTopLevel, "example.com as a top level window");
|
||||
Assert.ok(aboutMemoryFound, "about:memory");
|
||||
Assert.greater(heapUsage, 0, "got some memory value reported");
|
||||
Assert.ok(sharedWorker, "We got some info from a shared worker");
|
||||
let numCounters = counterIds.length;
|
||||
Assert.ok(
|
||||
numCounters > 5,
|
||||
"This test generated at least " + numCounters + " unique counters"
|
||||
);
|
||||
|
||||
// checking that subframes are not orphans
|
||||
for (let frameId of subFrameIds) {
|
||||
Assert.ok(topLevelIds.includes(frameId), "subframe is not orphan ");
|
||||
}
|
||||
|
||||
// Doing a second call, we shoud get bigger values
|
||||
let previousWorkerDuration = workerDuration;
|
||||
let previousWorkerTotal = workerTotal;
|
||||
let previousDuration = duration;
|
||||
let previousTotal = total;
|
||||
|
||||
results = await ChromeUtils.requestPerformanceMetrics();
|
||||
exploreResults(results);
|
||||
|
||||
Assert.ok(
|
||||
workerDuration > previousWorkerDuration,
|
||||
"Worker duration should be positive"
|
||||
);
|
||||
Assert.ok(
|
||||
workerTotal > previousWorkerTotal,
|
||||
"Worker count should be positive"
|
||||
);
|
||||
Assert.greater(duration, previousDuration, "Duration should be positive");
|
||||
Assert.greater(total, previousTotal, "Should get a positive count");
|
||||
|
||||
// load a tab with a setInterval, we should get counters on TaskCategory::Timer
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: INTERVAL_URL },
|
||||
async function (browser) {
|
||||
let tabId = gBrowser.selectedBrowser.outerWindowID;
|
||||
let previousTimerCalls = timerCalls;
|
||||
results = await ChromeUtils.requestPerformanceMetrics();
|
||||
exploreResults(results, tabId);
|
||||
Assert.greater(timerCalls, previousTimerCalls, "Got timer calls");
|
||||
}
|
||||
);
|
||||
|
||||
// load a tab with a setTimeout, we should get counters on TaskCategory::Timer
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: TIMEOUT_URL },
|
||||
async function (browser) {
|
||||
let tabId = gBrowser.selectedBrowser.outerWindowID;
|
||||
let previousTimerCalls = timerCalls;
|
||||
results = await ChromeUtils.requestPerformanceMetrics();
|
||||
exploreResults(results, tabId);
|
||||
Assert.greater(timerCalls, previousTimerCalls, "Got timer calls");
|
||||
}
|
||||
);
|
||||
|
||||
// load a tab with a sound
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: SOUND_URL },
|
||||
async function (browser) {
|
||||
let tabId = gBrowser.selectedBrowser.outerWindowID;
|
||||
results = await ChromeUtils.requestPerformanceMetrics();
|
||||
exploreResults(results, tabId);
|
||||
Assert.greater(mediaMemory, 0, "Got some memory used for media");
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
BrowserTestUtils.removeTab(page1);
|
||||
BrowserTestUtils.removeTab(page2);
|
||||
BrowserTestUtils.removeTab(page3);
|
||||
});
|
@ -1,31 +0,0 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=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/. */
|
||||
|
||||
const ROOT_URL = "http://example.com/browser/dom/tests/browser/perfmetrics";
|
||||
const PAGE_URL = ROOT_URL + "/unresponsive.html";
|
||||
|
||||
add_task(async function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: PAGE_URL },
|
||||
async function (browser) {
|
||||
let dataBack = 0;
|
||||
let tabId = gBrowser.selectedBrowser.outerWindowID;
|
||||
|
||||
function exploreResults(data, filterByWindowId) {
|
||||
for (let entry of data) {
|
||||
if (entry.windowId == tabId && entry.host != "about:blank") {
|
||||
dataBack += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
let results = await ChromeUtils.requestPerformanceMetrics();
|
||||
exploreResults(results);
|
||||
Assert.ok(dataBack == 0);
|
||||
}
|
||||
);
|
||||
});
|
@ -1,13 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Dummy test page</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
|
||||
</head>
|
||||
<body>
|
||||
<p>Dummy test page</p>
|
||||
<script>
|
||||
localStorage.setItem("foo", "bar");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript">
|
||||
|
||||
var myWorker;
|
||||
var shared;
|
||||
|
||||
function init() {
|
||||
myWorker = new Worker("ping_worker.js");
|
||||
for (let i = 0; i++; i < 10) myWorker.postMessage("ping");
|
||||
|
||||
shared = new SharedWorker("shared_worker.js");
|
||||
shared.port.start();
|
||||
shared.port.onmessage = function(e) {
|
||||
console.log(e);
|
||||
};
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<h1>A page with a worker and a shared worker</h1>
|
||||
</body>
|
||||
</html>
|
@ -1,11 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
function messageListener(event) {
|
||||
postMessage("pong");
|
||||
}
|
||||
|
||||
addEventListener("message", { handleEvent: messageListener });
|
@ -1,20 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript">
|
||||
|
||||
var shared;
|
||||
|
||||
function init() {
|
||||
shared = new SharedWorker("shared_worker.js");
|
||||
shared.port.start();
|
||||
for (let i = 0; i < 10; i++) shared.port.postMessage(["ok"]);
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<h1>A page with a shared worker</h1>
|
||||
</body>
|
||||
</html>
|
@ -1,19 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript">
|
||||
var interval;
|
||||
|
||||
function doSomething() {
|
||||
console.log("We are doing something here");
|
||||
clearInterval(interval);
|
||||
}
|
||||
|
||||
interval = setInterval(doSomething, 1);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>A page with a setInterval() call</h1>
|
||||
</body>
|
||||
</html>
|
@ -1,17 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript">
|
||||
|
||||
function doSomething() {
|
||||
console.log("We are doing something here");
|
||||
}
|
||||
|
||||
setTimeout(doSomething, 1);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>A page with a setTimeout() call</h1>
|
||||
</body>
|
||||
</html>
|
@ -1,7 +0,0 @@
|
||||
let onconnect = function (e) {
|
||||
var port = e.ports[0];
|
||||
|
||||
port.onmessage = function (e) {
|
||||
port.postMessage(e.data[0]);
|
||||
};
|
||||
};
|
@ -1,14 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Dummy test page</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
|
||||
</head>
|
||||
<body>
|
||||
<p>Page with a sound</p>
|
||||
<audio controls autoplay>
|
||||
<source src="hello.ogg" type="audio/ogg">
|
||||
</audio>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,21 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript">
|
||||
|
||||
function fn() {
|
||||
let start = Date.now();
|
||||
while (Date.now() - start < 5000)
|
||||
; // do nothing
|
||||
setTimeout(fn, 0);
|
||||
}
|
||||
|
||||
setTimeout(fn, 10);
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>An unresponsive page</h1>
|
||||
</body>
|
||||
</html>
|
@ -189,7 +189,6 @@ MOCHITEST_CHROME_MANIFESTS += [
|
||||
XPCSHELL_TESTS_MANIFESTS += ["unit/xpcshell.ini"]
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
"browser/browser.ini",
|
||||
"browser/perfmetrics/browser.ini",
|
||||
]
|
||||
|
||||
TEST_HARNESS_FILES.testing.mochitest.tests.dom.tests.mochitest.ajax.lib += [
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "mozilla/dom/WindowContext.h"
|
||||
#include "mozilla/AbstractThread.h"
|
||||
#include "mozilla/Encoding.h"
|
||||
#include "mozilla/PerformanceUtils.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsQueryObject.h"
|
||||
#include "nsThreadUtils.h"
|
||||
@ -498,107 +497,4 @@ void WorkerDebugger::ReportErrorToDebuggerOnMainThread(
|
||||
WorkerErrorReport::LogErrorToConsole(jsapi.cx(), report, 0);
|
||||
}
|
||||
|
||||
RefPtr<PerformanceInfoPromise> WorkerDebugger::ReportPerformanceInfo() {
|
||||
AssertIsOnMainThread();
|
||||
RefPtr<WorkerDebugger> self = this;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
uint32_t pid = GetCurrentProcessId();
|
||||
#else
|
||||
uint32_t pid = getpid();
|
||||
#endif
|
||||
bool isTopLevel = false;
|
||||
uint64_t windowID = mWorkerPrivate->WindowID();
|
||||
|
||||
// Walk up to our containing page and its window
|
||||
WorkerPrivate* wp = mWorkerPrivate;
|
||||
while (wp->GetParent()) {
|
||||
wp = wp->GetParent();
|
||||
}
|
||||
nsPIDOMWindowInner* win = wp->GetWindow();
|
||||
if (win) {
|
||||
BrowsingContext* context = win->GetBrowsingContext();
|
||||
if (context) {
|
||||
RefPtr<BrowsingContext> top = context->Top();
|
||||
if (top && top->GetCurrentWindowContext()) {
|
||||
windowID = top->GetCurrentWindowContext()->OuterWindowId();
|
||||
isTopLevel = context->IsTop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getting the worker URL
|
||||
RefPtr<nsIURI> scriptURI = mWorkerPrivate->GetResolvedScriptURI();
|
||||
if (NS_WARN_IF(!scriptURI)) {
|
||||
// This can happen at shutdown, let's stop here.
|
||||
return PerformanceInfoPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
nsCString url = scriptURI->GetSpecOrDefault();
|
||||
|
||||
const auto& perf = mWorkerPrivate->PerformanceCounterRef();
|
||||
uint64_t perfId = perf.GetID();
|
||||
uint16_t count = perf.GetTotalDispatchCount();
|
||||
uint64_t duration = perf.GetExecutionDuration();
|
||||
|
||||
// Workers only produce metrics for a single category -
|
||||
// DispatchCategory::Worker. We still return an array of CategoryDispatch so
|
||||
// the PerformanceInfo struct is common to all performance counters throughout
|
||||
// Firefox.
|
||||
FallibleTArray<CategoryDispatch> items;
|
||||
|
||||
if (mWorkerPrivate->GetParent()) {
|
||||
// We cannot properly measure the memory usage of nested workers
|
||||
// (https://phabricator.services.mozilla.com/D146673#4948924)
|
||||
return PerformanceInfoPromise::CreateAndResolve(
|
||||
PerformanceInfo(url, pid, windowID, duration, perfId, true, isTopLevel,
|
||||
PerformanceMemoryInfo(), items),
|
||||
__func__);
|
||||
}
|
||||
|
||||
CategoryDispatch item =
|
||||
CategoryDispatch(DispatchCategory::Worker.GetValue(), count);
|
||||
if (!items.AppendElement(item, fallible)) {
|
||||
NS_ERROR("Could not complete the operation");
|
||||
}
|
||||
|
||||
// Switch to the worker thread to gather the JS Runtime's memory usage.
|
||||
RefPtr<WorkerPrivate::JSMemoryUsagePromise> memoryUsagePromise =
|
||||
mWorkerPrivate->GetJSMemoryUsage();
|
||||
if (!memoryUsagePromise) {
|
||||
// The worker is shutting down, so we don't count the JavaScript memory.
|
||||
return PerformanceInfoPromise::CreateAndResolve(
|
||||
PerformanceInfo(url, pid, windowID, duration, perfId, true, isTopLevel,
|
||||
PerformanceMemoryInfo(), items),
|
||||
__func__);
|
||||
}
|
||||
|
||||
// We need to keep a ref on workerPrivate, passed to the promise,
|
||||
// to make sure it's still alive when collecting the info, and we can't do
|
||||
// this in WorkerPrivate::GetJSMemoryUsage() since that could cause it to be
|
||||
// freed on the worker thread.
|
||||
// Because CheckedUnsafePtr does not convert directly to RefPtr, we have an
|
||||
// extra step here.
|
||||
WorkerPrivate* workerPtr = mWorkerPrivate;
|
||||
RefPtr<WorkerPrivate> workerRef = workerPtr;
|
||||
|
||||
// This captures an unused reference to memoryUsagePromise because the worker
|
||||
// can be released while this promise is still alive.
|
||||
return memoryUsagePromise->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[url, pid, perfId, windowID, duration, isTopLevel,
|
||||
items = std::move(items), _w = std::move(workerRef),
|
||||
memoryUsagePromise](uint64_t jsMem) {
|
||||
PerformanceMemoryInfo memInfo;
|
||||
memInfo.jsMemUsage() = jsMem;
|
||||
return PerformanceInfoPromise::CreateAndResolve(
|
||||
PerformanceInfo(url, pid, windowID, duration, perfId, true,
|
||||
isTopLevel, memInfo, items),
|
||||
__func__);
|
||||
},
|
||||
[]() {
|
||||
return PerformanceInfoPromise::CreateAndReject(NS_ERROR_FAILURE,
|
||||
__func__);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
@ -7,7 +7,6 @@
|
||||
#ifndef mozilla_dom_workers_WorkerDebugger_h
|
||||
#define mozilla_dom_workers_WorkerDebugger_h
|
||||
|
||||
#include "mozilla/PerformanceTypes.h"
|
||||
#include "mozilla/dom/WorkerScope.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIWorkerDebugger.h"
|
||||
@ -43,12 +42,6 @@ class WorkerDebugger : public nsIWorkerDebugger {
|
||||
void ReportErrorToDebugger(const nsAString& aFilename, uint32_t aLineno,
|
||||
const nsAString& aMessage);
|
||||
|
||||
/*
|
||||
* Sends back a PerformanceInfo struct from the counters
|
||||
* in mWorkerPrivate. Counters are reset to zero after this call.
|
||||
*/
|
||||
RefPtr<PerformanceInfoPromise> ReportPerformanceInfo();
|
||||
|
||||
private:
|
||||
virtual ~WorkerDebugger();
|
||||
|
||||
|
@ -51,7 +51,6 @@ DIRS += [
|
||||
"parentalcontrols",
|
||||
"passwordmgr",
|
||||
"pdfjs",
|
||||
"perfmonitoring",
|
||||
"pictureinpicture",
|
||||
"places",
|
||||
"processtools",
|
||||
|
@ -1,315 +0,0 @@
|
||||
/* -*- 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/AbstractThread.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/PerformanceUtils.h"
|
||||
#include "mozilla/PerformanceMetricsCollector.h"
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
#include "mozilla/TaskQueue.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/WorkerDebugger.h"
|
||||
#include "mozilla/dom/WorkerDebuggerManager.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
static mozilla::LazyLogModule sPerfLog("PerformanceMetricsCollector");
|
||||
#ifdef LOG
|
||||
# undef LOG
|
||||
#endif
|
||||
#define LOG(args) MOZ_LOG(sPerfLog, mozilla::LogLevel::Debug, args)
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
//
|
||||
// class IPCTimeout
|
||||
//
|
||||
NS_IMPL_ISUPPORTS(IPCTimeout, nsITimerCallback, nsINamed)
|
||||
|
||||
// static
|
||||
IPCTimeout* IPCTimeout::CreateInstance(AggregatedResults* aResults) {
|
||||
MOZ_ASSERT(aResults);
|
||||
uint32_t delay = StaticPrefs::dom_performance_children_results_ipc_timeout();
|
||||
if (delay == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return new IPCTimeout(aResults, delay);
|
||||
}
|
||||
|
||||
IPCTimeout::IPCTimeout(AggregatedResults* aResults, uint32_t aDelay)
|
||||
: mResults(aResults) {
|
||||
MOZ_ASSERT(aResults);
|
||||
MOZ_ASSERT(aDelay > 0);
|
||||
mozilla::DebugOnly<nsresult> rv = NS_NewTimerWithCallback(
|
||||
getter_AddRefs(mTimer), this, aDelay, nsITimer::TYPE_ONE_SHOT);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
LOG(("IPCTimeout timer created"));
|
||||
}
|
||||
|
||||
IPCTimeout::~IPCTimeout() { Cancel(); }
|
||||
|
||||
void IPCTimeout::Cancel() {
|
||||
if (mTimer) {
|
||||
LOG(("IPCTimeout timer canceled"));
|
||||
mTimer->Cancel();
|
||||
mTimer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
IPCTimeout::Notify(nsITimer* aTimer) {
|
||||
LOG(("IPCTimeout timer triggered"));
|
||||
mResults->ResolveNow();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
IPCTimeout::GetName(nsACString& aName) {
|
||||
aName.AssignLiteral("IPCTimeout");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// class AggregatedResults
|
||||
//
|
||||
AggregatedResults::AggregatedResults(nsID aUUID,
|
||||
PerformanceMetricsCollector* aCollector)
|
||||
: mPendingResults(0), mCollector(aCollector), mUUID(aUUID) {
|
||||
MOZ_ASSERT(aCollector);
|
||||
mIPCTimeout = IPCTimeout::CreateInstance(this);
|
||||
}
|
||||
|
||||
void AggregatedResults::Abort(nsresult aReason) {
|
||||
MOZ_ASSERT(!mHolder.IsEmpty());
|
||||
MOZ_ASSERT(NS_FAILED(aReason));
|
||||
if (mIPCTimeout) {
|
||||
mIPCTimeout->Cancel();
|
||||
mIPCTimeout = nullptr;
|
||||
}
|
||||
mHolder.Reject(aReason, __func__);
|
||||
mPendingResults = 0;
|
||||
}
|
||||
|
||||
void AggregatedResults::ResolveNow() {
|
||||
MOZ_ASSERT(!mHolder.IsEmpty());
|
||||
LOG(("[%s] Early resolve", nsIDToCString(mUUID).get()));
|
||||
mHolder.Resolve(CopyableTArray(mData), __func__);
|
||||
mIPCTimeout = nullptr;
|
||||
mCollector->ForgetAggregatedResults(mUUID);
|
||||
}
|
||||
|
||||
void AggregatedResults::AppendResult(
|
||||
const nsTArray<dom::PerformanceInfo>& aMetrics) {
|
||||
if (mHolder.IsEmpty()) {
|
||||
// A previous call failed and the promise was already rejected
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(mPendingResults > 0);
|
||||
|
||||
// Each PerformanceInfo is converted into a PerformanceInfoDictionary
|
||||
for (const PerformanceInfo& result : aMetrics) {
|
||||
mozilla::dom::Sequence<mozilla::dom::CategoryDispatchDictionary> items;
|
||||
|
||||
for (const CategoryDispatch& entry : result.items()) {
|
||||
uint32_t count = entry.count();
|
||||
if (count == 0) {
|
||||
continue;
|
||||
}
|
||||
CategoryDispatchDictionary* item = items.AppendElement(fallible);
|
||||
if (NS_WARN_IF(!item)) {
|
||||
Abort(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
item->mCategory = entry.category();
|
||||
item->mCount = count;
|
||||
}
|
||||
|
||||
PerformanceInfoDictionary* data = mData.AppendElement(fallible);
|
||||
if (NS_WARN_IF(!data)) {
|
||||
Abort(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
data->mPid = result.pid();
|
||||
data->mWindowId = result.windowId();
|
||||
data->mHost.Assign(result.host());
|
||||
data->mDuration = result.duration();
|
||||
data->mCounterId = result.counterId();
|
||||
data->mIsWorker = result.isWorker();
|
||||
data->mIsTopLevel = result.isTopLevel();
|
||||
data->mMemoryInfo.mDomDom = result.memory().domDom();
|
||||
data->mMemoryInfo.mDomStyle = result.memory().domStyle();
|
||||
data->mMemoryInfo.mDomOther = result.memory().domOther();
|
||||
data->mMemoryInfo.mJsMemUsage = result.memory().jsMemUsage();
|
||||
data->mMemoryInfo.mMedia.mAudioSize = result.memory().media().audioSize();
|
||||
data->mMemoryInfo.mMedia.mVideoSize = result.memory().media().videoSize();
|
||||
data->mMemoryInfo.mMedia.mResourcesSize =
|
||||
result.memory().media().resourcesSize();
|
||||
data->mItems = items;
|
||||
}
|
||||
|
||||
mPendingResults--;
|
||||
if (mPendingResults) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(("[%s] All data collected, resolving promise",
|
||||
nsIDToCString(mUUID).get()));
|
||||
if (mIPCTimeout) {
|
||||
mIPCTimeout->Cancel();
|
||||
mIPCTimeout = nullptr;
|
||||
}
|
||||
nsTArray<dom::PerformanceInfoDictionary> data;
|
||||
data.Assign(mData);
|
||||
mHolder.Resolve(std::move(data), __func__);
|
||||
mCollector->ForgetAggregatedResults(mUUID);
|
||||
}
|
||||
|
||||
void AggregatedResults::SetNumResultsRequired(uint32_t aNumResultsRequired) {
|
||||
MOZ_ASSERT(!mPendingResults && aNumResultsRequired);
|
||||
mPendingResults = aNumResultsRequired;
|
||||
}
|
||||
|
||||
RefPtr<RequestMetricsPromise> AggregatedResults::GetPromise() {
|
||||
return mHolder.Ensure(__func__);
|
||||
}
|
||||
|
||||
//
|
||||
// class PerformanceMetricsCollector (singleton)
|
||||
//
|
||||
|
||||
// raw pointer for the singleton
|
||||
PerformanceMetricsCollector* gInstance = nullptr;
|
||||
|
||||
PerformanceMetricsCollector::~PerformanceMetricsCollector() {
|
||||
MOZ_ASSERT(gInstance == this);
|
||||
gInstance = nullptr;
|
||||
}
|
||||
|
||||
void PerformanceMetricsCollector::ForgetAggregatedResults(const nsID& aUUID) {
|
||||
MOZ_ASSERT(gInstance);
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
// This Remove() call will trigger AggregatedResults DTOR and if its
|
||||
// the last in the table, the DTOR of PerformanceMetricsCollector.
|
||||
// That's why we need to make sure we hold a reference here before the call
|
||||
RefPtr<PerformanceMetricsCollector> kungFuDeathGrip = this;
|
||||
LOG(("[%s] Removing from the table", nsIDToCString(aUUID).get()));
|
||||
mAggregatedResults.Remove(aUUID);
|
||||
}
|
||||
|
||||
// static
|
||||
RefPtr<RequestMetricsPromise> PerformanceMetricsCollector::RequestMetrics() {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
RefPtr<PerformanceMetricsCollector> pmc = gInstance;
|
||||
if (!pmc) {
|
||||
pmc = new PerformanceMetricsCollector();
|
||||
gInstance = pmc;
|
||||
}
|
||||
return pmc->RequestMetricsInternal();
|
||||
}
|
||||
|
||||
RefPtr<RequestMetricsPromise>
|
||||
PerformanceMetricsCollector::RequestMetricsInternal() {
|
||||
// each request has its own UUID
|
||||
nsID uuid;
|
||||
nsresult rv = nsID::GenerateUUIDInPlace(uuid);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return RequestMetricsPromise::CreateAndReject(rv, __func__);
|
||||
}
|
||||
|
||||
LOG(("[%s] Requesting Performance Metrics", nsIDToCString(uuid).get()));
|
||||
|
||||
// Getting all content processes
|
||||
nsTArray<ContentParent*> children;
|
||||
ContentParent::GetAll(children);
|
||||
uint32_t numChildren = children.Length();
|
||||
|
||||
// keep track of all results in an AggregatedResults instance
|
||||
UniquePtr<AggregatedResults> results =
|
||||
MakeUnique<AggregatedResults>(uuid, this);
|
||||
RefPtr<RequestMetricsPromise> promise = results->GetPromise();
|
||||
|
||||
// We want to get back as many results as children + one parent if needed
|
||||
uint32_t numResultsRequired = children.Length();
|
||||
nsTArray<RefPtr<PerformanceInfoPromise>> localPromises =
|
||||
CollectPerformanceInfo();
|
||||
if (!localPromises.IsEmpty()) {
|
||||
numResultsRequired++;
|
||||
}
|
||||
|
||||
LOG(("[%s] Expecting %d results back", nsIDToCString(uuid).get(),
|
||||
numResultsRequired));
|
||||
results->SetNumResultsRequired(numResultsRequired);
|
||||
const auto& aggregatedResult =
|
||||
mAggregatedResults.InsertOrUpdate(uuid, std::move(results));
|
||||
|
||||
// calling all content processes via IPDL (async)
|
||||
for (uint32_t i = 0; i < numChildren; i++) {
|
||||
if (NS_WARN_IF(!children[i]->SendRequestPerformanceMetrics(uuid))) {
|
||||
LOG(("[%s] Failed to send request to child %d", nsIDToCString(uuid).get(),
|
||||
i));
|
||||
aggregatedResult->Abort(NS_ERROR_FAILURE);
|
||||
return RequestMetricsPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
LOG(("[%s] Request sent to child %d", nsIDToCString(uuid).get(), i));
|
||||
}
|
||||
|
||||
nsTArray<RefPtr<PerformanceInfoPromise>> promises = CollectPerformanceInfo();
|
||||
if (promises.IsEmpty()) {
|
||||
return promise;
|
||||
}
|
||||
|
||||
// collecting the current process PerformanceInfo
|
||||
PerformanceInfoPromise::All(NS_GetCurrentThread(), localPromises)
|
||||
->Then(
|
||||
NS_GetCurrentThread(), __func__,
|
||||
[uuid](const nsTArray<mozilla::dom::PerformanceInfo> aResult) {
|
||||
LOG(("[%s] Local CollectPerformanceInfo promise resolved",
|
||||
nsIDToCString(uuid).get()));
|
||||
DataReceived(uuid, aResult);
|
||||
},
|
||||
[](const nsresult aResult) {});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult PerformanceMetricsCollector::DataReceived(
|
||||
const nsID& aUUID, const nsTArray<PerformanceInfo>& aMetrics) {
|
||||
// If some content process were unresponsive on shutdown, we may get called
|
||||
// here with late data received from children - so instead of asserting
|
||||
// that gInstance is available, we just return.
|
||||
if (!gInstance) {
|
||||
LOG(("[%s] gInstance is gone", nsIDToCString(aUUID).get()));
|
||||
return NS_OK;
|
||||
}
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
return gInstance->DataReceivedInternal(aUUID, aMetrics);
|
||||
}
|
||||
|
||||
nsresult PerformanceMetricsCollector::DataReceivedInternal(
|
||||
const nsID& aUUID, const nsTArray<PerformanceInfo>& aMetrics) {
|
||||
MOZ_ASSERT(gInstance == this);
|
||||
auto results = mAggregatedResults.Lookup(aUUID);
|
||||
if (!results) {
|
||||
LOG(("[%s] UUID is gone from mAggregatedResults",
|
||||
nsIDToCString(aUUID).get()));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
LOG(("[%s] Received one PerformanceInfo array", nsIDToCString(aUUID).get()));
|
||||
AggregatedResults* aggregatedResults = results->get();
|
||||
MOZ_ASSERT(aggregatedResults);
|
||||
|
||||
// If this is the last result, AppendResult() will trigger the deletion
|
||||
// of this collector, nothing should be done after this line.
|
||||
aggregatedResults->AppendResult(aMetrics);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
@ -1,106 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef PerformanceMetricsCollector_h
|
||||
#define PerformanceMetricsCollector_h
|
||||
|
||||
#include "nsIObserver.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsID.h"
|
||||
#include "nsTHashMap.h"
|
||||
#include "mozilla/dom/ChromeUtilsBinding.h" // defines PerformanceInfoDictionary
|
||||
#include "mozilla/dom/DOMTypes.h" // defines PerformanceInfo
|
||||
#include "mozilla/PerformanceTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class Promise;
|
||||
}
|
||||
|
||||
class PerformanceMetricsCollector;
|
||||
class AggregatedResults;
|
||||
|
||||
class IPCTimeout final : public nsITimerCallback, public nsINamed {
|
||||
public:
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
NS_DECL_NSINAMED
|
||||
NS_DECL_ISUPPORTS
|
||||
static IPCTimeout* CreateInstance(AggregatedResults* aResults);
|
||||
void Cancel();
|
||||
|
||||
private:
|
||||
IPCTimeout(AggregatedResults* aResults, uint32_t aDelay);
|
||||
~IPCTimeout();
|
||||
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
AggregatedResults* mResults;
|
||||
};
|
||||
|
||||
// AggregatedResults receives PerformanceInfo results that are collected
|
||||
// asynchronously via IPDL from all content processes.
|
||||
// They are converted into an array of
|
||||
// PerformanceInfoDictionary dictionaries (webidl)
|
||||
//
|
||||
// Once every process have sent back its results, AggregatedResults will
|
||||
// resolve the MozPromise returned by GetPromise()
|
||||
// with all the collected data.
|
||||
//
|
||||
// See ChromeUtils::RequestPerformanceMetrics.
|
||||
class AggregatedResults final {
|
||||
public:
|
||||
AggregatedResults(nsID aUUID, PerformanceMetricsCollector* aCollector);
|
||||
~AggregatedResults() = default;
|
||||
void AppendResult(const nsTArray<dom::PerformanceInfo>& aMetrics);
|
||||
void SetNumResultsRequired(uint32_t aNumResultsRequired);
|
||||
void Abort(nsresult aReason);
|
||||
void ResolveNow();
|
||||
RefPtr<RequestMetricsPromise> GetPromise();
|
||||
|
||||
private:
|
||||
RefPtr<IPCTimeout> mIPCTimeout;
|
||||
MozPromiseHolder<RequestMetricsPromise> mHolder;
|
||||
uint32_t mPendingResults;
|
||||
FallibleTArray<dom::PerformanceInfoDictionary> mData;
|
||||
|
||||
// AggregatedResults keeps a reference on the collector
|
||||
// so it gets destructed when all pending AggregatedResults
|
||||
// are themselves destructed when removed from
|
||||
// PerformanceMetricsCollector::mAggregatedResults.
|
||||
//
|
||||
// This lifecycle ensures that everything is released once
|
||||
// all pending results are sent.
|
||||
RefPtr<PerformanceMetricsCollector> mCollector;
|
||||
nsID mUUID;
|
||||
};
|
||||
|
||||
//
|
||||
// PerformanceMetricsCollector is instanciated as a singleton, and creates
|
||||
// one AggregatedResults instance everytime metrics are requested.
|
||||
//
|
||||
// Each AggregatedResults has a unique identifier (UUID) that is used
|
||||
// to send metrics requests via IPDL. When metrics are back in an
|
||||
// asynchronous fashion, the UUID is used to append the data to the
|
||||
// right AggregatedResults instance and eventually let it resolve the
|
||||
// linked promise.
|
||||
//
|
||||
class PerformanceMetricsCollector final {
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(PerformanceMetricsCollector)
|
||||
static RefPtr<RequestMetricsPromise> RequestMetrics();
|
||||
static nsresult DataReceived(const nsID& aUUID,
|
||||
const nsTArray<dom::PerformanceInfo>& aMetrics);
|
||||
void ForgetAggregatedResults(const nsID& aUUID);
|
||||
|
||||
private:
|
||||
~PerformanceMetricsCollector();
|
||||
RefPtr<RequestMetricsPromise> RequestMetricsInternal();
|
||||
nsresult DataReceivedInternal(const nsID& aUUID,
|
||||
const nsTArray<dom::PerformanceInfo>& aMetrics);
|
||||
nsTHashMap<nsID, UniquePtr<AggregatedResults>> mAggregatedResults;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
#endif // PerformanceMetricsCollector_h
|
@ -1,31 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef PerformanceTypes_h
|
||||
#define PerformanceTypes_h
|
||||
|
||||
#include "mozilla/MozPromise.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class PerformanceInfo;
|
||||
class PerformanceMemoryInfo;
|
||||
struct PerformanceInfoDictionary;
|
||||
} // namespace dom
|
||||
|
||||
/**
|
||||
* Promises definitions
|
||||
*/
|
||||
typedef MozPromise<dom::PerformanceInfo, nsresult, true> PerformanceInfoPromise;
|
||||
typedef MozPromise<nsTArray<dom::PerformanceInfoDictionary>, nsresult, true>
|
||||
RequestMetricsPromise;
|
||||
typedef MozPromise<nsTArray<dom::PerformanceInfo>, nsresult, true>
|
||||
PerformanceInfoArrayPromise;
|
||||
typedef MozPromise<mozilla::dom::PerformanceMemoryInfo, nsresult, true>
|
||||
MemoryPromise;
|
||||
|
||||
} // namespace mozilla
|
||||
#endif // PerformanceTypes_h
|
@ -1,186 +0,0 @@
|
||||
/* -*- 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
|
@ -1,32 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef PerformanceUtils_h
|
||||
#define PerformanceUtils_h
|
||||
|
||||
#include "mozilla/PerformanceTypes.h"
|
||||
|
||||
class nsPIDOMWindowOuter;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class BrowsingContext;
|
||||
class DocGroup;
|
||||
} // namespace dom
|
||||
/**
|
||||
* Returns an array of promises to asynchronously collect all performance
|
||||
* info in the current process.
|
||||
*/
|
||||
nsTArray<RefPtr<PerformanceInfoPromise>> CollectPerformanceInfo();
|
||||
|
||||
/**
|
||||
* Asynchronously collects memory info for a given window
|
||||
*/
|
||||
RefPtr<MemoryPromise> CollectMemoryInfo(
|
||||
const RefPtr<dom::DocGroup>& aDocGroup,
|
||||
const RefPtr<AbstractThread>& aEventTarget);
|
||||
|
||||
} // namespace mozilla
|
||||
#endif // PerformanceUtils_h
|
@ -1,23 +0,0 @@
|
||||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Toolkit", "Performance Monitoring")
|
||||
|
||||
|
||||
UNIFIED_SOURCES += ["PerformanceMetricsCollector.cpp", "PerformanceUtils.cpp"]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
"PerformanceMetricsCollector.h",
|
||||
"PerformanceTypes.h",
|
||||
"PerformanceUtils.h",
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += ["/dom/base"]
|
||||
|
||||
FINAL_LIBRARY = "xul"
|
||||
|
||||
include("/ipc/chromium/chromium-config.mozbuild")
|
Loading…
x
Reference in New Issue
Block a user