Merge m-c to b2g-inbound. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 15 Jul 2015 21:30:15 -0400
changeset 253076 72835344333faa9c2f746e07aaada32c02104122
parent 253075 ebb47697c795cb57188c4e36b755f777917259e9 (current diff)
parent 253062 61eccd5a10ed3355e13c44ff872e471f25020efd (diff)
child 253077 d8023b434e25beed6cb5d38b57d6bb27aaf888df
child 253128 349868f3bec7b199562cabb0425cf3c5135a7c9c
child 253163 9eb7be0f006dc8f4ee8ad92a009bb7e0f5b4357e
child 253201 9e0864ad7475ea6d4ad263e75a5f2bf3d838f3ab
push id29058
push userryanvm@gmail.com
push dateThu, 16 Jul 2015 02:57:02 +0000
treeherdermozilla-central@72835344333f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone42.0a1
first release with
nightly linux32
72835344333f / 42.0a1 / 20150716030208 / files
nightly linux64
72835344333f / 42.0a1 / 20150716030208 / files
nightly mac
72835344333f / 42.0a1 / 20150716030208 / files
nightly win32
72835344333f / 42.0a1 / 20150716030208 / files
nightly win64
72835344333f / 42.0a1 / 20150716030208 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to b2g-inbound. a=merge CLOSED TREE
toolkit/components/perfmonitoring/PerformanceStats-content.js
--- a/toolkit/components/aboutperformance/content/aboutPerformance.js
+++ b/toolkit/components/aboutperformance/content/aboutPerformance.js
@@ -81,20 +81,17 @@ let AutoUpdate = {
   updateRefreshRate: function () {
     AutoUpdate.stop();
     AutoUpdate.start();
   }
 
 };
 
 let State = {
-  _monitor: PerformanceStats.getMonitor([
-    "jank", "cpow", "ticks",
-    "jank-content", "cpow-content", "ticks-content",
-  ]),
+  _monitor: PerformanceStats.getMonitor(["jank", "cpow", "ticks"]),
 
   /**
    * @type{PerformanceData}
    */
   _processData: null,
   /**
    * A mapping from name to PerformanceData
    *
@@ -242,17 +239,17 @@ let updateLiveData = Task.async(function
   try {
     let dataElt = document.getElementById("liveData");
     dataElt.innerHTML = "";
 
     // Generate table headers
     let headerElt = document.createElement("tr");
     dataElt.appendChild(headerElt);
     headerElt.classList.add("header");
-    for (let column of [...MEASURES, {key: "name", name: ""}, {key: "process", name: ""}]) {
+    for (let column of [...MEASURES, {key: "name", name: ""}]) {
       let el = document.createElement("td");
       el.classList.add(column.key);
       el.textContent = column.label;
       headerElt.appendChild(el);
     }
 
     let deltas = yield State.update();
 
@@ -278,47 +275,30 @@ let updateLiveData = Task.async(function
         let value = percentOfDeltaT ? Math.round(rawValue / deltas.deltaT) : rawValue;
         if (key == "longestDuration") {
           value += 1;
           el.classList.add("jank" + value);
         }
         el.textContent = value;
       }
 
-      {
-        // Name
-        let el = document.createElement("td");
-        let id = item.id;
-        el.classList.add("contents");
-        el.classList.add("name");
-        row.appendChild(el);
-        if (item.addonId) {
-          let _el = el;
-          let _item = item;
-          AddonManager.getAddonByID(item.addonId, a => {
-            _el.textContent = a ? a.name : _item.name
-          });
-        } else {
-          el.textContent = item.title || item.name;
-        }
-      }
-
-      {
-        // Process information.
-        let el = document.createElement("td");
-        el.classList.add("contents");
-        el.classList.add("process");
-        row.appendChild(el);
-        if (item.isChildProcess) {
-          el.textContent = "(child)";
-          row.classList.add("child");
-        } else {
-          el.textContent = "(parent)";
-          row.classList.add("parent");
-        }
+      // Name
+      let el = document.createElement("td");
+      let id = item.id;
+      el.classList.add("contents");
+      el.classList.add("name");
+      row.appendChild(el);
+      if (item.addonId) {
+        let _el = el;
+        let _item = item;
+        AddonManager.getAddonByID(item.addonId, a => {
+          _el.textContent = a ? a.name : _item.name
+        });
+      } else {
+        el.textContent = item.title || item.name;
       }
     }
   } catch (ex) {
     console.error(ex);
   }
 });
 
 function go() {
--- a/toolkit/components/aboutperformance/tests/browser/browser.ini
+++ b/toolkit/components/aboutperformance/tests/browser/browser.ini
@@ -1,8 +1,9 @@
 [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
deleted file mode 100644
--- a/toolkit/components/perfmonitoring/PerformanceStats-content.js
+++ /dev/null
@@ -1,144 +0,0 @@
-/* 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/. */
-
-/**
- * A proxy implementing communication between the PerformanceStats.jsm modules
- * of the parent and children processes.
- *
- * This script is loaded in all processes but is essentially a NOOP in the
- * parent process.
- */
-
-"use strict";
-
-const { utils: Cu, classes: Cc, interfaces: Ci } = Components;
-const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
-const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
-
-XPCOMUtils.defineLazyModuleGetter(this, "PerformanceStats",
-  "resource://gre/modules/PerformanceStats.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Task",
-  "resource://gre/modules/Task.jsm");
-
-/**
- * A global performance monitor used by this process.
- *
- * For the sake of simplicity, rather than attempting to map each PerformanceMonitor
- * of the parent to a PerformanceMonitor in each child process, we maintain a single
- * PerformanceMonitor in each child process. Probes activation/deactivation for this
- * monitor is controlled by the activation/deactivation of probes marked as "-content"
- * in the parent.
- *
- * In the parent, this is always an empty monitor.
- */
-let gMonitor = PerformanceStats.getMonitor([]);
-
-/**
- * `true` if this is a content process, `false` otherwise.
- */
-let isContent = Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
-
-/**
- * Handle message `performance-stats-service-acquire`: ensure that the global
- * monitor has a given probe. This message must be sent by the parent process
- * whenever a probe is activated application-wide.
- *
- * Note that we may miss acquire messages if they are sent before this process is
- * launched. For this reason, `performance-stats-service-collect` automatically
- * re-acquires probes if it realizes that they are missing.
- *
- * This operation is a NOOP on the parent process.
- *
- * @param {{payload: Array<string>}} msg.data The message received. `payload`
- * must be an array of probe names.
- */
-Services.cpmm.addMessageListener("performance-stats-service-acquire", function(msg) {
-  if (!isContent) {
-    return;
-  }
-  let name = msg.data.payload;
-  ensureAcquired(name);
-});
-
-/**
- * Handle message `performance-stats-service-release`: release a given probe
- * from the global monitor. This message must be sent by the parent process
- * whenever a probe is deactivated application-wide.
- *
- * Note that we may miss release messages if they are sent before this process is
- * launched. This is ok, as probes are inactive by default: if we miss the release
- * message, we have already missed the acquire message, and the effect of both
- * messages together is to reset to the default state.
- *
- * This operation is a NOOP on the parent process.
- *
- * @param {{payload: Array<string>}} msg.data The message received. `payload`
- * must be an array of probe names.
- */
-Services.cpmm.addMessageListener("performance-stats-service-release", function(msg) {
-  if (!isContent) {
-    return;
-  }
-  // Keep only the probes that do not appear in the payload
-  let probes = gMonitor.getProbeNames
-    .filter(x => msg.data.payload.indexOf(x) == -1);
-  gMonitor = PerformanceStats.getMonitor(probes);
-});
-
-/**
- * Ensure that this process has all the probes it needs.
- *
- * @param {Array<string>} probeNames The name of all probes needed by the
- * process.
- */
-function ensureAcquired(probeNames) {
-  let alreadyAcquired = gMonitor.probeNames;
-
-  // Algorithm is O(n^2) because we expect that n ≤ 3.
-  let shouldAcquire = [];
-  for (let probeName of probeNames) {
-    if (alreadyAcquired.indexOf(probeName) == -1) {
-      shouldAcquire.push(probeName)
-    }
-  }
-
-  if (shouldAcquire.length == 0) {
-    return;
-  }
-  gMonitor = PerformanceStats.getMonitor([...alreadyAcquired, ...shouldAcquire]);
-}
-
-/**
- * Handle message `performance-stats-service-collected`: collect the data
- * obtained by the monitor. This message must be sent by the parent process
- * whenever we grab a performance snapshot of the application.
- *
- * This operation provides `null` on the parent process.
- *
- * @param {{data: {payload: Array<string>}}} msg The message received. `payload`
- * must be an array of probe names.
- */
-Services.cpmm.addMessageListener("performance-stats-service-collect", Task.async(function*(msg) {
-  let {id, payload: {probeNames}} = msg.data;
-  if (!isContent) {
-    // This message was sent by the parent process to itself.
-    // As per protocol, respond `null`.
-    Services.cpmm.sendAsyncMessage("performance-stats-service-collect", {
-      id,
-      data: null
-    });
-    return;
-  }
-
-  // We may have missed acquire messages if the process was loaded too late.
-  // Catch up now.
-  ensureAcquired(probeNames);
-
-  // Collect and return data.
-  let data = yield gMonitor.promiseSnapshot({probeNames});
-  Services.cpmm.sendAsyncMessage("performance-stats-service-collect", {
-    id,
-    data
-  });
-}));
--- a/toolkit/components/perfmonitoring/PerformanceStats.jsm
+++ b/toolkit/components/perfmonitoring/PerformanceStats.jsm
@@ -18,49 +18,38 @@ const { classes: Cc, interfaces: Ci, uti
  * from the probes.
  *
  * Data is collected by "Performance Group". Typically, a Performance Group
  * is an add-on, or a frame, or the internals of the application.
  */
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
 Cu.import("resource://gre/modules/Services.jsm", this);
-Cu.import("resource://gre/modules/Task.jsm", this);
-
-XPCOMUtils.defineLazyModuleGetter(this, "PromiseUtils",
-  "resource://gre/modules/PromiseUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "setTimeout",
-  "resource://gre/modules/Timer.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "clearTimeout",
-  "resource://gre/modules/Timer.jsm");
 
 // The nsIPerformanceStatsService provides lower-level
 // access to SpiderMonkey and the probes.
 XPCOMUtils.defineLazyServiceGetter(this, "performanceStatsService",
   "@mozilla.org/toolkit/performance-stats-service;1",
   Ci.nsIPerformanceStatsService);
 
 // The finalizer lets us automatically release (and when possible deactivate)
 // probes when a monitor is garbage-collected.
 XPCOMUtils.defineLazyServiceGetter(this, "finalizer",
   "@mozilla.org/toolkit/finalizationwitness;1",
   Ci.nsIFinalizationWitnessService
 );
 
+
 // The topic used to notify that a PerformanceMonitor has been garbage-collected
 // and that we can release/close the probes it holds.
 const FINALIZATION_TOPIC = "performancemonitor-finalize";
 
-const PROPERTIES_META_IMMUTABLE = ["addonId", "isSystem", "isChildProcess", "groupId"];
-const PROPERTIES_META = [...PROPERTIES_META_IMMUTABLE, "windowId", "title", "name"];
+const PROPERTIES_META_IMMUTABLE = ["name", "addonId", "isSystem", "groupId"];
+const PROPERTIES_META = [...PROPERTIES_META_IMMUTABLE, "windowId", "title"];
 
-// How long we wait for children processes to respond.
-const MAX_WAIT_FOR_CHILD_PROCESS_MS = 5000;
-
-let isContent = Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
 /**
  * Access to a low-level performance probe.
  *
  * Each probe is dedicated to some form of performance monitoring.
  * As each probe may have a performance impact, a probe is activated
  * only when a client has requested a PerformanceMonitor for this probe,
  * and deactivated once all clients are disposed of.
  */
@@ -131,24 +120,24 @@ Probe.prototype = {
    * @param {object} a An object returned by `this.extract()`. May
    * NOT be `null`.
    * @param {object} b An object returned by `this.extract()`. May
    * be `null`.
    *
    * @return {object} An object representing `a - b`. If `b` is
    * `null`, this is `a`.
    */
-  subtract: function(a, b) {
+  substract: function(a, b) {
     if (a == null) {
       throw new TypeError();
     }
     if (b == null) {
       return a;
     }
-    return this._impl.subtract(a, b);
+    return this._impl.substract(a, b);
   },
 
   /**
    * The name of the probe.
    */
   get name() {
     return this._name;
   }
@@ -210,17 +199,17 @@ let Probes = {
       }
       for (let i = 0; i < a.durations.length; ++i) {
         if (a.durations[i] != b.durations[i]) {
           return false;
         }
       }
       return true;
     },
-    subtract: function(a, b) {
+    substract: function(a, b) {
       // invariant: `a` and `b` are both non-null
       let result = {
         totalUserTime: a.totalUserTime - b.totalUserTime,
         totalSystemTime: a.totalSystemTime - b.totalSystemTime,
         durations: [],
         longestDuration: -1,
       };
       for (let i = 0; i < a.durations.length; ++i) {
@@ -249,17 +238,17 @@ let Probes = {
     extract: function(xpcom) {
       return {
         totalCPOWTime: xpcom.totalCPOWTime
       };
     },
     isEqual: function(a, b) {
       return a.totalCPOWTime == b.totalCPOWTime;
     },
-    subtract: function(a, b) {
+    substract: function(a, b) {
       return {
         totalCPOWTime: a.totalCPOWTime - b.totalCPOWTime
       };
     }
   }),
 
   /**
    * A probe measuring activations, i.e. the number
@@ -278,88 +267,22 @@ let Probes = {
     extract: function(xpcom) {
       return {
         ticks: xpcom.ticks
       };
     },
     isEqual: function(a, b) {
       return a.ticks == b.ticks;
     },
-    subtract: function(a, b) {
+    substract: function(a, b) {
       return {
         ticks: a.ticks - b.ticks
       };
     }
   }),
-
-  "jank-content": new Probe("jank-content", {
-    _isActive: false,
-    set isActive(x) {
-      this._isActive = x;
-      if (x) {
-        Process.broadcast("acquire", ["jank"]);
-      } else {
-        Process.broadcast("release", ["jank"]);
-      }
-    },
-    get isActive() {
-      return this._isActive;
-    },
-    extract: function(xpcom) {
-      return {};
-    },
-    isEqual: function(a, b) {
-      return true;
-    },
-    subtract: function(a, b) {
-      return null;
-    }
-  }),
-
-  "cpow-content": new Probe("cpow-content", {
-    _isActive: false,
-    set isActive(x) {
-      this._isActive = x;
-      if (x) {
-        Process.broadcast("acquire", ["cpow"]);
-      } else {
-        Process.broadcast("release", ["cpow"]);
-      }
-    },
-    get isActive() {
-      return this._isActive;
-    },
-    extract: function(xpcom) {
-      return {};
-    },
-    isEqual: function(a, b) {
-      return true;
-    },
-    subtract: function(a, b) {
-      return null;
-    }
-  }),
-
-  "ticks-content": new Probe("ticks-content", {
-    set isActive(x) {
-      // Ignore: This probe is always active.
-    },
-    get isActive() {
-      return true;
-    },
-    extract: function(xpcom) {
-      return {};
-    },
-    isEqual: function(a, b) {
-      return true;
-    },
-    subtract: function(a, b) {
-      return null;
-    }
-  }),
 };
 
 
 /**
  * A monitor for a set of probes.
  *
  * Keeping probes active when they are unused is often a bad
  * idea for performance reasons. Upon destruction, or whenever
@@ -378,86 +301,52 @@ function PerformanceMonitor(probes) {
   // `this` object, a notification of `FINALIZATION_TOPIC` will be triggered
   // with `id` as message.
   this._id = PerformanceMonitor.makeId();
   this._finalizer = finalizer.make(FINALIZATION_TOPIC, this._id)
   PerformanceMonitor._monitors.set(this._id, probes);
 }
 PerformanceMonitor.prototype = {
   /**
-   * The names of probes activated in this monitor.
-   */
-  get probeNames() {
-    return [for (probe of this._probes) probe.name];
-  },
-
-  /**
    * Return asynchronously a snapshot with the data
    * for each probe monitored by this PerformanceMonitor.
    *
    * All numeric values are non-negative and can only increase. Depending on
    * the probe and the underlying operating system, probes may not be available
    * immediately and may miss some activity.
    *
    * Clients should NOT expect that the first call to `promiseSnapshot()`
    * will return a `Snapshot` in which all values are 0. For most uses,
    * the appropriate scenario is to perform a first call to `promiseSnapshot()`
    * to obtain a baseline, and then watch evolution of the values by calling
-   * `promiseSnapshot()` and `subtract()`.
+   * `promiseSnapshot()` and `substract()`.
    *
    * On the other hand, numeric values are also monotonic across several instances
    * of a PerformanceMonitor with the same probes. 
    *  let a = PerformanceStats.getMonitor(someProbes);
    *  let snapshot1 = yield a.promiseSnapshot();
    *
    *  // ...
    *  let b = PerformanceStats.getMonitor(someProbes); // Same list of probes
    *  let snapshot2 = yield b.promiseSnapshot();
    *
    *  // all values of `snapshot2` are greater or equal to values of `snapshot1`.
    *
-   * @param {object} options If provided, an object that may contain the following
-   *   fields:
-   *   {Array<string>} probeNames The subset of probes to use for this snapshot.
-   *      These probes must be a subset of the probes active in the monitor.
-   *
    * @return {Promise}
    * @resolve {Snapshot}
    */
-  promiseSnapshot: function(options = null) {
+  promiseSnapshot: function() {
     if (!this._finalizer) {
       throw new Error("dispose() has already been called, this PerformanceMonitor is not usable anymore");
     }
-    let probes;
-    if (options && options.probeNames || undefined) {
-      if (!Array.isArray(options.probeNames)) {
-        throw new TypeError();
-      }
-      // Make sure that we only request probes that we have
-      for (let probeName of options.probeNames) {
-        let probe = this._probes.find(probe => probe.name == probeName);
-        if (!probe) {
-          throw new TypeError(`I need probe ${probeName} but I only have ${this.probeNames}`);
-        }
-        if (!probes) {
-          probes = [];
-        }
-        probes.push(probe);
-      }
-    } else {
-      probes = this._probes;
-    }
-    return Task.spawn(function*() {
-      let collected = yield Process.broadcastAndCollect("collect", {probeNames: [for (probe of probes) probe.name]});
-      return new Snapshot({
-        xpcom: performanceStatsService.getSnapshot(),
-        childProcesses: collected,
-        probes
-      });
-    });
+    // Current implementation is actually synchronous.
+    return Promise.resolve().then(() => new Snapshot({
+      xpcom: performanceStatsService.getSnapshot(),
+      probes: this._probes
+    }));
   },
 
   /**
    * Release the probes used by this monitor.
    *
    * Releasing probes as soon as they are unused is a good idea, as some probes
    * cost CPU and/or memory.
    */
@@ -487,17 +376,17 @@ PerformanceMonitor._monitors = new Map()
 PerformanceMonitor.make = function(probeNames) {
   // Sanity checks
   if (!Array.isArray(probeNames)) {
     throw new TypeError("Expected an array, got " + probes);
   }
   let probes = [];
   for (let probeName of probeNames) {
     if (!(probeName in Probes)) {
-      throw new TypeError("Probe not implemented: " + probeName);
+      throw new TypeError("Probe not implemented: " + k);
     }
     probes.push(Probes[probeName]);
   }
 
   return new PerformanceMonitor(probes);
 };
 
 /**
@@ -573,34 +462,22 @@ this.PerformanceStats = {
  *   `undefined` if this probe is not active.
  *
  * @field {object|undefined} jank See the documentation of probe "jank".
  *   `undefined` if this probe is not active.
  *
  * @field {object|undefined} cpow See the documentation of probe "cpow".
  *   `undefined` if this probe is not active.
  */
-function PerformanceData({xpcom, json, probes}) {
-  if (xpcom && json) {
-    throw new TypeError("Cannot import both xpcom and json data");
-  }
-  let source = xpcom || json;
+function PerformanceData({xpcom, probes}) {
   for (let k of PROPERTIES_META) {
-    this[k] = source[k];
+    this[k] = xpcom[k];
   }
-  if (xpcom) {
-    for (let probe of probes) {
-      this[probe.name] = probe.extract(xpcom);
-    }
-    this.isChildProcess = false;
-  } else {
-    for (let probe of probes) {
-      this[probe.name] = json[probe.name];
-    }
-    this.isChildProcess = true;
+  for (let probe of probes) {
+    this[probe.name] = probe.extract(xpcom);
   }
 }
 PerformanceData.prototype = {
   /**
    * Compare two instances of `PerformanceData`
    *
    * @return `true` if `this` and `to` have equal values in all fields.
    */
@@ -637,166 +514,25 @@ PerformanceData.prototype = {
 function PerformanceDiff(current, old = null) {
   for (let k of PROPERTIES_META) {
     this[k] = current[k];
   }
 
   for (let probeName of Object.keys(Probes)) {
     let other = old ? old[probeName] : null;
     if (probeName in current) {
-      this[probeName] = Probes[probeName].subtract(current[probeName], other);
+      this[probeName] = Probes[probeName].substract(current[probeName], other);
     }
   }
 }
 
 /**
- * A snapshot of the performance usage of the application.
- *
- * @param {nsIPerformanceSnapshot} xpcom The data acquired from this process.
- * @param {Array<Object>} childProcesses The data acquired from children processes.
- * @param {Array<Probe>} probes The active probes.
+ * A snapshot of the performance usage of the process.
  */
-function Snapshot({xpcom, childProcesses, probes}) {
+function Snapshot({xpcom, probes}) {
   this.componentsData = [];
-
-  // Parent process
-  if (xpcom) {
-    let enumeration = xpcom.getComponentsData().enumerate();
-    while (enumeration.hasMoreElements()) {
-      let xpcom = enumeration.getNext().QueryInterface(Ci.nsIPerformanceStats);
-      this.componentsData.push(new PerformanceData({xpcom, probes}));
-    }
+  let enumeration = xpcom.getComponentsData().enumerate();
+  while (enumeration.hasMoreElements()) {
+    let stat = enumeration.getNext().QueryInterface(Ci.nsIPerformanceStats);
+    this.componentsData.push(new PerformanceData({xpcom: stat, probes}));
   }
-
-  // Content processes
-  if (childProcesses) {
-    for (let {componentsData} of childProcesses) {
-      // We are only interested in `componentsData` for the time being.
-      for (let json of componentsData) {
-        this.componentsData.push(new PerformanceData({json, probes}));
-      }
-    }
-  }
-
   this.processData = new PerformanceData({xpcom: xpcom.getProcessData(), probes});
 }
-
-/**
- * Communication with other processes
- */
-let Process = {
-  // `true` once communications have been initialized
-  _initialized: false,
-
-  // the message manager
-  _loader: null,
-
-  // a counter used to match responses to requests
-  _idcounter: 0,
-
-  /**
-   * If we are in a child process, return `null`.
-   * Otherwise, return the global parent process message manager
-   * and load the script to connect to children processes.
-   */
-  get loader() {
-    if (this._initialized) {
-      return this._loader;
-    }
-    this._initialized = true;
-    this._loader = Services.ppmm;
-    if (!this._loader) {
-      // We are in a child process.
-      return null;
-    }
-    this._loader.loadProcessScript("resource://gre/modules/PerformanceStats-content.js",
-      true/*including future processes*/);
-    return this._loader;
-  },
-
-  /**
-   * Broadcast a message to all children processes.
-   *
-   * NOOP if we are in a child process.
-   */
-  broadcast: function(topic, payload) {
-    if (!this.loader) {
-      return;
-    }
-    this.loader.broadcastAsyncMessage("performance-stats-service-" + topic, {payload});
-  },
-
-  /**
-   * Brodcast a message to all children processes and wait for answer.
-   *
-   * NOOP if we are in a child process, or if we have no children processes,
-   * in which case we return `undefined`.
-   *
-   * @return {undefined} If we have no children processes, in particular
-   * if we are in a child process.
-   * @return {Promise<Array<Object>>} If we have children processes, an
-   * array of objects with a structure similar to PerformanceData. Note
-   * that the array may be empty if no child process responded.
-   */
-  broadcastAndCollect: Task.async(function*(topic, payload) {
-    if (!this.loader || this.loader.childCount == 1) {
-      return undefined;
-    }
-    const TOPIC = "performance-stats-service-" + topic;
-    let id = this._idcounter++;
-
-    // The number of responses we are expecting. Note that we may
-    // not receive all responses if a process is too long to respond.
-    let expecting = this.loader.childCount;
-
-    // The responses we have collected, in arbitrary order.
-    let collected = [];
-    let deferred = PromiseUtils.defer();
-
-    // The content script may be loaded more than once (bug 1184115).
-    // To avoid double-responses, we keep track of who has already responded.
-    // Note that we could it on the other end, at the expense of implementing
-    // an additional .jsm just for that purpose.
-    let responders = new Set();
-    let observer = function({data, target}) {
-      if (data.id != id) {
-        // Collision between two collections,
-        // ignore the other one.
-        return;
-      }
-      if (responders.has(target)) {
-        return;
-      }
-      responders.add(target);
-      if (data.data) {
-        collected.push(data.data)
-      }
-      if (--expecting > 0) {
-        // We are still waiting for at least one response.
-        return;
-      }
-      deferred.resolve();
-    };
-    this.loader.addMessageListener(TOPIC, observer);
-    this.loader.broadcastAsyncMessage(
-      TOPIC,
-      {id, payload}
-    );
-
-    // Processes can die/freeze/be busy loading a page..., so don't expect
-    // that they will always respond.
-    let timeout = setTimeout(() => {
-      if (expecting == 0) {
-        return;
-      }
-      deferred.resolve();
-    }, MAX_WAIT_FOR_CHILD_PROCESS_MS);
-
-    deferred.promise.then(() => {
-      clearTimeout(timeout);
-    });
-
-    yield deferred.promise;
-    this.loader.removeMessageListener(TOPIC, observer);
-
-    return collected;
-  })
-};
--- a/toolkit/components/perfmonitoring/moz.build
+++ b/toolkit/components/perfmonitoring/moz.build
@@ -8,17 +8,16 @@ XPCSHELL_TESTS_MANIFESTS += ['tests/xpcs
 BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
 
 FAIL_ON_WARNINGS = True
 
 XPIDL_MODULE = 'toolkit_perfmonitoring'
 
 EXTRA_JS_MODULES += [
     'AddonWatcher.jsm',
-    'PerformanceStats-content.js',
     'PerformanceStats.jsm',
 ]
 
 XPIDL_SOURCES += [
     'nsIPerformanceStats.idl',
 ]
 
 UNIFIED_SOURCES += [
--- a/toolkit/components/perfmonitoring/nsPerformanceStats.cpp
+++ b/toolkit/components/perfmonitoring/nsPerformanceStats.cpp
@@ -255,17 +255,17 @@ nsPerformanceSnapshot::GetGroupId(JSCont
                                   uint64_t uid,
                                   nsString& groupId)
 {
   JSRuntime* rt = JS_GetRuntime(cx);
   uint64_t runtimeId = reinterpret_cast<uintptr_t>(rt);
 
   groupId.AssignLiteral("process: ");
   groupId.AppendInt(mProcessId);
-  groupId.AppendLiteral(", thread: ");
+  groupId.AssignLiteral(", thread: ");
   groupId.AppendInt(runtimeId);
   groupId.AppendLiteral(", group: ");
   groupId.AppendInt(uid);
 }
 
 /* static */ bool
 nsPerformanceSnapshot::GetIsSystem(JSContext*,
                                    JS::Handle<JSObject*> global)
--- a/toolkit/components/perfmonitoring/tests/browser/browser_compartments.js
+++ b/toolkit/components/perfmonitoring/tests/browser/browser_compartments.js
@@ -81,17 +81,17 @@ let SilentAssert = {
     }
     Assert.ok(a, msg);
   },
   leq: function(a, b, msg) {
     this.ok(a <= b, `${msg}: ${a} <= ${b}`);
   }
 };
 
-let isShuttingDown = false;
+
 function monotinicity_tester(source, testName) {
   // In the background, check invariants:
   // - numeric data can only ever increase;
   // - the name, addonId, isSystem of a component never changes;
   // - the name, addonId, isSystem of the process data;
   // - there is at most one component with a combination of `name` and `addonId`;
   // - types, etc.
   let previous = {
@@ -125,20 +125,16 @@ function monotinicity_tester(source, tes
     }
     for (let i = 0; i < next.jank.durations.length - 1; ++i) {
       SilentAssert.leq(next.jank.durations[i + 1], next.jank.durations[i],
         `Sanity check (${testName}): durations[${i}] >= durations[${i + 1}].`)
     }
   };
   let iteration = 0;
   let frameCheck = Task.async(function*() {
-    if (isShuttingDown) {
-      window.clearInterval(interval);
-      return;
-    }
     let name = `${testName}: ${iteration++}`;
     let snapshot = yield source();
     if (!snapshot) {
       // This can happen at the end of the test when we attempt
       // to communicate too late with the content process.
       window.clearInterval(interval);
       return;
     }
@@ -158,20 +154,17 @@ function monotinicity_tester(source, tes
         ["jank", "totalSystemTime"],
         ["cpow", "totalCPOWTime"]
       ]) {
         SilentAssert.leq(item[probe][k], snapshot.processData[probe][k],
           `Sanity check (${testName}): component has a lower ${k} than process`);
       }
 
       let key = item.groupId;
-      if (map.has(key)) {
-        let old = map.get(key);
-        Assert.ok(false, `Component ${key} has already been seen. Latest: ${item.title||item.addonId||item.name}, previous: ${old.title||old.addonId||old.name}`);
-      }
+      SilentAssert.ok(!map.has(key), "The component hasn't been seen yet.");
       map.set(key, item);
     }
     for (let [key, item] of map) {
       sanityCheck(previous.componentsMap.get(key), item);
       previous.componentsMap.set(key, item);
     }
   });
   let interval = window.setInterval(frameCheck, 300);
@@ -238,25 +231,19 @@ add_task(function* test() {
     Assert.ok(!titles.includes(FRAME_TITLE), "Searching by title, the frames don't show up in the list of components");
 
     info(`Searching for window title '${PARENT_TITLE}' in ${JSON.stringify(titles)} (I hope to find it)`);
     let parent = stats.componentsData.find(x => x.title == PARENT_TITLE);
     if (!parent) {
       info("Searching by title, we didn't find the main frame");
       continue;
     }
-    info("Found the main frame");
 
-    if (skipTotalUserTime) {
-      info("Not looking for total user time on this platform, we're done");
-    } else if (parent.jank.totalUserTime > 1000) {
-      info("Enough CPU time detected, we're done");
+    if (skipTotalUserTime || parent.jank.totalUserTime > 1000) {
       break;
     } else {
-      info(`Not enough CPU time detected: ${parent.jank.totalUserTime}`);
-      info(`Details: ${JSON.stringify(parent, null, "\t")}`);
+      info(`Not enough CPU time detected: ${parent.jank.totalUserTime}`)
     }
   }
-  isShuttingDown = true;
 
   // Cleanup
   gBrowser.removeTab(newTab);
 });