Backed out 17 changesets (bug 1277504, bug 1218577, bug 1218576) for ASAN bc2 failures a=backout
authorWes Kocher <wkocher@mozilla.com>
Wed, 07 Sep 2016 10:18:17 -0700
changeset 313071 1530103e032c225c93bf7ac8fc581ccbab898275
parent 313035 4589f5daf170465565e2b091fcc094baea83d872
child 313074 6d68d4884890523adb0c5179f76f16ff7f5f25b9
push id20479
push userkwierso@gmail.com
push dateThu, 08 Sep 2016 01:08:46 +0000
treeherderfx-team@fb7c6b034329 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1277504, 1218577, 1218576
milestone51.0a1
backs out62009556e4ad9cdb7910a3b5b0346a1c4902d582
57f9849f0f8f93b1609a327f70b1cd49838e524b
9595c56c9db29296d8313ad17b4c94a3fab8deb6
9d15ae92f2faf5671531bffab52b036c3eb9f451
ea7282078b054f7618bd1e8b54b544f18e2a4fff
848f4ef30978ebbe1126012e0d1a29b59d8626ac
1b6666eb3b815fb289b8dc342f35fea47dffdb1b
ce2a2dabb0421fa8fd375f4baff9c9eac15cf723
3caacb5c213bd7187b78456ab8b7c4388473813b
c68fc5ad5ecff9621aafb4fc889d2374ec5f4121
1678482b2fad73f0aa0c298ae9c41b46b6fd9d1e
df28918fe2361f0b54ca9ce4773a29c4c0675d06
eb5dbe28ab209f742c60ea6ec9c76dc5cba19eba
baf105cbe0c84c9531a29d3fd0680b4b1d95563d
7fdd6b6ab5945eab4bc7cddbcba34ce0c2fb2fbf
a0a4829d0ca0184e22e9e0232553c7ebdf0adc52
fc16cda7781bf831684253c5e31e3fd87011e3c2
Backed out 17 changesets (bug 1277504, bug 1218577, bug 1218576) for ASAN bc2 failures a=backout Backed out changeset 62009556e4ad (bug 1218576) Backed out changeset 57f9849f0f8f (bug 1218576) Backed out changeset 9595c56c9db2 (bug 1277504) Backed out changeset 9d15ae92f2fa (bug 1218576) Backed out changeset ea7282078b05 (bug 1218576) Backed out changeset 848f4ef30978 (bug 1218576) Backed out changeset 1b6666eb3b81 (bug 1218576) Backed out changeset ce2a2dabb042 (bug 1218576) Backed out changeset 3caacb5c213b (bug 1218576) Backed out changeset c68fc5ad5ecf (bug 1218576) Backed out changeset 1678482b2fad (bug 1218576) Backed out changeset df28918fe236 (bug 1218576) Backed out changeset eb5dbe28ab20 (bug 1218576) Backed out changeset baf105cbe0c8 (bug 1218576) Backed out changeset 7fdd6b6ab594 (bug 1218576) Backed out changeset a0a4829d0ca0 (bug 1218577) Backed out changeset fc16cda7781b (bug 1218576)
dom/base/test/browser_use_counters.js
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
toolkit/components/telemetry/Telemetry.cpp
toolkit/components/telemetry/Telemetry.h
toolkit/components/telemetry/TelemetryComms.h
toolkit/components/telemetry/TelemetryHistogram.cpp
toolkit/components/telemetry/TelemetryHistogram.h
toolkit/components/telemetry/TelemetrySession.jsm
toolkit/components/telemetry/moz.build
toolkit/components/telemetry/nsITelemetry.idl
toolkit/components/telemetry/tests/unit/test_ChildHistograms.js
toolkit/content/aboutTelemetry.css
toolkit/content/aboutTelemetry.js
toolkit/content/aboutTelemetry.xhtml
--- a/dom/base/test/browser_use_counters.js
+++ b/dom/base/test/browser_use_counters.js
@@ -1,14 +1,13 @@
 /* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*- */
 
 requestLongerTimeout(2);
 
 var {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
-Cu.import("resource://gre/modules/Services.jsm");
 
 const gHttpTestRoot = "http://example.com/browser/dom/base/test/";
 
 /**
  * Enable local telemetry recording for the duration of the tests.
  */
 var gOldContentCanRecord = false;
 add_task(function* test_initialize() {
@@ -100,42 +99,46 @@ function waitForPageLoad(browser) {
         removeEventListener("load", listener, true);
         resolve();
       }
       addEventListener("load", listener, true);
     });
   });
 }
 
