Bug 1476609 - Add display labels for categorical keyed histograms - r=chutten
authorArash Fotouhi <arash9k@gmail.com>
Thu, 11 Jun 2020 17:38:12 +0000
changeset 535172 a1381c5099e132ffaaee1351b7e874acdbd2b51d
parent 535171 2de8589705628bf36f53ef52eee501602e5ccea5
child 535173 b4b75948f7ddb3e7e834dfaa504ac2240f36b49a
push id118782
push userchutten@mozilla.com
push dateThu, 11 Jun 2020 19:21:57 +0000
treeherderautoland@a1381c5099e1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerschutten
bugs1476609
milestone79.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 1476609 - Add display labels for categorical keyed histograms - r=chutten Differential Revision: https://phabricator.services.mozilla.com/D73002
toolkit/components/telemetry/core/Telemetry.cpp
toolkit/components/telemetry/core/TelemetryHistogram.cpp
toolkit/components/telemetry/core/TelemetryHistogram.h
toolkit/components/telemetry/core/nsITelemetry.idl
toolkit/components/telemetry/tests/unit/test_TelemetryHistograms.js
--- a/toolkit/components/telemetry/core/Telemetry.cpp
+++ b/toolkit/components/telemetry/core/Telemetry.cpp
@@ -617,16 +617,22 @@ TelemetryImpl::GetSnapshotForKeyedHistog
                              ? nsITelemetry::DATASET_PRERELEASE_CHANNELS
                              : nsITelemetry::DATASET_ALL_CHANNELS;
   return TelemetryHistogram::GetKeyedHistogramSnapshots(
       aCx, aResult, aStoreName.IsVoid() ? defaultStore : aStoreName, dataset,
       aClearStore, aFilterTest);
 }
 
 NS_IMETHODIMP
+TelemetryImpl::GetCategoricalLabels(JSContext* aCx,
+                                    JS::MutableHandleValue aResult) {
+  return TelemetryHistogram::GetCategoricalHistogramLabels(aCx, aResult);
+}
+
+NS_IMETHODIMP
 TelemetryImpl::GetSnapshotForScalars(const nsACString& aStoreName,
                                      bool aClearStore, bool aFilterTest,
                                      JSContext* aCx,
                                      JS::MutableHandleValue aResult) {
   NS_NAMED_LITERAL_CSTRING(defaultStore, "main");
   unsigned int dataset = mCanRecordExtended
                              ? nsITelemetry::DATASET_PRERELEASE_CHANNELS
                              : nsITelemetry::DATASET_ALL_CHANNELS;
--- a/toolkit/components/telemetry/core/TelemetryHistogram.cpp
+++ b/toolkit/components/telemetry/core/TelemetryHistogram.cpp
@@ -2767,16 +2767,54 @@ nsresult TelemetryHistogram::GetAllStore
     store.AssignASCII(name);
     if (!set.PutEntry(store)) {
       return NS_ERROR_FAILURE;
     }
   }
   return NS_OK;
 }
 
