Bug 715927 - addon telemetry, C++ side; r=taras

--HG--
extra : rebase_source : 21fc9e5dd98e4aa2ed09023a512df9e42bd1c4c9
This commit is contained in:
Nathan Froyd 2012-01-20 13:56:48 -08:00
parent 77160ffd5a
commit 15a992cd01
2 changed files with 248 additions and 3 deletions

View File

@ -146,6 +146,27 @@ private:
bool ShouldReflectHistogram(Histogram *h);
void IdentifyCorruptHistograms(StatisticsRecorder::Histograms &hs);
typedef StatisticsRecorder::Histograms::iterator HistogramIterator;
struct AddonHistogramInfo {
PRUint32 min;
PRUint32 max;
PRUint32 bucketCount;
PRUint32 histogramType;
Histogram *h;
};
typedef nsBaseHashtableET<nsCStringHashKey, AddonHistogramInfo> AddonHistogramEntryType;
typedef AutoHashtable<AddonHistogramEntryType> AddonHistogramMapType;
typedef nsBaseHashtableET<nsCStringHashKey, AddonHistogramMapType *> AddonEntryType;
typedef AutoHashtable<AddonEntryType> AddonMapType;
struct AddonEnumeratorArgs {
JSContext *cx;
JSObject *obj;
};
static bool AddonHistogramReflector(AddonHistogramEntryType *entry,
JSContext *cx, JSObject *obj);
static bool AddonReflector(AddonEntryType *entry, JSContext *cx, JSObject *obj);
AddonMapType mAddonMap;
// This is used for speedy string->Telemetry::ID conversions
typedef nsBaseHashtableET<nsCharPtrHashKey, Telemetry::ID> CharPtrEntryType;
typedef AutoHashtable<CharPtrEntryType> HistogramMapType;
@ -612,6 +633,111 @@ TelemetryImpl::ShouldReflectHistogram(Histogram *h)
}
}
// 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
AddonHistogramName(const nsACString &id, const nsACString &name,
nsACString &ret)
{
ret.Append(id);
ret.Append(NS_LITERAL_CSTRING(":"));
ret.Append(name);
}
NS_IMETHODIMP
TelemetryImpl::RegisterAddonHistogram(const nsACString &id,
const nsACString &name,
PRUint32 min, PRUint32 max,
PRUint32 bucketCount,
PRUint32 histogramType)
{
AddonEntryType *addonEntry = mAddonMap.GetEntry(id);
if (!addonEntry) {
addonEntry = mAddonMap.PutEntry(id);
if (NS_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 (NS_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;
}
NS_IMETHODIMP
TelemetryImpl::GetAddonHistogram(const nsACString &id, const nsACString &name,
JSContext *cx, jsval *ret)
{
AddonEntryType *addonEntry = mAddonMap.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;
}
AddonHistogramInfo &info = histogramEntry->mData;
Histogram *h;
if (info.h) {
h = info.h;
} else {
nsCAutoString actualName;
AddonHistogramName(id, name, actualName);
nsresult rv = HistogramGet(PromiseFlatCString(actualName).get(),
info.min, info.max, info.bucketCount,
info.histogramType, &h);
if (NS_FAILED(rv)) {
return rv;
}
// 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 WrapAndReturnHistogram(h, cx, ret);
}
NS_IMETHODIMP
TelemetryImpl::UnregisterAddonHistograms(const nsACString &id)
{
AddonEntryType *addonEntry = mAddonMap.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;
mAddonMap.RemoveEntry(id);
}
return NS_OK;
}
NS_IMETHODIMP
TelemetryImpl::GetHistogramSnapshots(JSContext *cx, jsval *ret)
{
@ -660,6 +786,73 @@ TelemetryImpl::GetHistogramSnapshots(JSContext *cx, jsval *ret)
return NS_OK;
}
bool
TelemetryImpl::AddonHistogramReflector(AddonHistogramEntryType *entry,
JSContext *cx, JSObject *obj)
{
// Never even accessed the histogram.
if (!entry->mData.h) {
return true;
}
JSObject *snapshot = JS_NewObject(cx, NULL, NULL, NULL);
js::AutoObjectRooter r(cx, snapshot);
switch (ReflectHistogramSnapshot(cx, snapshot, entry->mData.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(),
OBJECT_TO_JSVAL(snapshot), NULL, NULL,
JSPROP_ENUMERATE)) {
return false;
}
break;
}
return true;
}
bool
TelemetryImpl::AddonReflector(AddonEntryType *entry,
JSContext *cx, JSObject *obj)
{
const nsACString &addonId = entry->GetKey();
JSObject *subobj = JS_NewObject(cx, NULL, NULL, NULL);
if (!subobj) {
return false;
}
js::AutoObjectRooter r(cx, subobj);
AddonHistogramMapType *map = entry->mData;
if (!(map->ReflectHashtable(AddonHistogramReflector, cx, subobj)
&& JS_DefineProperty(cx, obj,
PromiseFlatCString(addonId).get(),
OBJECT_TO_JSVAL(subobj), NULL, NULL,
JSPROP_ENUMERATE))) {
return false;
}
return true;
}
NS_IMETHODIMP
TelemetryImpl::GetAddonHistogramSnapshots(JSContext *cx, jsval *ret)
{
*ret = JSVAL_VOID;
JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
if (!obj) {
return NS_ERROR_FAILURE;
}
js::AutoObjectRooter r(cx, obj);
if (!mAddonMap.ReflectHashtable(AddonReflector, cx, obj)) {
return NS_ERROR_FAILURE;
}
*ret = OBJECT_TO_JSVAL(obj);
return NS_OK;
}
NS_IMETHODIMP
TelemetryImpl::GetSlowSQL(JSContext *cx, jsval *ret)
{

View File

@ -58,7 +58,7 @@ interface nsITelemetry : nsISupports
* where data is consists of the following properties:
* min - Minimal bucket size
* max - Maximum bucket size
* histogram_type - HISTOGRAM_EXPONENTIAL or HISTOGRAM_LINEAR
* histogram_type - HISTOGRAM_EXPONENTIAL, HISTOGRAM_LINEAR, or HISTOGRAM_BOOLEAN
* counts - array representing contents of the buckets in the histogram
* ranges - an array with calculated bucket sizes
* sum - sum of the bucket contents
@ -94,13 +94,13 @@ interface nsITelemetry : nsISupports
readonly attribute jsval registeredHistograms;
/**
* Create and return a histogram where bucket sizes increase exponentially. Parameters:
* Create and return a histogram. Parameters:
*
* @param name Unique histogram name
* @param min - Minimal bucket size
* @param max - Maximum bucket size
* @param bucket_count - number of buckets in the histogram.
* @param type - HISTOGRAM_EXPONENTIAL or HISTOGRAM_LINEAR
* @param type - HISTOGRAM_EXPONENTIAL, HISTOGRAM_LINEAR or HISTOGRAM_BOOLEAN
* 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()
@ -136,4 +136,56 @@ interface nsITelemetry : nsISupports
* A flag indicating whether Telemetry can submit official results.
*/
readonly attribute boolean canSend;
/** 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 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
*/
void registerAddonHistogram(in ACString addon_id, in ACString name,
in PRUint32 min, in PRUint32 max,
in PRUint32 bucket_count,
in unsigned long histogram_type);
/**
* 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
*
* The returned object has the same functions as a histogram returned
* from newHistogram.
*/
[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);
/**
* 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;
};