toolkit/components/telemetry/Telemetry.h
author Wes Kocher <wkocher@mozilla.com>
Wed, 07 Sep 2016 10:18:17 -0700
changeset 313071 1530103e032c225c93bf7ac8fc581ccbab898275
parent 312992 fc16cda7781bf831684253c5e31e3fd87011e3c2
child 314436 9b792ae11734c602485896031a6d3400a3f603b3
permissions -rw-r--r--
Backed out 17 changesets (bug 1277504, bug 1218577, bug 1218576) for ASAN bc2 failures a=backout Backed out changeset 62009556e4ad (bug 1218576) Backed out changeset 57f9849f0f8f (bug 1218576) Backed out changeset 9595c56c9db2 (bug 1277504) Backed out changeset 9d15ae92f2fa (bug 1218576) Backed out changeset ea7282078b05 (bug 1218576) Backed out changeset 848f4ef30978 (bug 1218576) Backed out changeset 1b6666eb3b81 (bug 1218576) Backed out changeset ce2a2dabb042 (bug 1218576) Backed out changeset 3caacb5c213b (bug 1218576) Backed out changeset c68fc5ad5ecf (bug 1218576) Backed out changeset 1678482b2fad (bug 1218576) Backed out changeset df28918fe236 (bug 1218576) Backed out changeset eb5dbe28ab20 (bug 1218576) Backed out changeset baf105cbe0c8 (bug 1218576) Backed out changeset 7fdd6b6ab594 (bug 1218576) Backed out changeset a0a4829d0ca0 (bug 1218577) Backed out changeset fc16cda7781b (bug 1218576)

/* -*-  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 "nsStringGlue.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 {

enum TimerResolution {
  Millisecond,
  Microsecond
};

/**
 * Create and destroy the underlying base::StatisticsRecorder singleton.
 * Creation has to be done very early in the startup sequence.
 */
void CreateStatisticsRecorder();
void DestroyStatisticsRecorder();

/**
 * 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(ID id, uint32_t sample);

/**
 * 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(ID id, const nsCString& key, uint32_t sample = 1);

/**
 * 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<ID>(CategoricalLabelId<E>::value),
             static_cast<uint32_t>(enumValue));
};

/**
 * 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(ID id, const nsCString& label);

/**
 * 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(ID id, TimeStamp start, TimeStamp end = TimeStamp::Now());

/**
 * This clears the data for a histogram in TelemetryHistogramEnums.h.
 *
 * @param id - histogram id
 */
void ClearHistogram(ID id);

/**
 * Enable/disable recording for this histogram at runtime.
 * Recording is enabled by default, unless listed at kRecordingInitiallyDisabledIDs[].
 * id must be a valid telemetry enum, otherwise an assertion is triggered.
 *
 * @param id - histogram id
 * @param enabled - whether or not to enable recording from now on.
 */
void SetHistogramRecordingEnabled(ID id, bool enabled);

const char* GetHistogramName(ID id);

/**
 * Those wrappers are needed because the VS versions we use do not support free
 * functions with default template arguments.
 */
template<TimerResolution res>
struct AccumulateDelta_impl
{
  static void compute(ID id, TimeStamp start, TimeStamp end = TimeStamp::Now());
  static void compute(ID id, const nsCString& key, TimeStamp start, TimeStamp end = TimeStamp::Now());
};

template<>
struct AccumulateDelta_impl<Millisecond>
{
  static void compute(ID id, TimeStamp start, TimeStamp end = TimeStamp::Now()) {
    Accumulate(id, static_cast<uint32_t>((end - start).ToMilliseconds()));
  }
  static void compute(ID id, const nsCString& key, TimeStamp start, TimeStamp end = TimeStamp::Now()) {
    Accumulate(id, key, static_cast<uint32_t>((end - start).ToMilliseconds()));
  }
};

template<>
struct AccumulateDelta_impl<Microsecond>
{
  static void compute(ID id, TimeStamp start, TimeStamp end = TimeStamp::Now()) {
    Accumulate(id, static_cast<uint32_t>((end - start).ToMicroseconds()));
  }
  static void compute(ID id, const nsCString& key, TimeStamp start, TimeStamp end = TimeStamp::Now()) {
    Accumulate(id, key, static_cast<uint32_t>((end - start).ToMicroseconds()));
  }
};


template<ID id, TimerResolution res = Millisecond>
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_GUARD_OBJECT_NOTIFIER_INIT;
  }

  ~AutoTimer() {
    if (key.IsEmpty()) {
      AccumulateDelta_impl<res>::compute(id, start);
    } else {
      AccumulateDelta_impl<res>::compute(id, key, start);
    }
  }

private:
  const TimeStamp start;
  const nsCString key;
  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};

template<ID 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++() {
    ++counter;
  }

  // Chaining doesn't make any sense, don't return anything.
  void operator+=(int increment) {
    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();

/**
 * 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
 * @param loop - was this a Firefox Hello AKA Loop call
 */
void
RecordWebrtcIceCandidates(const uint32_t iceCandidateBitmask,
                          const bool success,
                          const bool loop);
/**
 * 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_ENABLE_PROFILER_SPS)
void RecordChromeHang(uint32_t aDuration,
                      ProcessedStack &aStack,
                      int32_t aSystemUptime,
                      int32_t aFirefoxUptime,
                      mozilla::UniquePtr<mozilla::HangMonitor::HangAnnotations>
                              aAnnotations);
#endif

class ThreadHangStats;

/**
 * Move a ThreadHangStats to Telemetry storage. Normally Telemetry queries
 * for active ThreadHangStats through BackgroundHangMonitor, but once a
 * thread exits, the thread's copy of ThreadHangStats needs to be moved to
 * inside Telemetry using this function.
 *
 * @param aStats ThreadHangStats to save; the data inside aStats
 *               will be moved and aStats should be treated as
 *               invalid after this function returns
 */
void RecordThreadHangStats(ThreadHangStats& aStats);

/**
 * 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 unsigned 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 numeric, unsigned 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 string 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 unsigned value the scalar is set to if its greater
 *        than the current value.
 */
void ScalarSetMaximum(mozilla::Telemetry::ScalarID aId, uint32_t aValue);

} // namespace Telemetry
} // namespace mozilla

#endif // Telemetry_h__