Bug 1156264 - Activate/deactivate jank and CPOW monitoring separately (high-level);r=mossop
authorDavid Rajchenbach-Teller <dteller@mozilla.com>
Thu, 04 Jun 2015 13:12:27 +0200
changeset 270706 54e1ca823b3f216794d1830223226581446100b4
parent 270476 06b4ce80e1d772edf6024a24e14a56fea44cbf96
child 270746 8f805f59f14b1c3a27f21ef90f14bd37ae9d8a17
push id2689
push userdteller@mozilla.com
push dateTue, 09 Jun 2015 06:56:29 +0000
reviewersmossop
bugs1156264
milestone41.0a1
Bug 1156264 - Activate/deactivate jank and CPOW monitoring separately (high-level);r=mossop
toolkit/components/perfmonitoring/PerformanceStats.jsm
toolkit/components/perfmonitoring/nsIPerformanceStats.idl
toolkit/components/perfmonitoring/nsPerformanceStats.cpp
toolkit/components/perfmonitoring/tests/browser/browser_compartments.js
toolkit/components/perfmonitoring/tests/xpcshell/test_compartments.js
--- a/toolkit/components/perfmonitoring/PerformanceStats.jsm
+++ b/toolkit/components/perfmonitoring/PerformanceStats.jsm
@@ -169,18 +169,22 @@ let Probes = {
    * kernel for this performance group, in µs.
    * @field {Array<number>} durations An array containing at each position `i`
    * the number of times execution of this component has lasted at least `2^i`
    * milliseconds.
    * @field {number} longestDuration The index of the highest non-0 value in
    * `durations`.
    */
   jank: new Probe("jank", {
-    set isActive(x) { /* always active in the current implementation */ },
-    get isActive() { return true; },
+    set isActive(x) {
+      performanceStatsService.isMonitoringJank = x;
+    },
+    get isActive() {
+      return performanceStatsService.isMonitoringJank;
+    },
     extract: function(xpcom) {
       let durations = xpcom.getDurations();
       return {
         totalUserTime: xpcom.totalUserTime,
         totalSystemTime: xpcom.totalSystemTime,
         durations: durations,
         longestDuration: lastNonZero(durations)
       }
@@ -220,18 +224,22 @@ let Probes = {
    * A probe measuring CPOW activity.
    *
    * Data provided by this probe uses the following format:
    *
    * @field {number} totalCPOWTime The amount of wallclock time
    * spent executing blocking cross-process calls, in µs.
    */
   cpow: new Probe("cpow", {
-    set isActive(x) { /* always active in the current implementation */ },
-    get isActive() { return true; },
+    set isActive(x) {
+      performanceStatsService.isMonitoringCPOW = x;
+    },
+    get isActive() {
+      return performanceStatsService.isMonitoringCPOW;
+    },
     extract: function(xpcom) {
       return {
         totalCPOWTime: xpcom.totalCPOWTime
       };
     },
     isEqual: function(a, b) {
       return a.totalCPOWTime == b.totalCPOWTime;
     },
@@ -523,12 +531,8 @@ function Snapshot({xpcom, probes}) {
   this.componentsData = [];
   let enumeration = xpcom.getComponentsData().enumerate();
   while (enumeration.hasMoreElements()) {
     let stat = enumeration.getNext().QueryInterface(Ci.nsIPerformanceStats);
     this.componentsData.push(new PerformanceData({xpcom: stat, probes}));
   }
   this.processData = new PerformanceData({xpcom: xpcom.getProcessData(), probes});
 }
-
-
-// In the current implementation, all probes are always active.
-performanceStatsService.isStopwatchActive = true;
--- a/toolkit/components/perfmonitoring/nsIPerformanceStats.idl
+++ b/toolkit/components/perfmonitoring/nsIPerformanceStats.idl
@@ -99,22 +99,27 @@ interface nsIPerformanceSnapshot: nsISup
    * This contains the total amount of time spent executing JS code,
    * the total amount of time spent waiting for system calls while
    * executing JS code, the total amount of time performing blocking
    * inter-process calls, etc.
    */
   nsIPerformanceStats getProcessData();
 };
 
-[scriptable, builtinclass, uuid(3a20d41d-9f24-44b3-bd65-0910f92d33d2)]
+[scriptable, builtinclass, uuid(0469e6af-95c3-4961-a385-4bc009128939)]
 interface nsIPerformanceStatsService : nsISupports {
   /**
-   * `true` if we should monitor performance, `false` otherwise.
+   * `true` if we should monitor CPOW, `false` otherwise.
    */
-  [implicit_jscontext] attribute bool isStopwatchActive;
+  [implicit_jscontext] attribute bool isMonitoringCPOW;
+
+  /**
+   * `true` if we should monitor jank, `false` otherwise.
+   */
+  [implicit_jscontext] attribute bool isMonitoringJank;
 
   /**
    * Capture a snapshot of the performance data.
    */
   [implicit_jscontext] nsIPerformanceSnapshot getSnapshot();
 };
 
 %{C++
--- a/toolkit/components/perfmonitoring/nsPerformanceStats.cpp
+++ b/toolkit/components/perfmonitoring/nsPerformanceStats.cpp
@@ -328,27 +328,41 @@ NS_IMPL_ISUPPORTS(nsPerformanceStatsServ
 nsPerformanceStatsService::nsPerformanceStatsService()
 {
 }
 
 nsPerformanceStatsService::~nsPerformanceStatsService()
 {
 }
 
-/* [implicit_jscontext] attribute bool isStopwatchActive; */
-NS_IMETHODIMP nsPerformanceStatsService::GetIsStopwatchActive(JSContext* cx, bool *aIsStopwatchActive)
+//[implicit_jscontext] attribute bool isMonitoringCPOW;
+NS_IMETHODIMP nsPerformanceStatsService::GetIsMonitoringCPOW(JSContext* cx, bool *aIsStopwatchActive)
+{
+  JSRuntime *runtime = JS_GetRuntime(cx);
+  *aIsStopwatchActive = js::GetStopwatchIsMonitoringCPOW(runtime);
+  return NS_OK;
+}
+NS_IMETHODIMP nsPerformanceStatsService::SetIsMonitoringCPOW(JSContext* cx, bool aIsStopwatchActive)
 {
   JSRuntime *runtime = JS_GetRuntime(cx);
-  *aIsStopwatchActive = js::IsStopwatchActive(runtime);
+  if (!js::SetStopwatchIsMonitoringCPOW(runtime, aIsStopwatchActive)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
   return NS_OK;
 }
-NS_IMETHODIMP nsPerformanceStatsService::SetIsStopwatchActive(JSContext* cx, bool aIsStopwatchActive)
+NS_IMETHODIMP nsPerformanceStatsService::GetIsMonitoringJank(JSContext* cx, bool *aIsStopwatchActive)
 {
   JSRuntime *runtime = JS_GetRuntime(cx);
-  if (!js::SetStopwatchActive(runtime, aIsStopwatchActive)) {
+  *aIsStopwatchActive = js::GetStopwatchIsMonitoringJank(runtime);
+  return NS_OK;
+}
+NS_IMETHODIMP nsPerformanceStatsService::SetIsMonitoringJank(JSContext* cx, bool aIsStopwatchActive)
+{
+  JSRuntime *runtime = JS_GetRuntime(cx);
+  if (!js::SetStopwatchIsMonitoringJank(runtime, aIsStopwatchActive)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   return NS_OK;
 }
 
 /* readonly attribute nsIPerformanceSnapshot snapshot; */
 NS_IMETHODIMP nsPerformanceStatsService::GetSnapshot(JSContext* cx, nsIPerformanceSnapshot * *aSnapshot)
 {
--- a/toolkit/components/perfmonitoring/tests/browser/browser_compartments.js
+++ b/toolkit/components/perfmonitoring/tests/browser/browser_compartments.js
@@ -12,54 +12,57 @@ Cu.import("resource://gre/modules/Perfor
 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() {
-  "use strict";
+  try {
+    "use strict";
 
-  const { utils: Cu, classes: Cc, interfaces: Ci } = Components;
-  Cu.import("resource://gre/modules/PerformanceStats.jsm");
+    const { utils: Cu, classes: Cc, interfaces: Ci } = Components;
+    Cu.import("resource://gre/modules/PerformanceStats.jsm");
 
-  let performanceStatsService =
-    Cc["@mozilla.org/toolkit/performance-stats-service;1"].
-    getService(Ci.nsIPerformanceStatsService);
+    let performanceStatsService =
+      Cc["@mozilla.org/toolkit/performance-stats-service;1"].
+      getService(Ci.nsIPerformanceStatsService);
 
-  // Make sure that the stopwatch is now active.
-  performanceStatsService.isStopwatchActive = true;
-
-  let monitor = PerformanceStats.getMonitor(["jank", "cpow", "ticks"]);
+    // Make sure that the stopwatch is now active.
+    let monitor = PerformanceStats.getMonitor(["jank", "cpow", "ticks"]);
 
-  addMessageListener("compartments-test:getStatistics", () => {
-    try {
-      monitor.promiseSnapshot().then(snapshot => {
-        sendAsyncMessage("compartments-test:getStatistics", snapshot);
-      });
-    } catch (ex) {
-      Cu.reportError("Error in content: " + ex);
-      Cu.reportError(ex.stack);
-    }
-  });
+    addMessageListener("compartments-test:getStatistics", () => {
+      try {
+        monitor.promiseSnapshot().then(snapshot => {
+          sendAsyncMessage("compartments-test:getStatistics", snapshot);
+        });
+      } catch (ex) {
+        Cu.reportError("Error in content (getStatistics): " + ex);
+        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}, "*");
+    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 (setTitles): " + ex);
+        Cu.reportError(ex.stack);
       }
-      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);
-    }
-  });
+    });
+  } catch (ex) {
+    Cu.reportError("Error in content (setup): " + ex);
+    Cu.reportError(ex.stack);    
+  }
 }
 
 // A variant of `Assert` that doesn't spam the logs
 // in case of success.
 let SilentAssert = {
   equal: function(a, b, msg) {
     if (a == b) {
       return;
--- a/toolkit/components/perfmonitoring/tests/xpcshell/test_compartments.js
+++ b/toolkit/components/perfmonitoring/tests/xpcshell/test_compartments.js
@@ -5,35 +5,46 @@ const {utils: Cu, interfaces: Ci, classe
 Cu.import("resource://gre/modules/Task.jsm", this);
 Cu.import("resource://gre/modules/Services.jsm", this);
 Cu.import("resource://gre/modules/PerformanceStats.jsm", this);
 
 function run_test() {
   run_next_test();
 }
 
-let monitor = PerformanceStats.getMonitor(["ticks", "jank", "cpow"]);
-
 let promiseStatistics = Task.async(function*(name) {
   yield Promise.resolve(); // Make sure that we wait until
   // statistics have been updated.
-  return monitor.promiseSnapshot();
+  let service = Cc["@mozilla.org/toolkit/performance-stats-service;1"].
+    getService(Ci.nsIPerformanceStatsService);
+  let snapshot = service.getSnapshot();
+  let componentsData = [];
+  let componentsEnum = snapshot.getComponentsData().enumerate();
+  while (componentsEnum.hasMoreElements()) {
+    componentsData.push(componentsEnum.getNext().QueryInterface(Ci.nsIPerformanceStats));
+  }
+  return {
+    processData: snapshot.getProcessData(),
+    componentsData
+  };
 });
 
 let promiseSetMonitoring = Task.async(function*(to) {
-  Cc["@mozilla.org/toolkit/performance-stats-service;1"].
-    getService(Ci.nsIPerformanceStatsService).
-    isStopwatchActive = to;
+  let service = Cc["@mozilla.org/toolkit/performance-stats-service;1"].
+    getService(Ci.nsIPerformanceStatsService);
+  service.isMonitoringJank = to;
+  service.isMonitoringCPOW = to;
   yield Promise.resolve();
 });
 
-function getBuiltinStatistics(snapshot) {
+function getBuiltinStatistics(name, snapshot) {
   let stats = snapshot.componentsData.find(stats =>
     stats.isSystem && !stats.addonId
   );
+  do_print(`Built-in statistics for ${name} were ${stats?"":"not "}found`);
   return stats;
 }
 
 function burnCPU(ms) {
   do_print("Burning CPU");
   let counter = 0;
   let ignored = [];
   let start = Date.now();
@@ -98,32 +109,32 @@ add_task(function* test_measure() {
   ensureEquals(stats0, stats1, "Initial state vs. Initial state + burn, without stopwatch");
   let process1 = stats1.processData;
   let process2 = stats2.processData;
   let process3 = stats3.processData;
   let process4 = stats4.processData;
   if (skipPrecisionTests) {
     do_print("Skipping totalUserTime check under Windows XP, as timer is not always updated by the OS.")
   } else {
-    Assert.ok(process2.jank.totalUserTime - process1.jank.totalUserTime >= 10000, `At least 10ms counted for process time (${process2.jank.totalUserTime - process1.jank.totalUserTime})`);
+    Assert.ok(process2.totalUserTime - process1.totalUserTime >= 10000, `At least 10ms counted for process time (${process2.totalUserTime - process1.totalUserTime})`);
   }
-  Assert.equal(process2.jank.totalCPOWTime, process1.jank.totalCPOWTime, "We haven't used any CPOW time during the first burn");
-  Assert.equal(process4.jank.totalUserTime, process3.jank.totalUserTime, "After deactivating the stopwatch, we didn't count any time");
-  Assert.equal(process4.jank.totalCPOWTime, process3.jank.totalCPOWTime, "After deactivating the stopwatch, we didn't count any CPOW time");
+  Assert.equal(process2.totalCPOWTime, process1.totalCPOWTime, "We haven't used any CPOW time during the first burn");
+  Assert.equal(process4.totalUserTime, process3.totalUserTime, "After deactivating the stopwatch, we didn't count any time");
+  Assert.equal(process4.totalCPOWTime, process3.totalCPOWTime, "After deactivating the stopwatch, we didn't count any CPOW time");
 
-  let builtin1 = getBuiltinStatistics(stats1) || { jank: { totalUserTime: 0 }, cpow: { totalCPOWTime: 0 } };
-  let builtin2 = getBuiltinStatistics(stats2);
-  let builtin3 = getBuiltinStatistics(stats3);
-  let builtin4 = getBuiltinStatistics(stats4);
+  let builtin1 = getBuiltinStatistics("Built-ins 1", stats1) || { totalUserTime: 0, totalCPOWTime: 0 };
+  let builtin2 = getBuiltinStatistics("Built-ins 2", stats2);
+  let builtin3 = getBuiltinStatistics("Built-ins 3", stats3);
+  let builtin4 = getBuiltinStatistics("Built-ins 4", stats4);
   Assert.notEqual(builtin2, null, "Found the statistics for built-ins 2");
   Assert.notEqual(builtin3, null, "Found the statistics for built-ins 3");
   Assert.notEqual(builtin4, null, "Found the statistics for built-ins 4");
 
   if (skipPrecisionTests) {
     do_print("Skipping totalUserTime check under Windows XP, as timer is not always updated by the OS.")
   } else {
-    Assert.ok(builtin2.jank.totalUserTime - builtin1.jank.totalUserTime >= 10000, `At least 10ms counted for built-in statistics (${builtin2.jank.totalUserTime - builtin1.jank.totalUserTime})`);
+    Assert.ok(builtin2.totalUserTime - builtin1.totalUserTime >= 10000, `At least 10ms counted for built-in statistics (${builtin2.totalUserTime - builtin1.totalUserTime})`);
   }
-  Assert.equal(builtin2.jank.totalCPOWTime, builtin1.jank.totalCPOWTime, "We haven't used any CPOW time during the first burn for the built-in");
-  Assert.equal(builtin2.jank.totalCPOWTime, builtin1.jank.totalCPOWTime, "No CPOW for built-in statistics");
-  Assert.equal(builtin4.jank.totalUserTime, builtin3.jank.totalUserTime, "After deactivating the stopwatch, we didn't count any time for the built-in");
-  Assert.equal(builtin4.jank.totalCPOWTime, builtin3.jank.totalCPOWTime, "After deactivating the stopwatch, we didn't count any CPOW time for the built-in");
+  Assert.equal(builtin2.totalCPOWTime, builtin1.totalCPOWTime, "We haven't used any CPOW time during the first burn for the built-in");
+  Assert.equal(builtin2.totalCPOWTime, builtin1.totalCPOWTime, "No CPOW for built-in statistics");
+  Assert.equal(builtin4.totalUserTime, builtin3.totalUserTime, "After deactivating the stopwatch, we didn't count any time for the built-in");
+  Assert.equal(builtin4.totalCPOWTime, builtin3.totalCPOWTime, "After deactivating the stopwatch, we didn't count any CPOW time for the built-in");
 });