bug 661574: Implement telemetry directory r=Mossop+glandium+mwu
authorTaras Glek <tglek@mozilla.com>
Mon, 20 Jun 2011 14:47:58 -0700
changeset 71329 aef1c7a2dd3cabcf4914fedaa6ea60af43a4e743
parent 71328 8c813f7586dfb85b3ac94e79da6ff65270f4027a
child 71330 e12bf65232fd7259f643ee17c98bb8dd2341e612
push id145
push usertglek@mozilla.com
push dateMon, 20 Jun 2011 21:48:28 +0000
treeherdermozilla-inbound@c70b52439e1c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMossop
bugs661574
milestone7.0a1
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
bug 661574: Implement telemetry directory r=Mossop+glandium+mwu
toolkit/components/telemetry/Makefile.in
toolkit/components/telemetry/Telemetry.cpp
toolkit/components/telemetry/Telemetry.h
toolkit/components/telemetry/TelemetryHistograms.h
toolkit/components/telemetry/TelemetryPing.js
toolkit/components/telemetry/nsITelemetry.idl
toolkit/components/telemetry/tests/unit/test_TelemetryPing.js
toolkit/components/telemetry/tests/unit/test_nsITelemetry.js
xpcom/base/Makefile.in
xpcom/base/nsCycleCollector.cpp
--- a/toolkit/components/telemetry/Makefile.in
+++ b/toolkit/components/telemetry/Makefile.in
@@ -49,16 +49,23 @@ MODULE_NAME = telemetry
 GRE_MODULE = 1
 
 LIBXUL_LIBRARY = 1
 EXPORT_LIBRARY = 1
 IS_COMPONENT = 1
 
 LIBRARY_NAME = telemetry
 
+EXPORTS_NAMESPACES = mozilla
+
+EXPORTS_mozilla = \
+  Telemetry.h \
+  TelemetryHistograms.h \
+  $(NULL)
+
 XPIDLSRCS = \
   nsITelemetry.idl \
   $(NULL)
 
 EXTRA_COMPONENTS = \
   TelemetryPing.manifest \
   TelemetryPing.js \
   $(NULL)
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -31,48 +31,134 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#define XPCOM_TRANSLATE_NSGM_ENTRY_POINT
 #include "base/histogram.h"
 #include "nsIComponentManager.h"
 #include "nsIServiceManager.h"
 #include "nsCOMPtr.h"
 #include "mozilla/ModuleUtils.h"
 #include "nsIXPConnect.h"
 #include "mozilla/Services.h"
 #include "jsapi.h" 
 #include "nsStringGlue.h"
 #include "nsITelemetry.h"
