summaryrefslogtreecommitdiffstats
path: root/toolkit/components/telemetry/core/TelemetryHistogram.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/telemetry/core/TelemetryHistogram.cpp')
-rw-r--r--toolkit/components/telemetry/core/TelemetryHistogram.cpp647
1 files changed, 0 insertions, 647 deletions
diff --git a/toolkit/components/telemetry/core/TelemetryHistogram.cpp b/toolkit/components/telemetry/core/TelemetryHistogram.cpp
index 88ac88eb9e..0ba7009d51 100644
--- a/toolkit/components/telemetry/core/TelemetryHistogram.cpp
+++ b/toolkit/components/telemetry/core/TelemetryHistogram.cpp
@@ -8,7 +8,6 @@
#include <limits>
#include "base/histogram.h"
-#include "geckoview/streaming/GeckoViewStreamingTelemetry.h"
#include "ipc/TelemetryIPCAccumulator.h"
#include "jsapi.h"
#include "jsfriendapi.h"
@@ -700,15 +699,6 @@ nsresult internal_HistogramAdd(const StaticMutexAutoLock& aLock,
return NS_OK;
}
- if (&histogram != gExpiredHistogram &&
- GetCurrentProduct() == SupportedProduct::GeckoviewStreaming) {
- const HistogramInfo& info = gHistogramInfos[id];
- GeckoViewStreamingTelemetry::HistogramAccumulate(
- nsDependentCString(info.name()),
- info.histogramType == nsITelemetry::HISTOGRAM_CATEGORICAL, value);
- return NS_OK;
- }
-
// The internal representation of a base::Histogram's buckets uses `int`.
// Clamp large values of `value` to be INT_MAX so they continue to be treated
// as large values (instead of negative ones).
@@ -3038,640 +3028,3 @@ size_t TelemetryHistogram::GetHistogramSizesOfIncludingThis(
return n;
}
-
-////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////
-//
-// PRIVATE: GeckoView specific helpers
-
-namespace base {
-class PersistedSampleSet : public base::Histogram::SampleSet {
- public:
- explicit PersistedSampleSet(const nsTArray<base::Histogram::Count>& aCounts,
- int64_t aSampleSum);
-};
-
-PersistedSampleSet::PersistedSampleSet(
- const nsTArray<base::Histogram::Count>& aCounts, int64_t aSampleSum) {
- // Initialize the data in the base class. See Histogram::SampleSet
- // for the fields documentation.
- const size_t numCounts = aCounts.Length();
- counts_.SetLength(numCounts);
-
- for (size_t i = 0; i < numCounts; i++) {
- counts_[i] = aCounts[i];
- redundant_count_ += aCounts[i];
- }
- sum_ = aSampleSum;
-};
-} // namespace base
-
-namespace {
-/**
- * Helper function to write histogram properties to JSON.
- * Please note that this needs to be called between
- * StartObjectProperty/EndObject calls that mark the histogram's
- * JSON creation.
- */
-void internal_ReflectHistogramToJSON(const HistogramSnapshotData& aSnapshot,
- mozilla::JSONWriter& aWriter) {
- aWriter.IntProperty("sum", aSnapshot.mSampleSum);
-
- // Fill the "counts" property.
- aWriter.StartArrayProperty("counts");
- for (size_t i = 0; i < aSnapshot.mBucketCounts.Length(); i++) {
- aWriter.IntElement(aSnapshot.mBucketCounts[i]);
- }
- aWriter.EndArray();
-}
-
-bool internal_CanRecordHistogram(const HistogramID id, ProcessID aProcessType) {
- // Check if we are allowed to record the data.
- if (!CanRecordDataset(gHistogramInfos[id].dataset, internal_CanRecordBase(),
- internal_CanRecordExtended())) {
- return false;
- }
-
- // Check if we're allowed to record in the given process.
- if (aProcessType == ProcessID::Parent && !internal_IsRecordingEnabled(id)) {
- return false;
- }
-
- if (aProcessType != ProcessID::Parent &&
- !CanRecordInProcess(gHistogramInfos[id].record_in_processes,
- aProcessType)) {
- return false;
- }
-
- // Don't record if the current platform is not enabled
- if (!CanRecordProduct(gHistogramInfos[id].products)) {
- return false;
- }
-
- return true;
-}
-
-nsresult internal_ParseHistogramData(
- JSContext* aCx, JS::Handle<JS::PropertyKey> aEntryId,
- JS::Handle<JSObject*> aContainerObj, nsACString& aOutName,
- nsTArray<base::Histogram::Count>& aOutCountArray, int64_t& aOutSum) {
- // Get the histogram name.
- nsAutoJSString histogramName;
- if (!histogramName.init(aCx, aEntryId)) {
- JS_ClearPendingException(aCx);
- return NS_ERROR_FAILURE;
- }
-
- CopyUTF16toUTF8(histogramName, aOutName);
-
- // Get the data for this histogram.
- JS::Rooted<JS::Value> histogramData(aCx);
- if (!JS_GetPropertyById(aCx, aContainerObj, aEntryId, &histogramData)) {
- JS_ClearPendingException(aCx);
- return NS_ERROR_FAILURE;
- }
-
- if (!histogramData.isObject()) {
- // base::Histogram data need to be an object. If that's not the case, skip
- // it and try to load the rest of the data.
- return NS_ERROR_FAILURE;
- }
-
- // Get the "sum" property.
- JS::Rooted<JS::Value> sumValue(aCx);
- JS::Rooted<JSObject*> histogramObj(aCx, &histogramData.toObject());
- if (!JS_GetProperty(aCx, histogramObj, "sum", &sumValue)) {
- JS_ClearPendingException(aCx);
- return NS_ERROR_FAILURE;
- }
-
- if (!JS::ToInt64(aCx, sumValue, &aOutSum)) {
- JS_ClearPendingException(aCx);
- return NS_ERROR_FAILURE;
- }
-
- // Get the "counts" array.
- JS::Rooted<JS::Value> countsArray(aCx);
- bool countsIsArray = false;
- if (!JS_GetProperty(aCx, histogramObj, "counts", &countsArray) ||
- !JS::IsArrayObject(aCx, countsArray, &countsIsArray)) {
- JS_ClearPendingException(aCx);
- return NS_ERROR_FAILURE;
- }
-
- if (!countsIsArray) {
- // The "counts" property needs to be an array. If this is not the case,
- // skip this histogram.
- return NS_ERROR_FAILURE;
- }
-
- // Get the length of the array.
- uint32_t countsLen = 0;
- JS::Rooted<JSObject*> countsArrayObj(aCx, &countsArray.toObject());
- if (!JS::GetArrayLength(aCx, countsArrayObj, &countsLen)) {
- JS_ClearPendingException(aCx);
- return NS_ERROR_FAILURE;
- }
-
- // Parse the "counts" in the array.
- for (uint32_t arrayIdx = 0; arrayIdx < countsLen; arrayIdx++) {
- JS::Rooted<JS::Value> elementValue(aCx);
- int countAsInt = 0;
- if (!JS_GetElement(aCx, countsArrayObj, arrayIdx, &elementValue) ||
- !JS::ToInt32(aCx, elementValue, &countAsInt)) {
- JS_ClearPendingException(aCx);
- return NS_ERROR_FAILURE;
- }
- aOutCountArray.AppendElement(countAsInt);
- }
-
- return NS_OK;
-}
-
-} // Anonymous namespace
-
-////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////
-//
-// PUBLIC: GeckoView serialization/deserialization functions.
-
-nsresult TelemetryHistogram::SerializeHistograms(mozilla::JSONWriter& aWriter) {
- MOZ_ASSERT(XRE_IsParentProcess(),
- "Only save histograms in the parent process");
- if (!XRE_IsParentProcess()) {
- return NS_ERROR_FAILURE;
- }
-
- // Include the GPU process in histogram snapshots only if we actually tried
- // to launch a process for it.
- bool includeGPUProcess = internal_AttemptedGPUProcess();
-
- // Take a snapshot of the histograms.
- HistogramProcessSnapshotsArray processHistArray;
- {
- StaticMutexAutoLock locker(gTelemetryHistogramMutex);
- // We always request the "opt-in"/"prerelease" dataset: we internally
- // record the right subset, so this will only return "prerelease" if
- // it was recorded.
- if (NS_FAILED(internal_GetHistogramsSnapshot(
- locker, "main"_ns, nsITelemetry::DATASET_PRERELEASE_CHANNELS,
- false /* aClearSubsession */, includeGPUProcess,
- false /* aFilterTest */, processHistArray))) {
- return NS_ERROR_FAILURE;
- }
- }
-
- // Make the JSON calls on the stashed histograms for every process
- for (uint32_t process = 0; process < processHistArray.length(); ++process) {
- aWriter.StartObjectProperty(
- mozilla::MakeStringSpan(GetNameForProcessID(ProcessID(process))));
-
- for (const HistogramSnapshotInfo& hData : processHistArray[process]) {
- HistogramID id = hData.histogramID;
-
- aWriter.StartObjectProperty(
- mozilla::MakeStringSpan(gHistogramInfos[id].name()));
- internal_ReflectHistogramToJSON(hData.data, aWriter);
- aWriter.EndObject();
- }
- aWriter.EndObject();
- }
-
- return NS_OK;
-}
-
-nsresult TelemetryHistogram::SerializeKeyedHistograms(
- mozilla::JSONWriter& aWriter) {
- MOZ_ASSERT(XRE_IsParentProcess(),
- "Only save keyed histograms in the parent process");
- if (!XRE_IsParentProcess()) {
- return NS_ERROR_FAILURE;
- }
-
- // Include the GPU process in histogram snapshots only if we actually tried
- // to launch a process for it.
- bool includeGPUProcess = internal_AttemptedGPUProcess();
-
- // Take a snapshot of the keyed histograms.
- KeyedHistogramProcessSnapshotsArray processHistArray;
- {
- StaticMutexAutoLock locker(gTelemetryHistogramMutex);
- // We always request the "opt-in"/"prerelease" dataset: we internally
- // record the right subset, so this will only return "prerelease" if
- // it was recorded.
- if (NS_FAILED(internal_GetKeyedHistogramsSnapshot(
- locker, "main"_ns, nsITelemetry::DATASET_PRERELEASE_CHANNELS,
- false /* aClearSubsession */, includeGPUProcess,
- false /* aFilterTest */, processHistArray))) {
- return NS_ERROR_FAILURE;
- }
- }
-
- // Serialize the keyed histograms for every process.
- for (uint32_t process = 0; process < processHistArray.length(); ++process) {
- aWriter.StartObjectProperty(
- mozilla::MakeStringSpan(GetNameForProcessID(ProcessID(process))));
-
- const KeyedHistogramSnapshotsArray& hArray = processHistArray[process];
- for (size_t i = 0; i < hArray.length(); ++i) {
- const KeyedHistogramSnapshotInfo& hData = hArray[i];
- HistogramID id = hData.histogramId;
- const HistogramInfo& info = gHistogramInfos[id];
-
- aWriter.StartObjectProperty(mozilla::MakeStringSpan(info.name()));
-
- // Each key is a new object with a "sum" and a "counts" property.
- for (const auto& entry : hData.data) {
- const HistogramSnapshotData& keyData = entry.GetData();
- aWriter.StartObjectProperty(PromiseFlatCString(entry.GetKey()));
- internal_ReflectHistogramToJSON(keyData, aWriter);
- aWriter.EndObject();
- }
-
- aWriter.EndObject();
- }
- aWriter.EndObject();
- }
-
- return NS_OK;
-}
-
-nsresult TelemetryHistogram::DeserializeHistograms(
- JSContext* aCx, JS::Handle<JS::Value> aData) {
- MOZ_ASSERT(XRE_IsParentProcess(),
- "Only load histograms in the parent process");
- if (!XRE_IsParentProcess()) {
- return NS_ERROR_FAILURE;
- }
-
- // Telemetry is disabled. This should never happen, but let's leave this check
- // for consistency with other histogram updates routines.
- if (!internal_CanRecordBase()) {
- return NS_OK;
- }
-
- typedef std::tuple<nsCString, nsTArray<base::Histogram::Count>, int64_t>
- PersistedHistogramTuple;
- typedef mozilla::Vector<PersistedHistogramTuple> PersistedHistogramArray;
- typedef mozilla::Vector<PersistedHistogramArray> PersistedHistogramStorage;
-
- // Before updating the histograms, we need to get the data out of the JS
- // wrappers. We can't hold the histogram mutex while handling JS stuff.
- // Build a <histogram name, value> map.
- JS::Rooted<JSObject*> histogramDataObj(aCx, &aData.toObject());
- JS::Rooted<JS::IdVector> processes(aCx, JS::IdVector(aCx));
- if (!JS_Enumerate(aCx, histogramDataObj, &processes)) {
- // We can't even enumerate the processes in the loaded data, so
- // there is nothing we could recover from the persistence file. Bail out.
- JS_ClearPendingException(aCx);
- return NS_ERROR_FAILURE;
- }
-
- // Make sure we have enough storage for all the processes.
- PersistedHistogramStorage histogramsToUpdate;
- if (!histogramsToUpdate.resize(static_cast<uint32_t>(ProcessID::Count))) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
-
- // The following block of code attempts to extract as much data as possible
- // from the serialized JSON, even in case of light data corruptions: if, for
- // example, the data for a single process is corrupted or is in an unexpected
- // form, we press on and attempt to load the data for the other processes.
- JS::Rooted<JS::PropertyKey> process(aCx);
- for (auto& processVal : processes) {
- // This is required as JS API calls require an Handle<jsid> and not a
- // plain jsid.
- process = processVal;
- // Get the process name.
- nsAutoJSString processNameJS;
- if (!processNameJS.init(aCx, process)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- // Make sure it's valid. Note that this is safe to call outside
- // of a locked section.
- NS_ConvertUTF16toUTF8 processName(processNameJS);
- ProcessID processID = GetIDForProcessName(processName.get());
- if (processID == ProcessID::Count) {
- NS_WARNING(
- nsPrintfCString("Failed to get process ID for %s", processName.get())
- .get());
- continue;
- }
-
- // And its probes.
- JS::Rooted<JS::Value> processData(aCx);
- if (!JS_GetPropertyById(aCx, histogramDataObj, process, &processData)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- if (!processData.isObject()) {
- // |processData| should be an object containing histograms. If this is
- // not the case, silently skip and try to load the data for the other
- // processes.
- continue;
- }
-
- // Iterate through each histogram.
- JS::Rooted<JSObject*> processDataObj(aCx, &processData.toObject());
- JS::Rooted<JS::IdVector> histograms(aCx, JS::IdVector(aCx));
- if (!JS_Enumerate(aCx, processDataObj, &histograms)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- // Get a reference to the deserialized data for this process.
- PersistedHistogramArray& deserializedProcessData =
- histogramsToUpdate[static_cast<uint32_t>(processID)];
-
- JS::Rooted<JS::PropertyKey> histogram(aCx);
- for (auto& histogramVal : histograms) {
- histogram = histogramVal;
-
- int64_t sum = 0;
- nsTArray<base::Histogram::Count> deserializedCounts;
- nsCString histogramName;
- if (NS_FAILED(internal_ParseHistogramData(aCx, histogram, processDataObj,
- histogramName,
- deserializedCounts, sum))) {
- continue;
- }
-
- // Finally append the deserialized data to the storage.
- if (!deserializedProcessData.emplaceBack(std::make_tuple(
- std::move(histogramName), std::move(deserializedCounts), sum))) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- }
- }
-
- // Update the histogram storage.
- {
- StaticMutexAutoLock locker(gTelemetryHistogramMutex);
-
- for (uint32_t process = 0; process < histogramsToUpdate.length();
- ++process) {
- PersistedHistogramArray& processArray = histogramsToUpdate[process];
-
- for (auto& histogramData : processArray) {
- // Attempt to get the corresponding ID for the deserialized histogram
- // name.
- HistogramID id;
- if (NS_FAILED(internal_GetHistogramIdByName(
- locker, std::get<0>(histogramData), &id))) {
- continue;
- }
-
- ProcessID procID = static_cast<ProcessID>(process);
- if (!internal_CanRecordHistogram(id, procID)) {
- // We're not allowed to record this, so don't try to restore it.
- continue;
- }
-
- // Get the Histogram instance: this will instantiate it if it doesn't
- // exist.
- Histogram* w = internal_GetHistogramById(locker, id, procID);
- MOZ_ASSERT(w);
-
- if (!w || w->IsExpired()) {
- continue;
- }
-
- base::Histogram* h = nullptr;
- constexpr auto store = "main"_ns;
- if (!w->GetHistogram(store, &h)) {
- continue;
- }
- MOZ_ASSERT(h);
-
- if (!h) {
- // Don't restore expired histograms.
- continue;
- }
-
- // Make sure that histogram counts have matching sizes. If not,
- // |AddSampleSet| will fail and crash.
- size_t numCounts = std::get<1>(histogramData).Length();
- if (h->bucket_count() != numCounts) {
- MOZ_ASSERT(false,
- "The number of restored buckets does not match with the "
- "on in the definition");
- continue;
- }
-
- // Update the data for the histogram.
- h->AddSampleSet(base::PersistedSampleSet(
- std::move(std::get<1>(histogramData)), std::get<2>(histogramData)));
- }
- }
- }
-
- return NS_OK;
-}
-
-nsresult TelemetryHistogram::DeserializeKeyedHistograms(
- JSContext* aCx, JS::Handle<JS::Value> aData) {
- MOZ_ASSERT(XRE_IsParentProcess(),
- "Only load keyed histograms in the parent process");
- if (!XRE_IsParentProcess()) {
- return NS_ERROR_FAILURE;
- }
-
- // Telemetry is disabled. This should never happen, but let's leave this check
- // for consistency with other histogram updates routines.
- if (!internal_CanRecordBase()) {
- return NS_OK;
- }
-
- typedef std::tuple<nsCString, nsCString, nsTArray<base::Histogram::Count>,
- int64_t>
- PersistedKeyedHistogramTuple;
- typedef mozilla::Vector<PersistedKeyedHistogramTuple>
- PersistedKeyedHistogramArray;
- typedef mozilla::Vector<PersistedKeyedHistogramArray>
- PersistedKeyedHistogramStorage;
-
- // Before updating the histograms, we need to get the data out of the JS
- // wrappers. We can't hold the histogram mutex while handling JS stuff.
- // Build a <histogram name, value> map.
- JS::Rooted<JSObject*> histogramDataObj(aCx, &aData.toObject());
- JS::Rooted<JS::IdVector> processes(aCx, JS::IdVector(aCx));
- if (!JS_Enumerate(aCx, histogramDataObj, &processes)) {
- // We can't even enumerate the processes in the loaded data, so
- // there is nothing we could recover from the persistence file. Bail out.
- JS_ClearPendingException(aCx);
- return NS_ERROR_FAILURE;
- }
-
- // Make sure we have enough storage for all the processes.
- PersistedKeyedHistogramStorage histogramsToUpdate;
- if (!histogramsToUpdate.resize(static_cast<uint32_t>(ProcessID::Count))) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
-
- // The following block of code attempts to extract as much data as possible
- // from the serialized JSON, even in case of light data corruptions: if, for
- // example, the data for a single process is corrupted or is in an unexpected
- // form, we press on and attempt to load the data for the other processes.
- JS::Rooted<JS::PropertyKey> process(aCx);
- for (auto& processVal : processes) {
- // This is required as JS API calls require an Handle<jsid> and not a
- // plain jsid.
- process = processVal;
- // Get the process name.
- nsAutoJSString processNameJS;
- if (!processNameJS.init(aCx, process)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- // Make sure it's valid. Note that this is safe to call outside
- // of a locked section.
- NS_ConvertUTF16toUTF8 processName(processNameJS);
- ProcessID processID = GetIDForProcessName(processName.get());
- if (processID == ProcessID::Count) {
- NS_WARNING(
- nsPrintfCString("Failed to get process ID for %s", processName.get())
- .get());
- continue;
- }
-
- // And its probes.
- JS::Rooted<JS::Value> processData(aCx);
- if (!JS_GetPropertyById(aCx, histogramDataObj, process, &processData)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- if (!processData.isObject()) {
- // |processData| should be an object containing histograms. If this is
- // not the case, silently skip and try to load the data for the other
- // processes.
- continue;
- }
-
- // Iterate through each keyed histogram.
- JS::Rooted<JSObject*> processDataObj(aCx, &processData.toObject());
- JS::Rooted<JS::IdVector> histograms(aCx, JS::IdVector(aCx));
- if (!JS_Enumerate(aCx, processDataObj, &histograms)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- // Get a reference to the deserialized data for this process.
- PersistedKeyedHistogramArray& deserializedProcessData =
- histogramsToUpdate[static_cast<uint32_t>(processID)];
-
- JS::Rooted<JS::PropertyKey> histogram(aCx);
- for (auto& histogramVal : histograms) {
- histogram = histogramVal;
- // Get the histogram name.
- nsAutoJSString histogramName;
- if (!histogramName.init(aCx, histogram)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- // Get the data for this histogram.
- JS::Rooted<JS::Value> histogramData(aCx);
- if (!JS_GetPropertyById(aCx, processDataObj, histogram, &histogramData)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- // Iterate through each key in the histogram.
- JS::Rooted<JSObject*> keysDataObj(aCx, &histogramData.toObject());
- JS::Rooted<JS::IdVector> keys(aCx, JS::IdVector(aCx));
- if (!JS_Enumerate(aCx, keysDataObj, &keys)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- JS::Rooted<JS::PropertyKey> key(aCx);
- for (auto& keyVal : keys) {
- key = keyVal;
-
- int64_t sum = 0;
- nsTArray<base::Histogram::Count> deserializedCounts;
- nsCString keyName;
- if (NS_FAILED(internal_ParseHistogramData(
- aCx, key, keysDataObj, keyName, deserializedCounts, sum))) {
- continue;
- }
-
- // Finally append the deserialized data to the storage.
- if (!deserializedProcessData.emplaceBack(std::make_tuple(
- nsCString(NS_ConvertUTF16toUTF8(histogramName)),
- std::move(keyName), std::move(deserializedCounts), sum))) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- }
- }
- }
-
- // Update the keyed histogram storage.
- {
- StaticMutexAutoLock locker(gTelemetryHistogramMutex);
-
- for (uint32_t process = 0; process < histogramsToUpdate.length();
- ++process) {
- PersistedKeyedHistogramArray& processArray = histogramsToUpdate[process];
-
- for (auto& histogramData : processArray) {
- // Attempt to get the corresponding ID for the deserialized histogram
- // name.
- HistogramID id;
- if (NS_FAILED(internal_GetHistogramIdByName(
- locker, std::get<0>(histogramData), &id))) {
- continue;
- }
-
- ProcessID procID = static_cast<ProcessID>(process);
- if (!internal_CanRecordHistogram(id, procID)) {
- // We're not allowed to record this, so don't try to restore it.
- continue;
- }
-
- KeyedHistogram* keyed = internal_GetKeyedHistogramById(id, procID);
- MOZ_ASSERT(keyed);
-
- if (!keyed || keyed->IsExpired()) {
- // Don't restore if we don't have a destination storage or the
- // histogram is expired.
- continue;
- }
-
- // Get data for the key we're looking for.
- base::Histogram* h = nullptr;
- if (NS_FAILED(keyed->GetHistogram("main"_ns, std::get<1>(histogramData),
- &h))) {
- continue;
- }
- MOZ_ASSERT(h);
-
- if (!h) {
- // Don't restore if we don't have a destination storage.
- continue;
- }
-
- // Make sure that histogram counts have matching sizes. If not,
- // |AddSampleSet| will fail and crash.
- size_t numCounts = std::get<2>(histogramData).Length();
- if (h->bucket_count() != numCounts) {
- MOZ_ASSERT(false,
- "The number of restored buckets does not match with the "
- "on in the definition");
- continue;
- }
-
- // Update the data for the histogram.
- h->AddSampleSet(base::PersistedSampleSet(
- std::move(std::get<2>(histogramData)), std::get<3>(histogramData)));
- }
- }
- }
-
- return NS_OK;
-}