Bug 1069873 - Add counter histogram type. r=froydnj

This commit is contained in:
Georg Fritzsche 2014-09-26 17:45:33 +02:00
Родитель 1d3f0255c9
Коммит ef6689ab60
11 изменённых файлов: 179 добавлений и 33 удалений

Просмотреть файл

@ -1048,6 +1048,61 @@ FlagHistogram::AddSampleSet(const SampleSet& sample) {
Accumulate(1, 1, one_index);
}
}
//------------------------------------------------------------------------------
// CountHistogram:
//------------------------------------------------------------------------------
Histogram *
CountHistogram::FactoryGet(const std::string &name, Flags flags)
{
Histogram *h(nullptr);
if (!StatisticsRecorder::FindHistogram(name, &h)) {
CountHistogram *fh = new CountHistogram(name);
fh->InitializeBucketRange();
fh->SetFlags(flags);
h = StatisticsRecorder::RegisterOrDeleteDuplicate(fh);
}
return h;
}
CountHistogram::CountHistogram(const std::string &name)
: LinearHistogram(name, 1, 2, 3) {
}
Histogram::ClassType
CountHistogram::histogram_type() const
{
return COUNT_HISTOGRAM;
}
void
CountHistogram::Accumulate(Sample value, Count count, size_t index)
{
size_t zero_index = BucketIndex(0);
LinearHistogram::Accumulate(1, 1, zero_index);
}
void
CountHistogram::AddSampleSet(const SampleSet& sample) {
DCHECK_EQ(bucket_count(), sample.size());
// We can't be sure the SampleSet provided came from another CountHistogram,
// so we at least check that the unused buckets are empty.
const size_t indices[] = { BucketIndex(0), BucketIndex(1), BucketIndex(2) };
if (sample.counts(indices[1]) != 0 || sample.counts(indices[2]) != 0) {
return;
}
if (sample.counts(indices[0]) != 0) {
Accumulate(1, sample.counts(indices[0]), indices[0]);
}
}
//------------------------------------------------------------------------------
// CustomHistogram:
//------------------------------------------------------------------------------

Просмотреть файл

@ -278,6 +278,7 @@ class Histogram {
LINEAR_HISTOGRAM,
BOOLEAN_HISTOGRAM,
FLAG_HISTOGRAM,
COUNT_HISTOGRAM,
CUSTOM_HISTOGRAM,
NOT_VALID_IN_RENDERER
};
@ -690,6 +691,24 @@ private:
DISALLOW_COPY_AND_ASSIGN(FlagHistogram);
};
// CountHistogram only allows a single monotic counter value.
class CountHistogram : public LinearHistogram
{
public:
static Histogram *FactoryGet(const std::string &name, Flags flags);
virtual ClassType histogram_type() const;
virtual void Accumulate(Sample value, Count count, size_t index);
virtual void AddSampleSet(const SampleSet& sample);
private:
explicit CountHistogram(const std::string &name);
DISALLOW_COPY_AND_ASSIGN(CountHistogram);
};
//------------------------------------------------------------------------------
// CustomHistogram is a histogram for a set of custom integers.

Просмотреть файл