+#include "Telemetry.h" 
+#include <map>
+#include <string.h>
 
 namespace {
 
 using namespace base;
+using namespace mozilla;
+using namespace std;
 
-class Telemetry : public nsITelemetry
+struct ltstr {
+  bool operator()(const char* s1, const char* s2) const {
+    return strcmp(s1, s2) < 0;
+  }
+};
+
+class TelemetryImpl : public nsITelemetry
 {
   NS_DECL_ISUPPORTS
   NS_DECL_NSITELEMETRY
 
 public:
-  static Telemetry* GetSingleton();
+
+private:
+  // This is used to cache JS string->Telemetry::ID conversions
+  typedef map<const char*, Telemetry::ID, ltstr> NameHistogramMap;
+  NameHistogramMap mHistogramMap;
 };
 
 // A initializer to initialize histogram collection
 StatisticsRecorder gStatisticsRecorder;
 
+// Hardcoded probes
+struct TelemetryHistogram {
+  Histogram *histogram;
+  const char *id;
+  const char *name;
+  PRUint32 min;
+  PRUint32 max;
+  PRUint32 bucketCount;
+  PRUint32 histogramType;
+};
+
+const TelemetryHistogram gHistograms[] = {
+#define HISTOGRAM(id, name, min, max, bucket_count, histogram_type, b) \
+  { NULL, NS_STRINGIFY(id), name, min, max, bucket_count, nsITelemetry::HISTOGRAM_ ## histogram_type },
+
+#include "TelemetryHistograms.h"
+
+#undef HISTOGRAM
+};
+
+nsresult
+HistogramGet(const char *name, PRUint32 min, PRUint32 max, PRUint32 bucketCount,
+             PRUint32 histogramType, Histogram **result)
+{
+  if (histogramType != nsITelemetry::HISTOGRAM_BOOLEAN) {
+    // Sanity checks for histogram parameters.
+    if (min >= max)
+      return NS_ERROR_ILLEGAL_VALUE;
+
+    if (bucketCount <= 2)
+      return NS_ERROR_ILLEGAL_VALUE;
+
+    if (min < 1)
+      return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  switch (histogramType) {
+  case nsITelemetry::HISTOGRAM_EXPONENTIAL:
+    *result = Histogram::FactoryGet(name, min, max, bucketCount, Histogram::kNoFlags);
+    break;
+  case nsITelemetry::HISTOGRAM_LINEAR:
+    *result = LinearHistogram::FactoryGet(name, min, max, bucketCount, Histogram::kNoFlags);
+    break;
+  case nsITelemetry::HISTOGRAM_BOOLEAN:
+    *result = BooleanHistogram::FactoryGet(name, Histogram::kNoFlags);
+    break;
+  default:
+    return NS_ERROR_INVALID_ARG;
+  }
+  return NS_OK;
+}
+
+// O(1) histogram lookup by numeric id
+nsresult
+GetHistogramByEnumId(Telemetry::ID id, Histogram **ret)
+{
+  static Histogram* knownHistograms[Telemetry::HistogramCount] = {0};
+  Histogram *h = knownHistograms[id];
+  if (h) {
+    *ret = h;
+    return NS_OK;
+  }
+
+  const TelemetryHistogram &p = gHistograms[id];
+  nsresult rv = HistogramGet(p.name, p.min, p.max, p.bucketCount, p.histogramType, &h);
+  if (NS_FAILED(rv))
+    return NS_ERROR_FAILURE;
+
+  *ret = knownHistograms[id] = h;
+  return NS_OK;
+}
+
 bool
 FillRanges(JSContext *cx, JSObject *array, Histogram *h)
 {
-  for (size_t i = 0;i < h->bucket_count();i++) {
+  for (size_t i = 0; i < h->bucket_count(); i++) {
     if (!JS_DefineElement(cx, array, i, INT_TO_JSVAL(h->ranges(i)), NULL, NULL, JSPROP_ENUMERATE))
       return false;
   }
   return true;
 }
 
 JSBool
 ReflectHistogramSnapshot(JSContext *cx, JSObject *obj, Histogram *h)
@@ -89,17 +175,17 @@ ReflectHistogramSnapshot(JSContext *cx, 
         && (rarray = JS_NewArrayObject(cx, count, NULL))
         && JS_DefineProperty(cx, obj, "ranges", OBJECT_TO_JSVAL(rarray), NULL, NULL, JSPROP_ENUMERATE)
         && FillRanges(cx, rarray, h)
         && (counts_array = JS_NewArrayObject(cx, count, NULL))
         && JS_DefineProperty(cx, obj, "counts", OBJECT_TO_JSVAL(counts_array), NULL, NULL, JSPROP_ENUMERATE)
         )) {
     return JS_FALSE;
   }
-  for (size_t i = 0;i < count;i++) {
+  for (size_t i = 0; i < count; i++) {
     if (!JS_DefineElement(cx, counts_array, i, INT_TO_JSVAL(ss.counts(i)), NULL, NULL, JSPROP_ENUMERATE)) {
       return JS_FALSE;
     }
   }
   return JS_TRUE;
 }
 
 JSBool
@@ -108,17 +194,21 @@ JSHistogram_Add(JSContext *cx, uintN arg
   jsval *argv = JS_ARGV(cx, vp);
   JSString *str;
   if (!JS_ConvertArguments(cx, argc, argv, "i", &str))
     return JS_FALSE;
   if (!JSVAL_IS_INT(argv[0]))
     return JS_FALSE;
   JSObject *obj = JS_THIS_OBJECT(cx, vp);
   Histogram *h = static_cast<Histogram*>(JS_GetPrivate(cx, obj));
-  h->Add(JSVAL_TO_INT(argv[0]));
+  PRUint32 value = JSVAL_TO_INT(argv[0]);
+  if (h->histogram_type() == Histogram::BOOLEAN_HISTOGRAM)
+    h->Add(!!value);
+  else
+    h->Add(value);
   return JS_TRUE;
 }
 
 JSBool
 JSHistogram_Snapshot(JSContext *cx, uintN argc, jsval *vp)
 {
   JSObject *obj = JS_THIS_OBJECT(cx, vp);
   Histogram *h = static_cast<Histogram*>(JS_GetPrivate(cx, obj));
@@ -143,41 +233,29 @@ WrapAndReturnHistogram(Histogram *h, JSC
   JSObject *obj = JS_NewObject(cx, &JSHistogram_class, NULL, NULL);
   if (!obj)
     return NS_ERROR_FAILURE;
   *ret = OBJECT_TO_JSVAL(obj);
   return (JS_SetPrivate(cx, obj, h)
           && JS_DefineFunction (cx, obj, "add", JSHistogram_Add, 1, 0)
           && JS_DefineFunction (cx, obj, "snapshot", JSHistogram_Snapshot, 1, 0)) ? NS_OK : NS_ERROR_FAILURE;
 }
-  
+
 NS_IMETHODIMP
-Telemetry::NewHistogram(const nsACString &name, PRUint32 min, PRUint32 max, PRUint32 bucket_count, PRUint32 histogram_type, JSContext *cx, jsval *ret)
+TelemetryImpl::NewHistogram(const nsACString &name, PRUint32 min, PRUint32 max, PRUint32 bucketCount, PRUint32 histogramType, JSContext *cx, jsval *ret)
 {
-  // Sanity checks on histogram parameters.
-  if (min < 1)
-    return NS_ERROR_ILLEGAL_VALUE;
-
-  if (min >= max)
-    return NS_ERROR_ILLEGAL_VALUE;
-
-  if (bucket_count <= 2)
-    return NS_ERROR_ILLEGAL_VALUE;
-
   Histogram *h;
-  if (histogram_type == nsITelemetry::HISTOGRAM_EXPONENTIAL) {
-    h = Histogram::FactoryGet(name.BeginReading(), min, max, bucket_count, Histogram::kNoFlags);
-  } else {
-    h = LinearHistogram::FactoryGet(name.BeginReading(), min, max, bucket_count, Histogram::kNoFlags);
-  }
+  nsresult rv = HistogramGet(PromiseFlatCString(name).get(), min, max, bucketCount, histogramType, &h);
+  if (NS_FAILED(rv))
+    return rv;
   return WrapAndReturnHistogram(h, cx, ret);
 }
 
 NS_IMETHODIMP
-Telemetry::GetHistogramSnapshots(JSContext *cx, jsval *ret)
+TelemetryImpl::GetHistogramSnapshots(JSContext *cx, jsval *ret)
 {
   JSObject *root_obj = JS_NewObject(cx, NULL, NULL, NULL);
   if (!root_obj)
     return NS_ERROR_FAILURE;
   *ret = OBJECT_TO_JSVAL(root_obj);
 
   StatisticsRecorder::Histograms h;
   StatisticsRecorder::GetHistograms(&h);
@@ -189,56 +267,85 @@ Telemetry::GetHistogramSnapshots(JSConte
                                OBJECT_TO_JSVAL(hobj), NULL, NULL, JSPROP_ENUMERATE)
           && ReflectHistogramSnapshot(cx, hobj, h))) {
       return NS_ERROR_FAILURE;
     }
   }
   return NS_OK;
 }
 
-NS_IMPL_THREADSAFE_ISUPPORTS1(Telemetry, nsITelemetry)
-
-Telemetry *gJarHandler = nsnull;
 
-void ShutdownTelemetry()
+NS_IMETHODIMP
+TelemetryImpl::GetHistogramById(const nsACString &name, JSContext *cx, jsval *ret)
 {
-  NS_IF_RELEASE(gJarHandler);
+  // Cache names for log(N) lookup
+  // Note the histogram names are statically allocated
+  if (Telemetry::HistogramCount && !mHistogramMap.size()) {
+    for (PRUint32 i = 0; i < Telemetry::HistogramCount; i++) {
+      mHistogramMap[gHistograms[i].id] = (Telemetry::ID) i;
+    }
+  }
+
+  NameHistogramMap::iterator it = mHistogramMap.find(PromiseFlatCString(name).get());
+  if (it == mHistogramMap.end())
+    return NS_ERROR_FAILURE;
+  
+  Histogram *h;
+  nsresult rv = GetHistogramByEnumId(it->second, &h);
+  if (NS_FAILED(rv))
+    return rv;
+
+  return WrapAndReturnHistogram(h, cx, ret);
 }
 
-Telemetry* Telemetry::GetSingleton()
+NS_IMPL_THREADSAFE_ISUPPORTS1(TelemetryImpl, nsITelemetry)
+
+already_AddRefed<nsITelemetry>
+CreateTelemetryInstance()
 {
-  if (!gJarHandler) {
-    gJarHandler = new Telemetry();
-    NS_ADDREF(gJarHandler);
-  }
-  NS_ADDREF(gJarHandler);
-  return gJarHandler;
+  nsCOMPtr<nsITelemetry> telemetry = new TelemetryImpl();
+  return telemetry.forget();
 }
 
-NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(Telemetry, Telemetry::GetSingleton)
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsITelemetry, CreateTelemetryInstance)
 
 #define NS_TELEMETRY_CID \
   {0xaea477f2, 0xb3a2, 0x469c, {0xaa, 0x29, 0x0a, 0x82, 0xd1, 0x32, 0xb8, 0x29}}
 NS_DEFINE_NAMED_CID(NS_TELEMETRY_CID);
 
