Backed out changesets 9eb2e0c7b864 and 19bdfb755eeb (bug 1147664) for various test failures.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 22 Jul 2015 13:18:54 -0400
changeset 254125 68596c2c0496cb4745ae005572495b76a5524dd7
parent 254124 1b94786e5516f75bb79c2b94cdd7ccc256d74237
child 254126 7abecce35aca1dd6a710177df7cdaeece449cad6
child 254168 ee371e7b0af09d6c2b9529f47f1f4c1495c4b5f1
push id29089
push userryanvm@gmail.com
push dateWed, 22 Jul 2015 20:29:27 +0000
treeherdermozilla-central@7abecce35aca [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1147664
milestone42.0a1
backs out9eb2e0c7b864e31c7eac6999f7a74920a5dc344c
19bdfb755eebb79704eda17585583849433aea84
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 changesets 9eb2e0c7b864 and 19bdfb755eeb (bug 1147664) for various test failures.
js/src/jsapi.cpp
js/src/jsapi.h
js/src/vm/Interpreter.cpp
js/src/vm/Runtime.cpp
js/src/vm/Runtime.h
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/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -312,82 +312,46 @@ IterPerformanceStats(JSContext* cx,
                     js::DefaultHasher<js::PerformanceGroup*>,
                     js::SystemAllocPolicy> Set;
     Set set;
     if (!set.init(100)) {
         return false;
     }
 
     JSRuntime* rt = JS_GetRuntime(cx);
-
-    // First report the shared groups
-    for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
+    for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next()) {
         JSCompartment* compartment = c.get();
-        if (!c->principals()) {
-            // Compartments without principals could show up here, but
-            // reporting them doesn't really make sense.
-            continue;
-        }
-        if (!c->performanceMonitoring.hasSharedGroup()) {
+        if (!compartment->performanceMonitoring.isLinked()) {
             // Don't report compartments that do not even have a PerformanceGroup.
             continue;
         }
+
         js::AutoCompartment autoCompartment(cx, compartment);
-        PerformanceGroup* group = compartment->performanceMonitoring.getSharedGroup(cx);
+        PerformanceGroup* group = compartment->performanceMonitoring.getGroup(cx);
+
         if (group->data.ticks == 0) {
             // Don't report compartments that have never been used.
             continue;
         }
 
         Set::AddPtr ptr = set.lookupForAdd(group);
         if (ptr) {
             // Don't report the same group twice.
             continue;
         }
 
-        if (!(*walker)(cx,
-                       group->data, group->uid, nullptr,
-                       closure)) {
+        if (!(*walker)(cx, group->data, group->uid, closure)) {
             // Issue in callback
             return false;
         }
         if (!set.add(ptr, group)) {
             // Memory issue
             return false;
         }
     }
-
-    // Then report the own groups
-    for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
-        JSCompartment* compartment = c.get();
-        if (!c->principals()) {
-            // Compartments without principals could show up here, but
-            // reporting them doesn't really make sense.
-            continue;
-        }
-        if (!c->performanceMonitoring.hasOwnGroup()) {
-            // Don't report compartments that do not even have a PerformanceGroup.
-            continue;
-        }
-        js::AutoCompartment autoCompartment(cx, compartment);
-        PerformanceGroup* ownGroup = compartment->performanceMonitoring.getOwnGroup(cx);
-        if (ownGroup->data.ticks == 0) {
-            // Don't report compartments that have never been used.
-            continue;
-        }
-        PerformanceGroup* sharedGroup = compartment->performanceMonitoring.getSharedGroup(cx);
-        if (!(*walker)(cx,
-                       ownGroup->data, ownGroup->uid, &sharedGroup->uid,
-                       closure)) {
-            // Issue in callback
-            return false;
-        }
-    }
-
-    // Finally, report the process stats
     *processStats = rt->stopwatch.performance;
     return true;
 }
 
 void
 AssertHeapIsIdle(JSRuntime* rt)
 {
     MOZ_ASSERT(!rt->isHeapBusy());
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5404,17 +5404,17 @@ BuildStackString(JSContext* cx, HandleOb
 
 } /* namespace JS */
 
 
 /* Stopwatch-based CPU monitoring. */
 
 namespace js {
 
-class AutoStopwatch;
+struct AutoStopwatch;
 
 // Container for performance data
 // All values are monotonic.
 struct PerformanceData {
     // Number of times we have spent at least 2^n consecutive
     // milliseconds executing code in this group.
     // durations[0] is increased whenever we spend at least 1 ms
     // executing code in this group
@@ -5535,67 +5535,55 @@ struct PerformanceGroup {
     friend struct PerformanceGroupHolder;
 
 private:
     // A reference counter. Maintained by PerformanceGroupHolder.
     uint64_t refCount_;
 };
 
 //
-// Each PerformanceGroupHolder handles:
-// - a reference-counted indirection towards a PerformanceGroup shared
-//   by several compartments
-// - a owned PerformanceGroup representing the performance of a single
-//   compartment.
+// Indirection towards a PerformanceGroup.
+// This structure handles reference counting for instances of PerformanceGroup.
 //
 struct PerformanceGroupHolder {
-    // Get the shared group.
+    // Get the group.
     // On first call, this causes a single Hashtable lookup.
     // Successive calls do not require further lookups.
-    js::PerformanceGroup* getSharedGroup(JSContext*);
-
-    // Get the own group.
-    js::PerformanceGroup* getOwnGroup(JSContext*);
-
-    // `true` if the this holder is currently associated to a shared
+    js::PerformanceGroup* getGroup(JSContext*);
+
+    // `true` if the this holder is currently associated to a
     // PerformanceGroup, `false` otherwise. Use this method to avoid
     // instantiating a PerformanceGroup if you only need to get
     // available performance data.
-    inline bool hasSharedGroup() const {
-        return sharedGroup_ != nullptr;
-    }
-    inline bool hasOwnGroup() const {
-        return ownGroup_ != nullptr;
+    inline bool isLinked() const {
+        return group_ != nullptr;
     }
 
     // Remove the link to the PerformanceGroup. This method is designed
     // as an invalidation mechanism if the JSCompartment changes nature
     // (new values of `isSystem()`, `principals()` or `addonId`).
     void unlink();
 
     explicit PerformanceGroupHolder(JSRuntime* runtime)
       : runtime_(runtime)
-      , sharedGroup_(nullptr)
-      , ownGroup_(nullptr)
+      , group_(nullptr)
     {   }
     ~PerformanceGroupHolder();
-
-  private:
+private:
     // Return the key representing this PerformanceGroup in
     // Runtime::Stopwatch.
     // Do not deallocate the key.
     void* getHashKey(JSContext* cx);
 
     JSRuntime *runtime_;
 
-    // The PerformanceGroups held by this object.
-    // Initially set to `nullptr` until the first call to `getGroup`.
+    // The PerformanceGroup held by this object.
+    // Initially set to `nullptr` until the first cal to `getGroup`.
     // May be reset to `nullptr` by a call to `unlink`.
-    js::PerformanceGroup* sharedGroup_;
-    js::PerformanceGroup* ownGroup_;
+    js::PerformanceGroup* group_;
 };
 
 /**
  * Reset any stopwatch currently measuring.
  *
  * This function is designed to be called when we process a new event.
  */
 extern JS_PUBLIC_API(void)
@@ -5611,34 +5599,28 @@ ResetStopwatches(JSRuntime*);
 extern JS_PUBLIC_API(bool)
 SetStopwatchIsMonitoringCPOW(JSRuntime*, bool);
 extern JS_PUBLIC_API(bool)
 GetStopwatchIsMonitoringCPOW(JSRuntime*);
 extern JS_PUBLIC_API(bool)
 SetStopwatchIsMonitoringJank(JSRuntime*, bool);
 extern JS_PUBLIC_API(bool)
 GetStopwatchIsMonitoringJank(JSRuntime*);
-extern JS_PUBLIC_API(bool)
-SetStopwatchIsMonitoringPerCompartment(JSRuntime*, bool);
-extern JS_PUBLIC_API(bool)
-GetStopwatchIsMonitoringPerCompartment(JSRuntime*);
 
 extern JS_PUBLIC_API(bool)
 IsStopwatchActive(JSRuntime*);
 
 /**
  * Access the performance information stored in a compartment.
  */
 extern JS_PUBLIC_API(PerformanceData*)
 GetPerformanceData(JSRuntime*);
 
 typedef bool
-(PerformanceStatsWalker)(JSContext* cx,
-                         const PerformanceData& stats, uint64_t uid,
-                         const uint64_t* parentId, void* closure);
+(PerformanceStatsWalker)(JSContext* cx, const PerformanceData& stats, uint64_t uid, void* closure);
 
 /**
  * Extract the performance statistics.
  *
  * Note that before calling `walker`, we enter the corresponding context.
  */
 extern JS_PUBLIC_API(bool)
 IterPerformanceStats(JSContext* cx, PerformanceStatsWalker* walker, js::PerformanceData* process, void* closure);
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -367,259 +367,147 @@ InvokeState::pushInterpreterFrame(JSCont
 
 InterpreterFrame*
 ExecuteState::pushInterpreterFrame(JSContext* cx)
 {
     return cx->runtime()->interpreterStack().pushExecuteFrame(cx, script_, thisv_, newTargetValue_,
                                                               scopeChain_, type_, evalInFrame_);
 }
 namespace js {
+
 // Implementation of per-performance group performance measurement.
 //
 //
 // All mutable state is stored in `Runtime::stopwatch` (per-process
 // performance stats and logistics) and in `PerformanceGroup` (per
 // group performance stats).
-class AutoStopwatch final
-{
-    // The context with which this object was initialized.
-    // Non-null.
-    JSContext* const cx_;
-
-    // An indication of the number of times we have entered the event
-    // loop.  Used only for comparison.
-    uint64_t iteration_;
-
-    // `true` if this object is currently used to monitor performance
-    // for a shared PerformanceGroup, `false` otherwise, i.e. if the
-    // stopwatch mechanism is off or if another stopwatch is already
-    // in charge of monitoring for the same PerformanceGroup.
-    bool isMonitoringForGroup_;
-
-    // `true` if this object is currently used to monitor performance
-    // for a single compartment, `false` otherwise, i.e. if the
-    // stopwatch mechanism is off or if another stopwatch is already
-    // in charge of monitoring for the same PerformanceGroup.
-    bool isMonitoringForSelf_;
-
-    // `true` if this stopwatch is the topmost stopwatch on the stack
-    // for this event, `false` otherwise.
-    bool isMonitoringForTop_;
-
-    // `true` if we are monitoring jank, `false` otherwise.
-    bool isMonitoringJank_;
-    // `true` if we are monitoring CPOW, `false` otherwise.
-    bool isMonitoringCPOW_;
-
-    // Timestamps captured while starting the stopwatch.
-    uint64_t userTimeStart_;
-    uint64_t systemTimeStart_;
-    uint64_t CPOWTimeStart_;
-
-   public:
+struct AutoStopwatch final
+{
     // If the stopwatch is active, constructing an instance of
     // AutoStopwatch causes it to become the current owner of the
     // stopwatch.
     //
     // Previous owner is restored upon destruction.
     explicit inline AutoStopwatch(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : cx_(cx)
       , iteration_(0)
-      , isMonitoringForGroup_(false)
-      , isMonitoringForSelf_(false)
-      , isMonitoringForTop_(false)
-      , isMonitoringJank_(false)
-      , isMonitoringCPOW_(false)
+      , isActive_(false)
+      , isTop_(false)
       , userTimeStart_(0)
       , systemTimeStart_(0)
       , CPOWTimeStart_(0)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
 
+        JSRuntime* runtime = JS_GetRuntime(cx_);
+        if (!runtime->stopwatch.isMonitoringJank())
+            return;
+
         JSCompartment* compartment = cx_->compartment();
         if (compartment->scheduledForDestruction)
             return;
 
-        JSRuntime* runtime = cx_->runtime();
         iteration_ = runtime->stopwatch.iteration;
 
-        PerformanceGroup* sharedGroup = compartment->performanceMonitoring.getSharedGroup(cx);
-        if (!sharedGroup) {
-            // Either this Runtime is not configured for Performance Monitoring, or we couldn't
-            // allocate the group, or there was a problem with the hashtable.
+        PerformanceGroup *group = compartment->performanceMonitoring.getGroup(cx);
+        MOZ_ASSERT(group);
+
+        if (group->hasStopwatch(iteration_)) {
+            // Someone is already monitoring this group during this
+            // tick, no need for further monitoring.
             return;
         }
 
-        if (!sharedGroup->hasStopwatch(iteration_)) {
-            // We are now in charge of monitoring this group for the tick,
-            // until destruction of `this` or until we enter a nested event
-            // loop and `iteration_` is incremented.
-            sharedGroup->acquireStopwatch(iteration_, this);
-            isMonitoringForGroup_ = true;
-        }
-
-        PerformanceGroup* ownGroup = nullptr;
-        if (runtime->stopwatch.isMonitoringPerCompartment()) {
-            // As above, but for the group representing just this compartment.
-            ownGroup = compartment->performanceMonitoring.getOwnGroup(cx);
-            if (!ownGroup->hasStopwatch(iteration_)) {
-                ownGroup->acquireStopwatch(iteration_, this);
-                isMonitoringForSelf_ = true;
-            }
-        }
+        // Start the stopwatch.
+        if (!this->getTimes(runtime, &userTimeStart_, &systemTimeStart_))
+            return;
+        isActive_ = true;
+        CPOWTimeStart_ = runtime->stopwatch.performance.totalCPOWTime;
+
+        // We are now in charge of monitoring this group for the tick,
+        // until destruction of `this` or until we enter a nested event
+        // loop and `iteration_` is incremented.
+        group->acquireStopwatch(iteration_, this);
 
         if (runtime->stopwatch.isEmpty) {
             // This is the topmost stopwatch on the stack.
             // It will be in charge of updating the per-process
             // performance data.
             runtime->stopwatch.isEmpty = false;
-            isMonitoringForTop_ = true;
-
-            MOZ_ASSERT(isMonitoringForGroup_);
+            runtime->stopwatch.performance.ticks++;
+            isTop_ = true;
         }
-
-        if (!isMonitoringForGroup_ && !isMonitoringForSelf_) {
+    }
+    inline ~AutoStopwatch() {
+        if (!isActive_) {
             // We are not in charge of monitoring anything.
-            // (isMonitoringForTop_ implies isMonitoringForGroup_,
-            // so we do not need to check it)
             return;
         }
 
-        enter();
-    }
-    ~AutoStopwatch() {
-        if (!isMonitoringForGroup_ && !isMonitoringForSelf_) {
-            // We are not in charge of monitoring anything.
-            // (isMonitoringForTop_ implies isMonitoringForGroup_,
-            // so we do not need to check it)
+        JSRuntime* runtime = JS_GetRuntime(cx_);
+        JSCompartment* compartment = cx_->compartment();
+
+        MOZ_ASSERT(!compartment->scheduledForDestruction);
+
+        if (!runtime->stopwatch.isMonitoringJank()) {
+            // Monitoring has been stopped while we were
+            // executing the code. Drop everything.
             return;
         }
 
-        JSCompartment* compartment = cx_->compartment();
-        if (compartment->scheduledForDestruction)
-            return;
-
-        JSRuntime* runtime = cx_->runtime();
         if (iteration_ != runtime->stopwatch.iteration) {
             // We have entered a nested event loop at some point.
             // Any information we may have is obsolete.
             return;
         }
 
-        // Finish and commit measures
-        exit();
-
-        // Now release groups.
-        if (isMonitoringForGroup_) {
-            PerformanceGroup* sharedGroup = compartment->performanceMonitoring.getSharedGroup(cx_);
-            MOZ_ASSERT(sharedGroup);
-            sharedGroup->releaseStopwatch(iteration_, this);
-        }
-
-        if (isMonitoringForSelf_) {
-            PerformanceGroup* ownGroup = compartment->performanceMonitoring.getOwnGroup(cx_);
-            MOZ_ASSERT(ownGroup);
-            ownGroup->releaseStopwatch(iteration_, this);
-        }
-
-        if (isMonitoringForTop_)
+        PerformanceGroup *group = compartment->performanceMonitoring.getGroup(cx_);
+        MOZ_ASSERT(group);
+
+        // Compute time spent.
+        group->releaseStopwatch(iteration_, this);
+        uint64_t userTimeEnd, systemTimeEnd;
+        if (!this->getTimes(runtime, &userTimeEnd, &systemTimeEnd))
+            return;
+
+        uint64_t userTimeDelta = userTimeEnd - userTimeStart_;
+        uint64_t systemTimeDelta = systemTimeEnd - systemTimeStart_;
+        uint64_t CPOWTimeDelta = runtime->stopwatch.performance.totalCPOWTime - CPOWTimeStart_;
+        group->data.totalUserTime += userTimeDelta;
+        group->data.totalSystemTime += systemTimeDelta;
+        group->data.totalCPOWTime += CPOWTimeDelta;
+
+        uint64_t totalTimeDelta = userTimeDelta + systemTimeDelta;
+        updateDurations(totalTimeDelta, group->data.durations);
+        group->data.ticks++;
+
+        if (isTop_) {
+            // This is the topmost stopwatch on the stack.
+            // Record the timing information.
+            runtime->stopwatch.performance.totalUserTime = userTimeEnd;
+            runtime->stopwatch.performance.totalSystemTime = systemTimeEnd;
+            updateDurations(totalTimeDelta, runtime->stopwatch.performance.durations);
             runtime->stopwatch.isEmpty = true;
-    }
-   private:
-    void enter() {
-        JSRuntime* runtime = cx_->runtime();
-
-        if (runtime->stopwatch.isMonitoringCPOW()) {
-            CPOWTimeStart_ = runtime->stopwatch.performance.totalCPOWTime;
-            isMonitoringCPOW_ = true;
-        }
-
-        if (runtime->stopwatch.isMonitoringJank()) {
-            if (this->getTimes(runtime, &userTimeStart_, &systemTimeStart_)) {
-                isMonitoringJank_ = true;
-            }
-        }
-
-    }
-
-    void exit() {
-        JSRuntime* runtime = cx_->runtime();
-
-        uint64_t userTimeDelta = 0;
-        uint64_t systemTimeDelta = 0;
-        if (isMonitoringJank_ && runtime->stopwatch.isMonitoringJank()) {
-            // We were monitoring jank when we entered and we still are.
-            uint64_t userTimeEnd, systemTimeEnd;
-            if (!this->getTimes(runtime, &userTimeEnd, &systemTimeEnd)) {
-                // We make no attempt to recover from this error. If
-                // we bail out here, we lose nothing of value, plus
-                // I'm nearly sure that this error cannot happen in
-                // practice.
-                return;
-            }
-            userTimeDelta = userTimeEnd - userTimeStart_;
-            systemTimeDelta = systemTimeEnd - systemTimeStart_;
-        }
-
-        uint64_t CPOWTimeDelta = 0;
-        if (isMonitoringCPOW_ && runtime->stopwatch.isMonitoringCPOW()) {
-            // We were monitoring CPOW when we entered and we still are.
-            CPOWTimeDelta = runtime->stopwatch.performance.totalCPOWTime - CPOWTimeStart_;
-
-        }
-        commitDeltasToGroups(userTimeDelta, systemTimeDelta, CPOWTimeDelta);
-    }
-
-    void commitDeltasToGroups(uint64_t userTimeDelta,
-                              uint64_t systemTimeDelta,
-                              uint64_t CPOWTimeDelta)
-    {
-        JSCompartment* compartment = cx_->compartment();
-
-        PerformanceGroup* sharedGroup = compartment->performanceMonitoring.getSharedGroup(cx_);
-        MOZ_ASSERT(sharedGroup);
-        applyDeltas(userTimeDelta, systemTimeDelta, CPOWTimeDelta, sharedGroup->data);
-
-        if (isMonitoringForSelf_) {
-            PerformanceGroup* ownGroup = compartment->performanceMonitoring.getOwnGroup(cx_);
-            MOZ_ASSERT(ownGroup);
-            applyDeltas(userTimeDelta, systemTimeDelta, CPOWTimeDelta, ownGroup->data);
-        }
-
-        if (isMonitoringForTop_) {
-            JSRuntime* runtime = cx_->runtime();
-            applyDeltas(userTimeDelta, systemTimeDelta, CPOWTimeDelta, runtime->stopwatch.performance);
         }
     }
 
-
-    void applyDeltas(uint64_t userTimeDelta,
-                     uint64_t systemTimeDelta,
-                     uint64_t CPOWTimeDelta,
-                     PerformanceData& data) const {
-
-        data.ticks++;
-
-        uint64_t totalTimeDelta = userTimeDelta + systemTimeDelta;
-        data.totalUserTime += userTimeDelta;
-        data.totalSystemTime += systemTimeDelta;
-        data.totalCPOWTime += CPOWTimeDelta;
-
-        // Update an array containing the number of times we have missed
-        // at least 2^0 successive ms, 2^1 successive ms, ...
-        // 2^i successive ms.
-
+ private:
+
+    // Update an array containing the number of times we have missed
+    // at least 2^0 successive ms, 2^1 successive ms, ...
+    // 2^i successive ms.
+    template<int N>
+    void updateDurations(uint64_t totalTimeDelta, uint64_t (&array)[N]) const {
         // Duration of one frame, i.e. 16ms in museconds
         size_t i = 0;
         uint64_t duration = 1000;
         for (i = 0, duration = 1000;
-             i < ArrayLength(data.durations) && duration < totalTimeDelta;
-             ++i, duration *= 2)
-        {
-            data.durations[i]++;
+             i < N && duration < totalTimeDelta;
+             ++i, duration *= 2) {
+            array[i]++;
         }
     }
 
     // Get the OS-reported time spent in userland/systemland, in
     // microseconds. On most platforms, this data is per-thread,
     // but on some platforms we need to fall back to per-process.
     bool getTimes(JSRuntime* runtime, uint64_t* userTime, uint64_t* systemTime) const {
         MOZ_ASSERT(userTime);
@@ -692,19 +580,41 @@ class AutoStopwatch final
         // Convert 100 ns to 1 us, make sure that the result is monotonic
         *userTime = runtime->stopwatch.userTimeFix.monotonize(userTimeInt.QuadPart / 10);
 
 #endif // defined(XP_MACOSX) || defined(XP_UNIX) || defined(XP_WIN)
 
         return true;
     }
 
-
-private:
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
+  private:
+    // The context with which this object was initialized.
+    // Non-null.
+    JSContext* const cx_;
+
+    // An indication of the number of times we have entered the event
+    // loop.  Used only for comparison.
+    uint64_t iteration_;
+
+    // `true` if this object is currently used to monitor performance,
+    // `false` otherwise, i.e. if the stopwatch mechanism is off or if
+    // another stopwatch is already in charge of monitoring for the
+    // same PerformanceGroup.
+    bool isActive_;
+
+    // `true` if this stopwatch is the topmost stopwatch on the stack
+    // for this event, `false` otherwise.
+    bool isTop_;
+
+    // Timestamps captured while starting the stopwatch.
+    uint64_t userTimeStart_;
+    uint64_t systemTimeStart_;
+    uint64_t CPOWTimeStart_;
+
+    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 } // namespace js
 
 // MSVC with PGO inlines a lot of functions in RunScript, resulting in large
 // stack frames and stack overflow issues, see bug 1167883. Turn off PGO to
 // avoid this.
 #ifdef _MSC_VER
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -894,27 +894,16 @@ js::SetStopwatchIsMonitoringCPOW(JSRunti
     return rt->stopwatch.setIsMonitoringCPOW(value);
 }
 bool
 js::GetStopwatchIsMonitoringCPOW(JSRuntime* rt)
 {
     return rt->stopwatch.isMonitoringCPOW();
 }
 
-bool
-js::SetStopwatchIsMonitoringPerCompartment(JSRuntime* rt, bool value)
-{
-    return rt->stopwatch.setIsMonitoringPerCompartment(value);
-}
-bool
-js::GetStopwatchIsMonitoringPerCompartment(JSRuntime* rt)
-{
-    return rt->stopwatch.isMonitoringPerCompartment();
-}
-
 js::PerformanceGroupHolder::~PerformanceGroupHolder()
 {
     unlink();
 }
 
 void*
 js::PerformanceGroupHolder::getHashKey(JSContext* cx)
 {
@@ -924,81 +913,57 @@ js::PerformanceGroupHolder::getHashKey(J
 
     // As a fallback, put everything in the same PerformanceGroup.
     return nullptr;
 }
 
 void
 js::PerformanceGroupHolder::unlink()
 {
-    if (ownGroup_) {
-        js_delete(ownGroup_);
-        ownGroup_ = nullptr;
-    }
-
-    if (!sharedGroup_) {
+    if (!group_) {
         // The group has never been instantiated.
         return;
     }
 
-    js::PerformanceGroup* group = sharedGroup_;
-    sharedGroup_ = nullptr;
+    js::PerformanceGroup* group = group_;
+    group_ = nullptr;
 
     if (group->decRefCount() > 0) {
         // The group has at least another owner.
         return;
     }
 
 
     JSRuntime::Stopwatch::Groups::Ptr ptr =
-        runtime_->stopwatch.groups().lookup(group->key_);
+        runtime_->stopwatch.groups_.lookup(group->key_);
     MOZ_ASSERT(ptr);
-    runtime_->stopwatch.groups().remove(ptr);
+    runtime_->stopwatch.groups_.remove(ptr);
     js_delete(group);
 }
 
 PerformanceGroup*
-js::PerformanceGroupHolder::getOwnGroup(JSContext* cx)
+js::PerformanceGroupHolder::getGroup(JSContext* cx)
 {
-    if (ownGroup_)
-        return ownGroup_;
-
-    ownGroup_ = runtime_->new_<PerformanceGroup>(cx, nullptr);
-    return ownGroup_;
-}
-
-PerformanceGroup*
-js::PerformanceGroupHolder::getSharedGroup(JSContext* cx)
-{
-    if (sharedGroup_)
-        return sharedGroup_;
-
-    if (!runtime_->stopwatch.groups().initialized())
-        return nullptr;
+    if (group_)
+        return group_;
 
     void* key = getHashKey(cx);
-    JSRuntime::Stopwatch::Groups::AddPtr ptr = runtime_->stopwatch.groups().lookupForAdd(key);
+    JSRuntime::Stopwatch::Groups::AddPtr ptr =
+        runtime_->stopwatch.groups_.lookupForAdd(key);
     if (ptr) {
-        sharedGroup_ = ptr->value();
-        MOZ_ASSERT(sharedGroup_);
+        group_ = ptr->value();
+        MOZ_ASSERT(group_);
     } else {
-        sharedGroup_ = runtime_->new_<PerformanceGroup>(cx, key);
-        if (!sharedGroup_)
-            return nullptr;
-
-        if (!runtime_->stopwatch.groups().add(ptr, key, sharedGroup_)) {
-            js_delete(sharedGroup_);
-            sharedGroup_ = nullptr;
-            return nullptr;
-        }
+        group_ = runtime_->new_<PerformanceGroup>(cx, key);
+        runtime_->stopwatch.groups_.add(ptr, key, group_);
     }
 
-    sharedGroup_->incRefCount();
+    group_->incRefCount();
 
-    return sharedGroup_;
+    return group_;
 }
 
 PerformanceData*
 js::GetPerformanceData(JSRuntime* rt)
 {
     return &rt->stopwatch.performance;
 }
 
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -1479,39 +1479,16 @@ struct JSRuntime : public JS::shadow::Ru
 
   public:
 
     /* ------------------------------------------
        Performance measurements
        ------------------------------------------ */
     struct Stopwatch {
         /**
-         * A map used to collapse compartments belonging to the same
-         * add-on (respectively to the same webpage, to the platform)
-         * into a single group.
-         *
-         * Keys: for system compartments, a `JSAddonId*` (which may be
-         * `nullptr`), and for webpages, a `JSPrincipals*` (which may
-         * not). Note that compartments may start as non-system
-         * compartments and become compartments later during their
-         * lifetime, which requires an invalidation.
-         *
-         * This map is meant to be accessed only by instances of
-         * PerformanceGroupHolder, which handle both reference-counting
-         * of the values and invalidation of the key/value pairs.
-         */
-        typedef js::HashMap<void*, js::PerformanceGroup*,
-                            js::DefaultHasher<void*>,
-                            js::SystemAllocPolicy> Groups;
-
-        Groups& groups() {
-            return groups_;
-        }
-
-        /**
          * The number of times we have entered the event loop.
          * Used to reset counters whenever we enter the loop,
          * which may be caused either by having completed the
          * previous run of the event loop, or by entering a
          * nested loop.
          *
          * Always incremented by 1, may safely overflow.
          */
@@ -1541,17 +1518,16 @@ struct JSRuntime : public JS::shadow::Ru
         JSCurrentPerfGroupCallback currentPerfGroupCallback;
 
         Stopwatch()
           : iteration(0)
           , isEmpty(true)
           , currentPerfGroupCallback(nullptr)
           , isMonitoringJank_(false)
           , isMonitoringCPOW_(false)
-          , isMonitoringPerCompartment_(false)
           , idCounter_(0)
         { }
 
         /**
          * Reset the stopwatch.
          *
          * This method is meant to be called whenever we start processing
          * an event, to ensure that stop any ongoing measurement that would
@@ -1583,31 +1559,16 @@ struct JSRuntime : public JS::shadow::Ru
 
             isMonitoringJank_ = value;
             return true;
         }
         bool isMonitoringJank() const {
             return isMonitoringJank_;
         }
 
-        bool setIsMonitoringPerCompartment(bool value) {
-            if (isMonitoringPerCompartment_ != value)
-                reset();
-
-            if (value && !groups_.initialized()) {
-                if (!groups_.init(128))
-                    return false;
-            }
-
-            isMonitoringPerCompartment_ = value;
-            return true;
-        }
-        bool isMonitoringPerCompartment() const {
-            return isMonitoringPerCompartment_;
-        }
 
         /**
          * Activate/deactivate stopwatch measurement of CPOW.
          */
         bool setIsMonitoringCPOW(bool value) {
             isMonitoringCPOW_ = value;
             return true;
         }
@@ -1641,25 +1602,43 @@ struct JSRuntime : public JS::shadow::Ru
             }
           private:
             uint64_t latestGood_;
         };
         MonotonicTimeStamp systemTimeFix;
         MonotonicTimeStamp userTimeFix;
 
     private:
+        /**
+         * A map used to collapse compartments belonging to the same
+         * add-on (respectively to the same webpage, to the platform)
+         * into a single group.
+         *
+         * Keys: for system compartments, a `JSAddonId*` (which may be
+         * `nullptr`), and for webpages, a `JSPrincipals*` (which may
+         * not). Note that compartments may start as non-system
+         * compartments and become compartments later during their
+         * lifetime, which requires an invalidation.
+         *
+         * This map is meant to be accessed only by instances of
+         * PerformanceGroupHolder, which handle both reference-counting
+         * of the values and invalidation of the key/value pairs.
+         */
+        typedef js::HashMap<void*, js::PerformanceGroup*,
+                            js::DefaultHasher<void*>,
+                            js::SystemAllocPolicy> Groups;
+
         Groups groups_;
         friend struct js::PerformanceGroupHolder;
 
         /**
          * `true` if stopwatch monitoring is active, `false` otherwise.
          */
         bool isMonitoringJank_;
         bool isMonitoringCPOW_;
-        bool isMonitoringPerCompartment_;
 
         /**
          * A counter used to generate unique identifiers for groups.
          */
         uint64_t idCounter_;
     };
     Stopwatch stopwatch;
 };
--- a/toolkit/components/perfmonitoring/PerformanceStats.jsm
+++ b/toolkit/components/perfmonitoring/PerformanceStats.jsm
@@ -141,26 +141,16 @@ Probe.prototype = {
       throw new TypeError();
     }
     if (b == null) {
       return a;
     }
     return this._impl.subtract(a, b);
   },
 
-  importChildren: function(parent, children) {
-    if (!Array.isArray(children)) {
-      throw new TypeError();
-    }
-    if (!parent || !(parent instanceof PerformanceData)) {
-      throw new TypeError();
-    }
-    return this._impl.importChildren(parent, children);
-  },
-
   /**
    * The name of the probe.
    */
   get name() {
     return this._name;
   }
 };
 
@@ -233,18 +223,17 @@ let Probes = {
         durations: [],
         longestDuration: -1,
       };
       for (let i = 0; i < a.durations.length; ++i) {
         result.durations[i] = a.durations[i] - b.durations[i];
       }
       result.longestDuration = lastNonZero(result.durations);
       return result;
-    },
-    importChildren: function() { /* nothing to do */ },
+    }
   }),
 
   /**
    * A probe measuring CPOW activity.
    *
    * Data provided by this probe uses the following format:
    *
    * @field {number} totalCPOWTime The amount of wallclock time
@@ -264,18 +253,17 @@ let Probes = {
     },
     isEqual: function(a, b) {
       return a.totalCPOWTime == b.totalCPOWTime;
     },
     subtract: function(a, b) {
       return {
         totalCPOWTime: a.totalCPOWTime - b.totalCPOWTime
       };
-    },
-    importChildren: function() { /* nothing to do */ },
+    }
   }),
 
   /**
    * A probe measuring activations, i.e. the number
    * of times code execution has entered a given
    * PerformanceGroup.
    *
    * Note that this probe is always active.
@@ -294,29 +282,29 @@ let Probes = {
     },
     isEqual: function(a, b) {
       return a.ticks == b.ticks;
     },
     subtract: function(a, b) {
       return {
         ticks: a.ticks - b.ticks
       };
-    },
-    importChildren: function() { /* nothing to do */ },
+    }
   }),
 
   "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;