+nsresult TelemetryHistogram::GetCategoricalHistogramLabels(
+    JSContext* aCx, JS::MutableHandle<JS::Value> aResult) {
+  JS::Rooted<JSObject*> root_obj(aCx, JS_NewPlainObject(aCx));
+  if (!root_obj) {
+    return NS_ERROR_FAILURE;
+  }
+  aResult.setObject(*root_obj);
+
+  for (const HistogramInfo& info : gHistogramInfos) {
+    if (info.histogramType != nsITelemetry::HISTOGRAM_CATEGORICAL) {
+      continue;
+    }
+
+    const char* name = info.name();
+    JS::RootedObject labels(aCx, JS::NewArrayObject(aCx, info.label_count));
+    if (!labels) {
+      return NS_ERROR_FAILURE;
+    }
+
+    if (!JS_DefineProperty(aCx, root_obj, name, labels, JSPROP_ENUMERATE)) {
+      return NS_ERROR_FAILURE;
+    }
+
+    for (uint32_t i = 0; i < info.label_count; ++i) {
+      uint32_t string_offset = gHistogramLabelTable[info.label_index + i];
+      const char* const label = &gHistogramStringTable[string_offset];
+      auto clabel = NS_ConvertASCIItoUTF16(label);
+      JS::Rooted<JS::Value> value(aCx);
+      value.setString(ToJSString(aCx, clabel));
+      if (!JS_DefineElement(aCx, labels, i, value, JSPROP_ENUMERATE)) {
+        return NS_ERROR_FAILURE;
+      }
+    }
+  }
+
+  return NS_OK;
+}
+
 nsresult TelemetryHistogram::GetHistogramById(
     const nsACString& name, JSContext* cx, JS::MutableHandle<JS::Value> ret) {
   HistogramID id;
   {
     StaticMutexAutoLock locker(gTelemetryHistogramMutex);
     nsresult rv = internal_GetHistogramIdByName(locker, name, &id);
     if (NS_FAILED(rv)) {
       return NS_ERROR_FAILURE;
--- a/toolkit/components/telemetry/core/TelemetryHistogram.h
+++ b/toolkit/components/telemetry/core/TelemetryHistogram.h
@@ -79,16 +79,19 @@ void AccumulateChildKeyed(
     const nsTArray<mozilla::Telemetry::KeyedHistogramAccumulation>&
         aAccumulations);
 
 /**
  * Append the list of registered stores to the given set.
  */
 nsresult GetAllStores(mozilla::Telemetry::Common::StringHashSet& set);
 
+nsresult GetCategoricalHistogramLabels(JSContext* aCx,
+                                       JS::MutableHandle<JS::Value> aResult);
+
 nsresult GetHistogramById(const nsACString& name, JSContext* cx,
                           JS::MutableHandle<JS::Value> ret);
 
 nsresult GetKeyedHistogramById(const nsACString& name, JSContext* cx,
                                JS::MutableHandle<JS::Value> ret);
 
 const char* GetHistogramName(mozilla::Telemetry::HistogramID id);
 
--- a/toolkit/components/telemetry/core/nsITelemetry.idl
+++ b/toolkit/components/telemetry/core/nsITelemetry.idl
@@ -45,16 +45,28 @@ interface nsITelemetry : nsISupports
    * Dataset types:
    * DATASET_ALL_CHANNELS - the basic dataset that is on-by-default on all channels
    * DATASET_PRERELEASE_CHANNELS - the extended dataset that is opt-in on release,
    *                                 opt-out on pre-release channels.
    */
   const unsigned long DATASET_ALL_CHANNELS = 0;
   const unsigned long DATASET_PRERELEASE_CHANNELS = 1;
 
+  /**
+   * Serializes the histogram labels for categorical hitograms.
+   * The returned structure looks like:
+   *   { "histogram1": [ "histogram1_label1", "histogram1_label2", ...],
+   *     "histogram2": [ "histogram2_label1", "histogram2_label2", ...]
+   *     ...
+   *     }
+   *
+   * Note that this function should only be used in tests and about:telemetry.
+   */
+  [implicit_jscontext]
+  jsval getCategoricalLabels();
 
   /**
    * Serializes the histograms from the given store to a JSON-style object.
    * The returned structure looks like:
    *   { "process": { "name1": histogramData1, "name2": histogramData2 }, ... }
    *
    * Each histogram is represented in a packed format and has the following properties:
    *   bucket_count - Number of buckets of this histogram
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryHistograms.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryHistograms.js
@@ -264,16 +264,42 @@ add_task(async function test_categorical
   }
 
   snapshot = h3.snapshot();
   Assert.equal(snapshot.sum, 3);
   Assert.deepEqual(snapshot.range, [1, 70]);
   Assert.deepEqual(snapshot.values, { 0: 1, 1: 1, 2: 1, 3: 0 });
 });
 
+add_task(async function test_getCategoricalLabels() {
+  let h = Telemetry.getCategoricalLabels();
+
+  Assert.deepEqual(h.TELEMETRY_TEST_CATEGORICAL, [
+    "CommonLabel",
+    "Label2",
+    "Label3",
+  ]);
+  Assert.deepEqual(h.TELEMETRY_TEST_CATEGORICAL_OPTOUT, [
+    "CommonLabel",
+    "Label4",
+    "Label5",
+    "Label6",
+  ]);
+  Assert.deepEqual(h.TELEMETRY_TEST_CATEGORICAL_NVALUES, [
+    "CommonLabel",
+    "Label7",
+    "Label8",
+  ]);
+  Assert.deepEqual(h.TELEMETRY_TEST_KEYED_CATEGORICAL, [
+    "CommonLabel",
+    "Label2",
+    "Label3",
+  ]);
+});
+
 add_task(async function test_add_error_behaviour() {
   const PLAIN_HISTOGRAMS_TO_TEST = [
     "TELEMETRY_TEST_FLAG",
     "TELEMETRY_TEST_EXPONENTIAL",
     "TELEMETRY_TEST_LINEAR",
     "TELEMETRY_TEST_BOOLEAN",
   ];