Backed out changeset 653179afb65f (bug 1175098) for frequent WinXP browser_compartments.js failures.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 15 Jul 2015 21:28:00 -0400
changeset 253062 61eccd5a10ed3355e13c44ff872e471f25020efd
parent 253061 9a42bc345feb549b0bf861970b648917fa406b1d
child 253076 72835344333faa9c2f746e07aaada32c02104122
child 253127 7204e34310f7e4674d697b0594ba755e8445062f
child 253200 b0738c7a39f0fb038b7c50b331e73dd69a118891
push id29057
push userryanvm@gmail.com
push dateThu, 16 Jul 2015 01:28:23 +0000
treeherdermozilla-central@61eccd5a10ed [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1175098
milestone42.0a1
backs out653179afb65ff47cdd49f7696512dd81007799ef
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset 653179afb65f (bug 1175098) for frequent WinXP browser_compartments.js failures. CLOSED TREE
toolkit/components/aboutperformance/content/aboutPerformance.js
toolkit/components/aboutperformance/tests/browser/browser.ini
toolkit/components/perfmonitoring/PerformanceStats-content.js
toolkit/components/perfmonitoring/PerformanceStats.jsm
toolkit/components/perfmonitoring/moz.build
toolkit/components/perfmonitoring/nsPerformanceStats.cpp
toolkit/components/perfmonitoring/tests/browser/browser_compartments.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);
 });