-const mozilla::Module::CIDEntry kTelemetryCIDs[] = {
-  { &kNS_TELEMETRY_CID, false, NULL, TelemetryConstructor },
+const Module::CIDEntry kTelemetryCIDs[] = {
+  { &kNS_TELEMETRY_CID, false, NULL, nsITelemetryConstructor },
   { NULL }
 };
 
-const mozilla::Module::ContractIDEntry kTelemetryContracts[] = {
+const Module::ContractIDEntry kTelemetryContracts[] = {
   { "@mozilla.org/base/telemetry;1", &kNS_TELEMETRY_CID },
   { NULL }
 };
 
-const mozilla::Module kTelemetryModule = {
-  mozilla::Module::kVersion,
+const Module kTelemetryModule = {
+  Module::kVersion,
   kTelemetryCIDs,
   kTelemetryContracts,
   NULL,
   NULL,
   NULL,
-  ShutdownTelemetry,
+  NULL,
 };
 
 } // anonymous namespace
 
+namespace mozilla {
+namespace Telemetry {
+
+void
+Accumulate(ID aHistogram, PRUint32 aSample)
+{
+  Histogram *h;
+  nsresult rv = GetHistogramByEnumId(aHistogram, &h);
+  if (NS_SUCCEEDED(rv))
+    h->Add(aSample);
+}
+
+} // namespace Telemetry
+} // namespace mozilla
+
 NSMODULE_DEFN(nsTelemetryModule) = &kTelemetryModule;
new file mode 100644
--- /dev/null
+++ b/toolkit/components/telemetry/Telemetry.h
@@ -0,0 +1,64 @@
+/* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Taras Glek <tglek@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef Telemetry_h__
+#define Telemetry_h__
+
+namespace mozilla {
+namespace Telemetry {
+
+enum ID {
+#define HISTOGRAM(name, a, b, c, d, e, f) name,
+
+#include "TelemetryHistograms.h"
+
+#undef HISTOGRAM
+HistogramCount
+};
+
+/**
+ * Adds sample to a histogram defined in TelemetryHistograms.h
+ *
+ * @param id - histogram id
+ * @param sample - value to record.
+ */
+void Accumulate(ID id, PRUint32 sample);
+
+} // namespace Telemetry
+} // namespace mozilla
+#endif // Telemetry_h__
new file mode 100644
--- /dev/null
+++ b/toolkit/components/telemetry/TelemetryHistograms.h
@@ -0,0 +1,50 @@
+/* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Taras Glek <tglek@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * This file lists Telemetry histograms collected by Firefox.
+ *  Format is HISTOGRAM(id, histogram name, minium, maximum, bucket count,
+ * histogram kind, human-readable description for about:telemetry)
+ */
+
+HISTOGRAM(CYCLE_COLLECTOR, "nsCycleCollector::Collect (ms)", 1, 10000, 50, EXPONENTIAL, "Time spent on cycle collection")
+HISTOGRAM(TELEMETRY_PING, "Telemetry.ping (ms)", 1, 3000, 10, EXPONENTIAL, "Telemetry submission lag")
+HISTOGRAM(TELEMETRY_SUCCESS, "Telemetry.success (No, Yes)", 0, 1, 2, BOOLEAN,  "Success rate of telemetry submissions")
+HISTOGRAM(MEMORY_JS_GC_HEAP, "Memory::explicit/js/gc-heap (MB)", 1024, 512 * 1024, 10, EXPONENTIAL, "Memory used by the JavaScript GC")
+HISTOGRAM(MEMORY_RESIDENT, "Memory::resident (MB)", 32 * 1024, 1024 * 1024, 10, EXPONENTIAL, "Resident memory reported by OS")
+HISTOGRAM(MEMORY_LAYOUT_ALL, "Memory::explicit/layout/all (MB)", 1024, 64 * 1024, 10, EXPONENTIAL, "Memory reported used by layout")
--- a/toolkit/components/telemetry/TelemetryPing.js
+++ b/toolkit/components/telemetry/TelemetryPing.js
@@ -49,19 +49,19 @@ const PAYLOAD_VERSION = 1;
 const PREF_SERVER = "toolkit.telemetry.server";
 const PREF_ENABLED = "toolkit.telemetry.enabled";
 // Do not gather data more than once a minute
 const TELEMETRY_INTERVAL = 60;
 // Delay before intializing telemetry (ms)
 const TELEMETRY_DELAY = 60000;
 // about:memory values to turn into histograms
 const MEM_HISTOGRAMS = {
-  "explicit/js/gc-heap": [1024, 512 * 1024, 10],
-  "resident": [32 * 1024, 1024 * 1024, 10],
-  "explicit/layout/all": [1024, 64 * 1025, 10]
+  "explicit/js/gc-heap": "MEMORY_JS_GC_HEAP",
+  "resident": "MEMORY_RESIDENT",
+  "explicit/layout/all": "MEMORY_LAYOUT_ALL"
 };
 
 XPCOMUtils.defineLazyGetter(this, "Telemetry", function () {
   return Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
 });
 
 /**
  * Returns a set of histograms that can be converted into JSON
@@ -195,25 +195,25 @@ TelemetryPing.prototype = {
       return
     }
 
     let e = mgr.enumerateReporters();
     let memReporters = {};
     while (e.hasMoreElements()) {
       let mr = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
       //  memReporters[mr.path] = mr.memoryUsed;
-      let specs = MEM_HISTOGRAMS[mr.path];
-      if (!specs) {
+      let id = MEM_HISTOGRAMS[mr.path];
+      if (!id) {
         continue;
       }
 
       let name = "Memory:" + mr.path + " (KB)";
       let h = this._histograms[name];
       if (!h) {
-        h = Telemetry.newHistogram(name, specs[0], specs[1], specs[2], Telemetry.HISTOGRAM_EXPONENTIAL);
+        h = Telemetry.getHistogramById(id);
         this._histograms[name] = h;
       }
       let v = Math.floor(mr.memoryUsed / 1024);
       h.add(v);
     }
     return memReporters;
   },
   
@@ -234,36 +234,36 @@ TelemetryPing.prototype = {
     // Generate a unique id once per session so the server can cope with duplicate submissions.
     // Use a deterministic url for testing.
     if (!this._path)
       this._path = "/submit/telemetry/" + (isTestPing ? reason : generateUUID());
     
     const TELEMETRY_PING = "telemetry.ping (ms)";
     const TELEMETRY_SUCCESS = "telemetry.success (No, Yes)";
 
-    let hping = Telemetry.newHistogram(TELEMETRY_PING, 1, 3000, 10, Telemetry.HISTOGRAM_EXPONENTIAL);
-    let hsuccess = Telemetry.newHistogram(TELEMETRY_SUCCESS, 1, 2, 3, Telemetry.HISTOGRAM_LINEAR);
+    let hping = Telemetry.getHistogramById("TELEMETRY_PING");
+    let hsuccess = Telemetry.getHistogramById("TELEMETRY_SUCCESS");
 
     let url = server + this._path;
     let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
                   .createInstance(Ci.nsIXMLHttpRequest);
     request.mozBackgroundRequest = true;
     request.open("POST", url, true);
     request.overrideMimeType("text/plain");
 
     let startTime = new Date()
 
     function finishRequest(success_metric) {
       hsuccess.add(success_metric);
       hping.add(new Date() - startTime);
       if (isTestPing)
         Services.obs.notifyObservers(null, "telemetry-test-xhr-complete", null);
     }
-    request.onerror = function(aEvent) finishRequest(1);
-    request.onload = function(aEvent) finishRequest(2);
+    request.onerror = function(aEvent) finishRequest(0);
+    request.onload = function(aEvent) finishRequest(1);
     request.send(nativeJSON.encode(payload));
   },
   
   /**
    * Initializes telemetry within a timer. If there is no PREF_SERVER set, don't turn on telemetry.
    */
   setup: function setup() {
     let enabled = false; 
--- a/toolkit/components/telemetry/nsITelemetry.idl
+++ b/toolkit/components/telemetry/nsITelemetry.idl
@@ -33,26 +33,28 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(29464d3d-f838-4afb-a737-319fe0c6cc04)]
+[scriptable, uuid(db854295-478d-4de9-8211-d73ed7d81cd0)]
 interface nsITelemetry : nsISupports
 {
   /**
    * Histogram types:
    * HISTOGRAM_EXPONENTIAL - buckets increase exponentially
    * HISTOGRAM_LINEAR - buckets increase linearly
+   * HISTOGRAM_BOOLEAN - For storing 0/1 values
    */
   const unsigned long HISTOGRAM_EXPONENTIAL = 0;
   const unsigned long HISTOGRAM_LINEAR = 1;
+  const unsigned long HISTOGRAM_BOOLEAN = 2;
 
   /*
    * An object containing a snapshot from all of the currently registered histograms.
    * { name1: {data1}, name2:{data2}...}
    * where data is consists of the following properties:
    *   min - Minimal bucket size
    *   max - Maximum bucket size
    *   histogram_type - HISTOGRAM_EXPONENTIAL or HISTOGRAM_LINEAR
@@ -60,20 +62,29 @@ interface nsITelemetry : nsISupports
    *   ranges -  an array with calculated bucket sizes
    *   sum - sum of the bucket contents
    */
   [implicit_jscontext]
   readonly attribute jsval histogramSnapshots;
 
   /** 
    * Create and return a histogram where bucket sizes increase exponentially. Parameters:
+   *
    * @param name Unique histogram name
    * @param min - Minimal bucket size
    * @param max - Maximum bucket size
    * @param bucket_count - number of buckets in the histogram.
    * @param type - HISTOGRAM_EXPONENTIAL or HISTOGRAM_LINEAR
    * The returned object has the following functions:
    *   add(int) - Adds an int value to the appropriate bucket
    *   snapshot() - Returns a snapshot of the histogram with the same data fields as in histogramSnapshots()
    */
   [implicit_jscontext]
   jsval newHistogram(in ACString name, in PRUint32 min, in PRUint32 max, in PRUint32 bucket_count, in unsigned long histogram_type);
+
+  /**
+   * Same as newHistogram above, but for histograms registered in TelemetryHistograms.h.
+   *
+   * @param id - unique identifier from TelemetryHistograms.h
+   */
+  [implicit_jscontext]
+  jsval getHistogramById(in ACString id);
 };
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js
@@ -67,26 +67,26 @@ function checkHistograms(request, respon
     appBuildID: "2007010101",
     platformBuildID: "2007010101"
   };
 
   for (let f in expected_info) {
     do_check_eq(payload.info[f], expected_info[f]);
   }
 