@@ -330,73 +318,48 @@ let Probes = {
     _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", {
-    _isActive: false,
     set isActive(x) {
-      this._isActive = x;
-      if (x) {
-        Process.broadcast("acquire", ["ticks"]);
-      } else {
-        Process.broadcast("release", ["ticks"]);
-      }
+      // Ignore: This probe is always active.
+    },
     get isActive() {
-      return this._isActive;
+      return true;
     },
     extract: function(xpcom) {
       return {};
     },
     isEqual: function(a, b) {
       return true;
     },
     subtract: function(a, b) {
       return null;
     }
   }),
-
-  compartments: new Probe("compartments", {
-    set isActive(x) {
-      performanceStatsService.isMonitoringPerCompartment = x;
-    },
-    get isActive() {
-      return performanceStatsService.isMonitoringPerCompartment;
-    },
-    extract: function(xpcom) {
-      return null;
-    },
-    isEqual: function(a, b) {
-      return true;
-    },
-    subtract: function(a, b) {
-      return true;
-    },
-    importChildren: function(parent, children) {
-      parent.children = children;
-    },
-  })
 };
 
 
 /**
  * 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
@@ -689,42 +652,26 @@ function PerformanceDiff(current, old = 
  *
  * @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.
  */
 function Snapshot({xpcom, childProcesses, probes}) {
   this.componentsData = [];
 
-  // Current process
+  // Parent process
   if (xpcom) {
-    let children = new Map();
     let enumeration = xpcom.getComponentsData().enumerate();
     while (enumeration.hasMoreElements()) {
       let xpcom = enumeration.getNext().QueryInterface(Ci.nsIPerformanceStats);
-      let stat = new PerformanceData({xpcom, probes});
-      if (!stat.parentId) {
-        this.componentsData.push(stat);
-      } else {
-        let siblings = children.get(stat.parentId);
-        if (!siblings) {
-          children.set(stat.parentId, (siblings = []));
-        }
-        siblings.push(stat);
-      }
-    }
-
-    for (let parent of this.componentsData) {
-      for (let probe of probes) {
-        probe.importChildren(parent, children.get(parent.groupId) || []);
-      }
+      this.componentsData.push(new PerformanceData({xpcom, probes}));
     }
   }
 
-  // Child processes
+  // 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}));
       }
     }
   }