@ -4368,6 +4368,11 @@
"kind": "flag",
"description": "a testing histogram; not meant to be touched"
},
"TELEMETRY_TEST_COUNT": {
"expires_in_version": "default",
"kind": "count",
"description": "a testing histogram; not meant to be touched"
},
"STARTUP_CRASH_DETECTED": {
"expires_in_version": "never",
"kind": "flag",

Просмотреть файл

@ -728,7 +728,8 @@ HistogramGet(const char *name, const char *expiration, uint32_t min, uint32_t ma
uint32_t bucketCount, uint32_t histogramType, Histogram **result)
{
if (histogramType != nsITelemetry::HISTOGRAM_BOOLEAN
&& histogramType != nsITelemetry::HISTOGRAM_FLAG) {
&& histogramType != nsITelemetry::HISTOGRAM_FLAG
&& histogramType != nsITelemetry::HISTOGRAM_COUNT) {
// Sanity checks for histogram parameters.
if (min >= max)
return NS_ERROR_ILLEGAL_VALUE;
@ -761,6 +762,9 @@ HistogramGet(const char *name, const char *expiration, uint32_t min, uint32_t ma
case nsITelemetry::HISTOGRAM_FLAG:
*result = FlagHistogram::FactoryGet(name, Histogram::kUmaTargetedHistogramFlag);
break;
case nsITelemetry::HISTOGRAM_COUNT:
*result = CountHistogram::FactoryGet(name, Histogram::kUmaTargetedHistogramFlag);
break;
default:
return NS_ERROR_INVALID_ARG;
}
@ -904,33 +908,37 @@ IsEmpty(const Histogram *h)
bool
JSHistogram_Add(JSContext *cx, unsigned argc, JS::Value *vp)
{
JS::CallArgs args = CallArgsFromVp(argc, vp);
if (!args.length()) {
JS_ReportError(cx, "Expected one argument");
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj) {
return false;
}
if (!(args[0].isNumber() || args[0].isBoolean())) {
JS_ReportError(cx, "Not a number");
return false;
}
Histogram *h = static_cast<Histogram*>(JS_GetPrivate(obj));
Histogram::ClassType type = h->histogram_type();
int32_t value;
if (!JS::ToInt32(cx, args[0], &value)) {
return false;
}
if (TelemetryImpl::CanRecord()) {
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj) {
int32_t value = 1;
if (type != base::CountHistogram::COUNT_HISTOGRAM) {
JS::CallArgs args = CallArgsFromVp(argc, vp);
if (!args.length()) {
JS_ReportError(cx, "Expected one argument");
return false;
}
Histogram *h = static_cast<Histogram*>(JS_GetPrivate(obj));
if (!(args[0].isNumber() || args[0].isBoolean())) {
JS_ReportError(cx, "Not a number");
return false;
}
if (!JS::ToInt32(cx, args[0], &value)) {
return false;
}
}
if (TelemetryImpl::CanRecord()) {
h->Add(value);
}
return true;
return true;
}
bool
@ -1583,10 +1591,12 @@ TelemetryImpl::GetHistogramSnapshots(JSContext *cx, JS::MutableHandle<JS::Value>
return NS_ERROR_FAILURE;
ret.setObject(*root_obj);
// Ensure that all the HISTOGRAM_FLAG histograms have been created, so
// that their values are snapshotted.
// Ensure that all the HISTOGRAM_FLAG & HISTOGRAM_COUNT histograms have
// been created, so that their values are snapshotted.
for (size_t i = 0; i < Telemetry::HistogramCount; ++i) {
if (gHistograms[i].histogramType == nsITelemetry::HISTOGRAM_FLAG) {
const uint32_t type = gHistograms[i].histogramType;
if (type == nsITelemetry::HISTOGRAM_FLAG ||
type == nsITelemetry::HISTOGRAM_COUNT) {
Histogram *h;
DebugOnly<nsresult> rv = GetHistogramByEnumId(Telemetry::ID(i), &h);
MOZ_ASSERT(NS_SUCCEEDED(rv));

Просмотреть файл

@ -28,7 +28,8 @@ def main(argv):
'flag': '3',
'enumerated': '1',
'linear': '1',
'exponential': '0'
'exponential': '0',
'count': '4',
}
# Use __setitem__ because Python lambdas are so limited.
histogram_tools.table_dispatch(histogram.kind(), table,

Просмотреть файл

@ -97,6 +97,9 @@ def static_asserts_for_boolean(histogram):
def static_asserts_for_flag(histogram):
pass
def static_asserts_for_count(histogram):
pass
def static_asserts_for_enumerated(histogram):
n_values = histogram.high()
static_assert("%s > 2" % n_values,
@ -128,6 +131,7 @@ def write_histogram_static_asserts(histograms):
table = {
'boolean' : static_asserts_for_boolean,
'flag' : static_asserts_for_flag,
'count': static_asserts_for_count,
'enumerated' : static_asserts_for_enumerated,
'linear' : static_asserts_for_linear,
'exponential' : static_asserts_for_exponential,

Просмотреть файл

@ -65,7 +65,7 @@ class Histogram:
definition is a dict-like object that must contain at least the keys:
- 'kind': The kind of histogram. Must be one of 'boolean', 'flag',
'enumerated', 'linear', or 'exponential'.
'count', 'enumerated', 'linear', or 'exponential'.
- 'description': A textual description of the histogram.
The key 'cpp_guard' is optional; if present, it denotes a preprocessor
@ -80,6 +80,7 @@ symbol that should guard C/C++ definitions associated with the histogram."""
self.compute_bucket_parameters(definition)
table = { 'boolean': 'BOOLEAN',
'flag': 'FLAG',
'count': 'COUNT',
'enumerated': 'LINEAR',
'linear': 'LINEAR',
'exponential': 'EXPONENTIAL' }
@ -96,7 +97,7 @@ symbol that should guard C/C++ definitions associated with the histogram."""
def kind(self):
"""Return the kind of the histogram.
Will be one of 'boolean', 'flag', 'enumerated', 'linear', or 'exponential'."""
Will be one of 'boolean', 'flag', 'count', 'enumerated', 'linear', or 'exponential'."""
return self._kind
def expiration(self):
@ -137,6 +138,7 @@ is enabled."""
"""Return an array of lower bounds for each bucket in the histogram."""
table = { 'boolean': linear_buckets,
'flag': linear_buckets,
'count': linear_buckets,
'enumerated': linear_buckets,
'linear': linear_buckets,
'exponential': exponential_buckets }
@ -147,6 +149,7 @@ is enabled."""
table = {
'boolean': Histogram.boolean_flag_bucket_parameters,
'flag': Histogram.boolean_flag_bucket_parameters,
'count': Histogram.boolean_flag_bucket_parameters,
'enumerated': Histogram.enumerated_bucket_parameters,
'linear': Histogram.linear_bucket_parameters,
'exponential': Histogram.exponential_bucket_parameters
@ -161,6 +164,7 @@ is enabled."""
table = {
'boolean': always_allowed_keys,
'flag': always_allowed_keys,
'count': always_allowed_keys,
'enumerated': always_allowed_keys + ['n_values'],
'linear': general_keys,
'exponential': general_keys + ['extended_statistics_ok']

Просмотреть файл

@ -12,7 +12,7 @@ interface nsIFetchTelemetryDataCallback : nsISupports
void complete();
};
[scriptable, uuid(4e4bfc35-dac6-4b28-ade4-7e45760051d5)]
[scriptable, uuid(df355bbf-437d-4332-80e6-a8a54db959f3)]
interface nsITelemetry : nsISupports
{
/**
@ -21,11 +21,13 @@ interface nsITelemetry : nsISupports
* HISTOGRAM_LINEAR - buckets increase linearly
* HISTOGRAM_BOOLEAN - For storing 0/1 values
* HISTOGRAM_FLAG - For storing a single value; its count is always == 1.
* HISTOGRAM_COUNT - For storing counter values without bucketing.
*/
const unsigned long HISTOGRAM_EXPONENTIAL = 0;
const unsigned long HISTOGRAM_LINEAR = 1;
const unsigned long HISTOGRAM_BOOLEAN = 2;
const unsigned long HISTOGRAM_FLAG = 3;
const unsigned long HISTOGRAM_COUNT = 4;
/*
* An object containing a snapshot from all of the currently registered histograms.
@ -33,7 +35,8 @@ interface nsITelemetry : nsISupports
* where data is consists of the following properties:
* min - Minimal bucket size
* max - Maximum bucket size
* histogram_type - HISTOGRAM_EXPONENTIAL, HISTOGRAM_LINEAR, or HISTOGRAM_BOOLEAN
* histogram_type - HISTOGRAM_EXPONENTIAL, HISTOGRAM_LINEAR, HISTOGRAM_BOOLEAN
* or HISTOGRAM_COUNT
* counts - array representing contents of the buckets in the histogram
* ranges - an array with calculated bucket sizes
* sum - sum of the bucket contents
@ -143,7 +146,7 @@ interface nsITelemetry : nsISupports
* @param min - Minimal bucket size
* @param max - Maximum bucket size
* @param bucket_count - number of buckets in the histogram.
* @param type - HISTOGRAM_EXPONENTIAL, HISTOGRAM_LINEAR or HISTOGRAM_BOOLEAN
* @param type - HISTOGRAM_EXPONENTIAL, HISTOGRAM_LINEAR, HISTOGRAM_BOOLEAN or HISTOGRAM_COUNT
* 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()
@ -192,8 +195,8 @@ interface nsITelemetry : nsISupports
* @param min - Minimal bucket size
* @param max - Maximum bucket size
* @param bucket_count - number of buckets in the histogram
* @param histogram_type - HISTOGRAM_EXPONENTIAL, HISTOGRAM_LINEAR, or
* HISTOGRAM_BOOLEAN
* @param histogram_type - HISTOGRAM_EXPONENTIAL, HISTOGRAM_LINEAR,
* HISTOGRAM_BOOLEAN or HISTOGRAM_COUNT
*/
void registerAddonHistogram(in ACString addon_id, in ACString name,
in uint32_t min, in uint32_t max,

Просмотреть файл

@ -5,6 +5,7 @@
// copied from toolkit/mozapps/extensions/test/xpcshell/head_addons.js
const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
let gAppInfo;
function createAppInfo(id, name, version, platformVersion) {
gAppInfo = {

Просмотреть файл

@ -80,8 +80,10 @@ function setupTestData() {
Services.startup.interrupted = true;
Telemetry.registerAddonHistogram(ADDON_NAME, ADDON_HISTOGRAM, 1, 5, 6,
Telemetry.HISTOGRAM_LINEAR);
h1 = Telemetry.getAddonHistogram(ADDON_NAME, ADDON_HISTOGRAM);
let h1 = Telemetry.getAddonHistogram(ADDON_NAME, ADDON_HISTOGRAM);
h1.add(1);
let h2 = Telemetry.getHistogramById("TELEMETRY_TEST_COUNT");
h2.add();
}
function getSavedHistogramsFile(basename) {
@ -209,9 +211,14 @@ function checkPayload(request, reason, successfulPings) {
const TELEMETRY_PING = "TELEMETRY_PING";
const TELEMETRY_SUCCESS = "TELEMETRY_SUCCESS";
const TELEMETRY_TEST_FLAG = "TELEMETRY_TEST_FLAG";
const TELEMETRY_TEST_COUNT = "TELEMETRY_TEST_COUNT";
const READ_SAVED_PING_SUCCESS = "READ_SAVED_PING_SUCCESS";
do_check_true(TELEMETRY_PING in payload.histograms);
do_check_true(READ_SAVED_PING_SUCCESS in payload.histograms);
do_check_true(TELEMETRY_TEST_FLAG in payload.histograms);
do_check_true(TELEMETRY_TEST_COUNT in payload.histograms);
let rh = Telemetry.registeredHistograms([]);
for (let name of rh) {
if (/SQLITE/.test(name) && name in payload.histograms) {
@ -234,6 +241,19 @@ function checkPayload(request, reason, successfulPings) {
let flag = payload.histograms[TELEMETRY_TEST_FLAG];
do_check_eq(uneval(flag), uneval(expected_flag));
// We should have a test count.
const expected_count = {
range: [1, 2],
bucket_count: 3,
histogram_type: 4,
values: {0:1, 1:0},
sum: 1,
sum_squares_lo: 1,
sum_squares_hi: 0,
};
let count = payload.histograms[TELEMETRY_TEST_COUNT];
do_check_eq(uneval(count), uneval(expected_count));
// There should be one successful report from the previous telemetry ping.
const expected_tc = {
range: [1, 2],

Просмотреть файл

@ -151,7 +151,7 @@ function test_flag_histogram()
var h = Telemetry.newHistogram("test::flag histogram", "never", 130, 4, 5, Telemetry.HISTOGRAM_FLAG);
var r = h.snapshot().ranges;
// Flag histograms ignore numeric parameters.
do_check_eq(uneval(r), uneval([0, 1, 2]))
do_check_eq(uneval(r), uneval([0, 1, 2]));
// Should already have a 0 counted.
var c = h.snapshot().counts;
var s = h.snapshot().sum;
@ -172,6 +172,23 @@ function test_flag_histogram()
do_check_eq(h.snapshot().histogram_type, Telemetry.HISTOGRAM_FLAG);
}
function test_count_histogram()
{
let h = Telemetry.newHistogram("test::count histogram", "never", 1, 2, 3, Telemetry.HISTOGRAM_COUNT);
let s = h.snapshot();
do_check_eq(uneval(s.ranges), uneval([0, 1, 2]));
do_check_eq(uneval(s.counts), uneval([0, 0, 0]));
do_check_eq(s.sum, 0);
h.add();
s = h.snapshot();
do_check_eq(uneval(s.counts), uneval([1, 0, 0]));
do_check_eq(s.sum, 1);
h.add();
s = h.snapshot();
do_check_eq(uneval(s.counts), uneval([2, 0, 0]));
do_check_eq(s.sum, 2);
}
function test_getHistogramById() {
try {
Telemetry.getHistogramById("nonexistent");
@ -217,7 +234,8 @@ function test_histogramFrom() {
"CYCLE_COLLECTOR", // EXPONENTIAL
"GC_REASON_2", // LINEAR
"GC_RESET", // BOOLEAN
"TELEMETRY_TEST_FLAG" // FLAG
"TELEMETRY_TEST_FLAG", // FLAG
"TELEMETRY_TEST_COUNT", // COUNT
];
for each (let name in names) {
@ -227,11 +245,16 @@ function test_histogramFrom() {
compareHistograms(original, clone);
}
// Additionally, set the flag on TELEMETRY_TEST_FLAG, and check it gets set on the clone.
// Additionally, set TELEMETRY_TEST_FLAG and TELEMETRY_TEST_COUNT
// and check they get set on the clone.
let testFlag = Telemetry.getHistogramById("TELEMETRY_TEST_FLAG");
testFlag.add(1);
let testCount = Telemetry.getHistogramById("TELEMETRY_TEST_COUNT");
testCount.add();
let clone = Telemetry.histogramFrom("FlagClone", "TELEMETRY_TEST_FLAG");
compareHistograms(testFlag, clone);
clone = Telemetry.histogramFrom("CountClone", "TELEMETRY_TEST_COUNT");
compareHistograms(testCount, clone);
}
function test_getSlowSQL() {
@ -379,6 +402,7 @@ function run_test()
test_boolean_histogram();
test_flag_histogram();
test_count_histogram();
test_getHistogramById();
test_histogramFrom();
test_getSlowSQL();