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