mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-23 02:05:42 +00:00
bug 1428885 - Allow C++ to accumulate multiple samples into a keyed histogram in one call r=chutten
Extended the Telemetry::Accumulate API to take a Histogram ID, string key, and a nsTArray<uint32_t> of samples. Test cases check for linear, count and histograms with a set of allowed keys. Made changes to fix try failures.
This commit is contained in:
parent
c3f3b8d161
commit
1dc396f38a
@ -1942,6 +1942,12 @@ Accumulate(HistogramID aID, const nsCString& aKey, uint32_t aSample)
|
||||
TelemetryHistogram::Accumulate(aID, aKey, aSample);
|
||||
}
|
||||
|
||||
void
|
||||
Accumulate(HistogramID aID, const nsCString& aKey, const nsTArray<uint32_t>& aSamples)
|
||||
{
|
||||
TelemetryHistogram::Accumulate(aID, aKey, aSamples);
|
||||
}
|
||||
|
||||
void
|
||||
Accumulate(const char* name, uint32_t sample)
|
||||
{
|
||||
|
@ -74,6 +74,14 @@ void Accumulate(HistogramID id, const nsTArray<uint32_t>& samples);
|
||||
*/
|
||||
void Accumulate(HistogramID id, const nsCString& key, uint32_t sample = 1);
|
||||
|
||||
/**
|
||||
* Adds an array of samples to a histogram defined in TelemetryHistograms.h
|
||||
* @param id - histogram id
|
||||
* @param samples - values to record.
|
||||
* @param key - the string key
|
||||
*/
|
||||
void Accumulate(HistogramID id, const nsCString& key, const nsTArray<uint32_t>& samples);
|
||||
|
||||
/**
|
||||
* Adds a sample to a histogram defined in TelemetryHistogramEnums.h.
|
||||
* This function is here to support telemetry measurements from Java,
|
||||
|
@ -1915,6 +1915,36 @@ TelemetryHistogram::Accumulate(HistogramID aID,
|
||||
internal_Accumulate(aID, aKey, aSample);
|
||||
}
|
||||
|
||||
void
|
||||
TelemetryHistogram::Accumulate(HistogramID aID, const nsCString& aKey,
|
||||
const nsTArray<uint32_t>& aSamples)
|
||||
{
|
||||
if (NS_WARN_IF(!internal_IsHistogramEnumId(aID))) {
|
||||
MOZ_ASSERT_UNREACHABLE("Histogram usage requires valid ids");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that this histogram is keyed
|
||||
MOZ_ASSERT(gHistogramInfos[aID].keyed, "Cannot accumulate into a non-keyed histogram using a key.");
|
||||
|
||||
// Check if we're allowed to record in the provided key, for this histogram.
|
||||
if (!gHistogramInfos[aID].allows_key(aKey)) {
|
||||
nsPrintfCString msg("%s - key '%s' not allowed for this keyed histogram",
|
||||
gHistogramInfos[aID].name(),
|
||||
aKey.get());
|
||||
LogToBrowserConsole(nsIScriptError::errorFlag, NS_ConvertUTF8toUTF16(msg));
|
||||
TelemetryScalar::Add(
|
||||
mozilla::Telemetry::ScalarID::TELEMETRY_ACCUMULATE_UNKNOWN_HISTOGRAM_KEYS,
|
||||
NS_ConvertASCIItoUTF16(gHistogramInfos[aID].name()), 1);
|
||||
return;
|
||||
}
|
||||
|
||||
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
|
||||
for(uint32_t sample: aSamples){
|
||||
internal_Accumulate(aID, aKey, sample);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TelemetryHistogram::Accumulate(const char* name, uint32_t sample)
|
||||
{
|
||||
|
@ -39,6 +39,8 @@ void Accumulate(mozilla::Telemetry::HistogramID aHistogram, uint32_t aSample);
|
||||
void Accumulate(mozilla::Telemetry::HistogramID aHistogram, const nsTArray<uint32_t>& aSamples);
|
||||
void Accumulate(mozilla::Telemetry::HistogramID aID, const nsCString& aKey,
|
||||
uint32_t aSample);
|
||||
void Accumulate(mozilla::Telemetry::HistogramID aID, const nsCString& aKey,
|
||||
const nsTArray<uint32_t>& aSamples);
|
||||
void Accumulate(const char* name, uint32_t sample);
|
||||
void Accumulate(const char* name, const nsCString& key, uint32_t sample);
|
||||
|
||||
|
@ -349,3 +349,183 @@ TEST_F(TelemetryTestFixture, AccumulateLinearHistogram_DifferentSamples)
|
||||
ASSERT_EQ(uCountFirst, kExpectedCountFirst) << "The first bucket did not accumulate the correct number of values";
|
||||
ASSERT_EQ(uCountLast, kExpectedCountLast) << "The last bucket did not accumulate the correct number of values";
|
||||
}
|
||||
|
||||
TEST_F(TelemetryTestFixture, AccumulateKeyedCountHistogram_MultipleSamples)
|
||||
{
|
||||
const nsTArray<uint32_t> samples({5, 10, 15});
|
||||
const uint32_t kExpectedSum = 5 + 10 + 15;
|
||||
|
||||
AutoJSContextWithGlobal cx(mCleanGlobal);
|
||||
|
||||
GetAndClearHistogram(cx.GetJSContext(), mTelemetry,
|
||||
NS_LITERAL_CSTRING("TELEMETRY_TEST_KEYED_COUNT"), true);
|
||||
|
||||
// Accumulate data in the provided key within the histogram
|
||||
Telemetry::Accumulate(Telemetry::TELEMETRY_TEST_KEYED_COUNT, NS_LITERAL_CSTRING("sample"),
|
||||
samples);
|
||||
|
||||
// Get a snapshot for all the histograms
|
||||
JS::RootedValue snapshot(cx.GetJSContext());
|
||||
GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_KEYED_COUNT", &snapshot, true);
|
||||
|
||||
// Get the histogram from the snapshot
|
||||
JS::RootedValue histogram(cx.GetJSContext());
|
||||
GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_KEYED_COUNT", snapshot, &histogram);
|
||||
|
||||
// Get "sample" property from histogram
|
||||
JS::RootedValue expectedKeyData(cx.GetJSContext());
|
||||
GetProperty(cx.GetJSContext(), "sample", histogram, &expectedKeyData);
|
||||
|
||||
// Get "sum" property from keyed data
|
||||
JS::RootedValue sum(cx.GetJSContext());
|
||||
GetProperty(cx.GetJSContext(), "sum", expectedKeyData, &sum);
|
||||
|
||||
// Check that the sum stored in the histogram matches with |kExpectedSum|
|
||||
uint32_t uSum = 0;
|
||||
JS::ToUint32(cx.GetJSContext(), sum, &uSum);
|
||||
ASSERT_EQ(uSum, kExpectedSum) << "The histogram is not returning expected sum";
|
||||
}
|
||||
|
||||
TEST_F(TelemetryTestFixture, TestKeyedLinearHistogram_MultipleSamples)
|
||||
{
|
||||
AutoJSContextWithGlobal cx(mCleanGlobal);
|
||||
|
||||
GetAndClearHistogram(cx.GetJSContext(), mTelemetry,
|
||||
NS_LITERAL_CSTRING("TELEMETRY_TEST_KEYED_LINEAR"), true);
|
||||
|
||||
const nsTArray<uint32_t> samples({1,5,250000});
|
||||
// Test the accumulation on the key 'testkey', using
|
||||
// the API that accepts histogram IDs.
|
||||
Telemetry::Accumulate(Telemetry::TELEMETRY_TEST_KEYED_LINEAR,
|
||||
NS_LITERAL_CSTRING("testkey"), samples);
|
||||
|
||||
// Get a snapshot for all the histograms
|
||||
JS::RootedValue snapshot(cx.GetJSContext());
|
||||
GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_KEYED_LINEAR", &snapshot, true);
|
||||
|
||||
// Get the histogram from the snapshot
|
||||
JS::RootedValue histogram(cx.GetJSContext());
|
||||
GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_KEYED_LINEAR", snapshot, &histogram);
|
||||
|
||||
// Get "testkey" property from histogram.
|
||||
JS::RootedValue expectedKeyData(cx.GetJSContext());
|
||||
GetProperty(cx.GetJSContext(), "testkey", histogram, &expectedKeyData);
|
||||
ASSERT_TRUE(!expectedKeyData.isUndefined())
|
||||
<< "Cannot find the expected key in the histogram data";
|
||||
|
||||
// Get counts array from 'testkey' histogram.
|
||||
JS::RootedValue counts(cx.GetJSContext());
|
||||
GetProperty(cx.GetJSContext(), "counts", expectedKeyData, &counts);
|
||||
|
||||
// Get counts in first and last buckets.
|
||||
JS::RootedValue countFirst(cx.GetJSContext());
|
||||
JS::RootedValue countLast(cx.GetJSContext());
|
||||
const uint32_t firstIndex = 1;
|
||||
const uint32_t lastIndex = 9;
|
||||
GetElement(cx.GetJSContext(), firstIndex, counts, &countFirst);
|
||||
GetElement(cx.GetJSContext(), lastIndex, counts, &countLast);
|
||||
|
||||
// Check that the counts match.
|
||||
uint32_t uCountFirst = 0;
|
||||
uint32_t uCountLast = 0;
|
||||
JS::ToUint32(cx.GetJSContext(), countFirst, &uCountFirst);
|
||||
JS::ToUint32(cx.GetJSContext(), countLast, &uCountLast);
|
||||
|
||||
const uint32_t kExpectedCountFirst = 2;
|
||||
const uint32_t kExpectedCountLast = 1;
|
||||
ASSERT_EQ(uCountFirst, kExpectedCountFirst)
|
||||
<< "The first bucket did not accumulate the correct number of values for key 'testkey'";
|
||||
ASSERT_EQ(uCountLast, kExpectedCountLast)
|
||||
<< "The last bucket did not accumulate the correct number of values for key 'testkey'";
|
||||
}
|
||||
|
||||
TEST_F(TelemetryTestFixture, TestKeyedKeysHistogram_MultipleSamples)
|
||||
{
|
||||
AutoJSContextWithGlobal cx(mCleanGlobal);
|
||||
mTelemetry->ClearScalars();
|
||||
const nsTArray<uint32_t> samples({false, false, true, 32, true});
|
||||
|
||||
GetAndClearHistogram(cx.GetJSContext(), mTelemetry,
|
||||
NS_LITERAL_CSTRING("TELEMETRY_TEST_KEYED_KEYS"), true);
|
||||
|
||||
// Test the accumulation on both the allowed and unallowed keys, using
|
||||
// the API that accepts histogram IDs.
|
||||
Telemetry::Accumulate(Telemetry::TELEMETRY_TEST_KEYED_KEYS,
|
||||
NS_LITERAL_CSTRING("not-allowed"), samples);
|
||||
Telemetry::Accumulate(Telemetry::TELEMETRY_TEST_KEYED_KEYS,
|
||||
NS_LITERAL_CSTRING("testkey"), samples);
|
||||
|
||||
// Get a snapshot for all the histograms
|
||||
JS::RootedValue snapshot(cx.GetJSContext());
|
||||
GetSnapshots(cx.GetJSContext(), mTelemetry, "TELEMETRY_TEST_KEYED_KEYS", &snapshot, true);
|
||||
|
||||
// Get the histogram from the snapshot
|
||||
JS::RootedValue histogram(cx.GetJSContext());
|
||||
GetProperty(cx.GetJSContext(), "TELEMETRY_TEST_KEYED_KEYS", snapshot, &histogram);
|
||||
|
||||
// Get "testkey" property from histogram and check that it stores the correct data.
|
||||
JS::RootedValue testKeyData(cx.GetJSContext());
|
||||
GetProperty(cx.GetJSContext(), "testkey", histogram, &testKeyData);
|
||||
ASSERT_TRUE(!testKeyData.isUndefined())
|
||||
<< "Cannot find the key 'testkey' in the histogram data";
|
||||
|
||||
JS::RootedValue counts(cx.GetJSContext());
|
||||
GetProperty(cx.GetJSContext(), "counts", testKeyData, &counts);
|
||||
|
||||
// Get counts in buckets 0,1,2
|
||||
const uint32_t falseIndex = 0;
|
||||
const uint32_t trueIndex = 1;
|
||||
const uint32_t otherIndex = 2;
|
||||
|
||||
JS::RootedValue countFalse(cx.GetJSContext());
|
||||
JS::RootedValue countTrue(cx.GetJSContext());
|
||||
JS::RootedValue countOther(cx.GetJSContext());
|
||||
|
||||
GetElement(cx.GetJSContext(), falseIndex, counts, &countFalse);
|
||||
GetElement(cx.GetJSContext(), trueIndex, counts, &countTrue);
|
||||
GetElement(cx.GetJSContext(), otherIndex, counts, &countOther);
|
||||
|
||||
uint32_t uCountFalse = 0;
|
||||
uint32_t uCountTrue = 0;
|
||||
uint32_t uCountOther = 0;
|
||||
JS::ToUint32(cx.GetJSContext(), countFalse, &uCountFalse);
|
||||
JS::ToUint32(cx.GetJSContext(), countTrue, &uCountTrue);
|
||||
JS::ToUint32(cx.GetJSContext(), countOther, &uCountOther);
|
||||
|
||||
const uint32_t kExpectedCountFalse = 2;
|
||||
const uint32_t kExpectedCountTrue = 3;
|
||||
const uint32_t kExpectedCountOther = 0;
|
||||
|
||||
ASSERT_EQ(uCountFalse, kExpectedCountFalse)
|
||||
<< "The histogram did not accumulate the correct number of 'false' booleans for key 'testkey'";
|
||||
ASSERT_EQ(uCountTrue, kExpectedCountTrue)
|
||||
<< "The histogram did not accumulate the correct number of 'true' booleans for key 'testkey'";
|
||||
ASSERT_EQ(uCountOther, kExpectedCountOther)
|
||||
<< "The histogram did not accumulate the correct number of undefined values for key 'testkey'";
|
||||
|
||||
// Here we check that we are not accumulating to a different (but still 'allowed') key.
|
||||
// Get "CommonKey" property from histogram and check that it has no data.
|
||||
// Since we accumulated no data to it, commonKeyData should be undefined.
|
||||
JS::RootedValue commonKeyData(cx.GetJSContext());
|
||||
GetProperty(cx.GetJSContext(), "CommonKey", histogram, &commonKeyData);
|
||||
ASSERT_TRUE(commonKeyData.isUndefined())
|
||||
<< "Found data in key 'CommonKey' even though we accumulated no data to it";
|
||||
|
||||
// Here we check that our function does not allow accumulation into unallowed keys.
|
||||
// Get 'not-allowed' property from histogram and check that this also has no data.
|
||||
// This should contain no data because this key is not allowed.
|
||||
JS::RootedValue notAllowedKeyData(cx.GetJSContext());
|
||||
GetProperty(cx.GetJSContext(), "not-allowed", histogram, ¬AllowedKeyData);
|
||||
ASSERT_TRUE(notAllowedKeyData.isUndefined())
|
||||
<< "Found data in key 'not-allowed' even though accumuling data to it is not allowed";
|
||||
|
||||
// The 'not-allowed' key accumulation for 'TELEMETRY_TESTED_KEYED_KEYS' was
|
||||
// attemtped once, so we expect the count of
|
||||
// 'telemetry.accumulate_unknown_histogram_keys' to be 1
|
||||
const uint32_t expectedAccumulateUnknownCount = 1;
|
||||
JS::RootedValue scalarsSnapshot(cx.GetJSContext());
|
||||
GetScalarsSnapshot(true, cx.GetJSContext(),&scalarsSnapshot);
|
||||
CheckKeyedUintScalar("telemetry.accumulate_unknown_histogram_keys",
|
||||
"TELEMETRY_TEST_KEYED_KEYS", cx.GetJSContext(),
|
||||
scalarsSnapshot, expectedAccumulateUnknownCount);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user