--- a/toolkit/components/perfmonitoring/nsIPerformanceStats.idl
+++ b/toolkit/components/perfmonitoring/nsIPerformanceStats.idl
@@ -12,42 +12,32 @@
  * Mechanisms for querying the current process about performance
  * information.
  *
  * JavaScript clients should rather use PerformanceStats.jsm.
  */
 
 /**
  * Snapshot of the performance of a component, e.g. an add-on, a web
- * page, system built-ins, a module or the entire process itself.
+ * page, system built-ins, or the entire process itself.
  *
  * All values are monotonic and are updated only when
  * `nsIPerformanceStatsService.isStopwatchActive` is `true`.
  */
-[scriptable, uuid(1bc2d016-e9ae-4186-97c6-9478eddda245)]
+[scriptable, uuid(47f8d36d-1d67-43cb-befd-d2f4720ac568)]
 interface nsIPerformanceStats: nsISupports {
   /**
    * An identifier unique to the component.
    *
    * This identifier is somewhat human-readable to aid with debugging,
    * but clients should not rely upon the format.
    */
   readonly attribute AString groupId;
 
   /**
-   * If this component is part of a larger component, the larger
-   * component. Otherwise, null.
-   *
-   * As of this writing, there can be at most two levels of components:
-   * - compartments (a single module, iframe, etc.);
-   * - groups (an entire add-on, an entire webpage, etc.).
-   */
-  readonly attribute AString parentId;
-
-  /**
    * The name of the component:
    * - for the process itself, "<process>";
    * - for platform code, "<platform>";
    * - for an add-on, the identifier of the addon (e.g. "myaddon@foo.bar");
    * - for a webpage, the url of the page.
    */
   readonly attribute AString name;
 
@@ -117,36 +107,29 @@ 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(60973d54-13e2-455c-a3c6-84dea5dfc8b9)]
+[scriptable, builtinclass, uuid(0469e6af-95c3-4961-a385-4bc009128939)]
 interface nsIPerformanceStatsService : nsISupports {
   /**
    * `true` if we should monitor CPOW, `false` otherwise.
    */
   [implicit_jscontext] attribute bool isMonitoringCPOW;
 
   /**
    * `true` if we should monitor jank, `false` otherwise.
    */
   [implicit_jscontext] attribute bool isMonitoringJank;
 
   /**
-   * `true` if all compartments need to be monitored individually,
-   * `false` if only performance groups (i.e. entire add-ons, entire
-   * webpages, etc.) need to be monitored.
-   */
-  [implicit_jscontext] attribute bool isMonitoringPerCompartment;
-
-  /**
    * Capture a snapshot of the performance data.
    */
   [implicit_jscontext] nsIPerformanceSnapshot getSnapshot();
 };
 
 %{C++
 #define NS_TOOLKIT_PERFORMANCESTATSSERVICE_CID {0xfd7435d4, 0x9ec4, 0x4699, \
       {0xad, 0xd4, 0x1b, 0xe8, 0x3d, 0xd6, 0x8e, 0xf3} }
