Bug 1149486 - Extract a window title and window ID for PerformanceStats. r=mossop

--HG--
extra : transplant_source : %F7%D1L%A8%FB%F8%CBw%BC%E2%7B%2B%9Ct%1F1%1B%A8l%1A
extra : histedit_source : 9db98672acaee8652460351beb6c1b2c48058d57
This commit is contained in:
David Rajchenbach-Teller 2015-05-18 10:40:20 +02:00
Родитель 91395b3e2d
Коммит a1eae9d45f
14 изменённых файлов: 404 добавлений и 117 удалений

Просмотреть файл

@ -11,6 +11,9 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
const { AddonWatcher } = Cu.import("resource://gre/modules/AddonWatcher.jsm", {});
const { PerformanceStats } = Cu.import("resource://gre/modules/PerformanceStats.jsm", {});
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
const UPDATE_TOPIC = "about:performance-update-immediately";
/**
* The various measures we display.
@ -277,7 +280,7 @@ function updateLiveData() {
_el.textContent = a ? a.name : _item.name
});
} else {
el.textContent = item.name;
el.textContent = item.title || item.name;
}
}
} catch (ex) {
@ -294,5 +297,8 @@ function go() {
document.getElementById("intervalDropdown").addEventListener("change", () => AutoUpdate.updateRefreshRate());
State.update();
setTimeout(update, 1000);
}
let observer = update;
Services.obs.addObserver(update, UPDATE_TOPIC, false);
window.addEventListener("unload", () => Services.obs.removeObserver(update, UPDATE_TOPIC));
}

Просмотреть файл

@ -1,11 +1,9 @@
# 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/.
[DEFAULT]
head = head.js
support-files =
browser_compartments.html
browser_compartments_frame.html
browser_compartments_script.js
[browser_aboutperformance.js]
skip-if = e10s # Feature not implemented yet – bug 1140310

Просмотреть файл

@ -11,9 +11,19 @@ const URL = "http://example.com/browser/toolkit/components/aboutperformance/test
function frameScript() {
"use strict";
addMessageListener("aboutperformance-test:hasItems", ({data: url}) => {
addMessageListener("aboutperformance-test:done", () => {
content.postMessage("stop", "*");
sendAsyncMessage("aboutperformance-test:done", null);
});
addMessageListener("aboutperformance-test:setTitle", ({data: title}) => {
content.document.title = title;
sendAsyncMessage("aboutperformance-test:setTitle", null);
});
addMessageListener("aboutperformance-test:hasItems", ({data: title}) => {
Services.obs.notifyObservers(null, "about:performance-update-immediately", "");
let hasPlatform = false;
let hasURL = false;
let hasTitle = false;
try {
let eltData = content.document.getElementById("liveData");
@ -24,42 +34,51 @@ function frameScript() {
// Find if we have a row for "platform"
hasPlatform = eltData.querySelector("tr.platform") != null;
// Find if we have a row for our URL
hasURL = false;
for (let eltContent of eltData.querySelectorAll("tr.content td.name")) {
if (eltContent.textContent == url) {
hasURL = true;
break;
}
}
// Find if we have a row for our content page
let titles = [for (eltContent of eltData.querySelectorAll("td.contents.name")) eltContent.textContent];
hasTitle = titles.includes(title);
} catch (ex) {
Cu.reportError("Error in content: " + ex);
Cu.reportError(ex.stack);
} finally {
sendAsyncMessage("aboutperformance-test:hasItems", {hasPlatform, hasURL});
sendAsyncMessage("aboutperformance-test:hasItems", {hasPlatform, hasTitle});
}
});
}
add_task(function* test() {
let tabAboutPerformance = gBrowser.addTab("about:performance");
let tabContent = gBrowser.addTab(URL);
add_task(function* go() {
info("Setting up about:performance");
let tabAboutPerformance = gBrowser.selectedTab = gBrowser.addTab("about:performance");
yield ContentTask.spawn(tabAboutPerformance.linkedBrowser, null, frameScript);
info(`Setting up ${URL}`);
let tabContent = gBrowser.addTab(URL);
yield ContentTask.spawn(tabContent.linkedBrowser, null, frameScript);
let title = "Testing about:performance " + Math.random();
info(`Setting up title ${title}`);
while (true) {
yield promiseContentResponse(tabContent.linkedBrowser, "aboutperformance-test:setTitle", title);
yield new Promise(resolve => setTimeout(resolve, 100));
let {hasPlatform, hasURL} = (yield promiseContentResponse(tabAboutPerformance.linkedBrowser, "aboutperformance-test:hasItems", URL));
info(`Platform: ${hasPlatform}, url: ${hasURL}`);
if (hasPlatform && hasURL) {
Assert.ok(true, "Found a row for <platform> and a row for our URL");
let {hasPlatform, hasTitle} = (yield promiseContentResponse(tabAboutPerformance.linkedBrowser, "aboutperformance-test:hasItems", title));
info(`Platform: ${hasPlatform}, title: ${hasTitle}`);
if (hasPlatform && hasTitle) {
Assert.ok(true, "Found a row for <platform> and a row for our page");
break;
}
}
// Cleanup
gBrowser.removeTab(tabContent);
gBrowser.removeTab(tabAboutPerformance);
info("Cleaning up");
yield promiseContentResponse(tabAboutPerformance.linkedBrowser, "aboutperformance-test:done", null);
info("Closing tabs");
for (let tab of gBrowser.tabs) {
yield BrowserTestUtils.removeTab(tab);
}
info("Done");
gBrowser.selectedTab = null;
});

Просмотреть файл

@ -2,24 +2,19 @@
<html>
<head>
<title>
browser_compartments.html
Main frame for test browser_aboutperformance.js
</title>
<script type="text/javascript">
// Use some CPU.
window.setInterval(() => {
// Compute an arbitrary value, print it out to make sure that the JS
// engine doesn't discard all our computation.
var date = Date.now();
var array = [];
var i = 0;
while (Date.now() - date <= 100) {
array[i%2] = i++;
}
console.log("Arbitrary value", array);
}, 300);
</script>
</head>
<body>
browser_compartments.html
Main frame.
<iframe src="browser_compartments_frame.html?frame=1">
Subframe 1
</iframe>
<iframe src="browser_compartments_frame.html?frame=2">
Subframe 2.
</iframe>
</body>
</html>

Просмотреть файл

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<title>
Subframe for test browser_compartments.html (do not change this title)
</title>
<script src="browser_compartments_script.js"></script>
</head>
<body>
Subframe loaded.
</body>
</html>

Просмотреть файл

@ -0,0 +1,29 @@
var carryOn = true;
window.addEventListener("message", e => {
console.log("frame content", "message", e);
if ("title" in e.data) {
document.title = e.data.title;
}
if ("stop" in e.data) {
carryOn = false;
}
});
// Use some CPU.
var interval = window.setInterval(() => {
if (!carryOn) {
window.clearInterval(interval);
return;
}
// Compute an arbitrary value, print it out to make sure that the JS
// engine doesn't discard all our computation.
var date = Date.now();
var array = [];
var i = 0;
while (Date.now() - date <= 100) {
array[i%2] = i++;
}
}, 300);

Просмотреть файл

@ -25,7 +25,8 @@ let performanceStatsService =
const PROPERTIES_NUMBERED = ["totalUserTime", "totalSystemTime", "totalCPOWTime", "ticks"];
const PROPERTIES_META = ["name", "addonId", "isSystem"];
const PROPERTIES_META_IMMUTABLE = ["name", "addonId", "isSystem"];
const PROPERTIES_META = [...PROPERTIES_META_IMMUTABLE, "windowId", "title"];
const PROPERTIES_FLAT = [...PROPERTIES_NUMBERED, ...PROPERTIES_META];
/**
@ -41,6 +42,15 @@ const PROPERTIES_FLAT = [...PROPERTIES_NUMBERED, ...PROPERTIES_META];
*
* @field {string} addonId The identifier of the addon (e.g. "myaddon@foo.bar").
*
* @field {string|null} title The title of the webpage to which this code
* belongs. Note that this is the title of the entire webpage (i.e. the tab),
* even if the code is executed in an iframe. Also note that this title may
* change over time.
*
* @field {number} windowId The outer window ID of the top-level nsIDOMWindow
* to which this code belongs. May be 0 if the code doesn't belong to any
* nsIDOMWindow.
*
* @field {boolean} isSystem `true` if the component is a system component (i.e.
* an add-on or platform-code), `false` otherwise (i.e. a webpage).
*

Просмотреть файл

@ -28,4 +28,8 @@ EXPORTS += [
'nsPerformanceStats.h'
]
LOCAL_INCLUDES += [
'/dom/base',
]
FINAL_LIBRARY = 'xul'

Просмотреть файл

@ -6,6 +6,7 @@
#include "nsISupports.idl"
#include "nsIArray.idl"
#include "nsIDOMWindow.idl"
/**
* Mechanisms for querying the current process about performance
@ -21,7 +22,7 @@
* All values are monotonic and are updated only when
* `nsIPerformanceStatsService.isStopwatchActive` is `true`.
*/
[scriptable, uuid(f015cbad-e16f-4982-a080-67e4e69a5b2e)]
[scriptable, uuid(7741ba2d-3171-42cd-9f36-e46a5ce6d5b1)]
interface nsIPerformanceStats: nsISupports {
/**
* The name of the component:
@ -38,6 +39,18 @@ interface nsIPerformanceStats: nsISupports {
*/
readonly attribute AString addonId;
/**
* If the component is code executed in a window, the ID of the topmost
* outer window (i.e. the tab), otherwise 0.
*/
readonly attribute uint64_t windowId;
/**
* If the component is code executed in a window, the title of the topmost
* window (i.e. the tab), otherwise an empty string.
*/
readonly attribute AString title;
/**
* Total amount of time spent executing code in this group, in
* microseconds.
@ -91,7 +104,7 @@ interface nsIPerformanceSnapshot: nsISupports {
nsIPerformanceStats getProcessData();
};
[scriptable, builtinclass, uuid(5795113a-39a1-4087-ba09-98b7d07d025a)]
[scriptable, builtinclass, uuid(c989c220-6581-4252-9aad-358fdec9ec8c)]
interface nsIPerformanceStatsService : nsISupports {
/**
* `true` if we should monitor performance, `false` otherwise.
@ -101,7 +114,7 @@ interface nsIPerformanceStatsService : nsISupports {
/**
* Capture a snapshot of the performance data.
*/
nsIPerformanceSnapshot getSnapshot();
[implicit_jscontext] nsIPerformanceSnapshot getSnapshot();
};
%{C++

Просмотреть файл

@ -3,24 +3,37 @@
* 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 "jsapi.h"
#include "nsPerformanceStats.h"
#include "nsMemory.h"
#include "nsLiteralString.h"
#include "nsCRTGlue.h"
#include "nsIJSRuntimeService.h"
#include "nsServiceManagerUtils.h"
#include "nsCOMArray.h"
#include "nsIMutableArray.h"
#include "jsapi.h"
#include "nsJSUtils.h"
#include "xpcpublic.h"
#include "jspubtd.h"
#include "nsIJSRuntimeService.h"
#include "nsIDOMWindow.h"
#include "nsGlobalWindow.h"
class nsPerformanceStats: public nsIPerformanceStats {
public:
nsPerformanceStats(nsAString& aName, nsAString& aAddonId, bool aIsSystem, js::PerformanceData& aPerformanceData)
nsPerformanceStats(const nsAString& aName,
const nsAString& aAddonId,
const nsAString& aTitle,
const uint64_t aWindowId,
const bool aIsSystem,
const js::PerformanceData& aPerformanceData)
: mName(aName)
, mAddonId(aAddonId)
, mTitle(aTitle)
, mWindowId(aWindowId)
, mIsSystem(aIsSystem)
, mPerformanceData(aPerformanceData)
{
@ -41,6 +54,24 @@ public:
return NS_OK;
};
/* readonly attribute uint64_t windowId; */
NS_IMETHOD GetWindowId(uint64_t *aWindowId) override {
*aWindowId = mWindowId;
return NS_OK;
}
/* readonly attribute AString title; */
NS_IMETHOD GetTitle(nsAString & aTitle) override {
aTitle.Assign(mTitle);
return NS_OK;
}
/* readonly attribute bool isSystem; */
NS_IMETHOD GetIsSystem(bool *_retval) override {
*_retval = mIsSystem;
return NS_OK;
}
/* readonly attribute unsigned long long totalUserTime; */
NS_IMETHOD GetTotalUserTime(uint64_t *aTotalUserTime) override {
*aTotalUserTime = mPerformanceData.totalUserTime;
@ -78,16 +109,13 @@ public:
return NS_OK;
};
/* readonly attribute bool isSystem; */
NS_IMETHOD GetIsSystem(bool *_retval) override {
*_retval = mIsSystem;
return NS_OK;
}
private:
nsString mName;
nsString mAddonId;
nsString mTitle;
uint64_t mWindowId;
bool mIsSystem;
js::PerformanceData mPerformanceData;
virtual ~nsPerformanceStats() {}
@ -103,15 +131,45 @@ public:
NS_DECL_NSIPERFORMANCESNAPSHOT
nsPerformanceSnapshot();
nsresult Init();
nsresult Init(JSContext*);
private:
virtual ~nsPerformanceSnapshot();
/**
* Import a `PerformanceStats` as a `nsIPerformanceStats`.
* Import a `js::PerformanceStats` as a `nsIPerformanceStats`.
*
* Precondition: this method assumes that we have entered the JSCompartment for which data `c`
* has been collected.
*
* `cx` may be `nullptr` if we are importing the statistics for the
* entire process, rather than the statistics for a specific set of
* compartments.
*/
already_AddRefed<nsIPerformanceStats> ImportStats(js::PerformanceStats* c);
already_AddRefed<nsIPerformanceStats> ImportStats(JSContext* cx, const js::PerformanceData& data);
/**
* Callbacks for iterating through the `PerformanceStats` of a runtime.
*/
bool IterPerformanceStatsCallbackInternal(JSContext* cx, const js::PerformanceData& stats);
static bool IterPerformanceStatsCallback(JSContext* cx, const js::PerformanceData& stats, void* self);
// If the context represents a window, extract the title and window ID.
// Otherwise, extract "" and 0.
static void GetWindowData(JSContext*,
nsString& title,
uint64_t* windowId);
// If the context presents an add-on, extract the addon ID.
// Otherwise, extract "".
static void GetAddonId(JSContext*,
JS::Handle<JSObject*> global,
nsAString& addonId);
// Determine whether a context is part of the system principals.
static bool GetIsSystem(JSContext*,
JS::Handle<JSObject*> global);
private:
nsCOMArray<nsIPerformanceStats> mComponentsData;
nsCOMPtr<nsIPerformanceStats> mProcessData;
};
@ -126,36 +184,119 @@ nsPerformanceSnapshot::~nsPerformanceSnapshot()
{
}
already_AddRefed<nsIPerformanceStats>
nsPerformanceSnapshot::ImportStats(js::PerformanceStats* c) {
nsString addonId;
if (c->addonId) {
AssignJSFlatString(addonId, (JSFlatString*)c->addonId);
/* static */ void
nsPerformanceSnapshot::GetWindowData(JSContext* cx,
nsString& title,
uint64_t* windowId)
{
MOZ_ASSERT(windowId);
title.SetIsVoid(true);
*windowId = 0;
nsCOMPtr<nsPIDOMWindow> win = xpc::CurrentWindowOrNull(cx);
if (!win) {
return;
}
nsCString cname(c->name);
NS_ConvertUTF8toUTF16 name(cname);
nsCOMPtr<nsIPerformanceStats> result = new nsPerformanceStats(name, addonId, c->isSystem, c->performance);
nsCOMPtr<nsIDOMWindow> top;
nsresult rv = win->GetTop(getter_AddRefs(top));
if (!top || NS_FAILED(rv)) {
return;
}
nsCOMPtr<nsPIDOMWindow> ptop = do_QueryInterface(top);
if (!ptop) {
return;
}
nsCOMPtr<nsIDocument> doc = ptop->GetExtantDoc();
if (!doc) {
return;
}
doc->GetTitle(title);
*windowId = ptop->WindowID();
}
/* static */ void
nsPerformanceSnapshot::GetAddonId(JSContext*,
JS::Handle<JSObject*> global,
nsAString& addonId)
{
addonId.AssignLiteral("");
JSAddonId* jsid = AddonIdOfObject(global);
if (!jsid) {
return;
}
AssignJSFlatString(addonId, (JSFlatString*)jsid);
}
/* static */ bool
nsPerformanceSnapshot::GetIsSystem(JSContext*,
JS::Handle<JSObject*> global)
{
return nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(global));
}
already_AddRefed<nsIPerformanceStats>
nsPerformanceSnapshot::ImportStats(JSContext* cx, const js::PerformanceData& performance) {
JS::RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
if (!global) {
// While it is possible for a compartment to have no global
// (e.g. atoms), this compartment is not very interesting for us.
return nullptr;
}
nsString addonId;
GetAddonId(cx, global, addonId);
nsString title;
uint64_t windowId;
GetWindowData(cx, title, &windowId);
nsAutoString name;
nsAutoCString cname;
xpc::GetCurrentCompartmentName(cx, cname);
name.Assign(NS_ConvertUTF8toUTF16(cname));
bool isSystem = GetIsSystem(cx, global);
nsCOMPtr<nsIPerformanceStats> result =
new nsPerformanceStats(name, addonId, title, windowId, isSystem, performance);
return result.forget();
}
nsresult
nsPerformanceSnapshot::Init() {
JSRuntime* rt;
nsCOMPtr<nsIJSRuntimeService> svc(do_GetService("@mozilla.org/js/xpc/RuntimeService;1"));
NS_ENSURE_TRUE(svc, NS_ERROR_FAILURE);
svc->GetRuntime(&rt);
js::PerformanceStats processStats;
js::PerformanceStatsVector componentsStats;
if (!js::GetPerformanceStats(rt, componentsStats, processStats)) {
return NS_ERROR_OUT_OF_MEMORY;
/*static*/ bool
nsPerformanceSnapshot::IterPerformanceStatsCallback(JSContext* cx, const js::PerformanceData& stats, void* self) {
return reinterpret_cast<nsPerformanceSnapshot*>(self)->IterPerformanceStatsCallbackInternal(cx, stats);
}
bool
nsPerformanceSnapshot::IterPerformanceStatsCallbackInternal(JSContext* cx, const js::PerformanceData& stats) {
nsCOMPtr<nsIPerformanceStats> result = ImportStats(cx, stats);
if (result) {
mComponentsData.AppendElement(result);
}
size_t num = componentsStats.length();
for (size_t pos = 0; pos < num; pos++) {
nsCOMPtr<nsIPerformanceStats> stats = ImportStats(&componentsStats[pos]);
mComponentsData.AppendObject(stats);
return true;
}
nsresult
nsPerformanceSnapshot::Init(JSContext* cx) {
js::PerformanceData processStats;
if (!js::IterPerformanceStats(cx, nsPerformanceSnapshot::IterPerformanceStatsCallback, &processStats, this)) {
return NS_ERROR_UNEXPECTED;
}
mProcessData = ImportStats(&processStats);
mProcessData = new nsPerformanceStats(NS_LITERAL_STRING("<process>"), // name
NS_LITERAL_STRING(""), // add-on id
NS_LITERAL_STRING(""), // title
0, // window id
true, // isSystem
processStats);
return NS_OK;
}
@ -209,10 +350,10 @@ NS_IMETHODIMP nsPerformanceStatsService::SetIsStopwatchActive(JSContext* cx, boo
}
/* readonly attribute nsIPerformanceSnapshot snapshot; */
NS_IMETHODIMP nsPerformanceStatsService::GetSnapshot(nsIPerformanceSnapshot * *aSnapshot)
NS_IMETHODIMP nsPerformanceStatsService::GetSnapshot(JSContext* cx, nsIPerformanceSnapshot * *aSnapshot)
{
nsRefPtr<nsPerformanceSnapshot> snapshot = new nsPerformanceSnapshot();
nsresult rv = snapshot->Init();
nsresult rv = snapshot->Init(cx);
if (NS_FAILED(rv)) {
return rv;
}

Просмотреть файл

@ -3,6 +3,7 @@ head = head.js
support-files =
browser_Addons_sample.xpi
browser_compartments.html
browser_compartments_frame.html
[browser_AddonWatcher.js]
[browser_compartments.js]

Просмотреть файл

@ -2,24 +2,19 @@
<html>
<head>
<title>
browser_compartments.html
Main frame for test browser_compartments.js
</title>
<script type="text/javascript">
// Use some CPU.
window.setInterval(() => {
// Compute an arbitrary value, print it out to make sure that the JS
// engine doesn't discard all our computation.
var date = Date.now();
var array = [];
var i = 0;
while (Date.now() - date <= 100) {
array[i%2] = i++;
}
console.log("Arbitrary value", array);
}, 300);
</script>
</head>
<body>
browser_compartments.html
Main frame.
<iframe src="browser_compartments_frame.html?frame=1">
Subframe 1
</iframe>
<iframe src="browser_compartments_frame.html?frame=2">
Subframe 2.
</iframe>
</body>
</html>

Просмотреть файл

@ -3,10 +3,17 @@
"use strict";
/**
* Test that we see jank that takes place in a webpage,
* and that jank from several iframes are actually charged
* to the top window.
*/
Cu.import("resource://gre/modules/PerformanceStats.jsm", this);
Cu.import("resource://testing-common/ContentTask.jsm", this);
const URL = "http://example.com/browser/toolkit/components/perfmonitoring/tests/browser/browser_compartments.html?test=" + Math.random();
const PARENT_TITLE = `Main frame for test browser_compartments.js ${Math.random()}`;
const FRAME_TITLE = `Subframe for test browser_compartments.js ${Math.random()}`;
// This function is injected as source as a frameScript
function frameScript() {
@ -30,6 +37,20 @@ function frameScript() {
Cu.reportError(ex.stack);
}
});
addMessageListener("compartments-test:setTitles", titles => {
try {
content.document.title = titles.data.parent;
for (let i = 0; i < content.frames.length; ++i) {
content.frames[i].postMessage({title: titles.data.frames}, "*");
}
console.log("content", "Done setting titles", content.document.title);
sendAsyncMessage("compartments-test:setTitles");
} catch (ex) {
Cu.reportError("Error in content: " + ex);
Cu.reportError(ex.stack);
}
});
}
// A variant of `Assert` that doesn't spam the logs
@ -72,7 +93,6 @@ function monotinicity_tester(source, testName) {
};
let sanityCheck = function(prev, next) {
info(`Sanity check: ${JSON.stringify(next, null, "\t")}`);
if (prev == null) {
return;
}
@ -116,18 +136,27 @@ function monotinicity_tester(source, testName) {
// Sanity check on components data.
let set = new Set();
let keys = [];
let map = new Map();
for (let item of snapshot.componentsData) {
let key = `{name: ${item.name}, addonId: ${item.addonId}, isSystem: ${item.isSystem}}`;
keys.push(key);
set.add(key);
sanityCheck(previous.componentsMap.get(key), item);
previous.componentsMap.set(key, item);
for (let k of ["totalUserTime", "totalSystemTime", "totalCPOWTime"]) {
SilentAssert.leq(item[k], snapshot.processData[k],
`Sanity check (${testName}): component has a lower ${k} than process`);
}
let key = `{name: ${item.name}, window: ${item.windowId}, addonId: ${item.addonId}, isSystem: ${item.isSystem}}`;
if (set.has(key)) {
// There are at least two components with the same name (e.g. about:blank).
// Don't perform sanity checks on that name until we know how to make
// the difference.
map.delete(key);
continue;
}
map.set(key, item);
set.add(key);
}
for (let [key, item] of map) {
sanityCheck(previous.componentsMap.get(key), item);
previous.componentsMap.set(key, item);
}
info(`Deactivating deduplication check (Bug 1150045)`);
if (false) {
@ -147,7 +176,7 @@ add_task(function* test() {
Assert.ok(!stats0.componentsData.find(stat => stat.name.indexOf(URL) != -1),
"The url doesn't appear yet");
let newTab = gBrowser.addTab();
let newTab = gBrowser.selectedTab = gBrowser.addTab();
let browser = newTab.linkedBrowser;
// Setup monitoring in the tab
info("Setting up monitoring in the tab");
@ -166,17 +195,40 @@ add_task(function* test() {
let skipTotalUserTime = hasLowPrecision();
while (true) {
let stats = (yield promiseContentResponse(browser, "compartments-test:getStatistics", null));
let found = stats.componentsData.find(stat => {
return (stat.name.indexOf(URL) != -1)
&& (skipTotalUserTime || stat.totalUserTime > 1000)
yield new Promise(resolve => setTimeout(resolve, 100));
// We may have race conditions with DOM loading.
// Don't waste too much brainpower here, let's just ask
// repeatedly for the title to be changed, until this works.
info("Setting titles");
yield promiseContentResponse(browser, "compartments-test:setTitles", {
parent: PARENT_TITLE,
frames: FRAME_TITLE
});
if (found) {
info(`Expected totalUserTime > 1000, got ${found.totalUserTime}`);
info("Titles set");
let stats = (yield promiseContentResponse(browser, "compartments-test:getStatistics", null));
// While the webpage consists in three compartments, we should see only
// one `PerformanceData` in `componentsData`. Its `name` is undefined
// (could be either the main frame or one of its subframes), but its
// `title` should be the title of the main frame.
let frame = stats.componentsData.find(stat => stat.title == FRAME_TITLE);
Assert.equal(frame, null, "Searching by title, the frames don't show up in the list of components");
let parent = stats.componentsData.find(stat => stat.title == PARENT_TITLE);
if (!parent) {
info("Searching by title, we didn't find the main frame");
continue;
}
info("Searching by title, we found the main frame");
info(`Total user time: ${parent.totalUserTime}`);
if (skipTotalUserTime || parent.totalUserTime > 1000) {
break;
}
yield new Promise(resolve => setTimeout(resolve, 100));
}
// Cleanup

Просмотреть файл

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<title>
Subframe for test browser_compartments.html (do not change this title)
</title>
<script src="browser_compartments_script.js"></script>
</head>
<body>
Subframe loaded.
</body>
</html>