NS_IMETHODIMP TelemetryImpl::GetHistogramSnapshots(JSContext *cx, jsval *ret) { JSObject *root_obj = JS_NewObject(cx, NULL, NULL, NULL); if (!root_obj) return NS_ERROR_FAILURE; *ret = OBJECT_TO_JSVAL(root_obj); StatisticsRecorder::Histograms h; StatisticsRecorder::GetHistograms(&h); for (StatisticsRecorder::Histograms::iterator it = h.begin(); it != h.end();++it) { Histogram *h = *it; JSObject *hobj = JS_NewObject(cx, NULL, NULL, NULL); if (!(hobj && JS_DefineProperty(cx, root_obj, h->histogram_name().c_str(), OBJECT_TO_JSVAL(hobj), NULL, NULL, JSPROP_ENUMERATE) && ReflectHistogramSnapshot(cx, hobj, h))) { return NS_ERROR_FAILURE; } } MutexAutoLock hashMutex(mHashMutex); // Add info about slow SQL queries on the main thread if (!AddSlowSQLInfo(cx, root_obj, true)) return NS_ERROR_FAILURE; // Add info about slow SQL queries on other threads if (!AddSlowSQLInfo(cx, root_obj, false)) return NS_ERROR_FAILURE; return NS_OK; }
NS_IMETHODIMP TelemetryImpl::GetHistogramSnapshots(JSContext *cx, jsval *ret) { JSObject *root_obj = JS_NewObject(cx, NULL, NULL, NULL); if (!root_obj) return NS_ERROR_FAILURE; *ret = OBJECT_TO_JSVAL(root_obj); // Ensure that all the HISTOGRAM_FLAG 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) { Histogram *h; DebugOnly<nsresult> rv = GetHistogramByEnumId(Telemetry::ID(i), &h); MOZ_ASSERT(NS_SUCCEEDED(rv)); } }; StatisticsRecorder::Histograms hs; StatisticsRecorder::GetHistograms(&hs); // We identify corrupt histograms first, rather than interspersing it // in the loop below, to ensure that our corruption statistics don't // depend on histogram enumeration order. // // Of course, we hope that all of these corruption-statistics // histograms are not themselves corrupt... IdentifyCorruptHistograms(hs); // OK, now we can actually reflect things. for (HistogramIterator it = hs.begin(); it != hs.end(); ++it) { Histogram *h = *it; if (!ShouldReflectHistogram(h) || IsEmpty(h)) { continue; } JSObject *hobj = JS_NewObject(cx, NULL, NULL, NULL); if (!hobj) { return NS_ERROR_FAILURE; } JS::AutoObjectRooter root(cx, hobj); switch (ReflectHistogramSnapshot(cx, hobj, h)) { case REFLECT_CORRUPT: // We can still hit this case even if ShouldReflectHistograms // returns true. The histogram lies outside of our control // somehow; just skip it. continue; case REFLECT_FAILURE: return NS_ERROR_FAILURE; case REFLECT_OK: if (!JS_DefineProperty(cx, root_obj, h->histogram_name().c_str(), OBJECT_TO_JSVAL(hobj), NULL, NULL, JSPROP_ENUMERATE)) { return NS_ERROR_FAILURE; } } } return NS_OK; }
NS_IMETHODIMP TelemetryImpl::GetHistogramSnapshots(JSContext *cx, jsval *ret) { JSObject *root_obj = JS_NewObject(cx, NULL, NULL, NULL); if (!root_obj) return NS_ERROR_FAILURE; *ret = OBJECT_TO_JSVAL(root_obj); StatisticsRecorder::Histograms hs; StatisticsRecorder::GetHistograms(&hs); // We identify corrupt histograms first, rather than interspersing it // in the loop below, to ensure that our corruption statistics don't // depend on histogram enumeration order. // // Of course, we hope that all of these corruption-statistics // histograms are not themselves corrupt... IdentifyCorruptHistograms(hs); // OK, now we can actually reflect things. for (HistogramIterator it = hs.begin(); it != hs.end(); ++it) { Histogram *h = *it; if (!ShouldReflectHistogram(h)) { continue; } JSObject *hobj = JS_NewObject(cx, NULL, NULL, NULL); if (!hobj) { return NS_ERROR_FAILURE; } switch (ReflectHistogramSnapshot(cx, hobj, h)) { case REFLECT_CORRUPT: // We can still hit this case even if ShouldReflectHistograms // returns true. The histogram lies outside of our control // somehow; just skip it. continue; case REFLECT_FAILURE: return NS_ERROR_FAILURE; case REFLECT_OK: if (!JS_DefineProperty(cx, root_obj, h->histogram_name().c_str(), OBJECT_TO_JSVAL(hobj), NULL, NULL, JSPROP_ENUMERATE)) { return NS_ERROR_FAILURE; } } } return NS_OK; }
void TelemetryImpl::IdentifyCorruptHistograms(StatisticsRecorder::Histograms &hs) { for (HistogramIterator it = hs.begin(); it != hs.end(); ++it) { Histogram *h = *it; Telemetry::ID id; nsresult rv = GetHistogramEnumId(h->histogram_name().c_str(), &id); // This histogram isn't a static histogram, just ignore it. if (NS_FAILED(rv)) { continue; } if (gCorruptHistograms[id]) { continue; } Histogram::SampleSet ss; h->SnapshotSample(&ss); Histogram::Inconsistencies check = h->FindCorruption(ss); bool corrupt = (check != Histogram::NO_INCONSISTENCIES); if (corrupt) { Telemetry::ID corruptID = Telemetry::HistogramCount; if (check & Histogram::RANGE_CHECKSUM_ERROR) { corruptID = Telemetry::RANGE_CHECKSUM_ERRORS; } else if (check & Histogram::BUCKET_ORDER_ERROR) { corruptID = Telemetry::BUCKET_ORDER_ERRORS; } else if (check & Histogram::COUNT_HIGH_ERROR) { corruptID = Telemetry::TOTAL_COUNT_HIGH_ERRORS; } else if (check & Histogram::COUNT_LOW_ERROR) { corruptID = Telemetry::TOTAL_COUNT_LOW_ERRORS; } Telemetry::Accumulate(corruptID, 1); } gCorruptHistograms[id] = corrupt; } }
NS_IMETHODIMP TelemetryImpl::GetHistogramSnapshots(JSContext *cx, jsval *ret) { JSObject *root_obj = JS_NewObject(cx, NULL, NULL, NULL); if (!root_obj) return NS_ERROR_FAILURE; *ret = OBJECT_TO_JSVAL(root_obj); StatisticsRecorder::Histograms h; StatisticsRecorder::GetHistograms(&h); for (StatisticsRecorder::Histograms::iterator it = h.begin(); it != h.end();++it) { Histogram *h = *it; JSObject *hobj = JS_NewObject(cx, NULL, NULL, NULL); if (!(hobj && JS_DefineProperty(cx, root_obj, h->histogram_name().c_str(), OBJECT_TO_JSVAL(hobj), NULL, NULL, JSPROP_ENUMERATE) && ReflectHistogramSnapshot(cx, hobj, h))) { return NS_ERROR_FAILURE; } } return NS_OK; }