mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-13 10:25:01 +00:00
Bug 1428888 - Allow C++ to accumulate multiple samples into a categorical histogram in one call r=chutten
Telemetry::Accumulate now supports two new signatures: Accumulate(HistogramId, nsTArray stringLabels) and Accumulate(nsTArray enumValues). In the stringLabels case, if the array contains an invalid label, then no samples are accumulated at all. In the enumValues array case, the class template ensures that we do not have a mismatch of labels in the array, since the enumValues class is tied to the id of the histogram we want to accumulate to.
This commit is contained in:
parent
1d7efd79f2
commit
2d08e81fe6
@ -1970,6 +1970,12 @@ AccumulateCategorical(HistogramID id, const nsCString& label)
|
||||
TelemetryHistogram::AccumulateCategorical(id, label);
|
||||
}
|
||||
|
||||
void
|
||||
AccumulateCategorical(HistogramID id, const nsTArray<nsCString>& labels)
|
||||
{
|
||||
TelemetryHistogram::AccumulateCategorical(id, labels);
|
||||
}
|
||||
|
||||
void
|
||||
AccumulateTimeDelta(HistogramID aHistogram, TimeStamp start, TimeStamp end)
|
||||
{
|
||||
|
@ -120,6 +120,30 @@ void AccumulateCategorical(E enumValue) {
|
||||
static_cast<uint32_t>(enumValue));
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds an array of samples to categorical histograms defined in TelemetryHistogramEnums.h
|
||||
* This is the typesafe - and preferred - way to use the categorical histograms
|
||||
* by passing values from the corresponding Telemetry::LABELS_* enums.
|
||||
*
|
||||
* @param enumValues - Array of labels from Telemetry::LABELS_* enums.
|
||||
*/
|
||||
template<class E>
|
||||
void
|
||||
AccumulateCategorical(const nsTArray<E>& enumValues)
|
||||
{
|
||||
static_assert(IsCategoricalLabelEnum<E>::value,
|
||||
"Only categorical label enum types are supported.");
|
||||
nsTArray<uint32_t> intSamples(enumValues.Length());
|
||||
|
||||
for (E aValue: enumValues){
|
||||
intSamples.AppendElement(static_cast<uint32_t>(aValue));
|
||||
}
|
||||
|
||||
HistogramID categoricalId = static_cast<HistogramID>(CategoricalLabelId<E>::value);
|
||||
|
||||
Accumulate(categoricalId, intSamples);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds sample to a keyed categorical histogram defined in TelemetryHistogramEnums.h
|
||||
* This is the typesafe - and preferred - way to use the keyed categorical histograms
|
||||
@ -148,6 +172,14 @@ void AccumulateCategoricalKeyed(const nsCString& key, E enumValue) {
|
||||
*/
|
||||
void AccumulateCategorical(HistogramID id, const nsCString& label);
|
||||
|
||||
/**
|
||||
* Adds an array of samples to a categorical histogram defined in Histograms.json
|
||||
*
|
||||
* @param id - The histogram id
|
||||
* @param labels - The array of labels to accumulate
|
||||
*/
|
||||
void AccumulateCategorical(HistogramID id, const nsTArray<nsCString>& labels);
|
||||
|
||||
/**
|
||||
* Adds time delta in milliseconds to a histogram defined in TelemetryHistogramEnums.h
|
||||
*
|
||||
|
@ -2050,6 +2050,39 @@ TelemetryHistogram::AccumulateCategorical(HistogramID aId,
|
||||
internal_Accumulate(aId, labelId);
|
||||
}
|
||||
|
||||
void
|
||||
TelemetryHistogram::AccumulateCategorical(HistogramID aId, const nsTArray<nsCString>& aLabels)
|
||||
{
|
||||
if (NS_WARN_IF(!internal_IsHistogramEnumId(aId))) {
|
||||
MOZ_ASSERT_UNREACHABLE("Histogram usage requires valid ids.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!internal_CanRecordBase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We use two loops, one for getting label_ids and another one for actually accumulating
|
||||
// the values. This ensures that in the case of an invalid label in the array, no values
|
||||
// are accumulated. In any call to this API, either all or (in case of error) none of the
|
||||
// values will be accumulated.
|
||||
|
||||
nsTArray<uint32_t> intSamples(aLabels.Length());
|
||||
for (const nsCString& label: aLabels){
|
||||
uint32_t labelId = 0;
|
||||
if (NS_FAILED(gHistogramInfos[aId].label_id(label.get(), &labelId))) {
|
||||
return;
|
||||
}
|
||||
intSamples.AppendElement(labelId);
|
||||
}
|
||||
|
||||
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
|
||||
|
||||
for (uint32_t sample: intSamples){
|
||||
internal_Accumulate(aId, sample);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TelemetryHistogram::AccumulateChild(ProcessID aProcessType,
|
||||
const nsTArray<HistogramAccumulation>& aAccumulations)
|
||||
|
@ -45,6 +45,7 @@ void Accumulate(const char* name, uint32_t sample);
|
||||
void Accumulate(const char* name, const nsCString& key, uint32_t sample);
|
||||
|
||||
void AccumulateCategorical(mozilla::Telemetry::HistogramID aId, const nsCString& aLabel);
|
||||
void AccumulateCategorical(mozilla::Telemetry::HistogramID aId, const nsTArray<nsCString>& aLabels);
|
||||
|
||||
void AccumulateChild(mozilla::Telemetry::ProcessID aProcessType,
|
||||
const nsTArray<mozilla::Telemetry::HistogramAccumulation>& aAccumulations);
|
||||
|
@ -529,3 +529,112 @@ TEST_F(TelemetryTestFixture, TestKeyedKeysHistogram_MultipleSamples)
|
||||
"TELEMETRY_TEST_KEYED_KEYS", cx.GetJSContext(),
|
||||
scalarsSnapshot, expectedAccumulateUnknownCount);
|
||||
}
|
||||
|
||||
TEST_F(TelemetryTestFixture, AccumulateCategoricalHistogram_MultipleStringLabels)
|
||||
{
|
||||
const uint32_t kExpectedValue = 2;
|
||||
const nsTArray<nsCString> labels({
|
||||
NS_LITERAL_CSTRING("CommonLabel"),
|
||||
NS_LITERAL_CSTRING("CommonLabel")});
|
||||
AutoJSContextWithGlobal cx(mCleanGlobal);
|
||||
|
||||
GetAndClearHistogram(cx.GetJSContext(), mTelemetry,
|
||||
NS_LITERAL_CSTRING("TELEMETRY_TEST_CATEGORICAL"), false);
|
||||
|
||||
// Accumulate the units into a categorical histogram using a string label
|
||||
Telemetry::AccumulateCategorical(Telemetry::TELEMETRY_TEST_CATEGORICAL, labels);
|
||||
|
||||
// Get a snapshot for all the histograms
|
||||
JS::RootedValue snapshot(cx.GetJSContext());
|
||||
GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_CATEGORICAL", &snapshot, false);
|
||||
|
||||
// Get our histogram from the snapshot
|
||||
JS::RootedValue histogram(cx.GetJSContext());
|
||||
GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_CATEGORICAL", snapshot, &histogram);
|
||||
|
||||
// Get counts array from histogram. Each entry in the array maps to a label in the histogram.
|
||||
JS::RootedValue counts(cx.GetJSContext());
|
||||
GetProperty(cx.GetJSContext(), "counts", histogram, &counts);
|
||||
|
||||
// Get the value for the label we care about
|
||||
JS::RootedValue value(cx.GetJSContext());
|
||||
GetElement(cx.GetJSContext(),
|
||||
static_cast<uint32_t>(Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL::CommonLabel),
|
||||
counts, &value);
|
||||
|
||||
// Check that the value stored in the histogram matches with |kExpectedValue|
|
||||
uint32_t uValue = 0;
|
||||
JS::ToUint32(cx.GetJSContext(), value, &uValue);
|
||||
ASSERT_EQ(uValue, kExpectedValue) << "The histogram is not returning expected value";
|
||||
|
||||
// Now we check for no accumulation when a bad label is present in the array.
|
||||
//
|
||||
// The 'counts' property is not initialized unless data is accumulated so keeping another test
|
||||
// to check for this case alone is wasteful as we will have to accumulate some data anyway.
|
||||
|
||||
const nsTArray<nsCString> badLabelArray({
|
||||
NS_LITERAL_CSTRING("CommonLabel"),
|
||||
NS_LITERAL_CSTRING("BadLabel")});
|
||||
|
||||
// Try to accumulate the array into the histogram.
|
||||
Telemetry::AccumulateCategorical(Telemetry::TELEMETRY_TEST_CATEGORICAL, badLabelArray);
|
||||
|
||||
// Get snapshot of all the histograms
|
||||
GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_CATEGORICAL", &snapshot, false);
|
||||
|
||||
// Get our histogram from the snapshot
|
||||
GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_CATEGORICAL", snapshot, &histogram);
|
||||
|
||||
// Get counts array from histogram
|
||||
GetProperty(cx.GetJSContext(), "counts", histogram, &counts);
|
||||
|
||||
// Get the value for the label we care about
|
||||
GetElement(cx.GetJSContext(),
|
||||
static_cast<uint32_t>(Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL::CommonLabel),
|
||||
counts, &value);
|
||||
|
||||
// Check that the value stored in the histogram matches with |kExpectedValue|
|
||||
uValue = 0;
|
||||
JS::ToUint32(cx.GetJSContext(), value, &uValue);
|
||||
ASSERT_EQ(uValue, kExpectedValue) << "The histogram accumulated data when it should not have";
|
||||
}
|
||||
|
||||
TEST_F(TelemetryTestFixture, AccumulateCategoricalHistogram_MultipleEnumValues)
|
||||
{
|
||||
const uint32_t kExpectedValue = 2;
|
||||
const nsTArray<Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL> enumLabels({
|
||||
Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL::CommonLabel,
|
||||
Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL::CommonLabel});
|
||||
|
||||
AutoJSContextWithGlobal cx(mCleanGlobal);
|
||||
|
||||
GetAndClearHistogram(cx.GetJSContext(), mTelemetry,
|
||||
NS_LITERAL_CSTRING("TELEMETRY_TEST_CATEGORICAL"), false);
|
||||
|
||||
// Accumulate the units into a categorical histogram using the enumLabels array
|
||||
Telemetry::AccumulateCategorical<Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL>(enumLabels);
|
||||
|
||||
// Get a snapshot for all the histograms
|
||||
JS::RootedValue snapshot(cx.GetJSContext());
|
||||
GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_CATEGORICAL", &snapshot, false);
|
||||
|
||||
// Get our histogram from the snapshot
|
||||
JS::RootedValue histogram(cx.GetJSContext());
|
||||
GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_CATEGORICAL", snapshot, &histogram);
|
||||
|
||||
// Get counts array from histogram. Each entry in the array maps to a label in the histogram.
|
||||
JS::RootedValue counts(cx.GetJSContext());
|
||||
GetProperty(cx.GetJSContext(), "counts", histogram, &counts);
|
||||
|
||||
// Get the value for the label we care about
|
||||
JS::RootedValue value(cx.GetJSContext());
|
||||
GetElement(cx.GetJSContext(),
|
||||
static_cast<uint32_t>(Telemetry::LABELS_TELEMETRY_TEST_CATEGORICAL::CommonLabel),
|
||||
counts, &value);
|
||||
|
||||
// Check that the value stored in the histogram matches with |kExpectedValue|
|
||||
uint32_t uValue = 0;
|
||||
JS::ToUint32(cx.GetJSContext(), value, &uValue);
|
||||
ASSERT_EQ(uValue, kExpectedValue) << "The histogram is not returning expected value";
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user