--- a/toolkit/components/perfmonitoring/nsPerformanceStats.cpp
+++ b/toolkit/components/perfmonitoring/nsPerformanceStats.cpp
@@ -25,35 +25,30 @@
 #include "windows.h"
 #else
 #include <unistd.h>
 #endif
 
 class nsPerformanceStats: public nsIPerformanceStats {
 public:
   nsPerformanceStats(const nsAString& aName,
-                     nsIPerformanceStats* aParent,
                      const nsAString& aGroupId,
                      const nsAString& aAddonId,
                      const nsAString& aTitle,
                      const uint64_t aWindowId,
                      const bool aIsSystem,
                      const js::PerformanceData& aPerformanceData)
     : mName(aName)
     , mGroupId(aGroupId)
     , mAddonId(aAddonId)
     , mTitle(aTitle)
     , mWindowId(aWindowId)
     , mIsSystem(aIsSystem)
     , mPerformanceData(aPerformanceData)
   {
-    if (aParent) {
-      mozilla::DebugOnly<nsresult> rv = aParent->GetGroupId(mParentId);
-      MOZ_ASSERT(NS_SUCCEEDED(rv));
-    }
   }
   explicit nsPerformanceStats() {}
 
   NS_DECL_ISUPPORTS
 
   /* readonly attribute AString name; */
   NS_IMETHOD GetName(nsAString& aName) override {
     aName.Assign(mName);
@@ -61,22 +56,16 @@ public:
   };
 
   /* readonly attribute AString groupId; */
   NS_IMETHOD GetGroupId(nsAString& aGroupId) override {
     aGroupId.Assign(mGroupId);
     return NS_OK;
   };
 
-  /* readonly attribute AString parentId; */
-  NS_IMETHOD GetParentId(nsAString& aParentId) override {
-    aParentId.Assign(mParentId);
-    return NS_OK;
-  };
-
   /* readonly attribute AString addonId; */
   NS_IMETHOD GetAddonId(nsAString& aAddonId) override {
     aAddonId.Assign(mAddonId);
     return NS_OK;
   };
 
   /* readonly attribute uint64_t windowId; */
   NS_IMETHOD GetWindowId(uint64_t *aWindowId) override {
@@ -130,17 +119,16 @@ public:
     for (size_t i = 0; i < length; ++i) {
       (*aNumberOfOccurrences)[i] = mPerformanceData.durations[i];
     }
     return NS_OK;
   };
 
 private:
   nsString mName;
-  nsString mParentId;
   nsString mGroupId;
   nsString mAddonId;
   nsString mTitle;
   uint64_t mWindowId;
   bool mIsSystem;
 
   js::PerformanceData mPerformanceData;
 
@@ -166,56 +154,45 @@ private:
    *
    * Precondition: this method assumes that we have entered the JSCompartment for which data `c`
    * has been collected.
    *
    * `cx` may be `nullptr` if we are importing the statistics for the
    * entire process, rather than the statistics for a specific set of
    * compartments.
    */
-  already_AddRefed<nsIPerformanceStats> ImportStats(JSContext* cx, const js::PerformanceData& data, uint64_t uid, nsIPerformanceStats* parent);
+  already_AddRefed<nsIPerformanceStats> ImportStats(JSContext* cx, const js::PerformanceData& data, uint64_t uid);
 
   /**
    * Callbacks for iterating through the `PerformanceStats` of a runtime.
    */
-  bool IterPerformanceStatsCallbackInternal(JSContext* cx,
-                                            const js::PerformanceData& ownStats, const uint64_t ownId,
-                                            const uint64_t* parentId);
-  static bool IterPerformanceStatsCallback(JSContext* cx,
-                                           const js::PerformanceData& ownStats, const uint64_t ownId,
-                                           const uint64_t* parentId,
-                                           void* self);
+  bool IterPerformanceStatsCallbackInternal(JSContext* cx, const js::PerformanceData& stats, uint64_t uid);
+  static bool IterPerformanceStatsCallback(JSContext* cx, const js::PerformanceData& stats, uint64_t uid, void* self);
 
   // If the context represents a window, extract the title and window ID.
   // Otherwise, extract "" and 0.
   static void GetWindowData(JSContext*,
                             nsString& title,
                             uint64_t* windowId);
   void GetGroupId(JSContext*,
                   uint64_t uid,
                   nsString& groupId);
-
-  static void GetName(JSContext*,
-                      JS::Handle<JSObject*> global,
-                      nsString& name);
-
   // If the context presents an add-on, extract the addon ID.
   // Otherwise, extract "".
   static void GetAddonId(JSContext*,
                          JS::Handle<JSObject*> global,
                          nsAString& addonId);
 
   // Determine whether a context is part of the system principals.
   static bool GetIsSystem(JSContext*,
                           JS::Handle<JSObject*> global);
 
 private:
   nsCOMArray<nsIPerformanceStats> mComponentsData;
   nsCOMPtr<nsIPerformanceStats> mProcessData;
-  nsBaseHashtable<nsUint64HashKey, nsCOMPtr<nsIPerformanceStats>, nsCOMPtr<nsIPerformanceStats> > mCachedStats;
   uint64_t mProcessId;
 };
 
 NS_IMPL_ISUPPORTS(nsPerformanceSnapshot, nsIPerformanceSnapshot)
 
 nsPerformanceSnapshot::nsPerformanceSnapshot()
 {
 }
