зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
91395b3e2d
Коммит
a1eae9d45f
|
@ -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>
|
Загрузка…
Ссылка в новой задаче