-  const TELEMETRY_PING = "telemetry.ping (ms)";
-  const TELEMETRY_SUCCESS = "telemetry.success (No, Yes)";
+  const TELEMETRY_PING = "Telemetry.ping (ms)";
+  const TELEMETRY_SUCCESS = "Telemetry.success (No, Yes)";
   do_check_true(TELEMETRY_PING in payload.histograms)
 
   // There should be one successful report from the previos telemetry ping
   const expected_tc = {
     range: [1, 2],
     bucket_count: 3,
-    histogram_type: 1,
-    values: {1:0, 2:1}
+    histogram_type: 2,
+    values: {0:0, 1:1, 2:0}
   }
   let tc = payload.histograms[TELEMETRY_SUCCESS]
   do_check_eq(uneval(tc), 
               uneval(expected_tc));
 }
 
 // copied from toolkit/mozapps/extensions/test/xpcshell/head_addons.js
 const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
--- a/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js
+++ b/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js
@@ -37,20 +37,56 @@ function expect_fail(f) {
     f();
     failed = false;
   } catch (e) {
     failed = true;
   }
   do_check_true(failed);
 }
 
+function test_boolean_histogram()
+{
+  var h = Telemetry.newHistogram("test::boolean histogram", 99,1,4, Telemetry.HISTOGRAM_BOOLEAN);
+  var r = h.snapshot().ranges;
+  // boolean histograms ignore numeric parameters
+  do_check_eq(uneval(r), uneval([0, 1, 2]))
+  var sum = 0
+  for(var i=0;i<r.length;i++) {
+    var v = r[i];
+    sum += v;
+    h.add(v);
+  }
+  var s = h.snapshot();
+  do_check_eq(s.histogram_type, Telemetry.HISTOGRAM_BOOLEAN);
+  // last bucket should always be 0 since .add parameters are normalized to either 0 or 1
+  do_check_eq(s.counts[2],0);
+  do_check_eq(s.sum, 2);
+}
+
+function test_getHistogramById() {
+  try {
+    Telemetry.getHistogramById("nonexistent");
+    do_throw("This can't happen");
+  } catch (e) {
+    
+  }
+  var h = Telemetry.getHistogramById("CYCLE_COLLECTOR");
+  var s = h.snapshot();
+  do_check_eq(s.histogram_type, Telemetry.HISTOGRAM_EXPONENTIAL);
+  do_check_eq(s.min, 1);
+  do_check_eq(s.max, 10000);
+}
+
 function run_test()
 {
   let kinds = [Telemetry.HISTOGRAM_EXPONENTIAL, Telemetry.HISTOGRAM_LINEAR]
   for each (let histogram_type in kinds) {
     let [min, max, bucket_count] = [1, 10000, 10]
     test_histogram(histogram_type, "test::"+histogram_type, min, max, bucket_count);
     
     const nh = Telemetry.newHistogram;
     expect_fail(function () nh("test::min", 0, max, bucket_count, histogram_type));
     expect_fail(function () nh("test::bucket_count", min, max, 1, histogram_type));
   }
+
+  test_boolean_histogram();
+  test_getHistogramById();
 }