@@ -291,54 +268,18 @@ nsPerformanceSnapshot::GetGroupId(JSCont
 
 /* static */ bool
 nsPerformanceSnapshot::GetIsSystem(JSContext*,
                                    JS::Handle<JSObject*> global)
 {
   return nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(global));
 }
 
-/* static */
-void
-nsPerformanceSnapshot::GetName(JSContext* cx,
-                               JS::Handle<JSObject*> global,
-                               nsString& name)
-{
-  nsAutoCString cname;
-  do {
-    // Attempt to use the URL as name.
-    nsCOMPtr<nsIPrincipal> principal = nsContentUtils::ObjectPrincipal(global);
-    if (!principal) {
-      break;
-    }
-
-    nsCOMPtr<nsIURI> uri;
-    nsresult rv = principal->GetURI(getter_AddRefs(uri));
-    if (NS_FAILED(rv) || !uri) {
-      break;
-    }
-
-    rv = uri->GetSpec(cname);
-    if (NS_FAILED(rv)) {
-      break;
-    }
-
-    name.Assign(NS_ConvertUTF8toUTF16(cname));
-    return;
-  } while(false);
-  xpc::GetCurrentCompartmentName(cx, cname);
-  name.Assign(NS_ConvertUTF8toUTF16(cname));
-}
-
 already_AddRefed<nsIPerformanceStats>
