1 /* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2  */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef Telemetry_h__
8 #define Telemetry_h__
9 
10 #include "mozilla/GuardObjects.h"
11 #include "mozilla/TimeStamp.h"
12 #include "mozilla/StartupTimeline.h"
13 #include "nsTArray.h"
14 #include "nsString.h"
15 #include "nsXULAppAPI.h"
16 
17 #include "mozilla/TelemetryHistogramEnums.h"
18 #include "mozilla/TelemetryScalarEnums.h"
19 
20 /******************************************************************************
21  * This implements the Telemetry system.
22  * It allows recording into histograms as well some more specialized data
23  * points and gives access to the data.
24  *
25  * For documentation on how to add and use new Telemetry probes, see:
26  * https://developer.mozilla.org/en-US/docs/Mozilla/Performance/Adding_a_new_Telemetry_probe
27  *
28  * For more general information on Telemetry see:
29  * https://wiki.mozilla.org/Telemetry
30  *****************************************************************************/
31 
32 namespace mozilla {
33 namespace HangMonitor {
34 class HangAnnotations;
35 }  // namespace HangMonitor
36 namespace Telemetry {
37 
38 struct HistogramAccumulation;
39 struct KeyedHistogramAccumulation;
40 struct ScalarAction;
41 struct KeyedScalarAction;
42 struct ChildEventData;
43 
44 /**
45  * Initialize the Telemetry service on the main thread at startup.
46  */
47 void Init();
48 
49 /**
50  * Adds sample to a histogram defined in TelemetryHistogramEnums.h
51  *
52  * @param id - histogram id
53  * @param sample - value to record.
54  */
55 void Accumulate(HistogramID id, uint32_t sample);
56 
57 /**
58  * Adds an array of samples to a histogram defined in TelemetryHistograms.h
59  * @param id - histogram id
60  * @param samples - values to record.
61  */
62 void Accumulate(HistogramID id, const nsTArray<uint32_t>& samples);
63 
64 /**
65  * Adds sample to a keyed histogram defined in TelemetryHistogramEnums.h
66  *
67  * @param id - keyed histogram id
68  * @param key - the string key
69  * @param sample - (optional) value to record, defaults to 1.
70  */
71 void Accumulate(HistogramID id, const nsCString& key, uint32_t sample = 1);
72 
73 /**
74  * Adds an array of samples to a histogram defined in TelemetryHistograms.h
75  * @param id - histogram id
76  * @param samples - values to record.
77  * @param key - the string key
78  */
79 void Accumulate(HistogramID id, const nsCString& key,
80                 const nsTArray<uint32_t>& samples);
81 
82 /**
83  * Adds a sample to a histogram defined in TelemetryHistogramEnums.h.
84  * This function is here to support telemetry measurements from Java,
85  * where we have only names and not numeric IDs.  You should almost
86  * certainly be using the by-enum-id version instead of this one.
87  *
88  * @param name - histogram name
89  * @param sample - value to record
90  */
91 void Accumulate(const char* name, uint32_t sample);
92 
93 /**
94  * Adds a sample to a histogram defined in TelemetryHistogramEnums.h.
95  * This function is here to support telemetry measurements from Java,
96  * where we have only names and not numeric IDs.  You should almost
97  * certainly be using the by-enum-id version instead of this one.
98  *
99  * @param name - histogram name
100  * @param key - the string key
101  * @param sample - sample - (optional) value to record, defaults to 1.
102  */
103 void Accumulate(const char* name, const nsCString& key, uint32_t sample = 1);
104 
105 /**
106  * Adds sample to a categorical histogram defined in TelemetryHistogramEnums.h
107  * This is the typesafe - and preferred - way to use the categorical histograms
108  * by passing values from the corresponding Telemetry::LABELS_* enum.
109  *
110  * @param enumValue - Label value from one of the Telemetry::LABELS_* enums.
111  */
112 template <class E>
AccumulateCategorical(E enumValue)113 void AccumulateCategorical(E enumValue) {
114   static_assert(IsCategoricalLabelEnum<E>::value,
115                 "Only categorical label enum types are supported.");
116   Accumulate(static_cast<HistogramID>(CategoricalLabelId<E>::value),
117              static_cast<uint32_t>(enumValue));
118 };
119 
120 /**
121  * Adds an array of samples to categorical histograms defined in
122  * TelemetryHistogramEnums.h This is the typesafe - and preferred - way to use
123  * the categorical histograms by passing values from the corresponding
124  * Telemetry::LABELS_* enums.
125  *
126  * @param enumValues - Array of labels from Telemetry::LABELS_* enums.
127  */
128 template <class E>
AccumulateCategorical(const nsTArray<E> & enumValues)129 void AccumulateCategorical(const nsTArray<E>& enumValues) {
130   static_assert(IsCategoricalLabelEnum<E>::value,
131                 "Only categorical label enum types are supported.");
132   nsTArray<uint32_t> intSamples(enumValues.Length());
133 
134   for (E aValue : enumValues) {
135     intSamples.AppendElement(static_cast<uint32_t>(aValue));
136   }
137 
138   HistogramID categoricalId =
139       static_cast<HistogramID>(CategoricalLabelId<E>::value);
140 
141   Accumulate(categoricalId, intSamples);
142 }
143 
144 /**
145  * Adds sample to a keyed categorical histogram defined in
146  * TelemetryHistogramEnums.h This is the typesafe - and preferred - way to use
147  * the keyed categorical histograms by passing values from the corresponding
148  * Telemetry::LABELS_* enum.
149  *
150  * @param key - the string key
151  * @param enumValue - Label value from one of the Telemetry::LABELS_* enums.
152  */
153 template <class E>
AccumulateCategoricalKeyed(const nsCString & key,E enumValue)154 void AccumulateCategoricalKeyed(const nsCString& key, E enumValue) {
155   static_assert(IsCategoricalLabelEnum<E>::value,
156                 "Only categorical label enum types are supported.");
157   Accumulate(static_cast<HistogramID>(CategoricalLabelId<E>::value), key,
158              static_cast<uint32_t>(enumValue));
159 };
160 
161 /**
162  * Adds an array of samples to a keyed categorical histogram defined in
163  * TelemetryHistogramEnums.h. This is the typesafe - and preferred - way to use
164  * the keyed categorical histograms by passing values from the corresponding
165  * Telemetry::LABELS_*enum.
166  *
167  * @param key - the string key
168  * @param enumValue - Label value from one of the Telemetry::LABELS_* enums.
169  */
170 template <class E>
AccumulateCategoricalKeyed(const nsCString & key,const nsTArray<E> & enumValues)171 void AccumulateCategoricalKeyed(const nsCString& key,
172                                 const nsTArray<E>& enumValues) {
173   static_assert(IsCategoricalLabelEnum<E>::value,
174                 "Only categorical label enum types are supported.");
175   nsTArray<uint32_t> intSamples(enumValues.Length());
176 
177   for (E aValue : enumValues) {
178     intSamples.AppendElement(static_cast<uint32_t>(aValue));
179   }
180 
181   Accumulate(static_cast<HistogramID>(CategoricalLabelId<E>::value), key,
182              intSamples);
183 };
184 
185 /**
186  * Adds sample to a categorical histogram defined in TelemetryHistogramEnums.h
187  * This string will be matched against the labels defined in Histograms.json.
188  * If the string does not match a label defined for the histogram, nothing will
189  * be recorded.
190  *
191  * @param id - The histogram id.
192  * @param label - A string label value that is defined in Histograms.json for
193  * this histogram.
194  */
195 void AccumulateCategorical(HistogramID id, const nsCString& label);
196 
197 /**
198  * Adds an array of samples to a categorical histogram defined in
199  * Histograms.json
200  *
201  * @param id - The histogram id
202  * @param labels - The array of labels to accumulate
203  */
204 void AccumulateCategorical(HistogramID id, const nsTArray<nsCString>& labels);
205 
206 /**
207  * Adds time delta in milliseconds to a histogram defined in
208  * TelemetryHistogramEnums.h
209  *
210  * @param id - histogram id
211  * @param start - start time
212  * @param end - end time
213  */
214 void AccumulateTimeDelta(HistogramID id, TimeStamp start,
215                          TimeStamp end = TimeStamp::Now());
216 
217 /**
218  * Adds time delta in milliseconds to a keyed histogram defined in
219  * TelemetryHistogramEnums.h
220  *
221  * @param id - histogram id
222  * @param key - the string key
223  * @param start - start time
224  * @param end - end time
225  */
226 void AccumulateTimeDelta(HistogramID id, const nsCString& key, TimeStamp start,
227                          TimeStamp end = TimeStamp::Now());
228 
229 /**
230  * Enable/disable recording for this histogram in this process at runtime.
231  * Recording is enabled by default, unless listed at
232  * kRecordingInitiallyDisabledIDs[]. id must be a valid telemetry enum,
233  *
234  * @param id - histogram id
235  * @param enabled - whether or not to enable recording from now on.
236  */
237 void SetHistogramRecordingEnabled(HistogramID id, bool enabled);
238 
239 const char* GetHistogramName(HistogramID id);
240 
241 template <HistogramID id>
242 class MOZ_RAII AutoTimer {
243  public:
244   explicit AutoTimer(TimeStamp aStart = TimeStamp::Now()
245                          MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
start(aStart)246       : start(aStart) {
247     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
248   }
249 
250   explicit AutoTimer(const nsCString& aKey, TimeStamp aStart = TimeStamp::Now()
251                                                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
start(aStart)252       : start(aStart), key(aKey) {
253     MOZ_ASSERT(!aKey.IsEmpty(), "The key must not be empty.");
254     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
255   }
256 
~AutoTimer()257   ~AutoTimer() {
258     if (key.IsEmpty()) {
259       AccumulateTimeDelta(id, start);
260     } else {
261       AccumulateTimeDelta(id, key, start);
262     }
263   }
264 
265  private:
266   const TimeStamp start;
267   const nsCString key;
268   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
269 };
270 
271 template <HistogramID id>
272 class MOZ_RAII AutoCounter {
273  public:
274   explicit AutoCounter(
275       uint32_t counterStart = 0 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
counter(counterStart)276       : counter(counterStart) {
277     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
278   }
279 
~AutoCounter()280   ~AutoCounter() { Accumulate(id, counter); }
281 
282   // Prefix increment only, to encourage good habits.
283   void operator++() { ++counter; }
284 
285   // Chaining doesn't make any sense, don't return anything.
286   void operator+=(int increment) { counter += increment; }
287 
288  private:
289   uint32_t counter;
290   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
291 };
292 
293 /**
294  * Indicates whether Telemetry base data recording is turned on. Added for
295  * future uses.
296  */
297 bool CanRecordBase();
298 
299 /**
300  * Indicates whether Telemetry extended data recording is turned on.  This is
301  * intended to guard calls to Accumulate when the statistic being recorded is
302  * expensive to compute.
303  */
304 bool CanRecordExtended();
305 
306 /**
307  * Indicates whether Telemetry release data recording is turned on. Usually
308  * true.
309  *
310  * @see nsITelemetry.canRecordReleaseData
311  */
312 bool CanRecordReleaseData();
313 
314 /**
315  * Indicates whether Telemetry pre-release data recording is turned on. Tends
316  * to be true on pre-release channels.
317  *
318  * @see nsITelemetry.canRecordPrereleaseData
319  */
320 bool CanRecordPrereleaseData();
321 
322 /**
323  * Records slow SQL statements for Telemetry reporting.
324  *
325  * @param statement - offending SQL statement to record
326  * @param dbName - DB filename
327  * @param delay - execution time in milliseconds
328  */
329 void RecordSlowSQLStatement(const nsACString& statement,
330                             const nsACString& dbName, uint32_t delay);
331 
332 /**
333  * Record Webrtc ICE candidate type combinations in a 17bit bitmask
334  *
335  * @param iceCandidateBitmask - the bitmask representing local and remote ICE
336  *                              candidate types present for the connection
337  * @param success - did the peer connection connected
338  */
339 void RecordWebrtcIceCandidates(const uint32_t iceCandidateBitmask,
340                                const bool success);
341 /**
342  * Initialize I/O Reporting
343  * Initially this only records I/O for files in the binary directory.
344  *
345  * @param aXreDir - XRE directory
346  */
347 void InitIOReporting(nsIFile* aXreDir);
348 
349 /**
350  * Set the profile directory. Once called, files in the profile directory will
351  * be included in I/O reporting. We can't use the directory
352  * service to obtain this information because it isn't running yet.
353  */
354 void SetProfileDir(nsIFile* aProfD);
355 
356 /**
357  * Called to inform Telemetry that startup has completed.
358  */
359 void LeavingStartupStage();
360 
361 /**
362  * Called to inform Telemetry that shutdown is commencing.
363  */
364 void EnteringShutdownStage();
365 
366 /**
367  * Thresholds for a statement to be considered slow, in milliseconds
368  */
369 const uint32_t kSlowSQLThresholdForMainThread = 50;
370 const uint32_t kSlowSQLThresholdForHelperThreads = 100;
371 
372 class ProcessedStack;
373 
374 /**
375  * Record the main thread's call stack after it hangs.
376  *
377  * @param aDuration - Approximate duration of main thread hang, in seconds
378  * @param aStack - Array of PCs from the hung call stack
379  * @param aSystemUptime - System uptime at the time of the hang, in minutes
380  * @param aFirefoxUptime - Firefox uptime at the time of the hang, in minutes
381  * @param aAnnotations - Any annotations to be added to the report
382  */
383 #if defined(MOZ_GECKO_PROFILER)
384 void RecordChromeHang(uint32_t aDuration, ProcessedStack& aStack,
385                       int32_t aSystemUptime, int32_t aFirefoxUptime,
386                       mozilla::HangMonitor::HangAnnotations&& aAnnotations);
387 
388 /**
389  * Record the current thread's call stack on demand. Note that, the stack is
390  * only captured once. Subsequent calls result in incrementing the capture
391  * counter.
392  *
393  * @param aKey - A user defined key associated with the captured stack.
394  *
395  * NOTE: Unwinding call stacks is an expensive operation performance-wise.
396  */
397 void CaptureStack(const nsCString& aKey);
398 #endif
399 
400 /**
401  * Record a failed attempt at locking the user's profile.
402  *
403  * @param aProfileDir The profile directory whose lock attempt failed
404  */
405 void WriteFailedProfileLock(nsIFile* aProfileDir);
406 
407 /**
408  * Adds the value to the given scalar.
409  *
410  * @param aId The scalar enum id.
411  * @param aValue The value to add to the scalar.
412  */
413 void ScalarAdd(mozilla::Telemetry::ScalarID aId, uint32_t aValue);
414 
415 /**
416  * Sets the scalar to the given value.
417  *
418  * @param aId The scalar enum id.
419  * @param aValue The value to set the scalar to.
420  */
421 void ScalarSet(mozilla::Telemetry::ScalarID aId, uint32_t aValue);
422 
423 /**
424  * Sets the scalar to the given value.
425  *
426  * @param aId The scalar enum id.
427  * @param aValue The value to set the scalar to.
428  */
429 void ScalarSet(mozilla::Telemetry::ScalarID aId, bool aValue);
430 
431 /**
432  * Sets the scalar to the given value.
433  *
434  * @param aId The scalar enum id.
435  * @param aValue The value to set the scalar to, truncated to
436  *        50 characters if exceeding that length.
437  */
438 void ScalarSet(mozilla::Telemetry::ScalarID aId, const nsAString& aValue);
439 
440 /**
441  * Sets the scalar to the maximum of the current and the passed value.
442  *
443  * @param aId The scalar enum id.
444  * @param aValue The value the scalar is set to if its greater
445  *        than the current value.
446  */
447 void ScalarSetMaximum(mozilla::Telemetry::ScalarID aId, uint32_t aValue);
448 
449 /**
450  * Adds the value to the given scalar.
451  *
452  * @param aId The scalar enum id.
453  * @param aKey The scalar key.
454  * @param aValue The value to add to the scalar.
455  */
456 void ScalarAdd(mozilla::Telemetry::ScalarID aId, const nsAString& aKey,
457                uint32_t aValue);
458 
459 /**
460  * Sets the scalar to the given value.
461  *
462  * @param aId The scalar enum id.
463  * @param aKey The scalar key.
464  * @param aValue The value to set the scalar to.
465  */
466 void ScalarSet(mozilla::Telemetry::ScalarID aId, const nsAString& aKey,
467                uint32_t aValue);
468 
469 /**
470  * Sets the scalar to the given value.
471  *
472  * @param aId The scalar enum id.
473  * @param aKey The scalar key.
474  * @param aValue The value to set the scalar to.
475  */
476 void ScalarSet(mozilla::Telemetry::ScalarID aId, const nsAString& aKey,
477                bool aValue);
478 
479 /**
480  * Sets the scalar to the maximum of the current and the passed value.
481  *
482  * @param aId The scalar enum id.
483  * @param aKey The scalar key.
484  * @param aValue The value the scalar is set to if its greater
485  *        than the current value.
486  */
487 void ScalarSetMaximum(mozilla::Telemetry::ScalarID aId, const nsAString& aKey,
488                       uint32_t aValue);
489 
490 }  // namespace Telemetry
491 }  // namespace mozilla
492 
493 #endif  // Telemetry_h__
494