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