--- a/xpcom/base/Makefile.in
+++ b/xpcom/base/Makefile.in
@@ -146,18 +146,16 @@ XPIDLSRCS	+= nsIMacUtils.idl
 endif
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 # Force use of PIC
 FORCE_USE_PIC	= 1
 
-include $(topsrcdir)/config/config.mk
-include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 DEFINES		+= -D_IMPL_NS_COM
 
 ifneq (,$(filter gtk2,$(MOZ_WIDGET_TOOLKIT)))
 CXXFLAGS        += $(MOZ_GTK2_CFLAGS)
 endif
 
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -120,17 +120,16 @@
 
 #if !defined(__MINGW32__)
 #ifdef WIN32
 #include <crtdbg.h>
 #include <errno.h>
 #endif
 #endif
 
-#include "base/basictypes.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCycleCollectorUtils.h"
 #include "nsIProgrammingLanguage.h"
 #include "nsBaseHashtable.h"
 #include "nsHashKeys.h"
 #include "nsDeque.h"
 #include "nsCycleCollector.h"
 #include "nsThreadUtils.h"
@@ -147,31 +146,30 @@
 #include "nsThreadUtils.h"
 #include "nsTPtrArray.h"
 #include "nsTArray.h"
 #include "mozilla/Services.h"
 #include "nsICycleCollectorListener.h"
 #include "nsIXPConnect.h"
 #include "nsIJSRuntimeService.h"
 #include "xpcpublic.h"
