Bug 742500 - Disable expired telemetry probes. r=vladan

This commit is contained in:
Roberto A. Vitillo 2014-01-03 12:02:48 -05:00
parent a3b02a3245
commit 0c3e911899
8 changed files with 1077 additions and 202 deletions

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,8 @@ include $(topsrcdir)/config/makefiles/rcs.mk
LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/build
LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/threads
DEFINES += -DMOZ_APP_VERSION='"$(MOZ_APP_VERSION)"'
MOZ_HISTOGRAMS_VERSION ?= $(call getSourceRepo)/rev/$(firstword $(shell hg -R $(topsrcdir) parent --template='{node|short}\n' 2>/dev/null))
ifdef MOZ_HISTOGRAMS_VERSION
DEFINES += -DHISTOGRAMS_FILE_VERSION='$(MOZ_HISTOGRAMS_VERSION)'

View File

@ -23,6 +23,8 @@
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
#include "nsXPCOMPrivate.h"
#include "nsIXULAppInfo.h"
#include "nsVersionComparator.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/ModuleUtils.h"
#include "nsIXPConnect.h"
@ -57,6 +59,8 @@
#include "shared-libraries.h"
#endif
#define EXPIRED_ID "__expired__"
namespace {
using namespace base;
@ -388,9 +392,11 @@ struct TelemetryHistogram {
uint32_t bucketCount;
uint32_t histogramType;
uint32_t id_offset;
uint32_t expiration_offset;
bool extendedStatisticsOK;
const char *id() const;
const char *expiration() const;
};
#include "TelemetryHistogramData.inc"
@ -402,31 +408,27 @@ TelemetryHistogram::id() const
return &gHistogramStringTable[this->id_offset];
}
bool
TelemetryHistogramType(Histogram *h, uint32_t *result)
const char *
TelemetryHistogram::expiration() const
{
switch (h->histogram_type()) {
case Histogram::HISTOGRAM:
*result = nsITelemetry::HISTOGRAM_EXPONENTIAL;
break;
case Histogram::LINEAR_HISTOGRAM:
*result = nsITelemetry::HISTOGRAM_LINEAR;
break;
case Histogram::BOOLEAN_HISTOGRAM:
*result = nsITelemetry::HISTOGRAM_BOOLEAN;
break;
case Histogram::FLAG_HISTOGRAM:
*result = nsITelemetry::HISTOGRAM_FLAG;
break;
default:
return false;
}
return true;
return &gHistogramStringTable[this->expiration_offset];
}
bool
IsExpired(const char *expiration){
static Version current_version = Version(MOZ_APP_VERSION);
MOZ_ASSERT(expiration);
return strcmp(expiration, "never") && (mozilla::Version(expiration) <= current_version);
}
bool
IsExpired(const Histogram *histogram){
return histogram->histogram_name() == EXPIRED_ID;
}
nsresult
HistogramGet(const char *name, uint32_t min, uint32_t max, uint32_t bucketCount,
uint32_t histogramType, Histogram **result)
HistogramGet(const char *name, const char *expiration, uint32_t min, uint32_t max,
uint32_t bucketCount, uint32_t histogramType, Histogram **result)
{
if (histogramType != nsITelemetry::HISTOGRAM_BOOLEAN
&& histogramType != nsITelemetry::HISTOGRAM_FLAG) {
@ -441,6 +443,14 @@ HistogramGet(const char *name, uint32_t min, uint32_t max, uint32_t bucketCount,
return NS_ERROR_ILLEGAL_VALUE;
}
if (IsExpired(expiration)) {
name = EXPIRED_ID;
min = 1;
max = 2;
bucketCount = 3;
histogramType = nsITelemetry::HISTOGRAM_LINEAR;
}
switch (histogramType) {
case nsITelemetry::HISTOGRAM_EXPONENTIAL:
*result = Histogram::FactoryGet(name, min, max, bucketCount, Histogram::kUmaTargetedHistogramFlag);
@ -472,20 +482,22 @@ GetHistogramByEnumId(Telemetry::ID id, Histogram **ret)
}
const TelemetryHistogram &p = gHistograms[id];
nsresult rv = HistogramGet(p.id(), p.min, p.max, p.bucketCount, p.histogramType, &h);
nsresult rv = HistogramGet(p.id(), p.expiration(), p.min, p.max, p.bucketCount, p.histogramType, &h);
if (NS_FAILED(rv))
return rv;
#ifdef DEBUG
// Check that the C++ Histogram code computes the same ranges as the
// Python histogram code.
const struct bounds &b = gBucketLowerBoundIndex[id];
if (b.length != 0) {
MOZ_ASSERT(size_t(b.length) == h->bucket_count(),
"C++/Python bucket # mismatch");
for (int i = 0; i < b.length; ++i) {
MOZ_ASSERT(gBucketLowerBounds[b.offset + i] == h->ranges(i),
"C++/Python bucket mismatch");
if (!IsExpired(p.expiration())) {
const struct bounds &b = gBucketLowerBoundIndex[id];
if (b.length != 0) {
MOZ_ASSERT(size_t(b.length) == h->bucket_count(),
"C++/Python bucket # mismatch");
for (int i = 0; i < b.length; ++i) {
MOZ_ASSERT(gBucketLowerBounds[b.offset + i] == h->ranges(i),
"C++/Python bucket mismatch");
}
}
}
#endif
@ -966,12 +978,13 @@ TelemetryImpl::InitMemoryReporter() {
}
NS_IMETHODIMP
TelemetryImpl::NewHistogram(const nsACString &name, uint32_t min, uint32_t max,
uint32_t bucketCount, uint32_t histogramType,
TelemetryImpl::NewHistogram(const nsACString &name, const nsACString &expiration, uint32_t min,
uint32_t max, uint32_t bucketCount, uint32_t histogramType,
JSContext *cx, JS::Value *ret)
{
Histogram *h;
nsresult rv = HistogramGet(PromiseFlatCString(name).get(), min, max, bucketCount, histogramType, &h);
nsresult rv = HistogramGet(PromiseFlatCString(name).get(), PromiseFlatCString(expiration).get(),
min, max, bucketCount, histogramType, &h);
if (NS_FAILED(rv))
return rv;
h->ClearFlags(Histogram::kUmaTargetedHistogramFlag);
@ -1089,20 +1102,23 @@ NS_IMETHODIMP
TelemetryImpl::HistogramFrom(const nsACString &name, const nsACString &existing_name,
JSContext *cx, JS::Value *ret)
{
Histogram *existing;
nsresult rv = GetHistogramByName(existing_name, &existing);
if (NS_FAILED(rv))
Telemetry::ID id;
nsresult rv = GetHistogramEnumId(PromiseFlatCString(existing_name).get(), &id);
if (NS_FAILED(rv)) {
return rv;
}
const TelemetryHistogram &p = gHistograms[id];
uint32_t histogramType;
bool success = TelemetryHistogramType(existing, &histogramType);
if (!success)
return NS_ERROR_INVALID_ARG;
Histogram *existing;
rv = GetHistogramByEnumId(id, &existing);
if (NS_FAILED(rv)) {
return rv;
}
Histogram *clone;
rv = HistogramGet(PromiseFlatCString(name).get(), existing->declared_min(),
existing->declared_max(), existing->bucket_count(),
histogramType, &clone);
rv = HistogramGet(PromiseFlatCString(name).get(), p.expiration(),
existing->declared_min(), existing->declared_max(),
existing->bucket_count(), p.histogramType, &clone);
if (NS_FAILED(rv))
return rv;
@ -1302,7 +1318,7 @@ TelemetryImpl::GetHistogramSnapshots(JSContext *cx, JS::Value *ret)
JS::Rooted<JSObject*> hobj(cx);
for (HistogramIterator it = hs.begin(); it != hs.end(); ++it) {
Histogram *h = *it;
if (!ShouldReflectHistogram(h) || IsEmpty(h)) {
if (!ShouldReflectHistogram(h) || IsEmpty(h) || IsExpired(h)) {
continue;
}
@ -1333,7 +1349,7 @@ TelemetryImpl::CreateHistogramForAddon(const nsACString &name,
AddonHistogramInfo &info)
{
Histogram *h;
nsresult rv = HistogramGet(PromiseFlatCString(name).get(),
nsresult rv = HistogramGet(PromiseFlatCString(name).get(), "never",
info.min, info.max, info.bucketCount,
info.histogramType, &h);
if (NS_FAILED(rv)) {
@ -1950,15 +1966,21 @@ NS_IMETHODIMP
TelemetryImpl::RegisteredHistograms(uint32_t *aCount, char*** aHistograms)
{
size_t count = ArrayLength(gHistograms);
size_t offset = 0;
char** histograms = static_cast<char**>(nsMemory::Alloc(count * sizeof(char*)));
for (size_t i = 0; i < count; ++i) {
if (IsExpired(gHistograms[i].expiration())) {
offset++;
continue;
}
const char* h = gHistograms[i].id();
size_t len = strlen(h);
histograms[i] = static_cast<char*>(nsMemory::Clone(h, len+1));
histograms[i - offset] = static_cast<char*>(nsMemory::Clone(h, len+1));
}
*aCount = count;
*aCount = count - offset;
*aHistograms = histograms;
return NS_OK;
}

View File

@ -47,19 +47,23 @@ class StringTable:
return ", ".join(map(toCChar, string))
f.write("const char %s[] = {\n" % name)
for (string, offset) in entries[:-1]:
f.write(" /* %5d */ %s, '\\0',\n"
% (offset, explodeToCharArray(string)))
e = explodeToCharArray(string)
if e:
f.write(" /* %5d */ %s, '\\0',\n"
% (offset, explodeToCharArray(string)))
else:
f.write(" /* %5d */ '\\0',\n" % offset)
f.write(" /* %5d */ %s, '\\0' };\n\n"
% (entries[-1][1], explodeToCharArray(entries[-1][0])))
def print_array_entry(histogram, name_index):
def print_array_entry(histogram, name_index, exp_index):
cpp_guard = histogram.cpp_guard()
if cpp_guard:
print "#if defined(%s)" % cpp_guard
print " { %s, %s, %s, %s, %d, %s }," \
print " { %s, %s, %s, %s, %d, %d, %s }," \
% (histogram.low(), histogram.high(),
histogram.n_buckets(), histogram.nsITelemetry_kind(),
name_index,
name_index, exp_index,
"true" if histogram.extended_statistics_ok() else "false")
if cpp_guard:
print "#endif"
@ -70,7 +74,8 @@ def write_histogram_table(histograms):
print "const TelemetryHistogram gHistograms[] = {"
for histogram in histograms:
name_index = table.stringIndex(histogram.name())
print_array_entry(histogram, name_index)
exp_index = table.stringIndex(histogram.expiration())
print_array_entry(histogram, name_index, exp_index)
print "};"
strtab_name = "gHistogramStringTable"

View File

@ -4,6 +4,7 @@
import json
import math
import re
from collections import OrderedDict
@ -54,7 +55,7 @@ def exponential_buckets(dmin, dmax, n_buckets):
ret_array[bucket_index] = current
return ret_array
always_allowed_keys = ['kind', 'description', 'cpp_guard']
always_allowed_keys = ['kind', 'description', 'cpp_guard', 'expires_in_version']
class Histogram:
"""A class for representing a histogram definition."""
@ -75,6 +76,7 @@ symbol that should guard C/C++ definitions associated with the histogram."""
self._kind = definition['kind']
self._cpp_guard = definition.get('cpp_guard')
self._extended_statistics_ok = definition.get('extended_statistics_ok', False)
self._expiration = definition.get('expires_in_version')
self.compute_bucket_parameters(definition)
table = { 'boolean': 'BOOLEAN',
'flag': 'FLAG',
@ -97,6 +99,10 @@ symbol that should guard C/C++ definitions associated with the histogram."""
Will be one of 'boolean', 'flag', 'enumerated', 'linear', or 'exponential'."""
return self._kind
def expiration(self):
"""Return the expiration version of the histogram."""
return self._expiration
def nsITelemetry_kind(self):
"""Return the nsITelemetry constant corresponding to the kind of
the histogram."""
@ -162,6 +168,19 @@ is enabled."""
table_dispatch(definition['kind'], table,
lambda allowed_keys: Histogram.check_keys(name, definition, allowed_keys))
Histogram.check_expiration(name, definition)
@staticmethod
def check_expiration(name, definition):
expiration = definition['expires_in_version']
if not expiration:
return
if not re.match(r'[1-9][0-9]*\..*|never', expiration):
raise BaseException, '%s not permitted as an expiration version for %s; the complete version name is required ' \
'(see https://developer.mozilla.org/en-US/docs/Performance/Adding_a_new_Telemetry_probe)' % (expiration, name)
@staticmethod
def check_keys(name, definition, allowed_keys):
for key in definition.iterkeys():

View File

@ -12,7 +12,7 @@ interface nsIFetchTelemetryDataCallback : nsISupports
void complete();
};
[scriptable, uuid(cb97b7b4-dce6-45fa-be6a-47e436a9aef9)]
[scriptable, uuid(3bdb3c83-1ac0-482a-9c3d-b15141174af4)]
interface nsITelemetry : nsISupports
{
/**
@ -139,6 +139,7 @@ interface nsITelemetry : nsISupports
* Create and return a histogram. Parameters:
*
* @param name Unique histogram name
* @param expiration Expiration version
* @param min - Minimal bucket size
* @param max - Maximum bucket size
* @param bucket_count - number of buckets in the histogram.
@ -149,7 +150,7 @@ interface nsITelemetry : nsISupports
* clear() - Zeros out the histogram's buckets and sum
*/
[implicit_jscontext]
jsval newHistogram(in ACString name, in uint32_t min, in uint32_t max, in uint32_t bucket_count, in unsigned long histogram_type);
jsval newHistogram(in ACString name, in ACString expiration, in uint32_t min, in uint32_t max, in uint32_t bucket_count, in unsigned long histogram_type);
/**
* Create a histogram using the current state of an existing histogram. The

View File

@ -44,6 +44,16 @@ var httpserver = new HttpServer();
var serverStarted = false;
var gFinished = false;
function test_expired_histogram() {
var histogram_id = "FOOBAR";
var dummy = Telemetry.newHistogram(histogram_id, "30", 1, 2, 3, Telemetry.HISTOGRAM_EXPONENTIAL);
dummy.add(1);
do_check_eq(TelemetryPing.getPayload()["histograms"][histogram_id], undefined);
do_check_eq(TelemetryPing.getPayload()["histograms"]["TELEMETRY_TEST_EXPIRED"], undefined);
}
function telemetry_ping () {
TelemetryPing.gatherStartup();
TelemetryPing.enableLoadSaveNotifications();
@ -98,7 +108,7 @@ function nonexistentServerObserver(aSubject, aTopic, aData) {
}
function setupTestData() {
Telemetry.newHistogram(IGNORE_HISTOGRAM, 1, 2, 3, Telemetry.HISTOGRAM_BOOLEAN);
Telemetry.newHistogram(IGNORE_HISTOGRAM, "never", 1, 2, 3, Telemetry.HISTOGRAM_BOOLEAN);
Telemetry.histogramFrom(IGNORE_CLONED_HISTOGRAM, IGNORE_HISTOGRAM_TO_CLONE);
Services.startup.interrupted = true;
Telemetry.registerAddonHistogram(ADDON_NAME, ADDON_HISTOGRAM, 1, 5, 6,
@ -499,6 +509,7 @@ function actualTest() {
registerFakePluginHost();
runInvalidJSONTest();
test_expired_histogram();
addWrappedObserver(nonexistentServerObserver, "telemetry-test-xhr-complete");
telemetry_ping();

View File

@ -9,9 +9,26 @@ const INT_MAX = 0x7FFFFFFF;
const Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
Cu.import("resource://gre/modules/Services.jsm");
function test_expired_histogram() {
var histogram_id = "FOOBAR";
var test_expired_id = "TELEMETRY_TEST_EXPIRED";
var clone_id = "ExpiredClone";
var dummy = Telemetry.newHistogram(histogram_id, "28.0a1", 1, 2, 3, Telemetry.HISTOGRAM_EXPONENTIAL);
var dummy_clone = Telemetry.histogramFrom(clone_id, test_expired_id);
var rh = Telemetry.registeredHistograms([]);
dummy.add(1);
dummy_clone.add(1);
do_check_eq(Telemetry.histogramSnapshots["__expired__"], undefined);
do_check_eq(Telemetry.histogramSnapshots[histogram_id], undefined);
do_check_eq(Telemetry.histogramSnapshots[test_expired_id], undefined);
do_check_eq(Telemetry.histogramSnapshots[clone_id], undefined);
do_check_eq(rh[test_expired_id], undefined);
}
function test_histogram(histogram_type, name, min, max, bucket_count) {
var h = Telemetry.newHistogram(name, min, max, bucket_count, histogram_type);
var h = Telemetry.newHistogram(name, "never", min, max, bucket_count, histogram_type);
var r = h.snapshot().ranges;
var sum = 0;
var log_sum = 0;
@ -109,7 +126,7 @@ function expect_success(f) {
function test_boolean_histogram()
{
var h = Telemetry.newHistogram("test::boolean histogram", 99,1,4, Telemetry.HISTOGRAM_BOOLEAN);
var h = Telemetry.newHistogram("test::boolean histogram", "never", 99,1,4, Telemetry.HISTOGRAM_BOOLEAN);
var r = h.snapshot().ranges;
// boolean histograms ignore numeric parameters
do_check_eq(uneval(r), uneval([0, 1, 2]))
@ -131,7 +148,7 @@ function test_boolean_histogram()
function test_flag_histogram()
{
var h = Telemetry.newHistogram("test::flag histogram", 130, 4, 5, Telemetry.HISTOGRAM_FLAG);
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]))
@ -312,7 +329,7 @@ function test_addons() {
// Check that telemetry doesn't record in private mode
function test_privateMode() {
var h = Telemetry.newHistogram("test::private_mode_boolean", 1,2,3, Telemetry.HISTOGRAM_BOOLEAN);
var h = Telemetry.newHistogram("test::private_mode_boolean", "never", 1,2,3, Telemetry.HISTOGRAM_BOOLEAN);
var orig = h.snapshot();
Telemetry.canRecord = false;
h.add(1);
@ -349,10 +366,10 @@ function run_test()
for each (let histogram_type in kinds) {
let [min, max, bucket_count] = [1, INT_MAX - 1, 10]
test_histogram(histogram_type, "test::"+histogram_type, min, max, bucket_count);
const nh = Telemetry.newHistogram;
expect_fail(function () nh("test::min", 0, max, bucket_count, histogram_type));
expect_fail(function () nh("test::bucket_count", min, max, 1, histogram_type));
expect_fail(function () nh("test::min", "never", 0, max, bucket_count, histogram_type));
expect_fail(function () nh("test::bucket_count", "never", min, max, 1, histogram_type));
}
// Instantiate the storage for this histogram and make sure it doesn't
@ -367,4 +384,5 @@ function run_test()
test_privateMode();
test_addons();
test_extended_stats();
test_expired_histogram();
}