From 36b059df69ee574f74c3aa36dbfc466c6a1fdb2f Mon Sep 17 00:00:00 2001 From: Brad Lassey Date: Tue, 13 Jan 2015 17:38:05 -0800 Subject: [PATCH] bug 1096718 - - display time measured spent in each compartment r=billm,mossop --- docshell/base/nsAboutRedirector.cpp | 5 +- docshell/build/nsDocShellModule.cpp | 1 + js/src/jsapi.cpp | 24 +++++ js/src/jsapi.h | 13 +++ js/xpconnect/src/nsXPConnect.cpp | 8 ++ js/xpconnect/src/xpcpublic.h | 3 + .../content/aboutCompartments.js | 75 +++++++++++++++ .../content/aboutCompartments.xhtml | 43 +++++++++ toolkit/components/aboutcompartments/jar.mn | 7 ++ .../components/aboutcompartments/moz.build | 23 +++++ .../aboutcompartments/nsCompartmentInfo.cpp | 94 +++++++++++++++++++ .../aboutcompartments/nsCompartmentInfo.h | 25 +++++ .../aboutcompartments/nsICompartmentInfo.idl | 31 ++++++ toolkit/components/aboutmemory/jar.mn | 1 - toolkit/components/moz.build | 1 + xpcom/build/XPCOMInit.cpp | 4 + xpcom/build/XPCOMModule.inc | 1 + xpcom/build/nsXPCOMCID.h | 2 + 18 files changed, 357 insertions(+), 4 deletions(-) create mode 100644 toolkit/components/aboutcompartments/content/aboutCompartments.js create mode 100644 toolkit/components/aboutcompartments/content/aboutCompartments.xhtml create mode 100644 toolkit/components/aboutcompartments/jar.mn create mode 100644 toolkit/components/aboutcompartments/moz.build create mode 100644 toolkit/components/aboutcompartments/nsCompartmentInfo.cpp create mode 100644 toolkit/components/aboutcompartments/nsCompartmentInfo.h create mode 100644 toolkit/components/aboutcompartments/nsICompartmentInfo.idl diff --git a/docshell/base/nsAboutRedirector.cpp b/docshell/base/nsAboutRedirector.cpp index 30f59e9ad91c..b8c410ed8b6a 100644 --- a/docshell/base/nsAboutRedirector.cpp +++ b/docshell/base/nsAboutRedirector.cpp @@ -51,11 +51,10 @@ static RedirEntry kRedirMap[] = { nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::HIDE_FROM_ABOUTABOUT }, - { "compartments", "chrome://global/content/aboutCompartments.xhtml", - nsIAboutModule::ALLOW_SCRIPT | - nsIAboutModule::HIDE_FROM_ABOUTABOUT }, { "memory", "chrome://global/content/aboutMemory.xhtml", nsIAboutModule::ALLOW_SCRIPT }, + { "compartments", "chrome://global/content/aboutCompartments.xhtml", + nsIAboutModule::ALLOW_SCRIPT }, { "addons", "chrome://mozapps/content/extensions/extensions.xul", nsIAboutModule::ALLOW_SCRIPT }, { "newaddon", "chrome://mozapps/content/extensions/newaddon.xul", diff --git a/docshell/build/nsDocShellModule.cpp b/docshell/build/nsDocShellModule.cpp index 267a5d0b8150..c24d5b64d80a 100644 --- a/docshell/build/nsDocShellModule.cpp +++ b/docshell/build/nsDocShellModule.cpp @@ -168,6 +168,7 @@ const mozilla::Module::ContractIDEntry kDocShellContracts[] = { { NS_ABOUT_MODULE_CONTRACTID_PREFIX "neterror", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "compartments", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "memory", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, + { NS_ABOUT_MODULE_CONTRACTID_PREFIX "compartments", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "addons", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "newaddon", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "support", &kNS_ABOUT_REDIRECTOR_MODULE_CID }, diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index eaf2b6aca1ef..44913e38cf79 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -167,6 +167,30 @@ JS_GetEmptyString(JSRuntime *rt) return rt->emptyString; } +JS_PUBLIC_API(bool) +JS_GetCompartmentStats(JSRuntime *rt, CompartmentStatsVector &stats) +{ + if (!stats.resizeUninitialized(rt->numCompartments)) + return false; + + size_t pos = 0; + for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next()) { + CompartmentTimeStats *stat = &stats[pos]; + stat->time = c.get()->totalTime; + stat->compartment = c.get(); + stat->addonId = c.get()->addonId; + if (rt->compartmentNameCallback) { + (*rt->compartmentNameCallback)(rt, stat->compartment, + stat->compartmentName, + MOZ_ARRAY_LENGTH(stat->compartmentName)); + } else { + strcpy(stat->compartmentName, ""); + } + pos++; + } + return true; +} + namespace js { void diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 0aa89a17b9b8..0d8316d7be59 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1042,6 +1042,19 @@ JS_GetEmptyStringValue(JSContext *cx); extern JS_PUBLIC_API(JSString *) JS_GetEmptyString(JSRuntime *rt); +struct CompartmentTimeStats { + char compartmentName[1024]; + JSAddonId *addonId; + JSCompartment *compartment; + uint64_t time; // microseconds + uint64_t cpowTime; // microseconds +}; + +typedef js::Vector CompartmentStatsVector; + +extern JS_PUBLIC_API(bool) +JS_GetCompartmentStats(JSRuntime *rt, CompartmentStatsVector &stats); + /* * Format is a string of the following characters (spaces are insignificant), * specifying the tabulated type conversions: diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index ed3c44d3bf0a..3dab4eb90187 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -345,8 +345,16 @@ xpc::TraceXPCGlobal(JSTracer *trc, JSObject *obj) compartmentPrivate->scope->TraceInside(trc); } + namespace xpc { +uint64_t +GetCompartmentCPOWMicroseconds(JSCompartment *compartment) +{ + xpc::CompartmentPrivate *compartmentPrivate = xpc::CompartmentPrivate::Get(compartment); + return compartmentPrivate ? PR_IntervalToMicroseconds(compartmentPrivate->CPOWTime) : 0; +} + JSObject* CreateGlobalObject(JSContext *cx, const JSClass *clasp, nsIPrincipal *principal, JS::CompartmentOptions& aOptions) diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index 9393aed17727..2334ffea469c 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -139,6 +139,9 @@ XrayAwareCalleeGlobal(JSObject *fun); void TraceXPCGlobal(JSTracer *trc, JSObject *obj); +uint64_t +GetCompartmentCPOWMicroseconds(JSCompartment *compartment); + } /* namespace xpc */ namespace JS { diff --git a/toolkit/components/aboutcompartments/content/aboutCompartments.js b/toolkit/components/aboutcompartments/content/aboutCompartments.js new file mode 100644 index 000000000000..69535c3c9bfb --- /dev/null +++ b/toolkit/components/aboutcompartments/content/aboutCompartments.js @@ -0,0 +1,75 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 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/. */ + +"use strict"; + +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {}); + +function go() { + let compartmentInfo = Cc["@mozilla.org/compartment-info;1"] + .getService(Ci.nsICompartmentInfo); + let compartments = compartmentInfo.getCompartments(); + let count = compartments.length; + let addons = {}; + for (let i = 0; i < count; i++) { + let compartment = compartments.queryElementAt(i, Ci.nsICompartment); + if (addons[compartment.addonId]) { + addons[compartment.addonId].time += compartment.time; + addons[compartment.addonId].CPOWTime += compartment.CPOWTime; + addons[compartment.addonId].compartments.push(compartment); + } else { + addons[compartment.addonId] = { + time: compartment.time, + CPOWTime: compartment.CPOWTime, + compartments: [compartment] + }; + } + } + let dataDiv = document.getElementById("data"); + for (let addon in addons) { + let el = document.createElement("tr"); + let name = document.createElement("td"); + let time = document.createElement("td"); + let cpow = document.createElement("td"); + name.className = "addon"; + time.className = "time"; + cpow.className = "cpow"; + name.textContent = addon; + AddonManager.getAddonByID(addon, function(a) { + if (a) { + name.textContent = a.name; + } + }); + time.textContent = addons[addon].time +"μs"; + cpow.textContent = addons[addon].CPOWTime +"μs"; + el.appendChild(time); + el.appendChild(cpow); + el.appendChild(name); + let div = document.createElement("tr"); + for (let comp of addons[addon].compartments) { + let c = document.createElement("tr"); + let name = document.createElement("td"); + let time = document.createElement("td"); + let cpow = document.createElement("td"); + name.className = "addon"; + time.className = "time"; + cpow.className = "cpow"; + name.textContent = comp.label; + time.textContent = comp.time +"μs"; + cpow.textContent = comp.CPOWTime +"μs"; + c.appendChild(time); + c.appendChild(cpow); + c.appendChild(name); + div.appendChild(c); + div.className = "details"; + } + el.addEventListener("click", function() { div.style.display = (div.style.display != "block" ? "block" : "none"); }); + el.appendChild(div); + dataDiv.appendChild(el); + } +} diff --git a/toolkit/components/aboutcompartments/content/aboutCompartments.xhtml b/toolkit/components/aboutcompartments/content/aboutCompartments.xhtml new file mode 100644 index 000000000000..d3de58a17806 --- /dev/null +++ b/toolkit/components/aboutcompartments/content/aboutCompartments.xhtml @@ -0,0 +1,43 @@ + + + + + + + about:compartments + + + + + + + + + + +
timetime in CPOWsname
+ + diff --git a/toolkit/components/aboutcompartments/jar.mn b/toolkit/components/aboutcompartments/jar.mn new file mode 100644 index 000000000000..ca1a3352c577 --- /dev/null +++ b/toolkit/components/aboutcompartments/jar.mn @@ -0,0 +1,7 @@ +# 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/. + +toolkit.jar: ++ content/global/aboutCompartments.xhtml (content/aboutCompartments.xhtml) ++ content/global/aboutCompartments.js (content/aboutCompartments.js) diff --git a/toolkit/components/aboutcompartments/moz.build b/toolkit/components/aboutcompartments/moz.build new file mode 100644 index 000000000000..9872f4f72dea --- /dev/null +++ b/toolkit/components/aboutcompartments/moz.build @@ -0,0 +1,23 @@ +# -*- Mode: python; c-basic-offset: 4; 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/. + +JAR_MANIFESTS += ['jar.mn'] + +XPIDL_MODULE = 'compartments' + +XPIDL_SOURCES += [ + 'nsICompartmentInfo.idl', +] + +UNIFIED_SOURCES += [ + 'nsCompartmentInfo.cpp' +] + +EXPORTS += [ + 'nsCompartmentInfo.h' +] + +FINAL_LIBRARY = 'xul' diff --git a/toolkit/components/aboutcompartments/nsCompartmentInfo.cpp b/toolkit/components/aboutcompartments/nsCompartmentInfo.cpp new file mode 100644 index 000000000000..6a5c1bbd97c9 --- /dev/null +++ b/toolkit/components/aboutcompartments/nsCompartmentInfo.cpp @@ -0,0 +1,94 @@ +/* -*- 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/. */ + +#include "nsCompartmentInfo.h" +#include "nsMemory.h" +#include "nsLiteralString.h" +#include "nsCRTGlue.h" +#include "nsIJSRuntimeService.h" +#include "nsServiceManagerUtils.h" +#include "nsIMutableArray.h" +#include "nsJSUtils.h" +#include "xpcpublic.h" + +class nsCompartment : public nsICompartment { +public: + nsCompartment(nsAString& aCompartmentName, nsAString& aAddonId, + uint64_t aTime, uint64_t aCPOWTime) + : mCompartmentName(aCompartmentName), mAddonId(aAddonId), mTime(aTime), mCPOWTime(aCPOWTime) {} + + NS_DECL_ISUPPORTS + + /* readonly attribute wstring compartmentName; */ + NS_IMETHOD GetCompartmentName(nsAString& aCompartmentName){ + aCompartmentName.Assign(mCompartmentName); + return NS_OK; + }; + + /* readonly attribute unsigned long time; */ + NS_IMETHOD GetTime(uint64_t* aTime) { + *aTime = mTime; + return NS_OK; + } + /* readonly attribute wstring addon id; */ + NS_IMETHOD GetAddonId(nsAString& aAddonId){ + aAddonId.Assign(mAddonId); + return NS_OK; + }; + + /* readonly attribute unsigned long CPOW time; */ + NS_IMETHOD GetCPOWTime(uint64_t* aCPOWTime) { + *aCPOWTime = mCPOWTime; + return NS_OK; + } + +private: + nsString mCompartmentName; + nsString mAddonId; + uint64_t mTime; + uint64_t mCPOWTime; + virtual ~nsCompartment() {} +}; + +NS_IMPL_ISUPPORTS(nsCompartment, nsICompartment) +NS_IMPL_ISUPPORTS(nsCompartmentInfo, nsICompartmentInfo) + +nsCompartmentInfo::nsCompartmentInfo() +{ +} + +nsCompartmentInfo::~nsCompartmentInfo() +{ +} + +NS_IMETHODIMP +nsCompartmentInfo::GetCompartments(nsIArray** aCompartments) +{ + JSRuntime* rt; + nsCOMPtr svc(do_GetService("@mozilla.org/js/xpc/RuntimeService;1")); + NS_ENSURE_TRUE(svc, NS_ERROR_FAILURE); + svc->GetRuntime(&rt); + nsCOMPtr compartments = do_CreateInstance(NS_ARRAY_CONTRACTID); + CompartmentStatsVector stats; + if (!JS_GetCompartmentStats(rt, stats)) + return NS_ERROR_OUT_OF_MEMORY; + + size_t num = stats.length(); + for (size_t pos = 0; pos < num; pos++) { + nsString addonId; + if (stats[pos].addonId) { + AssignJSFlatString(addonId, (JSFlatString*)stats[pos].addonId); + } else { + addonId.AssignLiteral(""); + } + + uint32_t cpowTime = xpc::GetCompartmentCPOWMicroseconds(stats[pos].compartment); + nsCString compartmentName(stats[pos].compartmentName); + NS_ConvertUTF8toUTF16 name(compartmentName); + compartments->AppendElement(new nsCompartment(name, addonId, stats[pos].time, cpowTime), false); + } + compartments.forget(aCompartments); + return NS_OK; +} diff --git a/toolkit/components/aboutcompartments/nsCompartmentInfo.h b/toolkit/components/aboutcompartments/nsCompartmentInfo.h new file mode 100644 index 000000000000..4efba6d92f8e --- /dev/null +++ b/toolkit/components/aboutcompartments/nsCompartmentInfo.h @@ -0,0 +1,25 @@ +/* -*- 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 nsCompartmentInfo_h +#define nsCompartmentInfo_h + +#include "nsICompartmentInfo.h" + +class nsCompartmentInfo : public nsICompartmentInfo +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICOMPARTMENTINFO + + nsCompartmentInfo(); + +private: + virtual ~nsCompartmentInfo(); + +protected: +}; + +#endif diff --git a/toolkit/components/aboutcompartments/nsICompartmentInfo.idl b/toolkit/components/aboutcompartments/nsICompartmentInfo.idl new file mode 100644 index 000000000000..1e07c8ad2956 --- /dev/null +++ b/toolkit/components/aboutcompartments/nsICompartmentInfo.idl @@ -0,0 +1,31 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 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 "nsISupports.idl" +#include "nsIArray.idl" + +[scriptable, uuid(13dd4c09-ff11-4943-8dc2-d96eb69c963b)] +interface nsICompartment : nsISupports { + /* name of compartment */ + readonly attribute AString compartmentName; + /* time spent executing code in this compartment in microseconds */ + readonly attribute unsigned long long time; + /* the id of the addon associated with this compartment, or null */ + readonly attribute AString addonId; + /* time spent processing CPOWs in microseconds */ + readonly attribute unsigned long long CPOWTime; +}; + +[scriptable, builtinclass, uuid(5795113a-39a1-4087-ba09-98b7d07d025a)] +interface nsICompartmentInfo : nsISupports { + nsIArray getCompartments(); +}; + +%{C++ +#define NS_COMPARTMENT_INFO_CID \ +{ 0x2d3c2f2d, 0x698d, 0x471d, \ +{ 0xba, 0x3e, 0x14, 0x44, 0xdd, 0x52, 0x1e, 0x29 } } +%} diff --git a/toolkit/components/aboutmemory/jar.mn b/toolkit/components/aboutmemory/jar.mn index 1f8ba994ebea..82af6a5333d0 100644 --- a/toolkit/components/aboutmemory/jar.mn +++ b/toolkit/components/aboutmemory/jar.mn @@ -3,7 +3,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. toolkit.jar: -+ content/global/aboutCompartments.xhtml (content/aboutCompartments.xhtml) + content/global/aboutMemory.js (content/aboutMemory.js) + content/global/aboutMemory.xhtml (content/aboutMemory.xhtml) + content/global/aboutMemory.css (content/aboutMemory.css) diff --git a/toolkit/components/moz.build b/toolkit/components/moz.build index f5e3bdc3b36f..bdc5e51be384 100644 --- a/toolkit/components/moz.build +++ b/toolkit/components/moz.build @@ -10,6 +10,7 @@ if CONFIG['MOZ_ENABLE_XREMOTE']: DIRS += [ 'aboutcache', + 'aboutcompartments', 'aboutmemory', 'addoncompat', 'alerts', diff --git a/xpcom/build/XPCOMInit.cpp b/xpcom/build/XPCOMInit.cpp index 60757e8fe6cc..46192551372f 100644 --- a/xpcom/build/XPCOMInit.cpp +++ b/xpcom/build/XPCOMInit.cpp @@ -50,6 +50,8 @@ #include "nsThreadManager.h" #include "nsThreadPool.h" +#include "nsCompartmentInfo.h" + #include "xptinfo.h" #include "nsIInterfaceInfoManager.h" #include "xptiprivate.h" @@ -234,6 +236,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMemoryInfoDumper) NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsStatusReporterManager, Init) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsCompartmentInfo) + NS_GENERIC_FACTORY_CONSTRUCTOR(nsIOUtil) NS_GENERIC_FACTORY_CONSTRUCTOR(nsSecurityConsoleMessage) diff --git a/xpcom/build/XPCOMModule.inc b/xpcom/build/XPCOMModule.inc index 6386bafc5954..3b330462fe2f 100644 --- a/xpcom/build/XPCOMModule.inc +++ b/xpcom/build/XPCOMModule.inc @@ -82,3 +82,4 @@ COMPONENT(CYCLE_COLLECTOR_LOGGER, nsCycleCollectorLoggerConstructor) COMPONENT(MESSAGE_LOOP, nsMessageLoopConstructor) COMPONENT(STATUS_REPORTER_MANAGER, nsStatusReporterManagerConstructor) + COMPONENT(COMPARTMENT_INFO, nsCompartmentInfoConstructor) \ No newline at end of file diff --git a/xpcom/build/nsXPCOMCID.h b/xpcom/build/nsXPCOMCID.h index 6b830c3f1bf6..9a82773a4e0f 100644 --- a/xpcom/build/nsXPCOMCID.h +++ b/xpcom/build/nsXPCOMCID.h @@ -90,6 +90,8 @@ */ #define NS_MESSAGE_LOOP_CONTRACTID "@mozilla.org/message-loop;1" +#define NS_COMPARTMENT_INFO_CONTRACTID "@mozilla.org/compartment-info;1" + /** * The following are the CIDs and Contract IDs of the nsISupports wrappers for * primative types.