-#include "base/histogram.h"
-#include "base/logging.h"
 #include <stdio.h>
 #include <string.h>
 #ifdef WIN32
 #include <io.h>
 #include <process.h>
 #endif
 
 #ifdef XP_WIN
 #include <windows.h>
 #endif
 
 #include "mozilla/Mutex.h"
 #include "mozilla/CondVar.h"
+#include "mozilla/Telemetry.h"
 
 using namespace mozilla;
 
 //#define COLLECT_TIME_DEBUG
 
 #ifdef DEBUG_CC
 #define IF_DEBUG_CC_PARAM(_p) , _p
 #define IF_DEBUG_CC_ONLY_PARAM(_p) _p
@@ -2571,18 +2569,17 @@ nsCycleCollector::CleanupAfterCollection
     // possible.
     _heapmin();
 #endif
 
     PRUint32 interval((TimeStamp::Now() - mCollectionStart).ToMilliseconds());
 #ifdef COLLECT_TIME_DEBUG
     printf("cc: CleanupAfterCollection(), total time %ums\n", interval);
 #endif
-    UMA_HISTOGRAM_TIMES("nsCycleCollector::Collect (ms)",
-                        base::TimeDelta::FromMilliseconds(interval));
+    Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR, interval);
 
 #ifdef DEBUG_CC
     ExplainLiveExpectedGarbage();
 #endif
 }
 
 PRUint32
 nsCycleCollector::Collect(PRUint32 aTryCollections,