mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-22 17:55:50 +00:00
bad7346661
Made sure the telemetry AutoCounter and RuntimeAutoCounter increments are guarded against over/under flows. MozReview-Commit-ID: 8CZhpKkthoB --HG-- extra : rebase_source : 4eafb249555128f9bc9fc3ecea13983bfa402aab
599 lines
18 KiB
C++
599 lines
18 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef Telemetry_h__
|
|
#define Telemetry_h__
|
|
|
|
#include "mozilla/GuardObjects.h"
|
|
#include "mozilla/TimeStamp.h"
|
|
#include "mozilla/StartupTimeline.h"
|
|
#include "nsTArray.h"
|
|
#include "nsString.h"
|
|
#include "nsXULAppAPI.h"
|
|
|
|
#include "mozilla/TelemetryHistogramEnums.h"
|
|
#include "mozilla/TelemetryScalarEnums.h"
|
|
|
|
/******************************************************************************
|
|
* This implements the Telemetry system.
|
|
* It allows recording into histograms as well some more specialized data
|
|
* points and gives access to the data.
|
|
*
|
|
* For documentation on how to add and use new Telemetry probes, see:
|
|
* https://developer.mozilla.org/en-US/docs/Mozilla/Performance/Adding_a_new_Telemetry_probe
|
|
*
|
|
* For more general information on Telemetry see:
|
|
* https://wiki.mozilla.org/Telemetry
|
|
*****************************************************************************/
|
|
|
|
namespace mozilla {
|
|
namespace HangMonitor {
|
|
class HangAnnotations;
|
|
} // namespace HangMonitor
|
|
namespace Telemetry {
|
|
|
|
struct HistogramAccumulation;
|
|
struct KeyedHistogramAccumulation;
|
|
struct ScalarAction;
|
|
struct KeyedScalarAction;
|
|
struct ChildEventData;
|
|
|
|
/**
|
|
* Initialize the Telemetry service on the main thread at startup.
|
|
*/
|
|
void Init();
|
|
|
|
/**
|
|
* Adds sample to a histogram defined in TelemetryHistogramEnums.h
|
|
*
|
|
* @param id - histogram id
|
|
* @param sample - value to record.
|
|
*/
|
|
void Accumulate(HistogramID id, uint32_t sample);
|
|
|
|
/**
|
|
* Adds an array of samples to a histogram defined in TelemetryHistograms.h
|
|
* @param id - histogram id
|
|
* @param samples - values to record.
|
|
*/
|
|
void Accumulate(HistogramID id, const nsTArray<uint32_t>& samples);
|
|
|
|
/**
|
|
* Adds sample to a keyed histogram defined in TelemetryHistogramEnums.h
|
|
*
|
|
* @param id - keyed histogram id
|
|
* @param key - the string key
|
|
* @param sample - (optional) value to record, defaults to 1.
|
|
*/
|
|
void Accumulate(HistogramID id, const nsCString& key, uint32_t sample = 1);
|
|
|
|
/**
|
|
* Adds an array of samples to a histogram defined in TelemetryHistograms.h
|
|
* @param id - histogram id
|
|
* @param samples - values to record.
|
|
* @param key - the string key
|
|
*/
|
|
void Accumulate(HistogramID id, const nsCString& key, const nsTArray<uint32_t>& samples);
|
|
|
|
/**
|
|
* Adds a sample to a histogram defined in TelemetryHistogramEnums.h.
|
|
* This function is here to support telemetry measurements from Java,
|
|
* where we have only names and not numeric IDs. You should almost
|
|
* certainly be using the by-enum-id version instead of this one.
|
|
*
|
|
* @param name - histogram name
|
|
* @param sample - value to record
|
|
*/
|
|
void Accumulate(const char* name, uint32_t sample);
|
|
|
|
/**
|
|
* Adds a sample to a histogram defined in TelemetryHistogramEnums.h.
|
|
* This function is here to support telemetry measurements from Java,
|
|
* where we have only names and not numeric IDs. You should almost
|
|
* certainly be using the by-enum-id version instead of this one.
|
|
*
|
|
* @param name - histogram name
|
|
* @param key - the string key
|
|
* @param sample - sample - (optional) value to record, defaults to 1.
|
|
*/
|
|
void Accumulate(const char *name, const nsCString& key, uint32_t sample = 1);
|
|
|
|
/**
|
|
* Adds sample to a categorical histogram defined in TelemetryHistogramEnums.h
|
|
* This is the typesafe - and preferred - way to use the categorical histograms
|
|
* by passing values from the corresponding Telemetry::LABELS_* enum.
|
|
*
|
|
* @param enumValue - Label value from one of the Telemetry::LABELS_* enums.
|
|
*/
|
|
template<class E>
|
|
void AccumulateCategorical(E enumValue) {
|
|
static_assert(IsCategoricalLabelEnum<E>::value,
|
|
"Only categorical label enum types are supported.");
|
|
Accumulate(static_cast<HistogramID>(CategoricalLabelId<E>::value),
|
|
static_cast<uint32_t>(enumValue));
|
|
};
|
|
|
|
/**
|
|
* Adds an array of samples to categorical histograms defined in TelemetryHistogramEnums.h
|
|
* This is the typesafe - and preferred - way to use the categorical histograms
|
|
* by passing values from the corresponding Telemetry::LABELS_* enums.
|
|
*
|
|
* @param enumValues - Array of labels from Telemetry::LABELS_* enums.
|
|
*/
|
|
template<class E>
|
|
void
|
|
AccumulateCategorical(const nsTArray<E>& enumValues)
|
|
{
|
|
static_assert(IsCategoricalLabelEnum<E>::value,
|
|
"Only categorical label enum types are supported.");
|
|
nsTArray<uint32_t> intSamples(enumValues.Length());
|
|
|
|
for (E aValue: enumValues){
|
|
intSamples.AppendElement(static_cast<uint32_t>(aValue));
|
|
}
|
|
|
|
HistogramID categoricalId = static_cast<HistogramID>(CategoricalLabelId<E>::value);
|
|
|
|
Accumulate(categoricalId, intSamples);
|
|
}
|
|
|
|
/**
|
|
* Adds sample to a keyed categorical histogram defined in TelemetryHistogramEnums.h
|
|
* This is the typesafe - and preferred - way to use the keyed categorical histograms
|
|
* by passing values from the corresponding Telemetry::LABELS_* enum.
|
|
*
|
|
* @param key - the string key
|
|
* @param enumValue - Label value from one of the Telemetry::LABELS_* enums.
|
|
*/
|
|
template<class E>
|
|
void AccumulateCategoricalKeyed(const nsCString& key, E enumValue) {
|
|
static_assert(IsCategoricalLabelEnum<E>::value,
|
|
"Only categorical label enum types are supported.");
|
|
Accumulate(static_cast<HistogramID>(CategoricalLabelId<E>::value),
|
|
key,
|
|
static_cast<uint32_t>(enumValue));
|
|
};
|
|
|
|
/**
|
|
* Adds an array of samples to a keyed categorical histogram defined in TelemetryHistogramEnums.h.
|
|
* This is the typesafe - and preferred - way to use the keyed categorical histograms
|
|
* by passing values from the corresponding Telemetry::LABELS_*enum.
|
|
*
|
|
* @param key - the string key
|
|
* @param enumValue - Label value from one of the Telemetry::LABELS_* enums.
|
|
*/
|
|
template<class E>
|
|
void AccumulateCategoricalKeyed(const nsCString& key, const nsTArray<E>& enumValues) {
|
|
static_assert(IsCategoricalLabelEnum<E>::value,
|
|
"Only categorical label enum types are supported.");
|
|
nsTArray<uint32_t> intSamples(enumValues.Length());
|
|
|
|
for (E aValue: enumValues){
|
|
intSamples.AppendElement(static_cast<uint32_t>(aValue));
|
|
}
|
|
|
|
Accumulate(static_cast<HistogramID>(CategoricalLabelId<E>::value),
|
|
key,
|
|
intSamples);
|
|
};
|
|
|
|
/**
|
|
* Adds sample to a categorical histogram defined in TelemetryHistogramEnums.h
|
|
* This string will be matched against the labels defined in Histograms.json.
|
|
* If the string does not match a label defined for the histogram, nothing will
|
|
* be recorded.
|
|
*
|
|
* @param id - The histogram id.
|
|
* @param label - A string label value that is defined in Histograms.json for this histogram.
|
|
*/
|
|
void AccumulateCategorical(HistogramID id, const nsCString& label);
|
|
|
|
/**
|
|
* Adds an array of samples to a categorical histogram defined in Histograms.json
|
|
*
|
|
* @param id - The histogram id
|
|
* @param labels - The array of labels to accumulate
|
|
*/
|
|
void AccumulateCategorical(HistogramID id, const nsTArray<nsCString>& labels);
|
|
|
|
/**
|
|
* Adds time delta in milliseconds to a histogram defined in TelemetryHistogramEnums.h
|
|
*
|
|
* @param id - histogram id
|
|
* @param start - start time
|
|
* @param end - end time
|
|
*/
|
|
void AccumulateTimeDelta(HistogramID id, TimeStamp start, TimeStamp end = TimeStamp::Now());
|
|
|
|
/**
|
|
* Adds time delta in milliseconds to a keyed histogram defined in
|
|
* TelemetryHistogramEnums.h
|
|
*
|
|
* @param id - histogram id
|
|
* @param key - the string key
|
|
* @param start - start time
|
|
* @param end - end time
|
|
*/
|
|
void
|
|
AccumulateTimeDelta(HistogramID id,
|
|
const nsCString& key,
|
|
TimeStamp start,
|
|
TimeStamp end = TimeStamp::Now());
|
|
|
|
/**
|
|
* Enable/disable recording for this histogram in this process at runtime.
|
|
* Recording is enabled by default, unless listed at
|
|
* kRecordingInitiallyDisabledIDs[]. id must be a valid telemetry enum,
|
|
*
|
|
* @param id - histogram id
|
|
* @param enabled - whether or not to enable recording from now on.
|
|
*/
|
|
void SetHistogramRecordingEnabled(HistogramID id, bool enabled);
|
|
|
|
const char* GetHistogramName(HistogramID id);
|
|
|
|
class MOZ_RAII RuntimeAutoTimer
|
|
{
|
|
public:
|
|
explicit RuntimeAutoTimer(Telemetry::HistogramID aId,
|
|
TimeStamp aStart = TimeStamp::Now()
|
|
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
|
: id(aId)
|
|
, start(aStart)
|
|
{
|
|
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
|
}
|
|
explicit RuntimeAutoTimer(Telemetry::HistogramID aId,
|
|
const nsCString& aKey,
|
|
TimeStamp aStart = TimeStamp::Now()
|
|
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
|
: id(aId)
|
|
, key(aKey)
|
|
, start(aStart)
|
|
{
|
|
MOZ_ASSERT(!aKey.IsEmpty(), "The key must not be empty.");
|
|
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
|
}
|
|
|
|
~RuntimeAutoTimer()
|
|
{
|
|
if (key.IsEmpty()) {
|
|
AccumulateTimeDelta(id, start);
|
|
} else {
|
|
AccumulateTimeDelta(id, key, start);
|
|
}
|
|
}
|
|
|
|
private:
|
|
Telemetry::HistogramID id;
|
|
const nsCString key;
|
|
const TimeStamp start;
|
|
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
|
};
|
|
|
|
template<HistogramID id>
|
|
class MOZ_RAII AutoTimer
|
|
{
|
|
public:
|
|
explicit AutoTimer(TimeStamp aStart = TimeStamp::Now() MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
|
: start(aStart)
|
|
{
|
|
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
|
}
|
|
|
|
explicit AutoTimer(const nsCString& aKey, TimeStamp aStart = TimeStamp::Now() MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
|
: start(aStart)
|
|
, key(aKey)
|
|
{
|
|
MOZ_ASSERT(!aKey.IsEmpty(), "The key must not be empty.");
|
|
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
|
}
|
|
|
|
~AutoTimer() {
|
|
if (key.IsEmpty()) {
|
|
AccumulateTimeDelta(id, start);
|
|
} else {
|
|
AccumulateTimeDelta(id, key, start);
|
|
}
|
|
}
|
|
|
|
private:
|
|
const TimeStamp start;
|
|
const nsCString key;
|
|
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
|
};
|
|
|
|
class MOZ_RAII RuntimeAutoCounter
|
|
{
|
|
public:
|
|
explicit RuntimeAutoCounter(
|
|
HistogramID aId,
|
|
uint32_t counterStart = 0 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
|
: id(aId)
|
|
, counter(counterStart)
|
|
{
|
|
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
|
}
|
|
|
|
~RuntimeAutoCounter()
|
|
{
|
|
Accumulate(id, counter);
|
|
}
|
|
|
|
// Prefix increment only, to encourage good habits.
|
|
void operator++()
|
|
{
|
|
if (NS_WARN_IF(counter == std::numeric_limits<uint32_t>::max())) {
|
|
return;
|
|
}
|
|
++counter;
|
|
}
|
|
|
|
// Chaining doesn't make any sense, don't return anything.
|
|
void operator+=(int increment)
|
|
{
|
|
if (NS_WARN_IF(increment > 0 &&
|
|
static_cast<uint32_t>(increment) >
|
|
(std::numeric_limits<uint32_t>::max() - counter))) {
|
|
counter = std::numeric_limits<uint32_t>::max();
|
|
return;
|
|
}
|
|
if (NS_WARN_IF(increment < 0 &&
|
|
static_cast<uint32_t>(-increment) > counter)) {
|
|
counter = std::numeric_limits<uint32_t>::min();
|
|
return;
|
|
}
|
|
counter += increment;
|
|
}
|
|
|
|
private:
|
|
HistogramID id;
|
|
uint32_t counter;
|
|
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
|
};
|
|
|
|
template<HistogramID id>
|
|
class MOZ_RAII AutoCounter {
|
|
public:
|
|
explicit AutoCounter(uint32_t counterStart = 0 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
|
: counter(counterStart)
|
|
{
|
|
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
|
}
|
|
|
|
~AutoCounter() {
|
|
Accumulate(id, counter);
|
|
}
|
|
|
|
// Prefix increment only, to encourage good habits.
|
|
void operator++()
|
|
{
|
|
if (NS_WARN_IF(counter == std::numeric_limits<uint32_t>::max())) {
|
|
return;
|
|
}
|
|
++counter;
|
|
}
|
|
|
|
// Chaining doesn't make any sense, don't return anything.
|
|
void operator+=(int increment)
|
|
{
|
|
if (NS_WARN_IF(increment > 0 &&
|
|
static_cast<uint32_t>(increment) >
|
|
(std::numeric_limits<uint32_t>::max() - counter))) {
|
|
counter = std::numeric_limits<uint32_t>::max();
|
|
return;
|
|
}
|
|
if (NS_WARN_IF(increment < 0 &&
|
|
static_cast<uint32_t>(-increment) > counter)) {
|
|
counter = std::numeric_limits<uint32_t>::min();
|
|
return;
|
|
}
|
|
counter += increment;
|
|
}
|
|
|
|
private:
|
|
uint32_t counter;
|
|
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
|
};
|
|
|
|
/**
|
|
* Indicates whether Telemetry base data recording is turned on. Added for future uses.
|
|
*/
|
|
bool CanRecordBase();
|
|
|
|
/**
|
|
* Indicates whether Telemetry extended data recording is turned on. This is intended
|
|
* to guard calls to Accumulate when the statistic being recorded is expensive to compute.
|
|
*/
|
|
bool CanRecordExtended();
|
|
|
|
/**
|
|
* Indicates whether Telemetry release data recording is turned on. Usually true.
|
|
*
|
|
* @see nsITelemetry.canRecordReleaseData
|
|
*/
|
|
bool CanRecordReleaseData();
|
|
|
|
/**
|
|
* Indicates whether Telemetry pre-release data recording is turned on. Tends
|
|
* to be true on pre-release channels.
|
|
*
|
|
* @see nsITelemetry.canRecordPrereleaseData
|
|
*/
|
|
bool CanRecordPrereleaseData();
|
|
|
|
/**
|
|
* Records slow SQL statements for Telemetry reporting.
|
|
*
|
|
* @param statement - offending SQL statement to record
|
|
* @param dbName - DB filename
|
|
* @param delay - execution time in milliseconds
|
|
*/
|
|
void RecordSlowSQLStatement(const nsACString &statement,
|
|
const nsACString &dbName,
|
|
uint32_t delay);
|
|
|
|
/**
|
|
* Record Webrtc ICE candidate type combinations in a 17bit bitmask
|
|
*
|
|
* @param iceCandidateBitmask - the bitmask representing local and remote ICE
|
|
* candidate types present for the connection
|
|
* @param success - did the peer connection connected
|
|
*/
|
|
void
|
|
RecordWebrtcIceCandidates(const uint32_t iceCandidateBitmask,
|
|
const bool success);
|
|
/**
|
|
* Initialize I/O Reporting
|
|
* Initially this only records I/O for files in the binary directory.
|
|
*
|
|
* @param aXreDir - XRE directory
|
|
*/
|
|
void InitIOReporting(nsIFile* aXreDir);
|
|
|
|
/**
|
|
* Set the profile directory. Once called, files in the profile directory will
|
|
* be included in I/O reporting. We can't use the directory
|
|
* service to obtain this information because it isn't running yet.
|
|
*/
|
|
void SetProfileDir(nsIFile* aProfD);
|
|
|
|
/**
|
|
* Called to inform Telemetry that startup has completed.
|
|
*/
|
|
void LeavingStartupStage();
|
|
|
|
/**
|
|
* Called to inform Telemetry that shutdown is commencing.
|
|
*/
|
|
void EnteringShutdownStage();
|
|
|
|
/**
|
|
* Thresholds for a statement to be considered slow, in milliseconds
|
|
*/
|
|
const uint32_t kSlowSQLThresholdForMainThread = 50;
|
|
const uint32_t kSlowSQLThresholdForHelperThreads = 100;
|
|
|
|
class ProcessedStack;
|
|
|
|
/**
|
|
* Record the main thread's call stack after it hangs.
|
|
*
|
|
* @param aDuration - Approximate duration of main thread hang, in seconds
|
|
* @param aStack - Array of PCs from the hung call stack
|
|
* @param aSystemUptime - System uptime at the time of the hang, in minutes
|
|
* @param aFirefoxUptime - Firefox uptime at the time of the hang, in minutes
|
|
* @param aAnnotations - Any annotations to be added to the report
|
|
*/
|
|
#if defined(MOZ_GECKO_PROFILER)
|
|
void RecordChromeHang(uint32_t aDuration,
|
|
ProcessedStack &aStack,
|
|
int32_t aSystemUptime,
|
|
int32_t aFirefoxUptime,
|
|
mozilla::HangMonitor::HangAnnotations&& aAnnotations);
|
|
|
|
/**
|
|
* Record the current thread's call stack on demand. Note that, the stack is
|
|
* only captured once. Subsequent calls result in incrementing the capture
|
|
* counter.
|
|
*
|
|
* @param aKey - A user defined key associated with the captured stack.
|
|
*
|
|
* NOTE: Unwinding call stacks is an expensive operation performance-wise.
|
|
*/
|
|
void CaptureStack(const nsCString& aKey);
|
|
#endif
|
|
|
|
/**
|
|
* Record a failed attempt at locking the user's profile.
|
|
*
|
|
* @param aProfileDir The profile directory whose lock attempt failed
|
|
*/
|
|
void WriteFailedProfileLock(nsIFile* aProfileDir);
|
|
|
|
/**
|
|
* Adds the value to the given scalar.
|
|
*
|
|
* @param aId The scalar enum id.
|
|
* @param aValue The value to add to the scalar.
|
|
*/
|
|
void ScalarAdd(mozilla::Telemetry::ScalarID aId, uint32_t aValue);
|
|
|
|
/**
|
|
* Sets the scalar to the given value.
|
|
*
|
|
* @param aId The scalar enum id.
|
|
* @param aValue The value to set the scalar to.
|
|
*/
|
|
void ScalarSet(mozilla::Telemetry::ScalarID aId, uint32_t aValue);
|
|
|
|
/**
|
|
* Sets the scalar to the given value.
|
|
*
|
|
* @param aId The scalar enum id.
|
|
* @param aValue The value to set the scalar to.
|
|
*/
|
|
void ScalarSet(mozilla::Telemetry::ScalarID aId, bool aValue);
|
|
|
|
/**
|
|
* Sets the scalar to the given value.
|
|
*
|
|
* @param aId The scalar enum id.
|
|
* @param aValue The value to set the scalar to, truncated to
|
|
* 50 characters if exceeding that length.
|
|
*/
|
|
void ScalarSet(mozilla::Telemetry::ScalarID aId, const nsAString& aValue);
|
|
|
|
/**
|
|
* Sets the scalar to the maximum of the current and the passed value.
|
|
*
|
|
* @param aId The scalar enum id.
|
|
* @param aValue The value the scalar is set to if its greater
|
|
* than the current value.
|
|
*/
|
|
void ScalarSetMaximum(mozilla::Telemetry::ScalarID aId, uint32_t aValue);
|
|
|
|
/**
|
|
* Adds the value to the given scalar.
|
|
*
|
|
* @param aId The scalar enum id.
|
|
* @param aKey The scalar key.
|
|
* @param aValue The value to add to the scalar.
|
|
*/
|
|
void ScalarAdd(mozilla::Telemetry::ScalarID aId, const nsAString& aKey, uint32_t aValue);
|
|
|
|
/**
|
|
* Sets the scalar to the given value.
|
|
*
|
|
* @param aId The scalar enum id.
|
|
* @param aKey The scalar key.
|
|
* @param aValue The value to set the scalar to.
|
|
*/
|
|
void ScalarSet(mozilla::Telemetry::ScalarID aId, const nsAString& aKey, uint32_t aValue);
|
|
|
|
/**
|
|
* Sets the scalar to the given value.
|
|
*
|
|
* @param aId The scalar enum id.
|
|
* @param aKey The scalar key.
|
|
* @param aValue The value to set the scalar to.
|
|
*/
|
|
void ScalarSet(mozilla::Telemetry::ScalarID aId, const nsAString& aKey, bool aValue);
|
|
|
|
/**
|
|
* Sets the scalar to the maximum of the current and the passed value.
|
|
*
|
|
* @param aId The scalar enum id.
|
|
* @param aKey The scalar key.
|
|
* @param aValue The value the scalar is set to if its greater
|
|
* than the current value.
|
|
*/
|
|
void ScalarSetMaximum(mozilla::Telemetry::ScalarID aId, const nsAString& aKey, uint32_t aValue);
|
|
|
|
} // namespace Telemetry
|
|
} // namespace mozilla
|
|
|
|
#endif // Telemetry_h__
|