mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 23:05:42 +00:00
Bug 1120369 - Allow specifying the desired dataset in Histograms.json. r=vladan
This commit is contained in:
parent
a35dbaeebf
commit
f36ab0e55f
@ -4336,6 +4336,32 @@
|
||||
"keyed": true,
|
||||
"description": "a testing histogram; not meant to be touched"
|
||||
},
|
||||
"TELEMETRY_TEST_RELEASE_OPTOUT": {
|
||||
"expires_in_version": "default",
|
||||
"kind": "flag",
|
||||
"releaseChannelCollection": "opt-out",
|
||||
"description": "a testing histogram; not meant to be touched"
|
||||
},
|
||||
"TELEMETRY_TEST_RELEASE_OPTIN": {
|
||||
"expires_in_version": "default",
|
||||
"kind": "flag",
|
||||
"releaseChannelCollection": "opt-in",
|
||||
"description": "a testing histogram; not meant to be touched"
|
||||
},
|
||||
"TELEMETRY_TEST_KEYED_RELEASE_OPTIN": {
|
||||
"expires_in_version": "default",
|
||||
"kind": "flag",
|
||||
"keyed": true,
|
||||
"releaseChannelCollection": "opt-in",
|
||||
"description": "a testing histogram; not meant to be touched"
|
||||
},
|
||||
"TELEMETRY_TEST_KEYED_RELEASE_OPTOUT": {
|
||||
"expires_in_version": "default",
|
||||
"kind": "flag",
|
||||
"keyed": true,
|
||||
"releaseChannelCollection": "opt-out",
|
||||
"description": "a testing histogram; not meant to be touched"
|
||||
},
|
||||
"STARTUP_CRASH_DETECTED": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "flag",
|
||||
|
@ -626,184 +626,7 @@ ClearIOReporting()
|
||||
sTelemetryIOObserver = nullptr;
|
||||
}
|
||||
|
||||
class KeyedHistogram {
|
||||
public:
|
||||
KeyedHistogram(const nsACString &name, const nsACString &expiration,
|
||||
uint32_t histogramType, uint32_t min, uint32_t max,
|
||||
uint32_t bucketCount);
|
||||
nsresult GetHistogram(const nsCString& name, Histogram** histogram);
|
||||
Histogram* GetHistogram(const nsCString& name);
|
||||
uint32_t GetHistogramType() const { return mHistogramType; }
|
||||
nsresult GetJSKeys(JSContext* cx, JS::CallArgs& args);
|
||||
nsresult GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj);
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
typedef nsBaseHashtableET<nsCStringHashKey, Histogram*> KeyedHistogramEntry;
|
||||
typedef AutoHashtable<KeyedHistogramEntry> KeyedHistogramMapType;
|
||||
KeyedHistogramMapType mHistogramMap;
|
||||
|
||||
struct ReflectKeysArgs {
|
||||
JSContext* jsContext;
|
||||
JS::AutoValueVector* vector;
|
||||
};
|
||||
static PLDHashOperator ReflectKeys(KeyedHistogramEntry* entry, void* arg);
|
||||
|
||||
static bool ReflectKeyedHistogram(KeyedHistogramEntry* entry,
|
||||
JSContext* cx,
|
||||
JS::Handle<JSObject*> obj);
|
||||
|
||||
static PLDHashOperator ClearHistogramEnumerator(KeyedHistogramEntry*, void*);
|
||||
|
||||
const nsCString mName;
|
||||
const nsCString mExpiration;
|
||||
const uint32_t mHistogramType;
|
||||
const uint32_t mMin;
|
||||
const uint32_t mMax;
|
||||
const uint32_t mBucketCount;
|
||||
};
|
||||
|
||||
KeyedHistogram::KeyedHistogram(const nsACString &name, const nsACString &expiration,
|
||||
uint32_t histogramType, uint32_t min, uint32_t max,
|
||||
uint32_t bucketCount)
|
||||
: mHistogramMap()
|
||||
, mName(name)
|
||||
, mExpiration(expiration)
|
||||
, mHistogramType(histogramType)
|
||||
, mMin(min)
|
||||
, mMax(max)
|
||||
, mBucketCount(bucketCount)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
KeyedHistogram::GetHistogram(const nsCString& key, Histogram** histogram)
|
||||
{
|
||||
KeyedHistogramEntry* entry = mHistogramMap.GetEntry(key);
|
||||
if (entry) {
|
||||
*histogram = entry->mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCString histogramName = mName;
|
||||
histogramName.Append(KEYED_HISTOGRAM_NAME_SEPARATOR);
|
||||
histogramName.Append(key);
|
||||
|
||||
Histogram* h;
|
||||
nsresult rv = HistogramGet(histogramName.get(), mExpiration.get(),
|
||||
mHistogramType, mMin, mMax, mBucketCount,
|
||||
true, &h);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
h->ClearFlags(Histogram::kUmaTargetedHistogramFlag);
|
||||
h->SetFlags(Histogram::kExtendedStatisticsFlag);
|
||||
*histogram = h;
|
||||
|
||||
entry = mHistogramMap.PutEntry(key);
|
||||
if (MOZ_UNLIKELY(!entry)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
entry->mData = h;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Histogram*
|
||||
KeyedHistogram::GetHistogram(const nsCString& key)
|
||||
{
|
||||
Histogram* h = nullptr;
|
||||
if (NS_FAILED(GetHistogram(key, &h))) {
|
||||
return nullptr;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
/* static */
|
||||
PLDHashOperator
|
||||
KeyedHistogram::ClearHistogramEnumerator(KeyedHistogramEntry* entry, void*)
|
||||
{
|
||||
entry->mData->Clear();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
KeyedHistogram::Clear()
|
||||
{
|
||||
mHistogramMap.EnumerateEntries(&KeyedHistogram::ClearHistogramEnumerator, nullptr);
|
||||
mHistogramMap.Clear();
|
||||
}
|
||||
|
||||
/* static */
|
||||
PLDHashOperator
|
||||
KeyedHistogram::ReflectKeys(KeyedHistogramEntry* entry, void* arg)
|
||||
{
|
||||
ReflectKeysArgs* args = static_cast<ReflectKeysArgs*>(arg);
|
||||
|
||||
JS::RootedValue jsKey(args->jsContext);
|
||||
const NS_ConvertUTF8toUTF16 key(entry->GetKey());
|
||||
jsKey.setString(JS_NewUCStringCopyN(args->jsContext, key.Data(), key.Length()));
|
||||
args->vector->append(jsKey);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
KeyedHistogram::GetJSKeys(JSContext* cx, JS::CallArgs& args)
|
||||
{
|
||||
JS::AutoValueVector keys(cx);
|
||||
if (!keys.reserve(mHistogramMap.Count())) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
ReflectKeysArgs reflectArgs = { cx, &keys };
|
||||
const uint32_t num = mHistogramMap.EnumerateEntries(&KeyedHistogram::ReflectKeys,
|
||||
static_cast<void*>(&reflectArgs));
|
||||
if (num != mHistogramMap.Count()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
JS::RootedObject jsKeys(cx, JS_NewArrayObject(cx, keys));
|
||||
if (!jsKeys) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
args.rval().setObject(*jsKeys);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
KeyedHistogram::ReflectKeyedHistogram(KeyedHistogramEntry* entry, JSContext* cx, JS::Handle<JSObject*> obj)
|
||||
{
|
||||
JS::RootedObject histogramSnapshot(cx, JS_NewPlainObject(cx));
|
||||
if (!histogramSnapshot) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReflectHistogramSnapshot(cx, histogramSnapshot, entry->mData) != REFLECT_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const NS_ConvertUTF8toUTF16 key(entry->GetKey());
|
||||
if (!JS_DefineUCProperty(cx, obj, key.Data(), key.Length(),
|
||||
histogramSnapshot, JSPROP_ENUMERATE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
KeyedHistogram::GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj)
|
||||
{
|
||||
if (!mHistogramMap.ReflectIntoJS(&KeyedHistogram::ReflectKeyedHistogram, cx, obj)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
class KeyedHistogram;
|
||||
|
||||
class TelemetryImpl MOZ_FINAL
|
||||
: public nsITelemetry
|
||||
@ -940,6 +763,44 @@ TelemetryImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
|
||||
"Memory used by the telemetry system.");
|
||||
}
|
||||
|
||||
class KeyedHistogram {
|
||||
public:
|
||||
KeyedHistogram(const nsACString &name, const nsACString &expiration,
|
||||
uint32_t histogramType, uint32_t min, uint32_t max,
|
||||
uint32_t bucketCount);
|
||||
nsresult GetHistogram(const nsCString& name, Histogram** histogram);
|
||||
Histogram* GetHistogram(const nsCString& name);
|
||||
uint32_t GetHistogramType() const { return mHistogramType; }
|
||||
nsresult GetDataset(uint32_t* dataset) const;
|
||||
nsresult GetJSKeys(JSContext* cx, JS::CallArgs& args);
|
||||
nsresult GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj);
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
typedef nsBaseHashtableET<nsCStringHashKey, Histogram*> KeyedHistogramEntry;
|
||||
typedef AutoHashtable<KeyedHistogramEntry> KeyedHistogramMapType;
|
||||
KeyedHistogramMapType mHistogramMap;
|
||||
|
||||
struct ReflectKeysArgs {
|
||||
JSContext* jsContext;
|
||||
JS::AutoValueVector* vector;
|
||||
};
|
||||
static PLDHashOperator ReflectKeys(KeyedHistogramEntry* entry, void* arg);
|
||||
|
||||
static bool ReflectKeyedHistogram(KeyedHistogramEntry* entry,
|
||||
JSContext* cx,
|
||||
JS::Handle<JSObject*> obj);
|
||||
|
||||
static PLDHashOperator ClearHistogramEnumerator(KeyedHistogramEntry*, void*);
|
||||
|
||||
const nsCString mName;
|
||||
const nsCString mExpiration;
|
||||
const uint32_t mHistogramType;
|
||||
const uint32_t mMin;
|
||||
const uint32_t mMax;
|
||||
const uint32_t mBucketCount;
|
||||
};
|
||||
|
||||
// A initializer to initialize histogram collection
|
||||
StatisticsRecorder gStatisticsRecorder;
|
||||
|
||||
@ -951,6 +812,7 @@ struct TelemetryHistogram {
|
||||
uint32_t histogramType;
|
||||
uint32_t id_offset;
|
||||
uint32_t expiration_offset;
|
||||
uint32_t dataset;
|
||||
bool extendedStatisticsOK;
|
||||
bool keyed;
|
||||
|
||||
@ -992,6 +854,23 @@ IsValidHistogramName(const nsACString& name)
|
||||
return !FindInReadable(nsCString(KEYED_HISTOGRAM_NAME_SEPARATOR), name);
|
||||
}
|
||||
|
||||
bool
|
||||
IsInDataset(const TelemetryHistogram& h, uint32_t dataset)
|
||||
{
|
||||
if (h.dataset == dataset) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The "optin on release channel" dataset is a superset of the
|
||||
// "optout on release channel one".
|
||||
if (dataset == nsITelemetry::DATASET_RELEASE_CHANNEL_OPTIN
|
||||
&& h.dataset == nsITelemetry::DATASET_RELEASE_CHANNEL_OPTOUT) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CheckHistogramArguments(uint32_t histogramType, uint32_t min, uint32_t max,
|
||||
uint32_t bucketCount, bool haveOptArgs)
|
||||
@ -1272,6 +1151,26 @@ JSHistogram_Clear(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JSHistogram_Dataset(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
JSObject *obj = JS_THIS_OBJECT(cx, vp);
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Histogram *h = static_cast<Histogram*>(JS_GetPrivate(obj));
|
||||
Telemetry::ID id;
|
||||
nsresult rv = TelemetryImpl::GetHistogramEnumId(h->histogram_name().c_str(), &id);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
args.rval().setNumber(gHistograms[id].dataset);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WrapAndReturnHistogram(Histogram *h, JSContext *cx, JS::MutableHandle<JS::Value> ret)
|
||||
{
|
||||
@ -1285,7 +1184,8 @@ WrapAndReturnHistogram(Histogram *h, JSContext *cx, JS::MutableHandle<JS::Value>
|
||||
return NS_ERROR_FAILURE;
|
||||
if (!(JS_DefineFunction(cx, obj, "add", JSHistogram_Add, 1, 0)
|
||||
&& JS_DefineFunction(cx, obj, "snapshot", JSHistogram_Snapshot, 0, 0)
|
||||
&& JS_DefineFunction(cx, obj, "clear", JSHistogram_Clear, 0, 0))) {
|
||||
&& JS_DefineFunction(cx, obj, "clear", JSHistogram_Clear, 0, 0)
|
||||
&& JS_DefineFunction(cx, obj, "dataset", JSHistogram_Dataset, 0, 0))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
JS_SetPrivate(obj, h);
|
||||
@ -1448,6 +1348,30 @@ JSKeyedHistogram_Clear(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JSKeyedHistogram_Dataset(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
JSObject *obj = JS_THIS_OBJECT(cx, vp);
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
KeyedHistogram* keyed = static_cast<KeyedHistogram*>(JS_GetPrivate(obj));
|
||||
if (!keyed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t dataset = nsITelemetry::DATASET_RELEASE_CHANNEL_OPTIN;
|
||||
nsresult rv = keyed->GetDataset(&dataset);;
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setNumber(dataset);
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WrapAndReturnKeyedHistogram(KeyedHistogram *h, JSContext *cx, JS::MutableHandle<JS::Value> ret)
|
||||
{
|
||||
@ -1462,7 +1386,8 @@ WrapAndReturnKeyedHistogram(KeyedHistogram *h, JSContext *cx, JS::MutableHandle<
|
||||
if (!(JS_DefineFunction(cx, obj, "add", JSKeyedHistogram_Add, 2, 0)
|
||||
&& JS_DefineFunction(cx, obj, "snapshot", JSKeyedHistogram_Snapshot, 1, 0)
|
||||
&& JS_DefineFunction(cx, obj, "keys", JSKeyedHistogram_Keys, 0, 0)
|
||||
&& JS_DefineFunction(cx, obj, "clear", JSKeyedHistogram_Clear, 0, 0))) {
|
||||
&& JS_DefineFunction(cx, obj, "clear", JSKeyedHistogram_Clear, 0, 0)
|
||||
&& JS_DefineFunction(cx, obj, "dataset", JSKeyedHistogram_Dataset, 0, 0))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@ -2887,13 +2812,15 @@ TelemetryImpl::GetLateWrites(JSContext *cx, JS::MutableHandle<JS::Value> ret)
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetRegisteredHistogramIds(bool keyed, uint32_t *aCount, char*** aHistograms)
|
||||
GetRegisteredHistogramIds(bool keyed, uint32_t dataset, uint32_t *aCount,
|
||||
char*** aHistograms)
|
||||
{
|
||||
nsTArray<char*> collection;
|
||||
|
||||
for (size_t i = 0; i < ArrayLength(gHistograms); ++i) {
|
||||
const TelemetryHistogram& h = gHistograms[i];
|
||||
if (IsExpired(h.expiration()) || h.keyed != keyed) {
|
||||
if (IsExpired(h.expiration()) || h.keyed != keyed ||
|
||||
!IsInDataset(h, dataset)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -2912,15 +2839,17 @@ GetRegisteredHistogramIds(bool keyed, uint32_t *aCount, char*** aHistograms)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TelemetryImpl::RegisteredHistograms(uint32_t *aCount, char*** aHistograms)
|
||||
TelemetryImpl::RegisteredHistograms(uint32_t aDataset, uint32_t *aCount,
|
||||
char*** aHistograms)
|
||||
{
|
||||
return GetRegisteredHistogramIds(false, aCount, aHistograms);
|
||||
return GetRegisteredHistogramIds(false, aDataset, aCount, aHistograms);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TelemetryImpl::RegisteredKeyedHistograms(uint32_t *aCount, char*** aHistograms)
|
||||
TelemetryImpl::RegisteredKeyedHistograms(uint32_t aDataset, uint32_t *aCount,
|
||||
char*** aHistograms)
|
||||
{
|
||||
return GetRegisteredHistogramIds(true, aCount, aHistograms);
|
||||
return GetRegisteredHistogramIds(true, aDataset, aCount, aHistograms);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -3836,3 +3765,160 @@ XRE_TelemetryAccumulate(int aID, uint32_t aSample)
|
||||
{
|
||||
mozilla::Telemetry::Accumulate((mozilla::Telemetry::ID) aID, aSample);
|
||||
}
|
||||
|
||||
KeyedHistogram::KeyedHistogram(const nsACString &name, const nsACString &expiration,
|
||||
uint32_t histogramType, uint32_t min, uint32_t max,
|
||||
uint32_t bucketCount)
|
||||
: mHistogramMap()
|
||||
, mName(name)
|
||||
, mExpiration(expiration)
|
||||
, mHistogramType(histogramType)
|
||||
, mMin(min)
|
||||
, mMax(max)
|
||||
, mBucketCount(bucketCount)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
KeyedHistogram::GetHistogram(const nsCString& key, Histogram** histogram)
|
||||
{
|
||||
KeyedHistogramEntry* entry = mHistogramMap.GetEntry(key);
|
||||
if (entry) {
|
||||
*histogram = entry->mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCString histogramName = mName;
|
||||
histogramName.Append(KEYED_HISTOGRAM_NAME_SEPARATOR);
|
||||
histogramName.Append(key);
|
||||
|
||||
Histogram* h;
|
||||
nsresult rv = HistogramGet(histogramName.get(), mExpiration.get(),
|
||||
mHistogramType, mMin, mMax, mBucketCount,
|
||||
true, &h);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
h->ClearFlags(Histogram::kUmaTargetedHistogramFlag);
|
||||
h->SetFlags(Histogram::kExtendedStatisticsFlag);
|
||||
*histogram = h;
|
||||
|
||||
entry = mHistogramMap.PutEntry(key);
|
||||
if (MOZ_UNLIKELY(!entry)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
entry->mData = h;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Histogram*
|
||||
KeyedHistogram::GetHistogram(const nsCString& key)
|
||||
{
|
||||
Histogram* h = nullptr;
|
||||
if (NS_FAILED(GetHistogram(key, &h))) {
|
||||
return nullptr;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
nsresult
|
||||
KeyedHistogram::GetDataset(uint32_t* dataset) const
|
||||
{
|
||||
MOZ_ASSERT(dataset);
|
||||
|
||||
Telemetry::ID id;
|
||||
nsresult rv = TelemetryImpl::GetHistogramEnumId(mName.get(), &id);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
*dataset = gHistograms[id].dataset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
PLDHashOperator
|
||||
KeyedHistogram::ClearHistogramEnumerator(KeyedHistogramEntry* entry, void*)
|
||||
{
|
||||
entry->mData->Clear();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
KeyedHistogram::Clear()
|
||||
{
|
||||
mHistogramMap.EnumerateEntries(&KeyedHistogram::ClearHistogramEnumerator, nullptr);
|
||||
mHistogramMap.Clear();
|
||||
}
|
||||
|
||||
/* static */
|
||||
PLDHashOperator
|
||||
KeyedHistogram::ReflectKeys(KeyedHistogramEntry* entry, void* arg)
|
||||
{
|
||||
ReflectKeysArgs* args = static_cast<ReflectKeysArgs*>(arg);
|
||||
|
||||
JS::RootedValue jsKey(args->jsContext);
|
||||
const NS_ConvertUTF8toUTF16 key(entry->GetKey());
|
||||
jsKey.setString(JS_NewUCStringCopyN(args->jsContext, key.Data(), key.Length()));
|
||||
args->vector->append(jsKey);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
KeyedHistogram::GetJSKeys(JSContext* cx, JS::CallArgs& args)
|
||||
{
|
||||
JS::AutoValueVector keys(cx);
|
||||
if (!keys.reserve(mHistogramMap.Count())) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
ReflectKeysArgs reflectArgs = { cx, &keys };
|
||||
const uint32_t num = mHistogramMap.EnumerateEntries(&KeyedHistogram::ReflectKeys,
|
||||
static_cast<void*>(&reflectArgs));
|
||||
if (num != mHistogramMap.Count()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
JS::RootedObject jsKeys(cx, JS_NewArrayObject(cx, keys));
|
||||
if (!jsKeys) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
args.rval().setObject(*jsKeys);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
KeyedHistogram::ReflectKeyedHistogram(KeyedHistogramEntry* entry, JSContext* cx, JS::Handle<JSObject*> obj)
|
||||
{
|
||||
JS::RootedObject histogramSnapshot(cx, JS_NewPlainObject(cx));
|
||||
if (!histogramSnapshot) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReflectHistogramSnapshot(cx, histogramSnapshot, entry->mData) != REFLECT_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const NS_ConvertUTF8toUTF16 key(entry->GetKey());
|
||||
if (!JS_DefineUCProperty(cx, obj, key.Data(), key.Length(),
|
||||
histogramSnapshot, JSPROP_ENUMERATE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
KeyedHistogram::GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj)
|
||||
{
|
||||
if (!mHistogramMap.ReflectIntoJS(&KeyedHistogram::ReflectKeyedHistogram, cx, obj)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -460,7 +460,7 @@ let Impl = {
|
||||
getHistograms: function getHistograms(hls) {
|
||||
this._log.trace("getHistograms");
|
||||
|
||||
let registered = Telemetry.registeredHistograms([]);
|
||||
let registered = Telemetry.registeredHistograms(Ci.nsITelemetry.DATASET_EXTENDED, []);
|
||||
let ret = {};
|
||||
|
||||
for (let name of registered) {
|
||||
@ -496,7 +496,7 @@ let Impl = {
|
||||
getKeyedHistograms: function() {
|
||||
this._log.trace("getKeyedHistograms");
|
||||
|
||||
let registered = Telemetry.registeredKeyedHistograms([]);
|
||||
let registered = Telemetry.registeredKeyedHistograms(Ci.nsITelemetry.DATASET_EXTENDED, []);
|
||||
let ret = {};
|
||||
|
||||
for (let id of registered) {
|
||||
@ -771,7 +771,7 @@ let Impl = {
|
||||
gatherStartupHistograms: function gatherStartupHistograms() {
|
||||
this._log.trace("gatherStartupHistograms");
|
||||
|
||||
let info = Telemetry.registeredHistograms([]);
|
||||
let info = Telemetry.registeredHistograms(Ci.nsITelemetry.DATASET_EXTENDED, []);
|
||||
let snapshots = Telemetry.histogramSnapshots;
|
||||
for (let name of info) {
|
||||
// Only duplicate histograms with actual data.
|
||||
|
@ -60,10 +60,10 @@ 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, %d, %s, %s }," \
|
||||
print " { %s, %s, %s, %s, %d, %d, %s, %s, %s }," \
|
||||
% (histogram.low(), histogram.high(),
|
||||
histogram.n_buckets(), histogram.nsITelemetry_kind(),
|
||||
name_index, exp_index,
|
||||
name_index, exp_index, histogram.dataset(),
|
||||
"true" if histogram.extended_statistics_ok() else "false",
|
||||
"true" if histogram.keyed() else "false")
|
||||
if cpp_guard:
|
||||
|
@ -55,7 +55,8 @@ def exponential_buckets(dmin, dmax, n_buckets):
|
||||
ret_array[bucket_index] = current
|
||||
return ret_array
|
||||
|
||||
always_allowed_keys = ['kind', 'description', 'cpp_guard', 'expires_in_version', "alert_emails", 'keyed']
|
||||
always_allowed_keys = ['kind', 'description', 'cpp_guard', 'expires_in_version',
|
||||
'alert_emails', 'keyed', 'releaseChannelCollection']
|
||||
|
||||
class Histogram:
|
||||
"""A class for representing a histogram definition."""
|
||||
@ -88,6 +89,12 @@ symbol that should guard C/C++ definitions associated with the histogram."""
|
||||
'exponential': 'EXPONENTIAL' }
|
||||
table_dispatch(self.kind(), table,
|
||||
lambda k: self._set_nsITelemetry_kind(k))
|
||||
datasets = { 'opt-in': 'DATASET_RELEASE_CHANNEL_OPTIN',
|
||||
'opt-out': 'DATASET_RELEASE_CHANNEL_OPTOUT' }
|
||||
value = definition.get('releaseChannelCollection', 'opt-in')
|
||||
if not value in datasets:
|
||||
raise DefinitionException, "unknown release channel collection policy for " + name
|
||||
self._dataset = "nsITelemetry::" + datasets[value]
|
||||
|
||||
def name(self):
|
||||
"""Return the name of the histogram."""
|
||||
@ -135,6 +142,10 @@ associated with the histogram. Returns None if no guarding is necessary."""
|
||||
"""Returns True if this a keyed histogram, false otherwise."""
|
||||
return self._keyed
|
||||
|
||||
def dataset(self):
|
||||
"""Returns the dataset this histogram belongs into."""
|
||||
return self._dataset
|
||||
|
||||
def extended_statistics_ok(self):
|
||||
"""Return True if gathering extended statistics for this histogram
|
||||
is enabled."""
|
||||
|
@ -29,6 +29,16 @@ interface nsITelemetry : nsISupports
|
||||
const unsigned long HISTOGRAM_FLAG = 3;
|
||||
const unsigned long HISTOGRAM_COUNT = 4;
|
||||
|
||||
/**
|
||||
* Dataset types:
|
||||
* DATASET_RELEASE_CHANNEL_OPTOUT - the basic dataset that is on-by-default on all channels
|
||||
* DATASET_RELEASE_CHANNEL_OPTIN - the extended dataset that is opt-in on release,
|
||||
* opt-out on pre-release channels.
|
||||
*/
|
||||
const unsigned long DATASET_RELEASE_CHANNEL_OPTOUT = 0;
|
||||
const unsigned long DATASET_RELEASE_CHANNEL_OPTIN = 1;
|
||||
|
||||
|
||||
/*
|
||||
* An object containing a snapshot from all of the currently registered histograms.
|
||||
* { name1: {data1}, name2:{data2}...}
|
||||
@ -134,8 +144,11 @@ interface nsITelemetry : nsISupports
|
||||
/**
|
||||
* Returns an array whose values are the names of histograms defined
|
||||
* in Histograms.json.
|
||||
*
|
||||
* @param dataset - DATASET_RELEASE_CHANNEL_OPTOUT or DATASET_RELEASE_CHANNEL_OPTIN
|
||||
*/
|
||||
void registeredHistograms(out uint32_t count,
|
||||
void registeredHistograms(in uint32_t dataset,
|
||||
out uint32_t count,
|
||||
[retval, array, size_is(count)] out string histograms);
|
||||
|
||||
/**
|
||||
@ -151,6 +164,7 @@ interface nsITelemetry : nsISupports
|
||||
* 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()
|
||||
* clear() - Zeros out the histogram's buckets and sum
|
||||
* dataset() - identifies what dataset this is in: DATASET_RELEASE_CHANNEL_OPTOUT or ...OPTIN
|
||||
*/
|
||||
[implicit_jscontext, optional_argc]
|
||||
jsval newHistogram(in ACString name, in ACString expiration,
|
||||
@ -200,6 +214,7 @@ interface nsITelemetry : nsISupports
|
||||
* snapshot([optional] string key) - If key is provided, returns a snapshot for the histogram with that key or null. If key is not provided, returns the snapshots of all the registered keys in the form {key1: snapshot1, key2: snapshot2, ...}.
|
||||
* keys() - Returns an array with the string keys of the currently registered histograms
|
||||
* clear() - Clears the registered histograms from this.
|
||||
* dataset() - identifies what dataset this is in: DATASET_RELEASE_CHANNEL_OPTOUT or ...OPTIN
|
||||
*/
|
||||
[implicit_jscontext, optional_argc]
|
||||
jsval newKeyedHistogram(in ACString name,
|
||||
@ -212,8 +227,10 @@ interface nsITelemetry : nsISupports
|
||||
/**
|
||||
* Returns an array whose values are the names of histograms defined
|
||||
* in Histograms.json.
|
||||
*
|
||||
* @param dataset - DATASET_RELEASE_CHANNEL_OPTOUT or ...OPTIN
|
||||
*/
|
||||
void registeredKeyedHistograms(out uint32_t count,
|
||||
void registeredKeyedHistograms(in uint32_t dataset, out uint32_t count,
|
||||
[retval, array, size_is(count)] out string histograms);
|
||||
|
||||
/**
|
||||
|
@ -259,7 +259,7 @@ function checkPayload(request, reason, successfulPings) {
|
||||
do_check_true(TELEMETRY_TEST_FLAG in payload.histograms);
|
||||
do_check_true(TELEMETRY_TEST_COUNT in payload.histograms);
|
||||
|
||||
let rh = Telemetry.registeredHistograms([]);
|
||||
let rh = Telemetry.registeredHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, []);
|
||||
for (let name of rh) {
|
||||
if (/SQLITE/.test(name) && name in payload.histograms) {
|
||||
do_check_true(("STARTUP_" + name) in payload.histograms);
|
||||
|
@ -15,7 +15,8 @@ function test_expired_histogram() {
|
||||
var clone_id = "ExpiredClone";
|
||||
var dummy = Telemetry.newHistogram(histogram_id, "28.0a1", Telemetry.HISTOGRAM_EXPONENTIAL, 1, 2, 3);
|
||||
var dummy_clone = Telemetry.histogramFrom(clone_id, test_expired_id);
|
||||
var rh = Telemetry.registeredHistograms([]);
|
||||
var rh = Telemetry.registeredHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, []);
|
||||
Assert.ok(!!rh);
|
||||
|
||||
dummy.add(1);
|
||||
dummy_clone.add(1);
|
||||
@ -558,6 +559,52 @@ function test_keyed_histogram() {
|
||||
test_keyed_flag_histogram();
|
||||
}
|
||||
|
||||
function test_datasets()
|
||||
{
|
||||
// Check that datasets work as expected.
|
||||
|
||||
const RELEASE_CHANNEL_OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
|
||||
const RELEASE_CHANNEL_OPTIN = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN;
|
||||
|
||||
// Histograms should default to the extended dataset
|
||||
let h = Telemetry.getHistogramById("TELEMETRY_TEST_FLAG");
|
||||
Assert.equal(h.dataset(), RELEASE_CHANNEL_OPTIN);
|
||||
h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_FLAG");
|
||||
Assert.equal(h.dataset(), RELEASE_CHANNEL_OPTIN);
|
||||
|
||||
// Check test histograms with explicit dataset definitions
|
||||
h = Telemetry.getHistogramById("TELEMETRY_TEST_RELEASE_OPTIN");
|
||||
Assert.equal(h.dataset(), RELEASE_CHANNEL_OPTIN);
|
||||
h = Telemetry.getHistogramById("TELEMETRY_TEST_RELEASE_OPTOUT");
|
||||
Assert.equal(h.dataset(), RELEASE_CHANNEL_OPTOUT);
|
||||
h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTIN");
|
||||
Assert.equal(h.dataset(), RELEASE_CHANNEL_OPTIN);
|
||||
h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT");
|
||||
Assert.equal(h.dataset(), RELEASE_CHANNEL_OPTOUT);
|
||||
|
||||
// Check that registeredHistogram works properly
|
||||
let registered = Telemetry.registeredHistograms(RELEASE_CHANNEL_OPTIN, []);
|
||||
registered = new Set(registered);
|
||||
Assert.ok(registered.has("TELEMETRY_TEST_FLAG"));
|
||||
Assert.ok(registered.has("TELEMETRY_TEST_RELEASE_OPTIN"));
|
||||
Assert.ok(registered.has("TELEMETRY_TEST_RELEASE_OPTOUT"));
|
||||
registered = Telemetry.registeredHistograms(RELEASE_CHANNEL_OPTOUT, []);
|
||||
registered = new Set(registered);
|
||||
Assert.ok(!registered.has("TELEMETRY_TEST_FLAG"));
|
||||
Assert.ok(!registered.has("TELEMETRY_TEST_RELEASE_OPTIN"));
|
||||
Assert.ok(registered.has("TELEMETRY_TEST_RELEASE_OPTOUT"));
|
||||
|
||||
// Check that registeredKeyedHistograms works properly
|
||||
registered = Telemetry.registeredKeyedHistograms(RELEASE_CHANNEL_OPTIN, []);
|
||||
registered = new Set(registered);
|
||||
Assert.ok(registered.has("TELEMETRY_TEST_KEYED_FLAG"));
|
||||
Assert.ok(registered.has("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT"));
|
||||
registered = Telemetry.registeredKeyedHistograms(RELEASE_CHANNEL_OPTOUT, []);
|
||||
registered = new Set(registered);
|
||||
Assert.ok(!registered.has("TELEMETRY_TEST_KEYED_FLAG"));
|
||||
Assert.ok(registered.has("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT"));
|
||||
}
|
||||
|
||||
function generateUUID() {
|
||||
let str = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID().toString();
|
||||
// strip {}
|
||||
@ -592,4 +639,5 @@ function run_test()
|
||||
test_extended_stats();
|
||||
test_expired_histogram();
|
||||
test_keyed_histogram();
|
||||
test_datasets();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user