-nsPerformanceSnapshot::ImportStats(JSContext* cx, const js::PerformanceData& performance, const uint64_t uid, nsIPerformanceStats* parent) {
-  if (performance.ticks == 0) {
-    // Ignore compartments with no activity.
-    return nullptr;
-  }
+nsPerformanceSnapshot::ImportStats(JSContext* cx, const js::PerformanceData& performance, const uint64_t uid) {
   JS::RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
 
   if (!global) {
     // While it is possible for a compartment to have no global
     // (e.g. atoms), this compartment is not very interesting for us.
     return nullptr;
   }
 
@@ -347,63 +288,53 @@ nsPerformanceSnapshot::ImportStats(JSCon
 
   nsString addonId;
   GetAddonId(cx, global, addonId);
 
   nsString title;
   uint64_t windowId;
   GetWindowData(cx, title, &windowId);
 
-  nsString name;
-  GetName(cx, global, name);
+  nsAutoString name;
+  nsAutoCString cname;
+  xpc::GetCurrentCompartmentName(cx, cname);
+  name.Assign(NS_ConvertUTF8toUTF16(cname));
 
   bool isSystem = GetIsSystem(cx, global);
 
   nsCOMPtr<nsIPerformanceStats> result =
-    new nsPerformanceStats(name, parent, groupId, addonId, title, windowId, isSystem, performance);
+    new nsPerformanceStats(name, groupId, addonId, title, windowId, isSystem, performance);
   return result.forget();
 }
 
 /*static*/ bool
-nsPerformanceSnapshot::IterPerformanceStatsCallback(JSContext* cx,
-                                                    const js::PerformanceData& stats, const uint64_t id,
-                                                    const uint64_t* parentId,
-                                                    void* self) {
-  return reinterpret_cast<nsPerformanceSnapshot*>(self)->IterPerformanceStatsCallbackInternal(cx, stats, id, parentId);
+nsPerformanceSnapshot::IterPerformanceStatsCallback(JSContext* cx, const js::PerformanceData& stats, const uint64_t uid, void* self) {
+  return reinterpret_cast<nsPerformanceSnapshot*>(self)->IterPerformanceStatsCallbackInternal(cx, stats, uid);
 }
 
 bool
-nsPerformanceSnapshot::IterPerformanceStatsCallbackInternal(JSContext* cx,
-                                                            const js::PerformanceData& stats, const uint64_t id,
-                                                            const uint64_t* parentId) {
-
-  nsCOMPtr<nsIPerformanceStats> parent = parentId ? mCachedStats.Get(*parentId) : nullptr;
-  nsCOMPtr<nsIPerformanceStats> result = ImportStats(cx, stats, id, parent);
+nsPerformanceSnapshot::IterPerformanceStatsCallbackInternal(JSContext* cx, const js::PerformanceData& stats, const uint64_t uid) {
+  nsCOMPtr<nsIPerformanceStats> result = ImportStats(cx, stats, uid);
   if (result) {
     mComponentsData.AppendElement(result);
-    mCachedStats.Put(id, result);
   }
 
   return true;
 }
 
 nsresult
 nsPerformanceSnapshot::Init(JSContext* cx, uint64_t processId) {
   mProcessId = processId;
   js::PerformanceData processStats;
   if (!js::IterPerformanceStats(cx, nsPerformanceSnapshot::IterPerformanceStatsCallback, &processStats, this)) {
     return NS_ERROR_UNEXPECTED;
   }
 
-  nsAutoString processGroupId;
-  processGroupId.AssignLiteral("process: ");
-  processGroupId.AppendInt(processId);
   mProcessData = new nsPerformanceStats(NS_LITERAL_STRING("<process>"), // name
-                                        nullptr,                        // parent
-                                        processGroupId,                 // group id
+                                        NS_LITERAL_STRING("<process:?>"), // group id
                                         NS_LITERAL_STRING(""),          // add-on id
                                         NS_LITERAL_STRING(""),          // title
                                         0,                              // window id
                                         true,                           // isSystem
                                         processStats);
   return NS_OK;
 }
 
@@ -469,30 +400,16 @@ NS_IMETHODIMP nsPerformanceStatsService:
 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;
 }
-NS_IMETHODIMP nsPerformanceStatsService::GetIsMonitoringPerCompartment(JSContext* cx, bool *aIsStopwatchActive)
-{
-  JSRuntime *runtime = JS_GetRuntime(cx);
-  *aIsStopwatchActive = js::GetStopwatchIsMonitoringPerCompartment(runtime);
-  return NS_OK;
-}
-NS_IMETHODIMP nsPerformanceStatsService::SetIsMonitoringPerCompartment(JSContext* cx, bool aIsStopwatchActive)
-{
-  JSRuntime *runtime = JS_GetRuntime(cx);
-  if (!js::SetStopwatchIsMonitoringPerCompartment(runtime, aIsStopwatchActive)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  return NS_OK;
-}
 
 /* readonly attribute nsIPerformanceSnapshot snapshot; */
 NS_IMETHODIMP nsPerformanceStatsService::GetSnapshot(JSContext* cx, nsIPerformanceSnapshot * *aSnapshot)
 {
   nsRefPtr<nsPerformanceSnapshot> snapshot = new nsPerformanceSnapshot();
   nsresult rv = snapshot->Init(cx, mProcessId);
   if (NS_FAILED(rv)) {
     return rv;
--- a/toolkit/components/perfmonitoring/tests/browser/browser_compartments.js
+++ b/toolkit/components/perfmonitoring/tests/browser/browser_compartments.js
@@ -23,17 +23,17 @@ function frameScript() {
     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);
 
     // Make sure that the stopwatch is now active.
-    let monitor = PerformanceStats.getMonitor(["jank", "cpow", "ticks", "compartments"]);
+    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 (getStatistics): " + ex);
@@ -153,47 +153,27 @@ function monotinicity_tester(source, tes
     // Sanity check on components data.
     let map = new Map();
     for (let item of snapshot.componentsData) {
       for (let [probe, k] of [
         ["jank", "totalUserTime"],
         ["jank", "totalSystemTime"],
         ["cpow", "totalCPOWTime"]
       ]) {
-        // Note that we cannot expect components data to be always smaller
-        // than process data, as `getrusage` & co are not monotonic.
-        SilentAssert.leq(item[probe][k], 2 * snapshot.processData[probe][k],
-          `Sanity check (${testName}): ${k} of component is not impossibly larger than that of process`);
+        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}`);
       }
       map.set(key, item);
     }
-    for (let item of snapshot.componentsData) {
-      if (!item.parentId) {
-        continue;
-      }
-      let parent = map.get(item.parentId);
-      SilentAssert.ok(parent, `The parent exists ${item.parentId}`);
-
-      for (let [probe, k] of [
-        ["jank", "totalUserTime"],
-        ["jank", "totalSystemTime"],
-        ["cpow", "totalCPOWTime"]
-      ]) {
-        // Note that we cannot expect components data to be always smaller
-        // than parent data, as `getrusage` & co are not monotonic.
-        SilentAssert.leq(item[probe][k], 2 * parent[probe][k],
-          `Sanity check (${testName}): ${k} of component is not impossibly larger than that of parent`);
-      }
-    }
     for (let [key, item] of map) {
       sanityCheck(previous.componentsMap.get(key), item);
       previous.componentsMap.set(key, item);
     }
   });
   let interval = window.setInterval(frameCheck, 300);
   registerCleanupFunction(() => {
     window.clearInterval(interval);
--- a/toolkit/components/perfmonitoring/tests/xpcshell/test_compartments.js
+++ b/toolkit/components/perfmonitoring/tests/xpcshell/test_compartments.js
@@ -14,47 +14,37 @@ let promiseStatistics = Task.async(funct
   yield Promise.resolve(); // Make sure that we wait until
   // statistics have been updated.
   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()) {
-    let data = componentsEnum.getNext().QueryInterface(Ci.nsIPerformanceStats);
-    let normalized = JSON.parse(JSON.stringify(data));
-    componentsData.push(data);
+    componentsData.push(componentsEnum.getNext().QueryInterface(Ci.nsIPerformanceStats));
   }
   return {
-    processData: JSON.parse(JSON.stringify(snapshot.getProcessData())),
+    processData: snapshot.getProcessData(),
     componentsData
   };
 });
 
 let promiseSetMonitoring = Task.async(function*(to) {
   let service = Cc["@mozilla.org/toolkit/performance-stats-service;1"].
     getService(Ci.nsIPerformanceStatsService);
   service.isMonitoringJank = to;
   service.isMonitoringCPOW = to;
   yield Promise.resolve();
 });
 
-let promiseSetPerCompartment = Task.async(function*(to) {
-  let service = Cc["@mozilla.org/toolkit/performance-stats-service;1"].
-    getService(Ci.nsIPerformanceStatsService);
-  service.isMonitoringPerCompartment = to;
-  yield Promise.resolve();
-});
-
 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`);
-  do_print(JSON.stringify(snapshot.componentsData, null, "\t"));
   return stats;
 }
 
 function burnCPU(ms) {
   do_print("Burning CPU");
   let counter = 0;
   let ignored = [];
   let start = Date.now();
@@ -62,35 +52,27 @@ function burnCPU(ms) {
     ignored.push(0);
     ignored.shift();
     ++counter;
   }
   do_print("Burning CPU over, after " + counter + " iterations");
 }
 
 function ensureEquals(snap1, snap2, name) {
-  for (let k of Object.keys(snap1.processData)) {
-    if (k == "ticks") {
-      // Ticks monitoring cannot be deactivated
-      continue;
-    }
-    Assert.equal(snap1.processData[k], snap2.processData[k], `Same process data value ${k} (${name})`)
-  }
+  Assert.equal(
+    JSON.stringify(snap1.processData),
+    JSON.stringify(snap2.processData),
+    "Same process data: " + name);
   let stats1 = snap1.componentsData.sort((a, b) => a.name <= b.name);
   let stats2 = snap2.componentsData.sort((a, b) => a.name <= b.name);
-  Assert.equal(stats1.length, stats2.length, `Same number of components (${name})`);
-  for (let i = 0; i < stats1.length; ++i) {
-    for (let k of Object.keys(stats1[i])) {
-      if (k == "ticks") {
-        // Ticks monitoring cannot be deactivated
-        continue;
-      }
-      Assert.equal(stats1[i][k], stats1[i][k], `Same component data value ${i} ${k} (${name})`)
-    }
-  }
+  Assert.equal(
+    JSON.stringify(stats1),
+    JSON.stringify(stats2),
+    "Same components data: " + name
+  );
 }
 
 function hasLowPrecision() {
   let [sysName, sysVersion] = [Services.sysinfo.getPropertyAsAString("name"), Services.sysinfo.getPropertyAsDouble("version")];
   do_print(`Running ${sysName} version ${sysVersion}`);
 
   if (sysName == "Windows_NT" && sysVersion < 6) {
     do_print("Running old Windows, need to deactivate tests due to bad precision.");
@@ -101,17 +83,16 @@ function hasLowPrecision() {
     return true;
   }
   do_print("This platform has good precision.")
   return false;
 }
 
 add_task(function* test_measure() {
   let skipPrecisionTests = hasLowPrecision();
-  yield promiseSetPerCompartment(false);
 
   do_print("Burn CPU without the stopwatch");
   yield promiseSetMonitoring(false);
   let stats0 = yield promiseStatistics("Initial state");
   burnCPU(300);
   let stats1 = yield promiseStatistics("Initial state + burn, without stopwatch");
 
   do_print("Burn CPU with the stopwatch");
@@ -151,19 +132,9 @@ add_task(function* test_measure() {
     do_print("Skipping totalUserTime check under Windows XP, as timer is not always updated by the OS.")
   } else {
     Assert.ok(builtin2.totalUserTime - builtin1.totalUserTime >= 10000, `At least 10ms counted for built-in statistics (${builtin2.totalUserTime - builtin1.totalUserTime})`);
   }
   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");
-
-  // Ideally, we should be able to look for test_compartments.js, but
-  // it doesn't have its own compartment.
-  for (let stats of [stats1, stats2, stats3, stats4]) {
-    Assert.ok(!stats.componentsData.find(x => x.name.includes("Task.jsm")), "At this stage, Task.jsm doesn't show up in the components data");
-  }
-  yield promiseSetPerCompartment(true);
-  burnCPU(300);
-  let stats5 = yield promiseStatistics("With per-compartment monitoring");
-  Assert.ok(stats5.componentsData.find(x => x.name.includes("Task.jsm")), "With per-compartment monitoring, test_compartments.js shows up");
 });