-function grabHistogramsFromContent(use_counter_middlefix, page_before = null) {
-  let telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
-  let suffix = Services.appinfo.browserTabsRemoteAutostart ? "#content" : "";
-  let gather = () => [
-    telemetry.getHistogramById("USE_COUNTER2_" + use_counter_middlefix + "_PAGE" + suffix).snapshot().sum,
-    telemetry.getHistogramById("USE_COUNTER2_" + use_counter_middlefix + "_DOCUMENT" + suffix).snapshot().sum,
-    telemetry.getHistogramById("CONTENT_DOCUMENTS_DESTROYED" + suffix).snapshot().sum,
-    telemetry.getHistogramById("TOP_LEVEL_CONTENT_DOCUMENTS_DESTROYED" + suffix).snapshot().sum,
-  ];
-  return BrowserTestUtils.waitForCondition(() => {
-    return page_before != telemetry.getHistogramById("USE_COUNTER2_" + use_counter_middlefix + "_PAGE" + suffix).snapshot().sum;
-  }).then(gather, gather);
+function grabHistogramsFromContent(browser, use_counter_middlefix) {
+  return ContentTask.spawn(browser, { middlefix: use_counter_middlefix }, function* (arg) {
+    let telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
+    function snapshot_histogram(name) {
+      return telemetry.getHistogramById(name).snapshot();
+    }
+
+    let histogram_page_name = "USE_COUNTER2_" + arg.middlefix + "_PAGE";
+    let histogram_document_name = "USE_COUNTER2_" + arg.middlefix + "_DOCUMENT";
+    let histogram_page = snapshot_histogram(histogram_page_name);
+    let histogram_document = snapshot_histogram(histogram_document_name);
+    let histogram_docs = snapshot_histogram("CONTENT_DOCUMENTS_DESTROYED");
+    let histogram_toplevel_docs = snapshot_histogram("TOP_LEVEL_CONTENT_DOCUMENTS_DESTROYED");
+    return [histogram_page.sum, histogram_document.sum,
+            histogram_docs.sum, histogram_toplevel_docs.sum];
+  });
 }
 
 var check_use_counter_iframe = Task.async(function* (file, use_counter_middlefix, check_documents=true) {
   info("checking " + file + " with histogram " + use_counter_middlefix);
 
   let newTab = gBrowser.addTab( "about:blank");
   gBrowser.selectedTab = newTab;
   newTab.linkedBrowser.stop();
 
   // Hold on to the current values of the telemetry histograms we're
   // interested in.
   let [histogram_page_before, histogram_document_before,
        histogram_docs_before, histogram_toplevel_docs_before] =
-      yield grabHistogramsFromContent(use_counter_middlefix);
+      yield grabHistogramsFromContent(gBrowser.selectedBrowser, use_counter_middlefix);
 
   gBrowser.selectedBrowser.loadURI(gHttpTestRoot + "file_use_counter_outer.html");
   yield waitForPageLoad(gBrowser.selectedBrowser);
 
   // Inject our desired file into the iframe of the newly-loaded page.
   yield ContentTask.spawn(gBrowser.selectedBrowser, { file: file }, function(opts) {
     Cu.import("resource://gre/modules/PromiseUtils.jsm");
     let deferred = PromiseUtils.defer();
@@ -143,17 +146,17 @@ var check_use_counter_iframe = Task.asyn
     let wu = content.window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
 
     let iframe = content.document.getElementById('content');
     iframe.src = opts.file;
     let listener = (event) => {
       event.target.removeEventListener("load", listener, true);
 
       // We flush the main document first, then the iframe's document to
-      // ensure any propagation that might happen from content->parent should
+      // ensure any propagation that might happen from child->parent should
       // have already happened when counters are reported to telemetry.
       wu.forceUseCounterFlush(content.document);
       wu.forceUseCounterFlush(iframe.contentDocument);
 
       deferred.resolve();
     };
     iframe.addEventListener("load", listener, true);
 
@@ -166,17 +169,17 @@ var check_use_counter_iframe = Task.asyn
   // The histograms only get recorded when the document actually gets
   // destroyed, which might not have happened yet due to GC/CC effects, etc.
   // Try to force document destruction.
   yield waitForDestroyedDocuments();
 
   // Grab histograms again and compare.
   let [histogram_page_after, histogram_document_after,
        histogram_docs_after, histogram_toplevel_docs_after] =
-      yield grabHistogramsFromContent(use_counter_middlefix, histogram_page_before);
+      yield grabHistogramsFromContent(gBrowser.selectedBrowser, use_counter_middlefix);
 
   is(histogram_page_after, histogram_page_before + 1,
      "page counts for " + use_counter_middlefix + " after are correct");
   ok(histogram_toplevel_docs_after >= histogram_toplevel_docs_before + 1,
      "top level document counts are correct");
   if (check_documents) {
     is(histogram_document_after, histogram_document_before + 1,
        "document counts for " + use_counter_middlefix + " after are correct");
@@ -189,17 +192,17 @@ var check_use_counter_img = Task.async(f
   let newTab = gBrowser.addTab("about:blank");
   gBrowser.selectedTab = newTab;
   newTab.linkedBrowser.stop();
 
   // Hold on to the current values of the telemetry histograms we're
   // interested in.
   let [histogram_page_before, histogram_document_before,
        histogram_docs_before, histogram_toplevel_docs_before] =
-      yield grabHistogramsFromContent(use_counter_middlefix);
+      yield grabHistogramsFromContent(gBrowser.selectedBrowser, use_counter_middlefix);
 
   gBrowser.selectedBrowser.loadURI(gHttpTestRoot + "file_use_counter_outer.html");
   yield waitForPageLoad(gBrowser.selectedBrowser);
 
   // Inject our desired file into the img of the newly-loaded page.
   yield ContentTask.spawn(gBrowser.selectedBrowser, { file: file }, function(opts) {
     Cu.import("resource://gre/modules/PromiseUtils.jsm");
     let deferred = PromiseUtils.defer();
@@ -231,17 +234,17 @@ var check_use_counter_img = Task.async(f
   // The histograms only get recorded when the document actually gets
   // destroyed, which might not have happened yet due to GC/CC effects, etc.
   // Try to force document destruction.
   yield waitForDestroyedDocuments();
 
   // Grab histograms again and compare.
   let [histogram_page_after, histogram_document_after,
        histogram_docs_after, histogram_toplevel_docs_after] =
-      yield grabHistogramsFromContent(use_counter_middlefix, histogram_page_before);
+      yield grabHistogramsFromContent(gBrowser.selectedBrowser, use_counter_middlefix);
   is(histogram_page_after, histogram_page_before + 1,
      "page counts for " + use_counter_middlefix + " after are correct");
   is(histogram_document_after, histogram_document_before + 1,
      "document counts for " + use_counter_middlefix + " after are correct");
   ok(histogram_toplevel_docs_after >= histogram_toplevel_docs_before + 1,
      "top level document counts are correct");
   // 2 documents: one for the outer html page containing the <img> element, and
   // one for the SVG image itself.
@@ -255,17 +258,17 @@ var check_use_counter_direct = Task.asyn
   let newTab = gBrowser.addTab( "about:blank");
   gBrowser.selectedTab = newTab;
   newTab.linkedBrowser.stop();
 
   // Hold on to the current values of the telemetry histograms we're
   // interested in.
   let [histogram_page_before, histogram_document_before,
        histogram_docs_before, histogram_toplevel_docs_before] =
-      yield grabHistogramsFromContent(use_counter_middlefix);
+      yield grabHistogramsFromContent(gBrowser.selectedBrowser, use_counter_middlefix);
 
   gBrowser.selectedBrowser.loadURI(gHttpTestRoot + file);
   yield ContentTask.spawn(gBrowser.selectedBrowser, null, function*() {
     Cu.import("resource://gre/modules/PromiseUtils.jsm");
     yield new Promise(resolve => {
       let listener = () => {
         removeEventListener("load", listener, true);
 
@@ -284,17 +287,17 @@ var check_use_counter_direct = Task.asyn
   // The histograms only get recorded when the document actually gets
   // destroyed, which might not have happened yet due to GC/CC effects, etc.
   // Try to force document destruction.
   yield waitForDestroyedDocuments();
 
   // Grab histograms again and compare.
   let [histogram_page_after, histogram_document_after,
        histogram_docs_after, histogram_toplevel_docs_after] =
-      yield grabHistogramsFromContent(use_counter_middlefix, histogram_page_before);
+      yield grabHistogramsFromContent(gBrowser.selectedBrowser, use_counter_middlefix);
   (xfail ? todo_is : is)(histogram_page_after, histogram_page_before + 1,
                          "page counts for " + use_counter_middlefix + " after are correct");
   (xfail ? todo_is : is)(histogram_document_after, histogram_document_before + 1,
                          "document counts for " + use_counter_middlefix + " after are correct");
   ok(histogram_toplevel_docs_after >= histogram_toplevel_docs_before + 1,
      "top level document counts are correct");
   ok(histogram_docs_after >= histogram_docs_before + 1,
      "document counts are correct");
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -5399,24 +5399,8 @@ ContentParent::SendGetFilesResponseAndFo
                                              const GetFilesResponseResult& aResult)
 {
   GetFilesHelper* helper = mGetFilesPendingRequests.GetWeak(aUUID);
   if (helper) {
     mGetFilesPendingRequests.Remove(aUUID);
     Unused << SendGetFilesResponse(aUUID, aResult);
   }
 }
-
-bool
-ContentParent::RecvAccumulateChildHistogram(
-                InfallibleTArray<Accumulation>&& aAccumulations)
-{
-  Telemetry::AccumulateChild(aAccumulations);
-  return true;
-}
-
-bool
-ContentParent::RecvAccumulateChildKeyedHistogram(
-                InfallibleTArray<KeyedAccumulation>&& aAccumulations)
-{
-  Telemetry::AccumulateChildKeyed(aAccumulations);
-  return true;
-}
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -1129,20 +1129,16 @@ private:
   virtual bool RecvNotifyLowMemory() override;
 
   virtual bool RecvGetFilesRequest(const nsID& aID,
                                    const nsString& aDirectoryPath,
                                    const bool& aRecursiveFlag) override;
 
   virtual bool RecvDeleteGetFilesRequest(const nsID& aID) override;
 
-  virtual bool RecvAccumulateChildHistogram(
-                  InfallibleTArray<Accumulation>&& aAccumulations) override;
-  virtual bool RecvAccumulateChildKeyedHistogram(
-                  InfallibleTArray<KeyedAccumulation>&& aAccumulations) override;
 public:
   void SendGetFilesResponseAndForget(const nsID& aID,
                                      const GetFilesResponseResult& aResult);
 
 private:
 
   // If you add strong pointers to cycle collected objects here, be sure to
   // release these objects in ShutDownProcess.  See the comment there for more
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -95,18 +95,16 @@ using mozilla::dom::ContentParentId from
 using mozilla::LayoutDeviceIntPoint from "Units.h";
 using struct LookAndFeelInt from "mozilla/widget/WidgetMessageUtils.h";
 using class mozilla::dom::MessagePort from "mozilla/dom/MessagePort.h";
 using class mozilla::dom::ipc::StructuredCloneData from "mozilla/dom/ipc/StructuredCloneData.h";
 using mozilla::DataStorageType from "ipc/DataStorageIPCUtils.h";
 using mozilla::DocShellOriginAttributes from "mozilla/ipc/BackgroundUtils.h";
 using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
 using struct mozilla::dom::FlyWebPublishOptions from "mozilla/dom/FlyWebPublishOptionsIPCSerializer.h";
-using mozilla::Telemetry::Accumulation from "mozilla/TelemetryComms.h";
-using mozilla::Telemetry::KeyedAccumulation from "mozilla/TelemetryComms.h";
 
 union ChromeRegistryItem
 {
     ChromePackage;
     OverrideMapping;
     SubstitutionMapping;
 };
 
@@ -1213,22 +1211,16 @@ parent:
      async GetFilesRequest(nsID aID, nsString aDirectory, bool aRecursiveFlag);
      async DeleteGetFilesRequest(nsID aID);
 
      async StoreAndBroadcastBlobURLRegistration(nsCString url, PBlob blob,
                                                 Principal principal);
 
      async UnstoreAndBroadcastBlobURLUnregistration(nsCString url);
 
-    /**
-     * Messages for communicating child Telemetry to the parent process
-     */
-    async AccumulateChildHistogram(Accumulation[] accumulations);
-    async AccumulateChildKeyedHistogram(KeyedAccumulation[] accumulations);
-
 both:
      async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
                         Principal aPrincipal, ClonedMessageData aData);
 
     /**
      * Notify `push-subscription-modified` observers in the parent and child.
      */
     async NotifyPushSubscriptionModifiedObservers(nsCString scope,
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -2354,23 +2354,16 @@ TelemetryImpl::SnapshotScalars(unsigned 
 
 NS_IMETHODIMP
 TelemetryImpl::ClearScalars()
 {
   TelemetryScalar::ClearScalars();
   return NS_OK;
 }
 
-NS_IMETHODIMP
-TelemetryImpl::FlushBatchedChildTelemetry()
-{
-  TelemetryHistogram::IPCTimerFired(nullptr, nullptr);
-  return NS_OK;
-}
-
 size_t
 TelemetryImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
 {
   size_t n = aMallocSizeOf(this);
 
   // Ignore the hashtables in mAddonMap; they are not significant.
   n += TelemetryHistogram::GetMapShallowSizesOfExcludingThis(aMallocSizeOf);
   n += TelemetryScalar::GetMapShallowSizesOfExcludingThis(aMallocSizeOf);
@@ -2807,28 +2800,16 @@ AccumulateCategorical(ID id, const nsCSt
 void
 AccumulateTimeDelta(ID aHistogram, TimeStamp start, TimeStamp end)
 {
   Accumulate(aHistogram,
              static_cast<uint32_t>((end - start).ToMilliseconds()));
 }
 
 void
-AccumulateChild(const nsTArray<Accumulation>& aAccumulations)
-{
-  TelemetryHistogram::AccumulateChild(aAccumulations);
-}
-
-void
-AccumulateChildKeyed(const nsTArray<KeyedAccumulation>& aAccumulations)
-{
-  TelemetryHistogram::AccumulateChildKeyed(aAccumulations);
-}
-
-void
 ClearHistogram(ID aId)
 {
   TelemetryHistogram::ClearHistogram(aId);
 }
 
 const char*
 GetHistogramName(ID id)
 {
--- a/toolkit/components/telemetry/Telemetry.h
+++ b/toolkit/components/telemetry/Telemetry.h
@@ -28,19 +28,16 @@
  *****************************************************************************/
 
 namespace mozilla {
 namespace HangMonitor {
   class HangAnnotations;
 } // namespace HangMonitor
 namespace Telemetry {
 
-struct Accumulation;
-struct KeyedAccumulation;
-
 enum TimerResolution {
   Millisecond,
   Microsecond
 };
 
 /**
  * Create and destroy the underlying base::StatisticsRecorder singleton.
  * Creation has to be done very early in the startup sequence.
@@ -124,30 +121,16 @@ void AccumulateCategorical(ID id, const 
  *
  * @param id - histogram id
  * @param start - start time
  * @param end - end time
  */
 void AccumulateTimeDelta(ID id, TimeStamp start, TimeStamp end = TimeStamp::Now());
 
 /**
- * Accumulate child data into child histograms
- *
- * @param aAccumulations - accumulation actions to perform
- */
-void AccumulateChild(const nsTArray<Accumulation>& aAccumulations);
-
-/**
- * Accumulate child data into child keyed histograms
- *
- * @param aAccumulations - accumulation actions to perform
- */
-void AccumulateChildKeyed(const nsTArray<KeyedAccumulation>& aAccumulations);
-
-/**
  * This clears the data for a histogram in TelemetryHistogramEnums.h.
  *
  * @param id - histogram id
  */
 void ClearHistogram(ID id);
 
 /**
  * Enable/disable recording for this histogram at runtime.
deleted file mode 100644
--- a/toolkit/components/telemetry/TelemetryComms.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- */
-
-#ifndef Telemetry_Comms_h__
-#define Telemetry_Comms_h__
-
-#include "ipc/IPCMessageUtils.h"
-
-namespace mozilla {
-namespace Telemetry {
-
-enum ID : uint32_t;
-
-struct Accumulation
-{
-  mozilla::Telemetry::ID mId;
-  uint32_t mSample;
-};
-
-struct KeyedAccumulation
-{
-  mozilla::Telemetry::ID mId;
-  uint32_t mSample;
-  nsCString mKey;
-};
-
-} // namespace Telemetry
-} // namespace mozilla
-
-namespace IPC {
-
-template<>
-struct
-ParamTraits<mozilla::Telemetry::Accumulation>
-{
-  typedef mozilla::Telemetry::Accumulation paramType;
-
-  static void Write(Message* aMsg, const paramType& aParam)
-  {
-    aMsg->WriteUInt32(aParam.mId);
-    WriteParam(aMsg, aParam.mSample);
-  }
-
-  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
-  {
-    if (!aMsg->ReadUInt32(aIter, reinterpret_cast<uint32_t*>(&(aResult->mId))) ||
-        !ReadParam(aMsg, aIter, &(aResult->mSample))) {
-      return false;
-    }
-
-    return true;
-  }
-};
-
-template<>
-struct
-ParamTraits<mozilla::Telemetry::KeyedAccumulation>
-{
-  typedef mozilla::Telemetry::KeyedAccumulation paramType;
-
-  static void Write(Message* aMsg, const paramType& aParam)
-  {
-    aMsg->WriteUInt32(aParam.mId);
-    WriteParam(aMsg, aParam.mSample);
-    WriteParam(aMsg, aParam.mKey);
-  }
-
-  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
-  {
-    if (!aMsg->ReadUInt32(aIter, reinterpret_cast<uint32_t*>(&(aResult->mId))) ||
-        !ReadParam(aMsg, aIter, &(aResult->mSample)) ||
-        !ReadParam(aMsg, aIter, &(aResult->mKey))) {
-      return false;
-    }
-
-    return true;
-  }
-};
-
-} // namespace IPC
-
-#endif // Telemetry_Comms_h__
--- a/toolkit/components/telemetry/TelemetryHistogram.cpp
+++ b/toolkit/components/telemetry/TelemetryHistogram.cpp
@@ -9,40 +9,33 @@
 #include "js/GCAPI.h"
 #include "nsString.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "nsBaseHashtable.h"
 #include "nsClassHashtable.h"
 #include "nsITelemetry.h"
 
-#include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ToJSValue.h"
-#include "mozilla/Atomics.h"
 #include "mozilla/StartupTimeline.h"
 #include "mozilla/StaticMutex.h"
-#include "mozilla/StaticPtr.h"
-#include "mozilla/Unused.h"
 
 #include "TelemetryCommon.h"
 #include "TelemetryHistogram.h"
 
 #include "base/histogram.h"
 
 using base::Histogram;
 using base::StatisticsRecorder;
 using base::BooleanHistogram;
 using base::CountHistogram;
 using base::FlagHistogram;
 using base::LinearHistogram;
 using mozilla::StaticMutex;
 using mozilla::StaticMutexAutoLock;
-using mozilla::StaticAutoPtr;
-using mozilla::Telemetry::Accumulation;
-using mozilla::Telemetry::KeyedAccumulation;
 
 
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
 //
 // Naming: there are two kinds of functions in this file:
 //
 // * Functions named internal_*: these can only be reached via an
@@ -94,17 +87,16 @@ using mozilla::Telemetry::KeyedAccumulat
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
 //
 // PRIVATE TYPES
 
 #define EXPIRED_ID "__expired__"
 #define SUBSESSION_HISTOGRAM_PREFIX "sub#"
 #define KEYED_HISTOGRAM_NAME_SEPARATOR "#"
-#define CHILD_HISTOGRAM_SUFFIX "#content"
 
 namespace {
 
 using mozilla::Telemetry::Common::AutoHashtable;
 using mozilla::Telemetry::Common::IsExpiredVersion;
 using mozilla::Telemetry::Common::CanRecordDataset;
 using mozilla::Telemetry::Common::IsInDataset;
 
@@ -188,23 +180,16 @@ bool gCorruptHistograms[mozilla::Telemet
 // This is for gHistograms, gHistogramStringTable
 #include "TelemetryHistogramData.inc"
 
 AddonMapType gAddonMap;
 
 // The singleton StatisticsRecorder object for this process.
 base::StatisticsRecorder* gStatisticsRecorder = nullptr;
 
-// For batching and sending child process accumulations to the parent
-nsITimer* gIPCTimer = nullptr;
-mozilla::Atomic<bool, mozilla::Relaxed> gIPCTimerArmed(false);
-mozilla::Atomic<bool, mozilla::Relaxed> gIPCTimerArming(false);
-StaticAutoPtr<nsTArray<Accumulation>> gAccumulations;
-StaticAutoPtr<nsTArray<KeyedAccumulation>> gKeyedAccumulations;
-
 } // namespace
 
 
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
 //
 // PRIVATE CONSTANTS
 
@@ -214,22 +199,16 @@ namespace {
 const mozilla::Telemetry::ID kRecordingInitiallyDisabledIDs[] = {
   mozilla::Telemetry::FX_REFRESH_DRIVER_SYNC_SCROLL_FRAME_DELAY_MS,
 
   // The array must not be empty. Leave these item here.
   mozilla::Telemetry::TELEMETRY_TEST_COUNT_INIT_NO_RECORD,
   mozilla::Telemetry::TELEMETRY_TEST_KEYED_COUNT_INIT_NO_RECORD
 };
 
-// Sending each remote accumulation immediately places undue strain on the
-// IPC subsystem. Batch the remote accumulations for a period of time before
-// sending them all at once. This value was chosen as a balance between data
-// timeliness and performance (see bug 1218576)
-const uint32_t kBatchTimeoutMs = 2000;
-
 } // namespace
 
 
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
 //
 // PRIVATE: Misc small helpers
 
@@ -333,26 +312,16 @@ HistogramInfo::label_id(const char* labe
       *labelId = i;
       return NS_OK;
     }
   }
 
   return NS_ERROR_FAILURE;
 }
 
-bool
-StringEndsWith(const std::string& name, const std::string& suffix)
-{
-  if (name.size() < suffix.size()) {
-    return false;
-  }
-
-  return name.compare(name.size() - suffix.size(), suffix.size(), suffix) == 0;
-}
-
 } // namespace
 
 
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
 //
 // PRIVATE: Histogram Get, Add, Clone, Clear functions
 
@@ -427,70 +396,49 @@ internal_HistogramGet(const char *name, 
     break;
   default:
     NS_ASSERTION(false, "Invalid histogram type");
     return NS_ERROR_INVALID_ARG;
   }
   return NS_OK;
 }
 
-CharPtrEntryType*
-internal_GetHistogramMapEntry(const char* name)
-{
-  nsDependentCString histogramName(name);
-  NS_NAMED_LITERAL_CSTRING(suffix, CHILD_HISTOGRAM_SUFFIX);
-  if (!StringEndsWith(histogramName, suffix)) {
-    return gHistogramMap.GetEntry(name);
-  }
-  auto root = Substring(histogramName, 0, histogramName.Length() - suffix.Length());
-  return gHistogramMap.GetEntry(PromiseFlatCString(root).get());
-}
-
 nsresult
 internal_GetHistogramEnumId(const char *name, mozilla::Telemetry::ID *id)
 {
   if (!gInitDone) {
     return NS_ERROR_FAILURE;
   }
 
-  CharPtrEntryType *entry = internal_GetHistogramMapEntry(name);
+  CharPtrEntryType *entry = gHistogramMap.GetEntry(name);
   if (!entry) {
     return NS_ERROR_INVALID_ARG;
   }
   *id = entry->mData;
   return NS_OK;
 }
 
 // O(1) histogram lookup by numeric id
 nsresult
-internal_GetHistogramByEnumId(mozilla::Telemetry::ID id, Histogram **ret,
-                              bool child = false)
+internal_GetHistogramByEnumId(mozilla::Telemetry::ID id, Histogram **ret)
 {
   static Histogram* knownHistograms[mozilla::Telemetry::HistogramCount] = {0};
-  static Histogram* knownChildHistograms[mozilla::Telemetry::HistogramCount] = {0};
-  Histogram *h = child ? knownChildHistograms[id] : knownHistograms[id];
+  Histogram *h = knownHistograms[id];
   if (h) {
     *ret = h;
     return NS_OK;
   }
 
   const HistogramInfo &p = gHistograms[id];
   if (p.keyed) {
     return NS_ERROR_FAILURE;
   }
 
-  nsCString histogramName;
-  histogramName.Append(p.id());
-  if (child) {
-    histogramName.AppendLiteral(CHILD_HISTOGRAM_SUFFIX);
-  }
-
-  nsresult rv = internal_HistogramGet(histogramName.get(), p.expiration(),
-                                      p.histogramType, p.min, p.max,
-                                      p.bucketCount, true, &h);
+  nsresult rv = internal_HistogramGet(p.id(), p.expiration(), p.histogramType,
+                                      p.min, p.max, p.bucketCount, true, &h);
   if (NS_FAILED(rv))
     return rv;
 
 #ifdef DEBUG
   // Check that the C++ Histogram code computes the same ranges as the
   // Python histogram code.
   if (!IsExpiredVersion(p.expiration())) {
     const struct bounds &b = gBucketLowerBoundIndex[id];
@@ -500,37 +448,31 @@ internal_GetHistogramByEnumId(mozilla::T
       for (int i = 0; i < b.length; ++i) {
         MOZ_ASSERT(gBucketLowerBounds[b.offset + i] == h->ranges(i),
                    "C++/Python bucket mismatch");
       }
     }
   }
 #endif
 
-  if (child) {
-    *ret = knownChildHistograms[id] = h;
-  } else {
-    *ret = knownHistograms[id] = h;
-  }
+  *ret = knownHistograms[id] = h;
   return NS_OK;
 }
 
 nsresult
 internal_GetHistogramByName(const nsACString &name, Histogram **ret)
 {
   mozilla::Telemetry::ID id;
   nsresult rv
     = internal_GetHistogramEnumId(PromiseFlatCString(name).get(), &id);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
-  bool isChild = StringEndsWith(name,
-                                NS_LITERAL_CSTRING(CHILD_HISTOGRAM_SUFFIX));
-  rv = internal_GetHistogramByEnumId(id, ret, isChild);
+  rv = internal_GetHistogramByEnumId(id, ret);
   if (NS_FAILED(rv))
     return rv;
 
   return NS_OK;
 }
 
 /**
  * This clones a histogram |existing| with the id |existingId| to a
@@ -576,53 +518,42 @@ internal_CloneHistogram(const nsACString
   if (NS_FAILED(rv)) {
     return nullptr;
   }
 
   return internal_CloneHistogram(newName, existingId, *existing);
 }
 
 #if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
-
 Histogram*
 internal_GetSubsessionHistogram(Histogram& existing)
 {
   mozilla::Telemetry::ID id;
   nsresult rv
     = internal_GetHistogramEnumId(existing.histogram_name().c_str(), &id);
   if (NS_FAILED(rv) || gHistograms[id].keyed) {
     return nullptr;
   }
 
-  bool isChild = StringEndsWith(existing.histogram_name(),
-                                CHILD_HISTOGRAM_SUFFIX);
-
   static Histogram* subsession[mozilla::Telemetry::HistogramCount] = {};
-  static Histogram* subsessionChild[mozilla::Telemetry::HistogramCount] = {};
-  Histogram* cached = isChild ? subsessionChild[id] : subsession[id];
-  if (cached) {
-    return cached;
+  if (subsession[id]) {
+    return subsession[id];
   }
 
   NS_NAMED_LITERAL_CSTRING(prefix, SUBSESSION_HISTOGRAM_PREFIX);
   nsDependentCString existingName(gHistograms[id].id());
   if (StringBeginsWith(existingName, prefix)) {
     return nullptr;
   }
 
   nsCString subsessionName(prefix);
-  subsessionName.Append(existing.histogram_name().c_str());
+  subsessionName.Append(existingName);
 
-  Histogram* clone = internal_CloneHistogram(subsessionName, id, existing);
-  if (isChild) {
-    subsessionChild[id] = clone;
-  } else {
-    subsession[id] = clone;
-  }
-  return clone;
+  subsession[id] = internal_CloneHistogram(subsessionName, id, existing);
+  return subsession[id];
 }
 #endif
 
 nsresult
 internal_HistogramAdd(Histogram& histogram, int32_t value, uint32_t dataset)
 {
   // Check if we are allowed to record the data.
   bool canRecordDataset = CanRecordDataset(dataset,
@@ -661,23 +592,36 @@ internal_HistogramAdd(Histogram& histogr
       return NS_OK;
     }
     dataset = gHistograms[id].dataset;
   }
 
   return internal_HistogramAdd(histogram, value, dataset);
 }
 
+nsresult
+internal_HistogramAddCategorical(mozilla::Telemetry::ID id, const nsCString& label)
+{
+  uint32_t labelId = 0;
+  if (NS_FAILED(gHistograms[id].label_id(label.get(), &labelId))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  Histogram* h = nullptr;
+  nsresult rv = internal_GetHistogramByEnumId(id, &h);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  return internal_HistogramAdd(*h, labelId);
+}
+
 void
 internal_HistogramClear(Histogram& aHistogram, bool onlySubsession)
 {
-  MOZ_ASSERT(XRE_IsParentProcess());
-  if (!XRE_IsParentProcess()) {
-    return;
-  }
   if (!onlySubsession) {
     aHistogram.Clear();
   }
 
 #if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
   if (Histogram* subsession = internal_GetSubsessionHistogram(aHistogram)) {
     subsession->Clear();
   }
@@ -863,18 +807,16 @@ public:
                          bool subsession, bool clearSubsession);
 
   void SetRecordingEnabled(bool aEnabled) { mRecordingEnabled = aEnabled; };
   bool IsRecordingEnabled() const { return mRecordingEnabled; };
 
   nsresult Add(const nsCString& key, uint32_t aSample);
   void Clear(bool subsession);
 
-  nsresult GetEnumId(mozilla::Telemetry::ID& id);
-
 private:
   typedef nsBaseHashtableET<nsCStringHashKey, Histogram*> KeyedHistogramEntry;
   typedef AutoHashtable<KeyedHistogramEntry> KeyedHistogramMapType;
   KeyedHistogramMapType mHistogramMap;
 #if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
   KeyedHistogramMapType mSubsessionMap;
 #endif
 
@@ -1007,20 +949,16 @@ KeyedHistogram::Add(const nsCString& key
   subsession->Add(sample);
 #endif
   return NS_OK;
 }
 
 void
 KeyedHistogram::Clear(bool onlySubsession)
 {
-  MOZ_ASSERT(XRE_IsParentProcess());
-  if (!XRE_IsParentProcess()) {
-    return;
-  }
 #if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
   for (auto iter = mSubsessionMap.Iter(); !iter.Done(); iter.Next()) {
     iter.Get()->mData->Clear();
   }
   mSubsessionMap.Clear();
   if (onlySubsession) {
     return;
   }
@@ -1098,22 +1036,16 @@ KeyedHistogram::GetJSSnapshot(JSContext*
   if (subsession && clearSubsession) {
     Clear(true);
   }
 #endif
 
   return NS_OK;
 }
 
-nsresult
-KeyedHistogram::GetEnumId(mozilla::Telemetry::ID& id)
-{
-  return internal_GetHistogramEnumId(mName.get(), &id);
-}
-
 } // namespace
 
 
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
 //
 // PRIVATE: KeyedHistogram helpers
 
@@ -1132,315 +1064,16 @@ internal_GetKeyedHistogramById(const nsA
 }
 
 } // namespace
 
 
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
 //
-// PRIVATE: functions related to addon histograms
-
-namespace {
-
-// Compute the name to pass into Histogram for the addon histogram
-// 'name' from the addon 'id'.  We can't use 'name' directly because it
-// might conflict with other histograms in other addons or even with our
-// own.
-void
-internal_AddonHistogramName(const nsACString &id, const nsACString &name,
-                            nsACString &ret)
-{
-  ret.Append(id);
-  ret.Append(':');
-  ret.Append(name);
-}
-
-bool
-internal_CreateHistogramForAddon(const nsACString &name,
-                                 AddonHistogramInfo &info)
-{
-  Histogram *h;
-  nsresult rv = internal_HistogramGet(PromiseFlatCString(name).get(), "never",
-                                      info.histogramType, info.min, info.max,
-                                      info.bucketCount, true, &h);
-  if (NS_FAILED(rv)) {
-    return false;
-  }
-  // Don't let this histogram be reported via the normal means
-  // (e.g. Telemetry.registeredHistograms); we'll make it available in
-  // other ways.
-  h->ClearFlags(Histogram::kUmaTargetedHistogramFlag);
-  info.h = h;
-  return true;
-}
-
-bool
-internal_AddonHistogramReflector(AddonHistogramEntryType *entry,
-                                 JSContext *cx, JS::Handle<JSObject*> obj)
-{
-  AddonHistogramInfo &info = entry->mData;
-
-  // Never even accessed the histogram.
-  if (!info.h) {
-    // Have to force creation of HISTOGRAM_FLAG histograms.
-    if (info.histogramType != nsITelemetry::HISTOGRAM_FLAG)
-      return true;
-
-    if (!internal_CreateHistogramForAddon(entry->GetKey(), info)) {
-      return false;
-    }
-  }
-
-  if (internal_IsEmpty(info.h)) {
-    return true;
-  }
-
-  JS::Rooted<JSObject*> snapshot(cx, JS_NewPlainObject(cx));
-  if (!snapshot) {
-    // Just consider this to be skippable.
-    return true;
-  }
-  switch (internal_ReflectHistogramSnapshot(cx, snapshot, info.h)) {
-  case REFLECT_FAILURE:
-  case REFLECT_CORRUPT:
-    return false;
-  case REFLECT_OK:
-    const nsACString &histogramName = entry->GetKey();
-    if (!JS_DefineProperty(cx, obj, PromiseFlatCString(histogramName).get(),
-                           snapshot, JSPROP_ENUMERATE)) {
-      return false;
-    }
-    break;
-  }
-  return true;
-}
-
-bool
-internal_AddonReflector(AddonEntryType *entry, JSContext *cx,
-                        JS::Handle<JSObject*> obj)
-{
-  const nsACString &addonId = entry->GetKey();
-  JS::Rooted<JSObject*> subobj(cx, JS_NewPlainObject(cx));
-  if (!subobj) {
-    return false;
-  }
-
-  AddonHistogramMapType *map = entry->mData;
-  if (!(map->ReflectIntoJS(internal_AddonHistogramReflector, cx, subobj)
-        && JS_DefineProperty(cx, obj, PromiseFlatCString(addonId).get(),
-                             subobj, JSPROP_ENUMERATE))) {
-    return false;
-  }
-  return true;
-}
-
-} // namespace
-
-
-////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////
-//
-// PRIVATE: thread-unsafe helpers for the external interface
-
-// This is a StaticMutex rather than a plain Mutex (1) so that
-// it gets initialised in a thread-safe manner the first time
-// it is used, and (2) because it is never de-initialised, and
-// a normal Mutex would show up as a leak in BloatView.  StaticMutex
-// also has the "OffTheBooks" property, so it won't show as a leak
-// in BloatView.
-static StaticMutex gTelemetryHistogramMutex;
-
-namespace {
-
-void
-internal_SetHistogramRecordingEnabled(mozilla::Telemetry::ID aID, bool aEnabled)
-{
-  if (!internal_IsHistogramEnumId(aID)) {
-    MOZ_ASSERT(false, "Telemetry::SetHistogramRecordingEnabled(...) must be used with an enum id");
-    return;
-  }
-
-  if (gHistograms[aID].keyed) {
-    const nsDependentCString id(gHistograms[aID].id());
-    KeyedHistogram* keyed = internal_GetKeyedHistogramById(id);
-    if (keyed) {
-      keyed->SetRecordingEnabled(aEnabled);
-      return;
-    }
-  } else {
-    Histogram *h;
-    nsresult rv = internal_GetHistogramByEnumId(aID, &h);
-    if (NS_SUCCEEDED(rv)) {
-      h->SetRecordingEnabled(aEnabled);
-      return;
-    }
-  }
-
-  MOZ_ASSERT(false, "Telemetry::SetHistogramRecordingEnabled(...) id not found");
-}
-
-void internal_armIPCTimerMainThread()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  gIPCTimerArming = false;
-  if (gIPCTimerArmed) {
-    return;
-  }
-  if (!gIPCTimer) {
-    CallCreateInstance(NS_TIMER_CONTRACTID, &gIPCTimer);
-  }
-  if (gIPCTimer) {
-    gIPCTimer->InitWithFuncCallback(TelemetryHistogram::IPCTimerFired,
-                                    nullptr, kBatchTimeoutMs,
-                                    nsITimer::TYPE_ONE_SHOT);
-    gIPCTimerArmed = true;
-  }
-}
-
-void internal_armIPCTimer()
-{
-  if (gIPCTimerArmed || gIPCTimerArming) {
-    return;
-  }
-  gIPCTimerArming = true;
-  if (NS_IsMainThread()) {
-    internal_armIPCTimerMainThread();
-  } else {
-    NS_DispatchToMainThread(NS_NewRunnableFunction([]() -> void {
-      StaticMutexAutoLock locker(gTelemetryHistogramMutex);
-      internal_armIPCTimerMainThread();
-    }));
-  }
-}
-
-bool
-internal_RemoteAccumulate(mozilla::Telemetry::ID aId, uint32_t aSample)
-{
-  if (XRE_IsParentProcess()) {
-    return false;
-  }
-  if (!gAccumulations) {
-    gAccumulations = new nsTArray<Accumulation>();
-  }
-  gAccumulations->AppendElement(Accumulation{aId, aSample});
-  internal_armIPCTimer();
-  return true;
-}
-
-bool
-internal_RemoteAccumulate(mozilla::Telemetry::ID aId,
-                    const nsCString& aKey, uint32_t aSample)
-{
-  if (XRE_IsParentProcess()) {
-    return false;
-  }
-  if (!gKeyedAccumulations) {
-    gKeyedAccumulations = new nsTArray<KeyedAccumulation>();
-  }
-  gKeyedAccumulations->AppendElement(KeyedAccumulation{aId, aSample, aKey});
-  internal_armIPCTimer();
-  return true;
-}
-
-void internal_Accumulate(mozilla::Telemetry::ID aHistogram, uint32_t aSample)
-{
-  if (!internal_CanRecordBase() ||
-      internal_RemoteAccumulate(aHistogram, aSample)) {
-    return;
-  }
-  Histogram *h;
-  nsresult rv = internal_GetHistogramByEnumId(aHistogram, &h);
-  if (NS_SUCCEEDED(rv)) {
-    internal_HistogramAdd(*h, aSample, gHistograms[aHistogram].dataset);
-  }
-}
-
-void
-internal_Accumulate(mozilla::Telemetry::ID aID,
-                    const nsCString& aKey, uint32_t aSample)
-{
-  if (!gInitDone || !internal_CanRecordBase() ||
-      internal_RemoteAccumulate(aID, aKey, aSample)) {
-    return;
-  }
-  const HistogramInfo& th = gHistograms[aID];
-  KeyedHistogram* keyed
-     = internal_GetKeyedHistogramById(nsDependentCString(th.id()));
-  MOZ_ASSERT(keyed);
-  keyed->Add(aKey, aSample);
-}
-
-void
-internal_Accumulate(Histogram& aHistogram, uint32_t aSample)
-{
-  if (XRE_IsParentProcess()) {
-    internal_HistogramAdd(aHistogram, aSample);
-    return;
-  }
-
-  mozilla::Telemetry::ID id;
-  nsresult rv = internal_GetHistogramEnumId(aHistogram.histogram_name().c_str(), &id);
-  if (NS_SUCCEEDED(rv)) {
-    internal_RemoteAccumulate(id, aSample);
-  }
-}
-
-void
-internal_Accumulate(KeyedHistogram& aKeyed,
-                    const nsCString& aKey, uint32_t aSample)
-{
-  if (XRE_IsParentProcess()) {
-    aKeyed.Add(aKey, aSample);
-    return;
-  }
-
-  mozilla::Telemetry::ID id;
-  if (NS_SUCCEEDED(aKeyed.GetEnumId(id))) {
-    internal_RemoteAccumulate(id, aKey, aSample);
-  }
-}
-
-void
-internal_AccumulateChild(mozilla::Telemetry::ID aId, uint32_t aSample)
-{
-  if (!internal_CanRecordBase()) {
-    return;
-  }
-  Histogram* h;
-  nsresult rv = internal_GetHistogramByEnumId(aId, &h, true);
-  if (NS_SUCCEEDED(rv)) {
-    internal_HistogramAdd(*h, aSample, gHistograms[aId].dataset);
-  } else {
-    NS_WARNING("NS_FAILED GetHistogramByEnumId for CHILD");
-  }
-}
-
-void
-internal_AccumulateChildKeyed(mozilla::Telemetry::ID aId,
-                              const nsCString& aKey, uint32_t aSample)
-{
-  if (!gInitDone || !internal_CanRecordBase()) {
-    return;
-  }
-  const HistogramInfo& th = gHistograms[aId];
-  nsCString id;
-  id.Append(th.id());
-  id.AppendLiteral(CHILD_HISTOGRAM_SUFFIX);
-  KeyedHistogram* keyed = internal_GetKeyedHistogramById(id);
-  MOZ_ASSERT(keyed);
-  keyed->Add(aKey, aSample);
-}
-
-} // namespace
-
-
-////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////
-//
 // PRIVATE: JSHistogram_* functions
 
 // NOTE: the functions in this section:
 //
 //   internal_JSHistogram_Add
 //   internal_JSHistogram_Snapshot
 //   internal_JSHistogram_Clear
 //   internal_JSHistogram_Dataset
@@ -1470,57 +1103,62 @@ internal_JSHistogram_Add(JSContext *cx, 
   Histogram::ClassType type = h->histogram_type();
 
   JS::CallArgs args = CallArgsFromVp(argc, vp);
 
   if (!internal_CanRecordBase()) {
     return true;
   }
 
-  uint32_t value = 0;
-  mozilla::Telemetry::ID id;
+  // If we don't have an argument for the count histogram, assume an increment of 1.
+  // Otherwise, make sure to run some sanity checks on the argument.
   if ((type == base::CountHistogram::COUNT_HISTOGRAM) && (args.length() == 0)) {
-    // If we don't have an argument for the count histogram, assume an increment of 1.
-    // Otherwise, make sure to run some sanity checks on the argument.
-    value = 1;
-  } else if (type == base::LinearHistogram::LINEAR_HISTOGRAM &&
+    internal_HistogramAdd(*h, 1);
+    return true;
+  }
+
+  // For categorical histograms we allow passing a string argument that specifies the label.
+  mozilla::Telemetry::ID id;
+  if (type == base::LinearHistogram::LINEAR_HISTOGRAM &&
       (args.length() > 0) && args[0].isString() &&
       NS_SUCCEEDED(internal_GetHistogramEnumId(h->histogram_name().c_str(), &id)) &&
       gHistograms[id].histogramType == nsITelemetry::HISTOGRAM_CATEGORICAL) {
-    // For categorical histograms we allow passing a string argument that specifies the label.
     nsAutoJSString label;
     if (!label.init(cx, args[0])) {
       JS_ReportError(cx, "Invalid string parameter");
       return false;
     }
 
-    nsresult rv = gHistograms[id].label_id(NS_ConvertUTF16toUTF8(label).get(), &value);
+    nsresult rv = internal_HistogramAddCategorical(id, NS_ConvertUTF16toUTF8(label));
     if (NS_FAILED(rv)) {
       JS_ReportError(cx, "Unknown label for categorical histogram");
       return false;
     }
-  } else {
-    // All other accumulations expect one numerical argument.
-    if (!args.length()) {
-      JS_ReportError(cx, "Expected one argument");
-      return false;
-    }
+
+    return true;
+  }
 
-    if (!(args[0].isNumber() || args[0].isBoolean())) {
-      JS_ReportError(cx, "Not a number");
-      return false;
-    }
-
-    if (!JS::ToUint32(cx, args[0], &value)) {
-      JS_ReportError(cx, "Failed to convert argument");
-      return false;
-    }
+  // All other accumulations expect one numerical argument.
+  int32_t value = 0;
+  if (!args.length()) {
+    JS_ReportError(cx, "Expected one argument");
+    return false;
   }
 
-  internal_Accumulate(*h, value);
+  if (!(args[0].isNumber() || args[0].isBoolean())) {
+    JS_ReportError(cx, "Not a number");
+    return false;
+  }
+
+  if (!JS::ToInt32(cx, args[0], &value)) {
+    JS_ReportError(cx, "Failed to convert argument");
+    return false;
+  }
+
+  internal_HistogramAdd(*h, value);
   return true;
 }
 
 bool
 internal_JSHistogram_Snapshot(JSContext *cx, unsigned argc, JS::Value *vp)
 {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
   JSObject *obj = JS_THIS_OBJECT(cx, vp);
@@ -1758,17 +1396,17 @@ internal_JSKeyedHistogram_Add(JSContext 
       return false;
     }
 
     if (!JS::ToInt32(cx, args[1], &value)) {
       return false;
     }
   }
 
-  internal_Accumulate(*keyed, NS_ConvertUTF16toUTF8(key), value);
+  keyed->Add(NS_ConvertUTF16toUTF8(key), value);
   return true;
 }
 
 bool
 internal_JSKeyedHistogram_Keys(JSContext *cx, unsigned argc, JS::Value *vp)
 {
   JSObject *obj = JS_THIS_OBJECT(cx, vp);
   if (!obj) {
@@ -1911,18 +1549,191 @@ internal_WrapAndReturnKeyedHistogram(Key
 }
 
 } // namespace
 
 
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
 //
+// PRIVATE: functions related to addon histograms
+
+namespace {
+
+// Compute the name to pass into Histogram for the addon histogram
+// 'name' from the addon 'id'.  We can't use 'name' directly because it
+// might conflict with other histograms in other addons or even with our
+// own.
+void
+internal_AddonHistogramName(const nsACString &id, const nsACString &name,
+                            nsACString &ret)
+{
+  ret.Append(id);
+  ret.Append(':');
+  ret.Append(name);
+}
+
+bool
+internal_CreateHistogramForAddon(const nsACString &name,
+                                 AddonHistogramInfo &info)
+{
+  Histogram *h;
+  nsresult rv = internal_HistogramGet(PromiseFlatCString(name).get(), "never",
+                                      info.histogramType, info.min, info.max,
+                                      info.bucketCount, true, &h);
+  if (NS_FAILED(rv)) {
+    return false;
+  }
+  // Don't let this histogram be reported via the normal means
+  // (e.g. Telemetry.registeredHistograms); we'll make it available in
+  // other ways.
+  h->ClearFlags(Histogram::kUmaTargetedHistogramFlag);
+  info.h = h;
+  return true;
+}
+
+bool
+internal_AddonHistogramReflector(AddonHistogramEntryType *entry,
+                                 JSContext *cx, JS::Handle<JSObject*> obj)
+{
+  AddonHistogramInfo &info = entry->mData;
+
+  // Never even accessed the histogram.
+  if (!info.h) {
+    // Have to force creation of HISTOGRAM_FLAG histograms.
+    if (info.histogramType != nsITelemetry::HISTOGRAM_FLAG)
+      return true;
+
+    if (!internal_CreateHistogramForAddon(entry->GetKey(), info)) {
+      return false;
+    }
+  }
+
+  if (internal_IsEmpty(info.h)) {
+    return true;
+  }
+
+  JS::Rooted<JSObject*> snapshot(cx, JS_NewPlainObject(cx));
+  if (!snapshot) {
+    // Just consider this to be skippable.
+    return true;
+  }
+  switch (internal_ReflectHistogramSnapshot(cx, snapshot, info.h)) {
+  case REFLECT_FAILURE:
+  case REFLECT_CORRUPT:
+    return false;
+  case REFLECT_OK:
+    const nsACString &histogramName = entry->GetKey();
+    if (!JS_DefineProperty(cx, obj, PromiseFlatCString(histogramName).get(),
+                           snapshot, JSPROP_ENUMERATE)) {
+      return false;
+    }
+    break;
+  }
+  return true;
+}
+
+bool
+internal_AddonReflector(AddonEntryType *entry, JSContext *cx,
+                        JS::Handle<JSObject*> obj)
+{
+  const nsACString &addonId = entry->GetKey();
+  JS::Rooted<JSObject*> subobj(cx, JS_NewPlainObject(cx));
+  if (!subobj) {
+    return false;
+  }
+
+  AddonHistogramMapType *map = entry->mData;
+  if (!(map->ReflectIntoJS(internal_AddonHistogramReflector, cx, subobj)
+        && JS_DefineProperty(cx, obj, PromiseFlatCString(addonId).get(),
+                             subobj, JSPROP_ENUMERATE))) {
+    return false;
+  }
+  return true;
+}
+
+} // namespace
+
+
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+//
+// PRIVATE: thread-unsafe helpers for the external interface
+
+namespace {
+
+void
+internal_SetHistogramRecordingEnabled(mozilla::Telemetry::ID aID, bool aEnabled)
+{
+  if (!internal_IsHistogramEnumId(aID)) {
+    MOZ_ASSERT(false, "Telemetry::SetHistogramRecordingEnabled(...) must be used with an enum id");
+    return;
+  }
+
+  if (gHistograms[aID].keyed) {
+    const nsDependentCString id(gHistograms[aID].id());
+    KeyedHistogram* keyed = internal_GetKeyedHistogramById(id);
+    if (keyed) {
+      keyed->SetRecordingEnabled(aEnabled);
+      return;
+    }
+  } else {
+    Histogram *h;
+    nsresult rv = internal_GetHistogramByEnumId(aID, &h);
+    if (NS_SUCCEEDED(rv)) {
+      h->SetRecordingEnabled(aEnabled);
+      return;
+    }
+  }
+
+  MOZ_ASSERT(false, "Telemetry::SetHistogramRecordingEnabled(...) id not found");
+}
+
+void internal_Accumulate(mozilla::Telemetry::ID aHistogram, uint32_t aSample)
+{
+  if (!internal_CanRecordBase()) {
+    return;
+  }
+  Histogram *h;
+  nsresult rv = internal_GetHistogramByEnumId(aHistogram, &h);
+  if (NS_SUCCEEDED(rv)) {
+    internal_HistogramAdd(*h, aSample, gHistograms[aHistogram].dataset);
+  }
+}
+
+void
+internal_Accumulate(mozilla::Telemetry::ID aID,
+                    const nsCString& aKey, uint32_t aSample)
+{
+  if (!gInitDone || !internal_CanRecordBase()) {
+    return;
+  }
+  const HistogramInfo& th = gHistograms[aID];
+  KeyedHistogram* keyed
+     = internal_GetKeyedHistogramById(nsDependentCString(th.id()));
+  MOZ_ASSERT(keyed);
+  keyed->Add(aKey, aSample);
+}
+
+} // namespace
+
+
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+//
 // EXTERNALLY VISIBLE FUNCTIONS in namespace TelemetryHistogram::
 
+// This is a StaticMutex rather than a plain Mutex (1) so that
+// it gets initialised in a thread-safe manner the first time
+// it is used, and (2) because it is never de-initialised, and
+// a normal Mutex would show up as a leak in BloatView.  StaticMutex
+// also has the "OffTheBooks" property, so it won't show as a leak
+// in BloatView.
+static StaticMutex gTelemetryHistogramMutex;
+
 // All of these functions are actually in namespace TelemetryHistogram::,
 // but the ::TelemetryHistogram prefix is given explicitly.  This is
 // because it is critical to see which calls from these functions are
 // to another function in this interface.  Mis-identifying "inwards
 // calls" from "calls to another function in this interface" will lead
 // to deadlocking and/or races.  See comments at the top of the file
 // for further (important!) details.
 
@@ -1976,26 +1787,16 @@ void TelemetryHistogram::InitializeGloba
     if (!h.keyed) {
       continue;
     }
 
     const nsDependentCString id(h.id());
     const nsDependentCString expiration(h.expiration());
     gKeyedHistograms.Put(id, new KeyedHistogram(id, expiration, h.histogramType,
                                                 h.min, h.max, h.bucketCount, h.dataset));
-    if (XRE_IsParentProcess()) {
-      // We must create registered child keyed histograms as well or else the
-      // same code in TelemetrySession.jsm that fails without parent keyed
-      // histograms will fail without child keyed histograms.
-      nsCString childId(id);
-      childId.AppendLiteral(CHILD_HISTOGRAM_SUFFIX);
-      gKeyedHistograms.Put(childId,
-                           new KeyedHistogram(id, expiration, h.histogramType,
-                                              h.min, h.max, h.bucketCount, h.dataset));
-    }
   }
 
   // Some Telemetry histograms depend on the value of C++ constants and hardcode
   // their values in Histograms.json.
   // We add static asserts here for those values to match so that future changes
   // don't go unnoticed.
   // TODO: Compare explicitly with gHistograms[<histogram id>].bucketCount here
   // once we can make gHistograms constexpr (requires VS2015).
@@ -2016,21 +1817,16 @@ void TelemetryHistogram::InitializeGloba
 void TelemetryHistogram::DeInitializeGlobalState()
 {
   StaticMutexAutoLock locker(gTelemetryHistogramMutex);
   gCanRecordBase = false;
   gCanRecordExtended = false;
   gHistogramMap.Clear();
   gKeyedHistograms.Clear();
   gAddonMap.Clear();
-  gAccumulations = nullptr;
-  gKeyedAccumulations = nullptr;
-  if (gIPCTimer) {
-    NS_RELEASE(gIPCTimer);
-  }
   gInitDone = false;
 }
 
 #ifdef DEBUG
 bool TelemetryHistogram::GlobalStateHasBeenInitialized() {
   StaticMutexAutoLock locker(gTelemetryHistogramMutex);
   return gInitDone;
 }
@@ -2126,17 +1922,22 @@ TelemetryHistogram::Accumulate(const cha
   if (!internal_CanRecordBase()) {
     return;
   }
   mozilla::Telemetry::ID id;
   nsresult rv = internal_GetHistogramEnumId(name, &id);
   if (NS_FAILED(rv)) {
     return;
   }
-  internal_Accumulate(id, sample);
+
+  Histogram *h;
+  rv = internal_GetHistogramByEnumId(id, &h);
+  if (NS_SUCCEEDED(rv)) {
+    internal_HistogramAdd(*h, sample, gHistograms[id].dataset);
+  }
 }
 
 void
 TelemetryHistogram::Accumulate(const char* name,
                                const nsCString& key, uint32_t sample)
 {
   StaticMutexAutoLock locker(gTelemetryHistogramMutex);
   if (!internal_CanRecordBase()) {
@@ -2149,62 +1950,17 @@ TelemetryHistogram::Accumulate(const cha
   }
 }
 
 void
 TelemetryHistogram::AccumulateCategorical(mozilla::Telemetry::ID aId,
                                           const nsCString& label)
 {
   StaticMutexAutoLock locker(gTelemetryHistogramMutex);
-  if (!internal_CanRecordBase()) {
-    return;
-  }
-  uint32_t labelId = 0;
-  if (NS_FAILED(gHistograms[aId].label_id(label.get(), &labelId))) {
-    return;
-  }
-  internal_Accumulate(aId, labelId);
-}
-
-void
-TelemetryHistogram::AccumulateChild(const nsTArray<Accumulation>& aAccumulations)
-{
-  MOZ_ASSERT(XRE_IsParentProcess());
-  StaticMutexAutoLock locker(gTelemetryHistogramMutex);
-  if (!internal_CanRecordBase()) {
-    return;
-  }
-  for (uint32_t i = 0; i < aAccumulations.Length(); ++i) {
-    bool isValid = internal_IsHistogramEnumId(aAccumulations[i].mId);
-    MOZ_ASSERT(isValid);
-    if (!isValid) {
-      continue;
-    }
-    internal_AccumulateChild(aAccumulations[i].mId, aAccumulations[i].mSample);
-  }
-}
-
-void
-TelemetryHistogram::AccumulateChildKeyed(const nsTArray<KeyedAccumulation>& aAccumulations)
-{
-  MOZ_ASSERT(XRE_IsParentProcess());
-  StaticMutexAutoLock locker(gTelemetryHistogramMutex);
-  if (!internal_CanRecordBase()) {
-    return;
-  }
-  for (uint32_t i = 0; i < aAccumulations.Length(); ++i) {
-    bool isValid = internal_IsHistogramEnumId(aAccumulations[i].mId);
-    MOZ_ASSERT(isValid);
-    if (!isValid) {
-      continue;
-    }
-    internal_AccumulateChildKeyed(aAccumulations[i].mId,
-                                  aAccumulations[i].mKey,
-                                  aAccumulations[i].mSample);
-  }
+  internal_HistogramAddCategorical(aId, label);
 }
 
 void
 TelemetryHistogram::ClearHistogram(mozilla::Telemetry::ID aId)
 {
   StaticMutexAutoLock locker(gTelemetryHistogramMutex);
   if (!internal_CanRecordBase()) {
     return;
@@ -2339,18 +2095,16 @@ TelemetryHistogram::CreateHistogramSnaps
     }
     const uint32_t type = gHistograms[i].histogramType;
     if (type == nsITelemetry::HISTOGRAM_FLAG ||
         type == nsITelemetry::HISTOGRAM_COUNT) {
       Histogram *h;
       mozilla::DebugOnly<nsresult> rv
          = internal_GetHistogramByEnumId(mozilla::Telemetry::ID(i), &h);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
-      rv = internal_GetHistogramByEnumId(mozilla::Telemetry::ID(i), &h, true);
-      MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
   }
 
   StatisticsRecorder::Histograms hs;
   StatisticsRecorder::GetHistograms(&hs);
 
   // We identify corrupt histograms first, rather than interspersing it
   // in the loop below, to ensure that our corruption statistics don't
@@ -2604,48 +2358,8 @@ TelemetryHistogram::GetHistogramSizesofI
   StatisticsRecorder::GetHistograms(&hs);
   size_t n = 0;
   for (HistogramIterator it = hs.begin(); it != hs.end(); ++it) {
     Histogram *h = *it;
     n += h->SizeOfIncludingThis(aMallocSizeOf);
   }
   return n;
 }
-
-// This method takes the lock only to double-buffer the batched telemetry.
-// It releases the lock before calling out to IPC code which can (and does)
-// Accumulate (which would deadlock)
-//
-// To ensure we don't loop IPCTimerFired->AccumulateChild->arm timer, we don't
-// unset gIPCTimerArmed until the IPC completes
-//
-// This function must be called on the main thread, otherwise IPC will fail.
-void
-TelemetryHistogram::IPCTimerFired(nsITimer* aTimer, void* aClosure)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  nsTArray<Accumulation> accumulationsToSend;
-  nsTArray<KeyedAccumulation> keyedAccumulationsToSend;
-  {
-    StaticMutexAutoLock locker(gTelemetryHistogramMutex);
-    if (gAccumulations) {
-      accumulationsToSend.SwapElements(*gAccumulations);
-    }
-    if (gKeyedAccumulations) {
-      keyedAccumulationsToSend.SwapElements(*gKeyedAccumulations);
-    }
-  }
-
-  mozilla::dom::ContentChild* contentChild = mozilla::dom::ContentChild::GetSingleton();
-  mozilla::Unused << NS_WARN_IF(!contentChild);
-  if (contentChild) {
-    if (accumulationsToSend.Length()) {
-      mozilla::Unused <<
-        NS_WARN_IF(!contentChild->SendAccumulateChildHistogram(accumulationsToSend));
-    }
-    if (keyedAccumulationsToSend.Length()) {
-      mozilla::Unused <<
-        NS_WARN_IF(!contentChild->SendAccumulateChildKeyedHistogram(keyedAccumulationsToSend));
-    }
-  }
-
-  gIPCTimerArmed = false;
-}
--- a/toolkit/components/telemetry/TelemetryHistogram.h
+++ b/toolkit/components/telemetry/TelemetryHistogram.h
@@ -3,18 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef TelemetryHistogram_h__
 #define TelemetryHistogram_h__
 
 #include "mozilla/TelemetryHistogramEnums.h"
 
-#include "mozilla/TelemetryComms.h"
-
 // This module is internal to Telemetry.  It encapsulates Telemetry's
 // histogram accumulation and storage logic.  It should only be used by
 // Telemetry.cpp.  These functions should not be used anywhere else.
 // For the public interface to Telemetry functionality, see Telemetry.h.
 
 namespace TelemetryHistogram {
 
 void CreateStatisticsRecorder();
@@ -39,19 +37,16 @@ nsresult SetHistogramRecordingEnabled(co
 void Accumulate(mozilla::Telemetry::ID aHistogram, uint32_t aSample);
 void Accumulate(mozilla::Telemetry::ID aID, const nsCString& aKey,
                                             uint32_t aSample);
 void Accumulate(const char* name, uint32_t sample);
 void Accumulate(const char* name, const nsCString& key, uint32_t sample);
 
 void AccumulateCategorical(mozilla::Telemetry::ID aId, const nsCString& aLabel);
 
-void AccumulateChild(const nsTArray<mozilla::Telemetry::Accumulation>& aAccumulations);
-void AccumulateChildKeyed(const nsTArray<mozilla::Telemetry::KeyedAccumulation>& aAccumulations);
-
 void
 ClearHistogram(mozilla::Telemetry::ID aId);
 
 nsresult
 GetHistogramById(const nsACString &name, JSContext *cx,
                  JS::MutableHandle<JS::Value> ret);
 
 nsresult
@@ -102,13 +97,11 @@ nsresult
 GetAddonHistogramSnapshots(JSContext *cx, JS::MutableHandle<JS::Value> ret);
 
 size_t
 GetMapShallowSizesOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf);
 
 size_t
 GetHistogramSizesofIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
 
-void
-IPCTimerFired(nsITimer* aTimer, void* aClosure);
 } // namespace TelemetryHistogram
 
 #endif // TelemetryHistogram_h__
--- a/toolkit/components/telemetry/TelemetrySession.jsm
+++ b/toolkit/components/telemetry/TelemetrySession.jsm
@@ -36,37 +36,33 @@ const REASON_ABORTED_SESSION = "aborted-
 const REASON_DAILY = "daily";
 const REASON_SAVED_SESSION = "saved-session";
 const REASON_GATHER_PAYLOAD = "gather-payload";
 const REASON_GATHER_SUBSESSION_PAYLOAD = "gather-subsession-payload";
 const REASON_TEST_PING = "test-ping";
 const REASON_ENVIRONMENT_CHANGE = "environment-change";
 const REASON_SHUTDOWN = "shutdown";
 
-const HISTOGRAM_SUFFIXES = {
-  PARENT: "",
-  CONTENT: "#content",
-}
-
 const ENVIRONMENT_CHANGE_LISTENER = "TelemetrySession::onEnvironmentChange";
 
 const MS_IN_ONE_HOUR  = 60 * 60 * 1000;
 const MIN_SUBSESSION_LENGTH_MS = Preferences.get("toolkit.telemetry.minSubsessionLength", 10 * 60) * 1000;
 
 const LOGGER_NAME = "Toolkit.Telemetry";
 const LOGGER_PREFIX = "TelemetrySession" + (Utils.isContentProcess ? "#content::" : "::");
 
 const PREF_BRANCH = "toolkit.telemetry.";
 const PREF_PREVIOUS_BUILDID = PREF_BRANCH + "previousBuildID";
 const PREF_FHR_UPLOAD_ENABLED = "datareporting.healthreport.uploadEnabled";
 const PREF_ASYNC_PLUGIN_INIT = "dom.ipc.plugins.asyncInit.enabled";
 const PREF_UNIFIED = PREF_BRANCH + "unified";
 
 
 const MESSAGE_TELEMETRY_PAYLOAD = "Telemetry:Payload";
+const MESSAGE_TELEMETRY_GET_CHILD_PAYLOAD = "Telemetry:GetChildPayload";
 const MESSAGE_TELEMETRY_THREAD_HANGS = "Telemetry:ChildThreadHangs";
 const MESSAGE_TELEMETRY_GET_CHILD_THREAD_HANGS = "Telemetry:GetChildThreadHangs";
 const MESSAGE_TELEMETRY_USS = "Telemetry:USS";
 const MESSAGE_TELEMETRY_GET_CHILD_USS = "Telemetry:GetChildUSS";
 
 const DATAREPORTING_DIRECTORY = "datareporting";
 const ABORTED_SESSION_FILE_NAME = "aborted-session-ping";
 
@@ -540,16 +536,23 @@ this.TelemetrySession = Object.freeze({
    * @param reason Optional, the reason to trigger the payload.
    * @param clearSubsession Optional, whether to clear subsession specific data.
    * @returns Object
    */
   getPayload: function(reason, clearSubsession = false) {
     return Impl.getPayload(reason, clearSubsession);
   },
   /**
+   * Asks the content processes to send their payloads.
+   * @returns Object
+   */
+  requestChildPayloads: function() {
+    return Impl.requestChildPayloads();
+  },
+  /**
    * Returns a promise that resolves to an array of thread hang stats from content processes, one entry per process.
    * The structure of each entry is identical to that of "threadHangStats" in nsITelemetry.
    * While thread hang stats are also part of the child payloads, this function is useful for cheaply getting this information,
    * which is useful for realtime hang monitoring.
    * Child processes that do not respond, or spawn/die during execution of this function are excluded from the result.
    * @returns Promise
    */
   getChildThreadHangs: function() {
@@ -876,38 +879,33 @@ var Impl = {
    * @return {Integer} A value from nsITelemetry.DATASET_*.
    */
   getDatasetType: function() {
     return Telemetry.canRecordExtended ? Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN
                                        : Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
   },
 
   getHistograms: function getHistograms(subsession, clearSubsession) {
-    this._log.trace("getHistograms - subsession: " + subsession +
-                    ", clearSubsession: " + clearSubsession);
+    this._log.trace("getHistograms - subsession: " + subsession + ", clearSubsession: " + clearSubsession);
 
     let registered =
       Telemetry.registeredHistograms(this.getDatasetType(), []);
-    if (this._testing == false) {
-      // Omit telemetry test histograms outside of tests.
-      registered = registered.filter(n => !n.startsWith("TELEMETRY_TEST_"));
-    }
-    registered = registered.concat(registered.map(n => "STARTUP_" + n));
-
     let hls = subsession ? Telemetry.snapshotSubsessionHistograms(clearSubsession)
                          : Telemetry.histogramSnapshots;
     let ret = {};
 
     for (let name of registered) {
-      for (let suffix of Object.values(HISTOGRAM_SUFFIXES)) {
-        if (name + suffix in hls) {
-          if (!(suffix in ret)) {
-            ret[suffix] = {};
+      for (let n of [name, "STARTUP_" + name]) {
+        if (n in hls) {
+          // Omit telemetry test histograms outside of tests.
+          if (n.startsWith('TELEMETRY_TEST_') && this._testing == false) {
+            this._log.trace("getHistograms - Skipping test histogram: " + n);
+          } else {
+            ret[n] = this.packHistogram(hls[n]);
           }
-          ret[suffix][name] = this.packHistogram(hls[name + suffix]);
         }
       }
     }
 
     return ret;
   },
 
   getAddonHistograms: function getAddonHistograms() {
@@ -925,51 +923,46 @@ var Impl = {
       if (Object.keys(packedHistograms).length != 0)
         ret[addonName] = packedHistograms;
     }
 
     return ret;
   },
 
   getKeyedHistograms: function(subsession, clearSubsession) {
-    this._log.trace("getKeyedHistograms - subsession: " + subsession +
-                    ", clearSubsession: " + clearSubsession);
+    this._log.trace("getKeyedHistograms - subsession: " + subsession + ", clearSubsession: " + clearSubsession);
 
     let registered =
       Telemetry.registeredKeyedHistograms(this.getDatasetType(), []);
-    if (this._testing == false) {
-      // Omit telemetry test histograms outside of tests.
-      registered = registered.filter(id => !id.startsWith("TELEMETRY_TEST_"));
-    }
     let ret = {};
 
     for (let id of registered) {
-      for (let suffix of Object.values(HISTOGRAM_SUFFIXES)) {
-        let keyed = Telemetry.getKeyedHistogramById(id + suffix);
-        let snapshot = null;
-        if (subsession) {
-          snapshot = clearSubsession ? keyed.snapshotSubsessionAndClear()
-                                     : keyed.subsessionSnapshot();
-        } else {
-          snapshot = keyed.snapshot();
-        }
+      // Omit telemetry test histograms outside of tests.
+      if (id.startsWith('TELEMETRY_TEST_') && this._testing == false) {
+        this._log.trace("getKeyedHistograms - Skipping test histogram: " + id);
+        continue;
+      }
+      let keyed = Telemetry.getKeyedHistogramById(id);
+      let snapshot = null;
+      if (subsession) {
+        snapshot = clearSubsession ? keyed.snapshotSubsessionAndClear()
+                                   : keyed.subsessionSnapshot();
+      } else {
+        snapshot = keyed.snapshot();
+      }
 
-        let keys = Object.keys(snapshot);
-        if (keys.length == 0) {
-          // Skip empty keyed histogram.
-          continue;
-        }
+      let keys = Object.keys(snapshot);
+      if (keys.length == 0) {
+        // Skip empty keyed histogram.
+        continue;
+      }
 
-        if (!(suffix in ret)) {
-          ret[suffix] = {};
-        }
-        ret[suffix][id] = {};
-        for (let key of keys) {
-          ret[suffix][id][key] = this.packHistogram(snapshot[key]);
-        }
+      ret[id] = {};
+      for (let key of keys) {
+        ret[id][key] = this.packHistogram(snapshot[key]);
       }
     }
 
     return ret;
   },
 
   getScalars: function (subsession, clearSubsession) {
     this._log.trace("getScalars - subsession: " + subsession + ", clearSubsession: " + clearSubsession);
@@ -1245,58 +1238,53 @@ var Impl = {
   assemblePayloadWithMeasurements: function(simpleMeasurements, info, reason, clearSubsession) {
     const isSubsession = IS_UNIFIED_TELEMETRY && !this._isClassicReason(reason);
     clearSubsession = IS_UNIFIED_TELEMETRY && clearSubsession;
     this._log.trace("assemblePayloadWithMeasurements - reason: " + reason +
                     ", submitting subsession data: " + isSubsession);
 
     // This allows wrapping data retrieval calls in a try-catch block so that
     // failures don't break the rest of the ping assembly.
-    const protect = (fn, defaultReturn = null) => {
+    const protect = (fn) => {
       try {
         return fn();
       } catch (ex) {
         this._log.error("assemblePayloadWithMeasurements - caught exception", ex);
-        return defaultReturn;
+        return null;
       }
     };
 
     // Payload common to chrome and content processes.
     let payloadObj = {
       ver: PAYLOAD_VERSION,
       simpleMeasurements: simpleMeasurements,
+      histograms: protect(() => this.getHistograms(isSubsession, clearSubsession)),
+      keyedHistograms: protect(() => this.getKeyedHistograms(isSubsession, clearSubsession)),
     };
 
     // Add extended set measurements common to chrome & content processes
     if (Telemetry.canRecordExtended) {
       payloadObj.chromeHangs = protect(() => Telemetry.chromeHangs);
       payloadObj.threadHangStats = protect(() => this.getThreadHangStats(Telemetry.threadHangStats));
       payloadObj.log = protect(() => TelemetryLog.entries());
       payloadObj.webrtc = protect(() => Telemetry.webrtcStats);
     }
 
     if (Utils.isContentProcess) {
       return payloadObj;
     }
 
-    // Additional payload for chrome process.
-    let histograms = protect(() => this.getHistograms(isSubsession, clearSubsession), {});
-    let keyedHistograms = protect(() => this.getKeyedHistograms(isSubsession, clearSubsession), {});
-    payloadObj.histograms = histograms[HISTOGRAM_SUFFIXES.PARENT] || {};
-    payloadObj.keyedHistograms = keyedHistograms[HISTOGRAM_SUFFIXES.PARENT] || {};
+    // Set the scalars for the parent process.
     payloadObj.processes = {
       parent: {
         scalars: protect(() => this.getScalars(isSubsession, clearSubsession)),
-      },
-      content: {
-        histograms: histograms[HISTOGRAM_SUFFIXES.CONTENT],
-        keyedHistograms: keyedHistograms[HISTOGRAM_SUFFIXES.CONTENT],
-      },
+      }
     };
 
+    // Additional payload for chrome process.
     payloadObj.info = info;
 
     // Add extended set measurements for chrome process.
     if (Telemetry.canRecordExtended) {
       payloadObj.slowSQL = protect(() => Telemetry.slowSQL);
       payloadObj.fileIOReports = protect(() => Telemetry.fileIOReports);
       payloadObj.lateWrites = protect(() => Telemetry.lateWrites);
 
@@ -1528,16 +1516,17 @@ var Impl = {
     this._testing = testing;
 
     if (!Telemetry.canRecordBase) {
       this._log.trace("setupContentProcess - base recording is disabled, not initializing");
       return;
     }
 
     Services.obs.addObserver(this, "content-child-shutdown", false);
+    cpml.addMessageListener(MESSAGE_TELEMETRY_GET_CHILD_PAYLOAD, this);
     cpml.addMessageListener(MESSAGE_TELEMETRY_GET_CHILD_THREAD_HANGS, this);
     cpml.addMessageListener(MESSAGE_TELEMETRY_GET_CHILD_USS, this);
 
     this.gatherStartupHistograms();
 
     let delayedTask = new DeferredTask(function* () {
       this._initialized = true;
 
@@ -1565,28 +1554,42 @@ var Impl = {
     this._log.trace("receiveMessage - Message name " + message.name);
     switch (message.name) {
     case MESSAGE_TELEMETRY_PAYLOAD:
     {
       // In parent process, receive Telemetry payload from child
       let source = message.data.childUUID;
       delete message.data.childUUID;
 
+      for (let child of this._childTelemetry) {
+        if (child.source === source) {
+          // Update existing telemetry data.
+          child.payload = message.data;
+          return;
+        }
+      }
+      // Did not find existing child in this._childTelemetry.
       this._childTelemetry.push({
         source: source,
         payload: message.data,
       });
 
       if (this._childTelemetry.length == MAX_NUM_CONTENT_PAYLOADS + 1) {
         this._childTelemetry.shift();
         Telemetry.getHistogramById("TELEMETRY_DISCARDED_CONTENT_PINGS_COUNT").add();
       }
 
       break;
     }
+    case MESSAGE_TELEMETRY_GET_CHILD_PAYLOAD:
+    {
+      // In child process, send the requested Telemetry payload
+      this.sendContentProcessPing("saved-session");
+      break;
+    }
     case MESSAGE_TELEMETRY_THREAD_HANGS:
     {
       // Accumulate child thread hang stats from this child
       this._childThreadHangs.push(message.data);
 
       // Check if we've got data from all the children, accounting for child processes dying
       // if it happens before the last response is received and no new child processes are spawned at the exact same time
       // If that happens, we can resolve the promise earlier rather than having to wait for the timeout to expire
@@ -1756,16 +1759,21 @@ var Impl = {
     if (Object.keys(this._slowSQLStartup).length == 0) {
       this.gatherStartupHistograms();
       this._slowSQLStartup = Telemetry.slowSQL;
     }
     this.gatherMemory();
     return this.getSessionPayload(reason, clearSubsession);
   },
 
+  requestChildPayloads: function() {
+    this._log.trace("requestChildPayloads");
+    ppmm.broadcastAsyncMessage(MESSAGE_TELEMETRY_GET_CHILD_PAYLOAD, {});
+  },
+
   getChildThreadHangs: function getChildThreadHangs() {
     return new Promise((resolve) => {
       // Return immediately if there are no child processes to get stats from
       if (ppmm.childCount === 0) {
         resolve([]);
         return;
       }
 
@@ -1833,17 +1841,17 @@ var Impl = {
       this._log.trace("observe - " + aTopic + " notified.");
     }
 
     switch (aTopic) {
     case "content-child-shutdown":
       // content-child-shutdown is only registered for content processes.
       Services.obs.removeObserver(this, "content-child-shutdown");
       this.uninstall();
-      Telemetry.flushBatchedChildTelemetry();
+
       this.sendContentProcessPing(REASON_SAVED_SESSION);
       break;
     case TOPIC_CYCLE_COLLECTOR_BEGIN:
       let now = new Date();
       if (!gLastMemoryPoll
           || (TELEMETRY_INTERVAL <= now - gLastMemoryPoll)) {
         gLastMemoryPoll = now;
         this.gatherMemory();
--- a/toolkit/components/telemetry/moz.build
+++ b/toolkit/components/telemetry/moz.build
@@ -14,17 +14,16 @@ XPIDL_SOURCES += [
 
 XPIDL_MODULE = 'telemetry'
 
 EXPORTS.mozilla += [
     '!TelemetryHistogramEnums.h',
     '!TelemetryScalarEnums.h',
     'ProcessedStack.h',
     'Telemetry.h',
-    'TelemetryComms.h',
     'ThreadHangStats.h',
 ]
 
 SOURCES += [
     'Telemetry.cpp',
     'TelemetryCommon.cpp',
     'TelemetryHistogram.cpp',
     'TelemetryScalar.cpp',
--- a/toolkit/components/telemetry/nsITelemetry.idl
+++ b/toolkit/components/telemetry/nsITelemetry.idl
@@ -411,15 +411,9 @@ interface nsITelemetry : nsISupports
    */
   [implicit_jscontext, optional_argc]
   jsval snapshotScalars(in uint32_t aDataset, [optional] in boolean aClear);
 
   /**
    * Resets all the stored scalars. This is intended to be only used in tests.
    */
   void clearScalars();
-
-  /**
-   * Immediately sends any Telemetry batched on this process to the parent
-   * process. This is intended only to be used on process shutdown.
-   */
-  void flushBatchedChildTelemetry();
 };
--- a/toolkit/components/telemetry/tests/unit/test_ChildHistograms.js
+++ b/toolkit/components/telemetry/tests/unit/test_ChildHistograms.js
@@ -1,13 +1,12 @@
 
 Cu.import("resource://gre/modules/TelemetryController.jsm", this);
 Cu.import("resource://gre/modules/TelemetrySession.jsm", this);
 Cu.import("resource://gre/modules/PromiseUtils.jsm", this);
-Cu.import("resource://testing-common/ContentTaskUtils.jsm", this);
 
 const MESSAGE_TELEMETRY_PAYLOAD = "Telemetry:Payload";
 const MESSAGE_TELEMETRY_GET_CHILD_PAYLOAD = "Telemetry:GetChildPayload";
 const MESSAGE_CHILD_TEST_DONE = "ChildTest:Done";
 
 const PLATFORM_VERSION = "1.9.2";
 const APP_VERSION = "1";
 const APP_ID = "xpcshell@tests.mozilla.org";
@@ -15,40 +14,38 @@ const APP_NAME = "XPCShell";
 
 function run_child_test() {
   // Setup histograms with some fixed values.
   let flagHist = Telemetry.getHistogramById("TELEMETRY_TEST_FLAG");
   flagHist.add(1);
   let countHist = Telemetry.getHistogramById("TELEMETRY_TEST_COUNT");
   countHist.add();
   countHist.add();
-  let categHist = Telemetry.getHistogramById("TELEMETRY_TEST_CATEGORICAL");
-  categHist.add("Label2");
-  categHist.add("Label3");
 
   let flagKeyed = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_FLAG");
   flagKeyed.add("a", 1);
   flagKeyed.add("b", 1);
   let countKeyed = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_COUNT");
   countKeyed.add("a");
   countKeyed.add("b");
   countKeyed.add("b");
+
+  // Check payload values.
+  const payload = TelemetrySession.getPayload("test-ping");
+  check_histogram_values(payload);
 }
 
 function check_histogram_values(payload) {
   const hs = payload.histograms;
   Assert.ok("TELEMETRY_TEST_COUNT" in hs, "Should have count test histogram.");
   Assert.ok("TELEMETRY_TEST_FLAG" in hs, "Should have flag test histogram.");
-  Assert.ok("TELEMETRY_TEST_CATEGORICAL" in hs, "Should have categorical test histogram.");
   Assert.equal(hs["TELEMETRY_TEST_COUNT"].sum, 2,
                "Count test histogram should have the right value.");
   Assert.equal(hs["TELEMETRY_TEST_FLAG"].sum, 1,
                "Flag test histogram should have the right value.");
-  Assert.equal(hs["TELEMETRY_TEST_CATEGORICAL"].sum, 3,
-               "Categorical test histogram should have the right sum.");
 
   const kh = payload.keyedHistograms;
   Assert.ok("TELEMETRY_TEST_KEYED_COUNT" in kh, "Should have keyed count test histogram.");
   Assert.ok("TELEMETRY_TEST_KEYED_FLAG" in kh, "Should have keyed flag test histogram.");
   Assert.equal(kh["TELEMETRY_TEST_KEYED_COUNT"]["a"].sum, 1,
                "Keyed count test histogram should have the right value.");
   Assert.equal(kh["TELEMETRY_TEST_KEYED_COUNT"]["b"].sum, 2,
                "Keyed count test histogram should have the right value.");
@@ -59,16 +56,18 @@ function check_histogram_values(payload)
 }
 
 add_task(function*() {
   if (!runningInParent) {
     TelemetryController.testSetupContent();
     run_child_test();
     dump("... done with child test\n");
     do_send_remote_message(MESSAGE_CHILD_TEST_DONE);
+    dump("... waiting for child payload collection\n");
+    yield do_await_remote_message(MESSAGE_TELEMETRY_GET_CHILD_PAYLOAD);
     return;
   }
 
   // Setup.
   do_get_profile(true);
   loadAddonManager(APP_ID, APP_NAME, APP_VERSION, PLATFORM_VERSION);
   Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true);
   yield TelemetryController.testSetup();
@@ -76,25 +75,25 @@ add_task(function*() {
     // Make sure we don't generate unexpected pings due to pref changes.
     yield setEmptyPrefWatchlist();
   }
 
   // Run test in child, don't wait for it to finish.
   let childPromise = run_test_in_child("test_ChildHistograms.js");
   yield do_await_remote_message(MESSAGE_CHILD_TEST_DONE);
 
-  yield ContentTaskUtils.waitForCondition(() => {
-    let payload = TelemetrySession.getPayload("test-ping");
-    return payload &&
-           "processes" in payload &&
-           "content" in payload.processes &&
-           "histograms" in payload.processes.content &&
-           "TELEMETRY_TEST_COUNT" in payload.processes.content.histograms;
-  });
+  // Gather payload from child.
+  dump("... requesting child payloads\n");
+  let promiseMessage = do_await_remote_message(MESSAGE_TELEMETRY_PAYLOAD);
+  TelemetrySession.requestChildPayloads();
+  yield promiseMessage;
+  dump("... received child payload\n");
+
+  // Check child payload.
   const payload = TelemetrySession.getPayload("test-ping");
-  Assert.ok("processes" in payload, "Should have processes section");
-  Assert.ok("content" in payload.processes, "Should have child process section");
-  Assert.ok("histograms" in payload.processes.content, "Child process section should have histograms.");
-  Assert.ok("keyedHistograms" in payload.processes.content, "Child process section should have keyed histograms.");
-  check_histogram_values(payload.processes.content);
+  Assert.ok("childPayloads" in payload, "Should have child payloads.");
+  Assert.equal(payload.childPayloads.length, 1, "Should have received one child payload so far.");
+  Assert.ok("histograms" in payload.childPayloads[0], "Child payload should have histograms.");
+  Assert.ok("keyedHistograms" in payload.childPayloads[0], "Child payload should have keyed histograms.");
+  check_histogram_values(payload.childPayloads[0]);
 
   do_test_finished();
 });
--- a/toolkit/content/aboutTelemetry.css
+++ b/toolkit/content/aboutTelemetry.css
@@ -224,24 +224,16 @@ body[dir="rtl"] .copy-node {
   padding-inline-start: 10em;
   display: none;
 }
 
 .has-data.expanded .filter-ui {
   display: inline;
 }
 
-.processes-ui {
-  display: none;
-}
-
-.has-data.expanded .processes-ui {
-  display: initial;
-}
-
 .filter-blocked {
   display: none;
 }
 
 #raw-ping-data-section {
   width: 100%;
   height: 100%;
   background-color:-moz-Dialog;
@@ -260,12 +252,8 @@ body[dir="rtl"] .copy-node {
   padding: 5px 10px;
 }
 
 /* addon subsection style */
 .addon-caption {
   font-size: larger;
   margin: 5px 0;
 }
-
-.process-picker {
-  margin: 0 0.5em;
-}
--- a/toolkit/content/aboutTelemetry.js
+++ b/toolkit/content/aboutTelemetry.js
@@ -301,20 +301,16 @@ var PingPicker = {
     }, false);
 
     document.getElementById("newer-ping")
             .addEventListener("click", () => this._movePingIndex(-1), false);
     document.getElementById("older-ping")
             .addEventListener("click", () => this._movePingIndex(1), false);
     document.getElementById("choose-payload")
             .addEventListener("change", () => displayPingData(gPingData), false);
-    document.getElementById("histograms-processes")
-            .addEventListener("change", () => displayPingData(gPingData), false);
-    document.getElementById("keyed-histograms-processes")
-            .addEventListener("change", () => displayPingData(gPingData), false);
   },
 
   onPingSourceChanged: function() {
     this.update();
   },
 
   onPingDisplayChanged: function() {
     this.update();
@@ -1781,43 +1777,16 @@ function sortStartupMilestones(aSimpleMe
   let result = {};
   for (let key of sortedKeys) {
     result[key] = aSimpleMeasurements[key];
   }
 
   return result;
 }
 
-function renderProcessList(ping, selectEl) {
-  removeAllChildNodes(selectEl);
-  let option = document.createElement("option");
-  option.appendChild(document.createTextNode("parent"));
-  option.setAttribute("value", "");
-  option.selected = true;
-  selectEl.appendChild(option);
-
-  if (!("processes" in ping.payload)) {
-    selectEl.disabled = true;
-    return;
-  }
-  selectEl.disabled = false;
-
-  for (let process of Object.keys(ping.payload.processes)) {
-    // TODO: parent hgrams are on root payload, not in payload.processes.parent
-    // When/If that gets moved, you'll need to remove this:
-    if (process === "parent") {
-      continue;
-    }
-    option = document.createElement("option");
-    option.appendChild(document.createTextNode(process));
-    option.setAttribute("value", process);
-    selectEl.appendChild(option);
-  }
-}
-
 function renderPayloadList(ping) {
   // Rebuild the payload select with options:
   //   Parent Payload (selected)
   //   Child Payload 1..ping.payload.childPayloads.length
   let listEl = document.getElementById("choose-payload");
   removeAllChildNodes(listEl);
 
   let option = document.createElement("option");
@@ -1876,21 +1845,19 @@ function displayPingData(ping, updatePay
   // Render raw ping data.
   let pre = document.getElementById("raw-ping-data");
   pre.textContent = JSON.stringify(gPingData, null, 2);
 
   // Update the structured data rendering.
   const keysHeader = bundle.GetStringFromName("keysHeader");
   const valuesHeader = bundle.GetStringFromName("valuesHeader");
 
-  // Update the payload list and process lists
+  // Update the payload list
   if (updatePayloadList) {
     renderPayloadList(ping);
-    renderProcessList(ping, document.getElementById("histograms-processes"));
-    renderProcessList(ping, document.getElementById("keyed-histograms-processes"));
   }
 
   // Show general data.
   GeneralData.render(ping);
 
   // Show environment data.
   EnvironmentData.render(ping);
 
@@ -1957,28 +1924,18 @@ function displayPingData(ping, updatePay
   // Show scalar data.
   Scalars.render(payload);
 
   // Show histogram data
   let hgramDiv = document.getElementById("histograms");
   removeAllChildNodes(hgramDiv);
 
   let histograms = payload.histograms;
-
-  let hgramsSelect = document.getElementById("histograms-processes");
-  let hgramsOption = hgramsSelect.selectedOptions.item(0);
-  let hgramsProcess = hgramsOption.getAttribute("value");
-  if (hgramsProcess &&
-      "processes" in ping.payload &&
-      hgramsProcess in ping.payload.processes) {
-    histograms = ping.payload.processes[hgramsProcess].histograms;
-  }
-
   hasData = Object.keys(histograms).length > 0;
-  setHasData("histograms-section", hasData || hgramsSelect.options.length);
+  setHasData("histograms-section", hasData);
 
   if (hasData) {
     for (let [name, hgram] of Object.entries(histograms)) {
       Histogram.render(hgramDiv, name, hgram, {unpacked: true});
     }
 
     let filterBox = document.getElementById("histograms-filter");
     filterBox.addEventListener("input", Histogram.histogramFilterChanged, false);
@@ -1988,37 +1945,27 @@ function displayPingData(ping, updatePay
 
     setHasData("histograms-section", true);
   }
 
   // Show keyed histogram data
   let keyedDiv = document.getElementById("keyed-histograms");
   removeAllChildNodes(keyedDiv);
 
+  setHasData("keyed-histograms-section", false);
   let keyedHistograms = payload.keyedHistograms;
-
-  let keyedHgramsSelect = document.getElementById("keyed-histograms-processes");
-  let keyedHgramsOption = keyedHgramsSelect.selectedOptions.item(0);
-  let keyedHgramsProcess = keyedHgramsOption.getAttribute("value");
-  if (keyedHgramsProcess &&
-      "processes" in ping.payload &&
-      keyedHgramsProcess in ping.payload.processes) {
-    keyedHistograms = ping.payload.processes[keyedHgramsProcess].keyedHistograms;
-  }
-
-  setHasData("keyed-histograms-section", keyedHgramsSelect.options.length);
   if (keyedHistograms) {
     let hasData = false;
     for (let [id, keyed] of Object.entries(keyedHistograms)) {
       if (Object.keys(keyed).length > 0) {
         hasData = true;
         KeyedHistogram.render(keyedDiv, id, keyed, {unpacked: true});
       }
     }
-    setHasData("keyed-histograms-section", hasData || keyedHgramsSelect.options.length);
+    setHasData("keyed-histograms-section", hasData);
   }
 
   // Show addon histogram data
   let addonDiv = document.getElementById("addon-histograms");
   removeAllChildNodes(addonDiv);
 
   let addonHistogramsRendered = false;
   let addonData = payload.addonHistograms;
--- a/toolkit/content/aboutTelemetry.xhtml
+++ b/toolkit/content/aboutTelemetry.xhtml
@@ -147,31 +147,25 @@
       <section id="histograms-section" class="data-section">
         <input type="checkbox" class="statebox"/>
         <h1 class="section-name">&aboutTelemetry.histogramsSection;</h1>
         <span class="toggle-caption">&aboutTelemetry.toggle;</span>
         <span class="empty-caption">&aboutTelemetry.emptySection;</span>
         <span class="filter-ui">
           &aboutTelemetry.filterText; <input type="text" class="filter" id="histograms-filter" target_id="histograms"/>
         </span>
-        <div class="processes-ui">
-          <select id="histograms-processes" class="process-picker"></select>
-        </div>
         <div id="histograms" class="data">
         </div>
       </section>
 
       <section id="keyed-histograms-section" class="data-section">
         <input type="checkbox" class="statebox"/>
         <h1 class="section-name">&aboutTelemetry.keyedHistogramsSection;</h1>
         <span class="toggle-caption">&aboutTelemetry.toggle;</span>
         <span class="empty-caption">&aboutTelemetry.emptySection;</span>
-        <div class="processes-ui">
-          <select id="keyed-histograms-processes" class="process-picker"></select>
-        </div>
         <div id="keyed-histograms" class="data">
         </div>
       </section>
 
       <section id="simple-measurements-section" class="data-section">
         <input type="checkbox" class="statebox"/>
         <h1 class="section-name">&aboutTelemetry.simpleMeasurementsSection;</h1>
         <span class="toggle-caption">&aboutTelemetry.toggle;</span>