зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1447768 - part 2 - Dispatch counters in the parent process - r=baku
Chromeutils.RequestPerformanceMetrics() is now composed of two parts: - calls content processes via IPDL to get their counters - directly dispatch counters from the parent process MozReview-Commit-ID: HlgcEOzkyAq --HG-- extra : rebase_source : 60e81a27cd3a1bf1378e6b977529964507633b63
This commit is contained in:
Родитель
0cc1d7259a
Коммит
f9138cc6f4
|
@ -12,6 +12,9 @@
|
|||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#ifndef RELEASE_OR_BETA
|
||||
#include "mozilla/PerformanceUtils.h"
|
||||
#endif
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/IdleDeadline.h"
|
||||
|
@ -659,11 +662,25 @@ ChromeUtils::ClearRecentJSDevError(GlobalObject&)
|
|||
ChromeUtils::RequestPerformanceMetrics(GlobalObject&)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
// calling all content processes via IPDL (async)
|
||||
nsTArray<ContentParent*> children;
|
||||
ContentParent::GetAll(children);
|
||||
for (uint32_t i = 0; i < children.Length(); i++) {
|
||||
mozilla::Unused << children[i]->SendRequestPerformanceMetrics();
|
||||
}
|
||||
|
||||
|
||||
// collecting the current process counters and notifying them
|
||||
nsTArray<PerformanceInfo> info;
|
||||
CollectPerformanceInfo(info);
|
||||
SystemGroup::Dispatch(TaskCategory::Performance,
|
||||
NS_NewRunnableFunction(
|
||||
"RequestPerformanceMetrics",
|
||||
[info]() { mozilla::Unused << NS_WARN_IF(NS_FAILED(NotifyPerformanceInfo(info))); }
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ struct PerformanceInfo
|
|||
// Host of the document, if any
|
||||
nsCString host;
|
||||
// process id
|
||||
uint16_t pid;
|
||||
uint32_t pid;
|
||||
// window id
|
||||
uint64_t wid;
|
||||
// "parent" window id
|
||||
|
|
|
@ -9,6 +9,7 @@ support-files =
|
|||
worker_bug1004814.js
|
||||
geo_leak_test.html
|
||||
dummy.html
|
||||
ping_worker.html
|
||||
test_largeAllocation.html
|
||||
test_largeAllocation.html^headers^
|
||||
test_largeAllocation2.html
|
||||
|
|
|
@ -4,52 +4,113 @@
|
|||
* 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 TEST_URL = "http://example.com/browser/dom/tests/browser/dummy.html";
|
||||
ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
const ROOT_URL = "http://example.com/browser/dom/tests/browser";
|
||||
const DUMMY_URL = ROOT_URL + "/dummy.html";
|
||||
const WORKER_URL = ROOT_URL + "/ping_worker.html";
|
||||
|
||||
|
||||
let nextId = 0;
|
||||
|
||||
function jsonrpc(tab, method, params) {
|
||||
let currentId = nextId++;
|
||||
let messageManager = tab.linkedBrowser.messageManager;
|
||||
messageManager.sendAsyncMessage("jsonrpc", {
|
||||
id: currentId,
|
||||
method: method,
|
||||
params: params
|
||||
});
|
||||
return new Promise(function (resolve, reject) {
|
||||
messageManager.addMessageListener("jsonrpc", function listener(event) {
|
||||
let { id, result, error } = event.data;
|
||||
if (id !== currentId) {
|
||||
return;
|
||||
}
|
||||
messageManager.removeMessageListener("jsonrpc", listener);
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function postMessageToWorker(tab, message) {
|
||||
return jsonrpc(tab, "postMessageToWorker", [WORKER_URL, message]);
|
||||
}
|
||||
|
||||
add_task(async function test() {
|
||||
if (!AppConstants.RELEASE_OR_BETA) {
|
||||
SpecialPowers.setBoolPref('dom.performance.enable_scheduler_timing', true);
|
||||
waitForExplicitFinish();
|
||||
SpecialPowers.setBoolPref('dom.performance.enable_scheduler_timing', true);
|
||||
waitForExplicitFinish();
|
||||
|
||||
await BrowserTestUtils.withNewTab({ gBrowser, url: "http://example.com" },
|
||||
async function(browser) {
|
||||
// Load 3 pages and wait. The 3rd one has a worker
|
||||
let page1 = await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser, opening: 'about:about', forceNewProcess: false
|
||||
});
|
||||
|
||||
// grab events..
|
||||
var events = [];
|
||||
function getInfoFromService(subject, topic, value) {
|
||||
subject = subject.QueryInterface(Ci.nsIPerformanceMetricsData);
|
||||
if (subject.host == "example.com") {
|
||||
events.push(subject);
|
||||
let page2 = await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser, opening: 'about:memory', forceNewProcess: false
|
||||
});
|
||||
|
||||
let page3 = await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser, opening: "about:performance", forceNewProcess: true
|
||||
});
|
||||
|
||||
let parent_process_event = false;
|
||||
let worker_event = false;
|
||||
|
||||
// load a 4th tab with a worker
|
||||
await BrowserTestUtils.withNewTab({ gBrowser, url: WORKER_URL },
|
||||
async function(browser) {
|
||||
// grab events..
|
||||
var events = [];
|
||||
function getInfoFromService(subject, topic, value) {
|
||||
subject = subject.QueryInterface(Ci.nsIMutableArray);
|
||||
let enumerator = subject.enumerate();
|
||||
while (enumerator.hasMoreElements()) {
|
||||
let item = enumerator.getNext();
|
||||
item = item.QueryInterface(Ci.nsIPerformanceMetricsData);
|
||||
if (item.pid == Services.appinfo.processID) {
|
||||
parent_process_event = true;
|
||||
}
|
||||
if (item.worker) {
|
||||
worker_event = true;
|
||||
}
|
||||
events.push(item);
|
||||
}
|
||||
Services.obs.addObserver(getInfoFromService, "performance-metrics");
|
||||
}
|
||||
|
||||
// trigger an IPDL call
|
||||
Services.obs.addObserver(getInfoFromService, "performance-metrics");
|
||||
|
||||
// wait until we get some events back by triggering requestPerformanceMetrics
|
||||
await BrowserTestUtils.waitForCondition(() => {
|
||||
ChromeUtils.requestPerformanceMetrics();
|
||||
return events.length > 10;
|
||||
}, "wait for events to come in", 500, 10);
|
||||
|
||||
// wait until we get the events back
|
||||
await BrowserTestUtils.waitForCondition(() => {
|
||||
return events.length > 0;
|
||||
}, "wait for events to come in", 100, 20);
|
||||
|
||||
// let's check the last example.com tab event we got
|
||||
let last = events[0];
|
||||
Assert.equal(last.host, "example.com", "host should be example.com");
|
||||
Assert.ok(last.duration > 0, "Duration should be positive");
|
||||
BrowserTestUtils.removeTab(page1);
|
||||
BrowserTestUtils.removeTab(page2);
|
||||
BrowserTestUtils.removeTab(page3);
|
||||
|
||||
// let's check the events
|
||||
let duration = 0;
|
||||
let total = 0;
|
||||
for (let i=0; i < events.length; i++) {
|
||||
duration += events[i].duration;
|
||||
// let's look at the XPCOM data we got back
|
||||
let items = last.items.QueryInterface(Ci.nsIMutableArray);
|
||||
let items = events[i].items.QueryInterface(Ci.nsIMutableArray);
|
||||
let enumerator = items.enumerate();
|
||||
let total = 0;
|
||||
while (enumerator.hasMoreElements()) {
|
||||
let item = enumerator.getNext();
|
||||
item = item.QueryInterface(Ci.nsIPerformanceMetricsDispatchCategory);
|
||||
total += item.count;
|
||||
}
|
||||
Assert.ok(total > 0);
|
||||
});
|
||||
SpecialPowers.clearUserPref('dom.performance.enable_scheduler_timing');
|
||||
}
|
||||
}
|
||||
|
||||
Assert.ok(duration > 0, "Duration should be positive");
|
||||
Assert.ok(total > 0, "Should get a positive count");
|
||||
Assert.ok(parent_process_event, "parent process sent back some events");
|
||||
});
|
||||
|
||||
SpecialPowers.clearUserPref('dom.performance.enable_scheduler_timing');
|
||||
});
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
|
||||
var myWorker;
|
||||
function init() {
|
||||
myWorker = new Worker('ping_worker.js');
|
||||
myWorker.postMessage("ping");
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<h1>A page with a worker</h1>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,11 @@
|
|||
/* 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 });
|
|
@ -502,12 +502,16 @@ WorkerDebugger::ReportPerformanceInfo()
|
|||
uint16_t count = perf->GetTotalDispatchCount();
|
||||
uint64_t duration = perf->GetExecutionDuration();
|
||||
RefPtr<nsIURI> uri = mWorkerPrivate->GetResolvedScriptURI();
|
||||
CategoryDispatch item = CategoryDispatch(DispatchCategory::Worker.GetValue(), count);
|
||||
|
||||
// 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;
|
||||
CategoryDispatch item = CategoryDispatch(DispatchCategory::Worker.GetValue(), count);
|
||||
if (!items.AppendElement(item, fallible)) {
|
||||
NS_ERROR("Could not complete the operation");
|
||||
return PerformanceInfo(uri->GetSpecOrDefault(), pid, wid, pwid, duration,
|
||||
true, items);
|
||||
true, items);
|
||||
}
|
||||
perf->ResetPerformanceCounters();
|
||||
return PerformanceInfo(uri->GetSpecOrDefault(), pid, wid, pwid, duration,
|
||||
|
|
|
@ -424,10 +424,14 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
// PerformanceStorage needs to be initialized on the worker thread before
|
||||
// being used on main-thread. Let's be sure that it is created before any
|
||||
// PerformanceStorage & PerformanceCounter both need to be initialized
|
||||
// on the worker thread before being used on main-thread.
|
||||
// Let's be sure that it is created before any
|
||||
// content loading.
|
||||
aWorkerPrivate->EnsurePerformanceStorage();
|
||||
#ifndef RELEASE_OR_BETA
|
||||
aWorkerPrivate->EnsurePerformanceCounter();
|
||||
#endif
|
||||
|
||||
ErrorResult rv;
|
||||
workerinternals::LoadMainScript(aWorkerPrivate, mScriptURL, WorkerScript, rv);
|
||||
|
@ -5210,15 +5214,19 @@ WorkerPrivate::DumpCrashInformation(nsACString& aString)
|
|||
}
|
||||
|
||||
#ifndef RELEASE_OR_BETA
|
||||
PerformanceCounter*
|
||||
WorkerPrivate::GetPerformanceCounter()
|
||||
void
|
||||
WorkerPrivate::EnsurePerformanceCounter()
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
if (!mPerformanceCounter) {
|
||||
mPerformanceCounter = new PerformanceCounter(NS_ConvertUTF16toUTF8(mWorkerName));
|
||||
}
|
||||
}
|
||||
|
||||
PerformanceCounter*
|
||||
WorkerPrivate::GetPerformanceCounter()
|
||||
{
|
||||
MOZ_ASSERT(mPerformanceCounter);
|
||||
return mPerformanceCounter;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -561,6 +561,11 @@ public:
|
|||
void
|
||||
EnsurePerformanceStorage();
|
||||
|
||||
#ifndef RELEASE_OR_BETA
|
||||
void
|
||||
EnsurePerformanceCounter();
|
||||
#endif
|
||||
|
||||
const ClientInfo&
|
||||
GetClientInfo() const;
|
||||
|
||||
|
|
|
@ -36,6 +36,9 @@ enum class TaskCategory {
|
|||
// Most DOM events (postMessage, media, plugins)
|
||||
Other,
|
||||
|
||||
// Runnables related to Performance Counting
|
||||
Performance,
|
||||
|
||||
Count
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче