Merge mozilla-central to autoland

--HG--
extra : rebase_source : 314f463721337b68ff25177cdb5d9eb7dcde7371
This commit is contained in:
Carsten "Tomcat" Book 2017-04-13 10:11:47 +02:00
Родитель f1d7d1e1c9 a0d18fc1fe
Коммит 1e57d7d5e5
13 изменённых файлов: 551 добавлений и 88 удалений

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

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 1351074 - required because bug 1352982 means removing a .jsm requires a clobber
Bug 1356151 - Clobber needed after bug 1353295 was backed out

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

@ -260,10 +260,27 @@ Target.prototype = {
this._logHistogram(data.metric);
},
_getAddonHistogram(item) {
let appName = this._getAddonHistogramName(item, APPNAME_IDX);
let histName = this._getAddonHistogramName(item, HISTNAME_IDX);
return Services.telemetry.getAddonHistogram(appName, CUSTOM_HISTOGRAM_PREFIX
+ histName);
},
_getAddonHistogramName(item, index) {
let array = item.split('_');
return array[index].toUpperCase();
},
_clearTelemetryData() {
developerHUD._histograms.forEach(function(item) {
Services.telemetry.getKeyedHistogramById(item).clear();
});
developerHUD._customHistograms.forEach(item => {
this._getAddonHistogram(item).clear();
});
},
_sendTelemetryData() {
@ -274,6 +291,7 @@ Target.prototype = {
let frame = this.frame;
let payload = {
keyedHistograms: {},
addonHistograms: {}
};
// Package the hud histograms.
developerHUD._histograms.forEach(function(item) {
@ -281,6 +299,20 @@ Target.prototype = {
Services.telemetry.getKeyedHistogramById(item).snapshot();
});
// Package the registered hud custom histograms
developerHUD._customHistograms.forEach(item => {
let appName = this._getAddonHistogramName(item, APPNAME_IDX);
let histName = CUSTOM_HISTOGRAM_PREFIX +
this._getAddonHistogramName(item, HISTNAME_IDX);
let addonHist = Services.telemetry.getAddonHistogram(appName, histName).snapshot();
if (!(appName in payload.addonHistograms)) {
payload.addonHistograms[appName] = {};
}
// Do not include histograms with sum of 0.
if (addonHist.sum > 0) {
payload.addonHistograms[appName][histName] = addonHist;
}
});
shell.sendEvent(frame, 'advanced-telemetry-update', Cu.cloneInto(payload, frame));
},

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

@ -125,8 +125,6 @@ var gFailedOpaqueLayerMessages = [];
var gFailedAssignedLayer = false;
var gFailedAssignedLayerMessages = [];
var gStartAfter = undefined;
// The enabled-state of the test-plugins, stored so they can be reset later
var gTestPluginEnabledStates = null;
@ -391,12 +389,6 @@ function InitAndStartRefTests()
gFocusFilterMode = prefs.getCharPref("reftest.focusFilterMode");
} catch(e) {}
try {
gStartAfter = prefs.getCharPref("reftest.startAfter");
} catch(e) {
gStartAfter = undefined;
}
#ifdef MOZ_STYLO
try {
gCompareStyloToGecko = prefs.getBoolPref("reftest.compareStyloToGecko");
@ -552,24 +544,7 @@ function StartTests()
}
if (gShuffle) {
if (gStartAfter !== undefined) {
logger.error("Can't resume from a crashed test when " +
"--shuffle is enabled, continue by shuffling " +
"all the tests");
DoneTests();
return;
}
Shuffle(gURLs);
} else if (gStartAfter !== undefined) {
// Skip through previously crashed test
// We have to do this after chunking so we don't break the numbers
var crash_idx = gURLs.map(function(url) {
return url['url1']['spec'];
}).indexOf(gStartAfter);
if (crash_idx == -1) {
throw "Can't find the previously crashed test";
}
gURLs = gURLs.slice(crash_idx + 1);
}
gTotalTests = gURLs.length;

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

@ -227,15 +227,12 @@ class RemoteReftest(RefTest):
def stopWebServer(self, options):
self.server.stop()
def createReftestProfile(self, options, manifest, startAfter=None):
def createReftestProfile(self, options, manifest):
profile = RefTest.createReftestProfile(self,
options,
manifest,
server=options.remoteWebServer,
port=options.httpPort)
if startAfter is not None:
print ("WARNING: Continuing after a crash is not supported for remote "
"reftest yet.")
profileDir = profile.profile
prefs = {}

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

@ -247,7 +247,7 @@ class RefTest(object):
return os.path.normpath(os.path.join(self.oldcwd, os.path.expanduser(path)))
def createReftestProfile(self, options, manifests, server='localhost', port=0,
profile_to_clone=None, startAfter=None):
profile_to_clone=None):
"""Sets up a profile for reftest.
:param options: Object containing command line options
@ -286,9 +286,6 @@ class RefTest(object):
prefs['reftest.logLevel'] = options.log_tbpl_level or 'info'
prefs['reftest.manifests'] = json.dumps(manifests)
if startAfter is not None:
prefs['reftest.startAfter'] = startAfter
if options.e10s:
prefs['browser.tabs.remote.autostart'] = True
prefs['extensions.e10sBlocksEnabling'] = False
@ -352,8 +349,7 @@ class RefTest(object):
else:
profile = mozprofile.Profile(**kwargs)
if os.path.join(here, 'chrome') not in options.extraProfileFiles:
options.extraProfileFiles.append(os.path.join(here, 'chrome'))
options.extraProfileFiles.append(os.path.join(here, 'chrome'))
self.copyExtraFilesToProfile(options, profile)
return profile
@ -660,7 +656,7 @@ class RefTest(object):
runner.cleanup()
if not status and crashed:
status = 1
return status, self.lastTestSeen
return status
def runSerialTests(self, manifests, options, cmdargs=None):
debuggerInfo = None
@ -669,56 +665,37 @@ class RefTest(object):
options.debuggerInteractive)
profileDir = None
startAfter = None # When the previous run crashed, we skip the tests we ran before
prevStartAfter = None
status = 1 # Just to start the loop
while status != 0:
try:
if cmdargs is None:
cmdargs = []
try:
if cmdargs is None:
cmdargs = []
if self.use_marionette:
cmdargs.append('-marionette')
if self.use_marionette:
cmdargs.append('-marionette')
profile = self.createReftestProfile(options,
manifests,
startAfter=startAfter)
profileDir = profile.profile # name makes more sense
profile = self.createReftestProfile(options, manifests)
profileDir = profile.profile # name makes more sense
# browser environment
browserEnv = self.buildBrowserEnv(options, profileDir)
# browser environment
browserEnv = self.buildBrowserEnv(options, profileDir)
self.log.info("Running with e10s: {}".format(options.e10s))
status, startAfter = self.runApp(profile,
binary=options.app,
cmdargs=cmdargs,
# give the JS harness 30 seconds to deal with
# its own timeouts
env=browserEnv,
timeout=options.timeout + 30.0,
symbolsPath=options.symbolsPath,
options=options,
debuggerInfo=debuggerInfo)
self.log.info("Process mode: {}".format('e10s' if options.e10s else 'non-e10s'))
mozleak.process_leak_log(self.leakLogFile,
leak_thresholds=options.leakThresholds,
stack_fixer=get_stack_fixer_function(options.utilityPath,
options.symbolsPath))
self.cleanup(profileDir)
if startAfter is not None and options.shuffle:
self.log.error("Can not resume from a crash with --shuffle "
"enabled. Please consider disabling --shuffle")
break
if startAfter == prevStartAfter:
# If the test stuck on the same test, or there the crashed
# test appeared more then once, stop
self.log.error("Force stop because we keep running into "
"test \"{}\"".format(startAfter))
break
prevStartAfter = startAfter
# TODO: we need to emit an SUITE-END log if it crashed
finally:
self.cleanup(profileDir)
self.log.info("Running with e10s: {}".format(options.e10s))
status = self.runApp(profile,
binary=options.app,
cmdargs=cmdargs,
# give the JS harness 30 seconds to deal with
# its own timeouts
env=browserEnv,
timeout=options.timeout + 30.0,
symbolsPath=options.symbolsPath,
options=options,
debuggerInfo=debuggerInfo)
self.log.info("Process mode: {}".format('e10s' if options.e10s else 'non-e10s'))
mozleak.process_leak_log(self.leakLogFile,
leak_thresholds=options.leakThresholds,
stack_fixer=get_stack_fixer_function(options.utilityPath,
options.symbolsPath))
finally:
self.cleanup(profileDir)
return status
def copyExtraFilesToProfile(self, options, profile):

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

@ -1315,6 +1315,31 @@ TelemetryImpl::AddSQLInfo(JSContext *cx, JS::Handle<JSObject*> rootObj, bool mai
statsObj, JSPROP_ENUMERATE);
}
NS_IMETHODIMP
TelemetryImpl::RegisterAddonHistogram(const nsACString &id,
const nsACString &name,
uint32_t histogramType,
uint32_t min, uint32_t max,
uint32_t bucketCount,
uint8_t optArgCount)
{
return TelemetryHistogram::RegisterAddonHistogram
(id, name, histogramType, min, max, bucketCount, optArgCount);
}
NS_IMETHODIMP
TelemetryImpl::GetAddonHistogram(const nsACString &id, const nsACString &name,
JSContext *cx, JS::MutableHandle<JS::Value> ret)
{
return TelemetryHistogram::GetAddonHistogram(id, name, cx, ret);
}
NS_IMETHODIMP
TelemetryImpl::UnregisterAddonHistograms(const nsACString &id)
{
return TelemetryHistogram::UnregisterAddonHistograms(id);
}
NS_IMETHODIMP
TelemetryImpl::SetHistogramRecordingEnabled(const nsACString &id, bool aEnabled)
{
@ -1340,6 +1365,12 @@ TelemetryImpl::SnapshotSubsessionHistograms(bool clearSubsession,
#endif
}
NS_IMETHODIMP
TelemetryImpl::GetAddonHistogramSnapshots(JSContext *cx, JS::MutableHandle<JS::Value> ret)
{
return TelemetryHistogram::GetAddonHistogramSnapshots(cx, ret);
}
NS_IMETHODIMP
TelemetryImpl::GetKeyedHistogramSnapshots(JSContext *cx, JS::MutableHandle<JS::Value> ret)
{
@ -2927,6 +2958,7 @@ TelemetryImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
{
size_t n = aMallocSizeOf(this);
// Ignore the hashtables in mAddonMap; they are not significant.
n += TelemetryHistogram::GetMapShallowSizesOfExcludingThis(aMallocSizeOf);
n += TelemetryScalar::GetMapShallowSizesOfExcludingThis(aMallocSizeOf);
n += mWebrtcTelemetry.SizeOfExcludingThis(aMallocSizeOf);

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

@ -57,8 +57,8 @@ namespace TelemetryIPCAccumulator = mozilla::TelemetryIPCAccumulator;
//
// * Functions named TelemetryHistogram::*. This is the external interface.
// Entries and exits to these functions are serialised using
// |gTelemetryHistogramMutex|, except for GetKeyedHistogramSnapshots and
// CreateHistogramSnapshots.
// |gTelemetryHistogramMutex|, except for GetAddonHistogramSnapshots,
// GetKeyedHistogramSnapshots and CreateHistogramSnapshots.
//
// Avoiding races and deadlocks:
//
@ -138,6 +138,14 @@ struct HistogramInfo {
nsresult label_id(const char* label, uint32_t* labelId) const;
};
struct AddonHistogramInfo {
uint32_t min;
uint32_t max;
uint32_t bucketCount;
uint32_t histogramType;
Histogram *h;
};
enum reflectStatus {
REFLECT_OK,
REFLECT_CORRUPT,
@ -146,6 +154,17 @@ enum reflectStatus {
typedef StatisticsRecorder::Histograms::iterator HistogramIterator;
typedef nsBaseHashtableET<nsCStringHashKey, AddonHistogramInfo>
AddonHistogramEntryType;
typedef AutoHashtable<AddonHistogramEntryType>
AddonHistogramMapType;
typedef nsBaseHashtableET<nsCStringHashKey, AddonHistogramMapType *>
AddonEntryType;
typedef AutoHashtable<AddonEntryType> AddonMapType;
} // namespace
@ -171,6 +190,8 @@ bool gCorruptHistograms[mozilla::Telemetry::HistogramCount];
// This is for gHistograms, gHistogramStringTable
#include "TelemetryHistogramData.inc"
AddonMapType gAddonMap;
// The singleton StatisticsRecorder object for this process.
base::StatisticsRecorder* gStatisticsRecorder = nullptr;
@ -1121,6 +1142,108 @@ internal_GetKeyedHistogramById(const nsACString &name)
} // namespace
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//
// PRIVATE: functions related to addon histograms
namespace {
// Compute the name to pass into Histogram for the addon histogram
// 'name' from the addon 'id'. We can't use 'name' directly because it
// might conflict with other histograms in other addons or even with our
// own.
void
internal_AddonHistogramName(const nsACString &id, const nsACString &name,
nsACString &ret)
{
ret.Append(id);
ret.Append(':');
ret.Append(name);
}
bool
internal_CreateHistogramForAddon(const nsACString &name,
AddonHistogramInfo &info)
{
Histogram *h;
nsresult rv = internal_HistogramGet(PromiseFlatCString(name).get(), "never",
info.histogramType, info.min, info.max,
info.bucketCount, true, &h);
if (NS_FAILED(rv)) {
return false;
}
// Don't let this histogram be reported via the normal means
// (e.g. Telemetry.registeredHistograms); we'll make it available in
// other ways.
h->ClearFlags(Histogram::kUmaTargetedHistogramFlag);
info.h = h;
return true;
}
bool
internal_AddonHistogramReflector(AddonHistogramEntryType *entry,
JSContext *cx, JS::Handle<JSObject*> obj)
{
AddonHistogramInfo &info = entry->mData;
// Never even accessed the histogram.
if (!info.h) {
// Have to force creation of HISTOGRAM_FLAG histograms.
if (info.histogramType != nsITelemetry::HISTOGRAM_FLAG)
return true;
if (!internal_CreateHistogramForAddon(entry->GetKey(), info)) {
return false;
}
}
if (internal_IsEmpty(info.h)) {
return true;
}
JS::Rooted<JSObject*> snapshot(cx, JS_NewPlainObject(cx));
if (!snapshot) {
// Just consider this to be skippable.
return true;
}
switch (internal_ReflectHistogramSnapshot(cx, snapshot, info.h)) {
case REFLECT_FAILURE:
case REFLECT_CORRUPT:
return false;
case REFLECT_OK:
const nsACString &histogramName = entry->GetKey();
if (!JS_DefineProperty(cx, obj, PromiseFlatCString(histogramName).get(),
snapshot, JSPROP_ENUMERATE)) {
return false;
}
break;
}
return true;
}
bool
internal_AddonReflector(AddonEntryType *entry, JSContext *cx,
JS::Handle<JSObject*> obj)
{
const nsACString &addonId = entry->GetKey();
JS::Rooted<JSObject*> subobj(cx, JS_NewPlainObject(cx));
if (!subobj) {
return false;
}
AddonHistogramMapType *map = entry->mData;
if (!(map->ReflectIntoJS(internal_AddonHistogramReflector, cx, subobj)
&& JS_DefineProperty(cx, obj, PromiseFlatCString(addonId).get(),
subobj, JSPROP_ENUMERATE))) {
return false;
}
return true;
}
} // namespace
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//
@ -1891,6 +2014,7 @@ void TelemetryHistogram::DeInitializeGlobalState()
gCanRecordExtended = false;
gHistogramMap.Clear();
gKeyedHistograms.Clear();
gAddonMap.Clear();
gInitDone = false;
}
@ -2295,12 +2419,143 @@ TelemetryHistogram::GetKeyedHistogramSnapshots(JSContext *cx,
return NS_OK;
}
nsresult
TelemetryHistogram::RegisterAddonHistogram(const nsACString &id,
const nsACString &name,
uint32_t histogramType,
uint32_t min, uint32_t max,
uint32_t bucketCount,
uint8_t optArgCount)
{
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
if (histogramType == nsITelemetry::HISTOGRAM_EXPONENTIAL ||
histogramType == nsITelemetry::HISTOGRAM_LINEAR) {
if (optArgCount != 3) {
return NS_ERROR_INVALID_ARG;
}
// Sanity checks for histogram parameters.
if (min >= max)
return NS_ERROR_ILLEGAL_VALUE;
if (bucketCount <= 2)
return NS_ERROR_ILLEGAL_VALUE;
if (min < 1)
return NS_ERROR_ILLEGAL_VALUE;
} else {
min = 1;
max = 2;
bucketCount = 3;
}
AddonEntryType *addonEntry = gAddonMap.GetEntry(id);
if (!addonEntry) {
addonEntry = gAddonMap.PutEntry(id);
if (MOZ_UNLIKELY(!addonEntry)) {
return NS_ERROR_OUT_OF_MEMORY;
}
addonEntry->mData = new AddonHistogramMapType();
}
AddonHistogramMapType *histogramMap = addonEntry->mData;
AddonHistogramEntryType *histogramEntry = histogramMap->GetEntry(name);
// Can't re-register the same histogram.
if (histogramEntry) {
return NS_ERROR_FAILURE;
}
histogramEntry = histogramMap->PutEntry(name);
if (MOZ_UNLIKELY(!histogramEntry)) {
return NS_ERROR_OUT_OF_MEMORY;
}
AddonHistogramInfo &info = histogramEntry->mData;
info.min = min;
info.max = max;
info.bucketCount = bucketCount;
info.histogramType = histogramType;
return NS_OK;
}
nsresult
TelemetryHistogram::GetAddonHistogram(const nsACString &id,
const nsACString &name,
JSContext *cx,
JS::MutableHandle<JS::Value> ret)
{
AddonHistogramInfo* info = nullptr;
{
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
AddonEntryType *addonEntry = gAddonMap.GetEntry(id);
// The given id has not been registered.
if (!addonEntry) {
return NS_ERROR_INVALID_ARG;
}
AddonHistogramMapType *histogramMap = addonEntry->mData;
AddonHistogramEntryType *histogramEntry = histogramMap->GetEntry(name);
// The given histogram name has not been registered.
if (!histogramEntry) {
return NS_ERROR_INVALID_ARG;
}
info = &histogramEntry->mData;
if (!info->h) {
nsAutoCString actualName;
internal_AddonHistogramName(id, name, actualName);
if (!internal_CreateHistogramForAddon(actualName, *info)) {
return NS_ERROR_FAILURE;
}
}
}
// Runs without protection from |gTelemetryHistogramMutex|
return internal_WrapAndReturnHistogram(info->h, cx, ret);
}
nsresult
TelemetryHistogram::UnregisterAddonHistograms(const nsACString &id)
{
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
AddonEntryType *addonEntry = gAddonMap.GetEntry(id);
if (addonEntry) {
// Histogram's destructor is private, so this is the best we can do.
// The histograms the addon created *will* stick around, but they
// will be deleted if and when the addon registers histograms with
// the same names.
delete addonEntry->mData;
gAddonMap.RemoveEntry(addonEntry);
}
return NS_OK;
}
nsresult
TelemetryHistogram::GetAddonHistogramSnapshots(JSContext *cx,
JS::MutableHandle<JS::Value> ret)
{
// Runs without protection from |gTelemetryHistogramMutex|
JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
if (!obj) {
return NS_ERROR_FAILURE;
}
if (!gAddonMap.ReflectIntoJS(internal_AddonReflector, cx, obj)) {
return NS_ERROR_FAILURE;
}
ret.setObject(*obj);
return NS_OK;
}
size_t
TelemetryHistogram::GetMapShallowSizesOfExcludingThis(mozilla::MallocSizeOf
aMallocSizeOf)
{
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
return gHistogramMap.ShallowSizeOfExcludingThis(aMallocSizeOf);
return gAddonMap.ShallowSizeOfExcludingThis(aMallocSizeOf) +
gHistogramMap.ShallowSizeOfExcludingThis(aMallocSizeOf);
}
size_t

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

@ -76,6 +76,21 @@ RegisteredKeyedHistograms(uint32_t aDataset, uint32_t *aCount,
nsresult
GetKeyedHistogramSnapshots(JSContext *cx, JS::MutableHandle<JS::Value> ret);
nsresult
RegisterAddonHistogram(const nsACString &id, const nsACString &name,
uint32_t histogramType, uint32_t min, uint32_t max,
uint32_t bucketCount, uint8_t optArgCount);
nsresult
GetAddonHistogram(const nsACString &id, const nsACString &name,
JSContext *cx, JS::MutableHandle<JS::Value> ret);
nsresult
UnregisterAddonHistograms(const nsACString &id);
nsresult
GetAddonHistogramSnapshots(JSContext *cx, JS::MutableHandle<JS::Value> ret);
size_t
GetMapShallowSizesOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf);

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

@ -910,6 +910,23 @@ var Impl = {
return ret;
},
getAddonHistograms: function getAddonHistograms() {
let ahs = Telemetry.addonHistogramSnapshots;
let ret = {};
for (let addonName in ahs) {
let addonHistograms = ahs[addonName];
let packedHistograms = {};
for (let name in addonHistograms) {
packedHistograms[name] = this.packHistogram(addonHistograms[name]);
}
if (Object.keys(packedHistograms).length != 0)
ret[addonName] = packedHistograms;
}
return ret;
},
getKeyedHistograms(subsession, clearSubsession) {
let registered =
Telemetry.registeredKeyedHistograms(this.getDatasetType(), []);
@ -1316,6 +1333,12 @@ var Impl = {
payloadObj.fileIOReports = protect(() => Telemetry.fileIOReports);
payloadObj.lateWrites = protect(() => Telemetry.lateWrites);
// Add the addon histograms if they are present
let addonHistograms = protect(() => this.getAddonHistograms());
if (addonHistograms && Object.keys(addonHistograms).length > 0) {
payloadObj.addonHistograms = addonHistograms;
}
payloadObj.addonDetails = protect(() => AddonManagerPrivate.getTelemetryDetails());
let clearUIsession = !(reason == REASON_GATHER_PAYLOAD || reason == REASON_GATHER_SUBSESSION_PAYLOAD);

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

@ -69,6 +69,7 @@ Structure:
fileIOReports: {...},
lateWrites: {...},
addonDetails: {...},
addonHistograms: {...},
UIMeasurements: [...], // Android only
slowSQL: {...},
slowSQLstartup: {...},
@ -147,7 +148,7 @@ The recorded events are defined in the `Events.yaml <https://dxr.mozilla.org/moz
childPayloads
-------------
The Telemetry payloads sent by child processes, recorded on child process shutdown (event ``content-child-shutdown`` observed). They are reduced session payloads, only available with e10s. Among some other things, they don't contain histograms, keyed histograms, addon details, or UI Telemetry.
The Telemetry payloads sent by child processes, recorded on child process shutdown (event ``content-child-shutdown`` observed). They are reduced session payloads, only available with e10s. Among some other things, they don't contain histograms, keyed histograms, addon details, addon histograms, or UI Telemetry.
Note: Child payloads are not collected and cleared with subsession splits, they are currently only meaningful when analysed from ``saved-session`` or ``main`` pings with ``reason`` set to ``shutdown``.
@ -632,6 +633,10 @@ Structure:
...
}
addonHistograms
---------------
This section contains the histogram registered by the addons (`see here <https://dxr.mozilla.org/mozilla-central/rev/584870f1cbc5d060a57e147ce249f736956e2b62/toolkit/components/telemetry/nsITelemetry.idl#303>`_). This section is not present if no addon histogram is available.
UITelemetry
-----------
See the ``UITelemetry data format`` documentation.

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

@ -315,6 +315,46 @@ interface nsITelemetry : nsISupports
*/
readonly attribute boolean isOfficialTelemetry;
/** Addon telemetry hooks */
/**
* Register a histogram for an addon. Throws an error if the
* histogram name has been registered previously.
*
* @param addon_id - Unique ID of the addon
* @param name - Unique histogram name
* @param histogram_type - HISTOGRAM_EXPONENTIAL, HISTOGRAM_LINEAR,
* HISTOGRAM_BOOLEAN or HISTOGRAM_COUNT
* @param min - Minimal bucket size
* @param max - Maximum bucket size
* @param bucket_count - number of buckets in the histogram
*/
[optional_argc]
void registerAddonHistogram(in ACString addon_id, in ACString name,
in unsigned long histogram_type,
[optional] in uint32_t min,
[optional] in uint32_t max,
[optional] in uint32_t bucket_count);
/**
* Return a histogram previously registered via
* registerAddonHistogram. Throws an error if the id/name combo has
* not been registered via registerAddonHistogram.
*
* @param addon_id - Unique ID of the addon
* @param name - Registered histogram name
*
*/
[implicit_jscontext]
jsval getAddonHistogram(in ACString addon_id, in ACString name);
/**
* Delete all histograms associated with the given addon id.
*
* @param addon_id - Unique ID of the addon
*/
void unregisterAddonHistograms(in ACString addon_id);
/**
* Enable/disable recording for this histogram at runtime.
* Recording is enabled by default, unless listed at kRecordingInitiallyDisabledIDs[].
@ -325,6 +365,18 @@ interface nsITelemetry : nsISupports
*/
void setHistogramRecordingEnabled(in ACString id, in boolean enabled);
/**
* An object containing a snapshot from all of the currently
* registered addon histograms.
* { addon-id1 : data1, ... }
*
* where data is an object whose properties are the names of the
* addon's histograms and whose corresponding values are as in
* histogramSnapshots.
*/
[implicit_jscontext]
readonly attribute jsval addonHistogramSnapshots;
/**
* Read data from the previous run. After the callback is called, the last
* shutdown time is available in lastShutdownDuration and any late

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

@ -430,6 +430,94 @@ add_task(function* test_histogramRecording() {
"Histogram value should have incremented by 1 due to recording.");
});
add_task(function* test_addons() {
var addon_id = "testing-addon";
var fake_addon_id = "fake-addon";
var name1 = "testing-histogram1";
var register = Telemetry.registerAddonHistogram;
expect_success(() =>
register(addon_id, name1, Telemetry.HISTOGRAM_LINEAR, 1, 5, 6));
// Can't register the same histogram multiple times.
expect_fail(() =>
register(addon_id, name1, Telemetry.HISTOGRAM_LINEAR, 1, 5, 6));
// Make sure we can't get at it with another name.
expect_fail(() => Telemetry.getAddonHistogram(fake_addon_id, name1));
// Check for reflection capabilities.
var h1 = Telemetry.getAddonHistogram(addon_id, name1);
// Verify that although we've created storage for it, we don't reflect it into JS.
var snapshots = Telemetry.addonHistogramSnapshots;
do_check_false(name1 in snapshots[addon_id]);
h1.add(1);
h1.add(3);
var s1 = h1.snapshot();
do_check_eq(s1.histogram_type, Telemetry.HISTOGRAM_LINEAR);
do_check_eq(s1.min, 1);
do_check_eq(s1.max, 5);
do_check_eq(s1.counts[1], 1);
do_check_eq(s1.counts[3], 1);
var name2 = "testing-histogram2";
expect_success(() =>
register(addon_id, name2, Telemetry.HISTOGRAM_LINEAR, 2, 4, 4));
var h2 = Telemetry.getAddonHistogram(addon_id, name2);
h2.add(2);
h2.add(3);
var s2 = h2.snapshot();
do_check_eq(s2.histogram_type, Telemetry.HISTOGRAM_LINEAR);
do_check_eq(s2.min, 2);
do_check_eq(s2.max, 4);
do_check_eq(s2.counts[1], 1);
do_check_eq(s2.counts[2], 1);
// Check that we can register histograms for a different addon with
// identical names.
var extra_addon = "testing-extra-addon";
expect_success(() =>
register(extra_addon, name1, Telemetry.HISTOGRAM_BOOLEAN));
// Check that we can register flag histograms.
var flag_addon = "testing-flag-addon";
var flag_histogram = "flag-histogram";
expect_success(() =>
register(flag_addon, flag_histogram, Telemetry.HISTOGRAM_FLAG));
expect_success(() =>
register(flag_addon, name2, Telemetry.HISTOGRAM_LINEAR, 2, 4, 4));
// Check that we reflect registered addons and histograms.
snapshots = Telemetry.addonHistogramSnapshots;
do_check_true(addon_id in snapshots)
do_check_true(extra_addon in snapshots);
do_check_true(flag_addon in snapshots);
// Check that we have data for our created histograms.
do_check_true(name1 in snapshots[addon_id]);
do_check_true(name2 in snapshots[addon_id]);
var s1_alt = snapshots[addon_id][name1];
var s2_alt = snapshots[addon_id][name2];
do_check_eq(s1_alt.min, s1.min);
do_check_eq(s1_alt.max, s1.max);
do_check_eq(s1_alt.histogram_type, s1.histogram_type);
do_check_eq(s2_alt.min, s2.min);
do_check_eq(s2_alt.max, s2.max);
do_check_eq(s2_alt.histogram_type, s2.histogram_type);
// Even though we've registered it, it shouldn't show up until data is added to it.
do_check_false(name1 in snapshots[extra_addon]);
// Flag histograms should show up automagically.
do_check_true(flag_histogram in snapshots[flag_addon]);
do_check_false(name2 in snapshots[flag_addon]);
// Check that we can remove addon histograms.
Telemetry.unregisterAddonHistograms(addon_id);
snapshots = Telemetry.addonHistogramSnapshots;
do_check_false(addon_id in snapshots);
// Make sure other addons are unaffected.
do_check_true(extra_addon in snapshots);
});
add_task(function* test_expired_histogram() {
var test_expired_id = "TELEMETRY_TEST_EXPIRED";
var dummy = Telemetry.getHistogramById(test_expired_id);

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

@ -42,6 +42,8 @@ const APP_NAME = "XPCShell";
const IGNORE_HISTOGRAM_TO_CLONE = "MEMORY_HEAP_ALLOCATED";
const IGNORE_CLONED_HISTOGRAM = "test::ignore_me_also";
const ADDON_NAME = "Telemetry test addon";
const ADDON_HISTOGRAM = "addon-histogram";
// Add some unicode characters here to ensure that sending them works correctly.
const SHUTDOWN_TIME = 10000;
const FAILED_PROFILE_LOCK_ATTEMPTS = 2;
@ -99,6 +101,11 @@ function fakeIdleNotification(topic) {
function setupTestData() {
Services.startup.interrupted = true;
Telemetry.registerAddonHistogram(ADDON_NAME, ADDON_HISTOGRAM,
Telemetry.HISTOGRAM_LINEAR,
1, 5, 6);
let h1 = Telemetry.getAddonHistogram(ADDON_NAME, ADDON_HISTOGRAM);
h1.add(1);
let h2 = Telemetry.getHistogramById("TELEMETRY_TEST_COUNT");
h2.add();
@ -413,6 +420,11 @@ function checkPayload(payload, reason, successfulPings, savedPings) {
Assert.ok("MEMORY_JS_GC_HEAP" in payload.histograms); // UNITS_BYTES
Assert.ok("MEMORY_JS_COMPARTMENTS_SYSTEM" in payload.histograms); // UNITS_COUNT
// We should have included addon histograms.
Assert.ok("addonHistograms" in payload);
Assert.ok(ADDON_NAME in payload.addonHistograms);
Assert.ok(ADDON_HISTOGRAM in payload.addonHistograms[ADDON_NAME]);
Assert.ok(("mainThread" in payload.slowSQL) &&
("otherThreads" in payload.slowSQL));
@ -1884,7 +1896,7 @@ add_task(function* test_schedulerNothingDue() {
add_task(function* test_pingExtendedStats() {
const EXTENDED_PAYLOAD_FIELDS = [
"chromeHangs", "threadHangStats", "log", "slowSQL", "fileIOReports", "lateWrites",
"addonDetails", "webrtc"
"addonHistograms", "addonDetails", "webrtc"
];
if (AppConstants.platform == "android") {