|
1 /* Any copyright is dedicated to the Public Domain. |
|
2 http://creativecommons.org/publicdomain/zero/1.0/ */ |
|
3 |
|
4 const Cc = Components.classes; |
|
5 const Ci = Components.interfaces; |
|
6 const Cu = Components.utils; |
|
7 const INT_MAX = 0x7FFFFFFF; |
|
8 |
|
9 const Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry); |
|
10 Cu.import("resource://gre/modules/Services.jsm", this); |
|
11 |
|
12 function test_expired_histogram() { |
|
13 var histogram_id = "FOOBAR"; |
|
14 var test_expired_id = "TELEMETRY_TEST_EXPIRED"; |
|
15 var clone_id = "ExpiredClone"; |
|
16 var dummy = Telemetry.newHistogram(histogram_id, "28.0a1", 1, 2, 3, Telemetry.HISTOGRAM_EXPONENTIAL); |
|
17 var dummy_clone = Telemetry.histogramFrom(clone_id, test_expired_id); |
|
18 var rh = Telemetry.registeredHistograms([]); |
|
19 |
|
20 dummy.add(1); |
|
21 dummy_clone.add(1); |
|
22 |
|
23 do_check_eq(Telemetry.histogramSnapshots["__expired__"], undefined); |
|
24 do_check_eq(Telemetry.histogramSnapshots[histogram_id], undefined); |
|
25 do_check_eq(Telemetry.histogramSnapshots[test_expired_id], undefined); |
|
26 do_check_eq(Telemetry.histogramSnapshots[clone_id], undefined); |
|
27 do_check_eq(rh[test_expired_id], undefined); |
|
28 } |
|
29 |
|
30 function test_histogram(histogram_type, name, min, max, bucket_count) { |
|
31 var h = Telemetry.newHistogram(name, "never", min, max, bucket_count, histogram_type); |
|
32 var r = h.snapshot().ranges; |
|
33 var sum = 0; |
|
34 var log_sum = 0; |
|
35 var log_sum_squares = 0; |
|
36 for(var i=0;i<r.length;i++) { |
|
37 var v = r[i]; |
|
38 sum += v; |
|
39 if (histogram_type == Telemetry.HISTOGRAM_EXPONENTIAL) { |
|
40 var log_v = Math.log(1+v); |
|
41 log_sum += log_v; |
|
42 log_sum_squares += log_v*log_v; |
|
43 } |
|
44 h.add(v); |
|
45 } |
|
46 var s = h.snapshot(); |
|
47 // verify properties |
|
48 do_check_eq(sum, s.sum); |
|
49 if (histogram_type == Telemetry.HISTOGRAM_EXPONENTIAL) { |
|
50 // We do the log with float precision in C++ and double precision in |
|
51 // JS, so there's bound to be tiny discrepancies. Just check the |
|
52 // integer part. |
|
53 do_check_eq(Math.floor(log_sum), Math.floor(s.log_sum)); |
|
54 do_check_eq(Math.floor(log_sum_squares), Math.floor(s.log_sum_squares)); |
|
55 do_check_false("sum_squares_lo" in s); |
|
56 do_check_false("sum_squares_hi" in s); |
|
57 } else { |
|
58 // Doing the math to verify sum_squares was reflected correctly is |
|
59 // tedious in JavaScript. Just make sure we have something. |
|
60 do_check_neq(s.sum_squares_lo + s.sum_squares_hi, 0); |
|
61 do_check_false("log_sum" in s); |
|
62 do_check_false("log_sum_squares" in s); |
|
63 } |
|
64 |
|
65 // there should be exactly one element per bucket |
|
66 for each(var i in s.counts) { |
|
67 do_check_eq(i, 1); |
|
68 } |
|
69 var hgrams = Telemetry.histogramSnapshots |
|
70 gh = hgrams[name] |
|
71 do_check_eq(gh.histogram_type, histogram_type); |
|
72 |
|
73 do_check_eq(gh.min, min) |
|
74 do_check_eq(gh.max, max) |
|
75 |
|
76 // Check that booleans work with nonboolean histograms |
|
77 h.add(false); |
|
78 h.add(true); |
|
79 var s = h.snapshot().counts; |
|
80 do_check_eq(s[0], 2) |
|
81 do_check_eq(s[1], 2) |
|
82 |
|
83 // Check that clearing works. |
|
84 h.clear(); |
|
85 var s = h.snapshot(); |
|
86 for each(var i in s.counts) { |
|
87 do_check_eq(i, 0); |
|
88 } |
|
89 do_check_eq(s.sum, 0); |
|
90 if (histogram_type == Telemetry.HISTOGRAM_EXPONENTIAL) { |
|
91 do_check_eq(s.log_sum, 0); |
|
92 do_check_eq(s.log_sum_squares, 0); |
|
93 } else { |
|
94 do_check_eq(s.sum_squares_lo, 0); |
|
95 do_check_eq(s.sum_squares_hi, 0); |
|
96 } |
|
97 |
|
98 h.add(0); |
|
99 h.add(1); |
|
100 var c = h.snapshot().counts; |
|
101 do_check_eq(c[0], 1); |
|
102 do_check_eq(c[1], 1); |
|
103 } |
|
104 |
|
105 function expect_fail(f) { |
|
106 let failed = false; |
|
107 try { |
|
108 f(); |
|
109 failed = false; |
|
110 } catch (e) { |
|
111 failed = true; |
|
112 } |
|
113 do_check_true(failed); |
|
114 } |
|
115 |
|
116 function expect_success(f) { |
|
117 let succeeded = false; |
|
118 try { |
|
119 f(); |
|
120 succeeded = true; |
|
121 } catch (e) { |
|
122 succeeded = false; |
|
123 } |
|
124 do_check_true(succeeded); |
|
125 } |
|
126 |
|
127 function test_boolean_histogram() |
|
128 { |
|
129 var h = Telemetry.newHistogram("test::boolean histogram", "never", 99,1,4, Telemetry.HISTOGRAM_BOOLEAN); |
|
130 var r = h.snapshot().ranges; |
|
131 // boolean histograms ignore numeric parameters |
|
132 do_check_eq(uneval(r), uneval([0, 1, 2])) |
|
133 var sum = 0 |
|
134 for(var i=0;i<r.length;i++) { |
|
135 var v = r[i]; |
|
136 sum += v; |
|
137 h.add(v); |
|
138 } |
|
139 h.add(true); |
|
140 h.add(false); |
|
141 var s = h.snapshot(); |
|
142 do_check_eq(s.histogram_type, Telemetry.HISTOGRAM_BOOLEAN); |
|
143 // last bucket should always be 0 since .add parameters are normalized to either 0 or 1 |
|
144 do_check_eq(s.counts[2], 0); |
|
145 do_check_eq(s.sum, 3); |
|
146 do_check_eq(s.counts[0], 2); |
|
147 } |
|
148 |
|
149 function test_flag_histogram() |
|
150 { |
|
151 var h = Telemetry.newHistogram("test::flag histogram", "never", 130, 4, 5, Telemetry.HISTOGRAM_FLAG); |
|
152 var r = h.snapshot().ranges; |
|
153 // Flag histograms ignore numeric parameters. |
|
154 do_check_eq(uneval(r), uneval([0, 1, 2])) |
|
155 // Should already have a 0 counted. |
|
156 var c = h.snapshot().counts; |
|
157 var s = h.snapshot().sum; |
|
158 do_check_eq(uneval(c), uneval([1, 0, 0])); |
|
159 do_check_eq(s, 1); |
|
160 // Should switch counts. |
|
161 h.add(2); |
|
162 var c2 = h.snapshot().counts; |
|
163 var s2 = h.snapshot().sum; |
|
164 do_check_eq(uneval(c2), uneval([0, 1, 0])); |
|
165 do_check_eq(s, 1); |
|
166 // Should only switch counts once. |
|
167 h.add(3); |
|
168 var c3 = h.snapshot().counts; |
|
169 var s3 = h.snapshot().sum; |
|
170 do_check_eq(uneval(c3), uneval([0, 1, 0])); |
|
171 do_check_eq(s3, 1); |
|
172 do_check_eq(h.snapshot().histogram_type, Telemetry.FLAG_HISTOGRAM); |
|
173 } |
|
174 |
|
175 function test_getHistogramById() { |
|
176 try { |
|
177 Telemetry.getHistogramById("nonexistent"); |
|
178 do_throw("This can't happen"); |
|
179 } catch (e) { |
|
180 |
|
181 } |
|
182 var h = Telemetry.getHistogramById("CYCLE_COLLECTOR"); |
|
183 var s = h.snapshot(); |
|
184 do_check_eq(s.histogram_type, Telemetry.HISTOGRAM_EXPONENTIAL); |
|
185 do_check_eq(s.min, 1); |
|
186 do_check_eq(s.max, 10000); |
|
187 } |
|
188 |
|
189 function compareHistograms(h1, h2) { |
|
190 let s1 = h1.snapshot(); |
|
191 let s2 = h2.snapshot(); |
|
192 |
|
193 do_check_eq(s1.histogram_type, s2.histogram_type); |
|
194 do_check_eq(s1.min, s2.min); |
|
195 do_check_eq(s1.max, s2.max); |
|
196 do_check_eq(s1.sum, s2.sum); |
|
197 if (s1.histogram_type == Telemetry.HISTOGRAM_EXPONENTIAL) { |
|
198 do_check_eq(s1.log_sum, s2.log_sum); |
|
199 do_check_eq(s1.log_sum_squares, s2.log_sum_squares); |
|
200 } else { |
|
201 do_check_eq(s1.sum_squares_lo, s2.sum_squares_lo); |
|
202 do_check_eq(s1.sum_squares_hi, s2.sum_squares_hi); |
|
203 } |
|
204 |
|
205 do_check_eq(s1.counts.length, s2.counts.length); |
|
206 for (let i = 0; i < s1.counts.length; i++) |
|
207 do_check_eq(s1.counts[i], s2.counts[i]); |
|
208 |
|
209 do_check_eq(s1.ranges.length, s2.ranges.length); |
|
210 for (let i = 0; i < s1.ranges.length; i++) |
|
211 do_check_eq(s1.ranges[i], s2.ranges[i]); |
|
212 } |
|
213 |
|
214 function test_histogramFrom() { |
|
215 // Test one histogram of each type. |
|
216 let names = [ |
|
217 "CYCLE_COLLECTOR", // EXPONENTIAL |
|
218 "GC_REASON_2", // LINEAR |
|
219 "GC_RESET", // BOOLEAN |
|
220 "TELEMETRY_TEST_FLAG" // FLAG |
|
221 ]; |
|
222 |
|
223 for each (let name in names) { |
|
224 let [min, max, bucket_count] = [1, INT_MAX - 1, 10] |
|
225 let original = Telemetry.getHistogramById(name); |
|
226 let clone = Telemetry.histogramFrom("clone" + name, name); |
|
227 compareHistograms(original, clone); |
|
228 } |
|
229 |
|
230 // Additionally, set the flag on TELEMETRY_TEST_FLAG, and check it gets set on the clone. |
|
231 let testFlag = Telemetry.getHistogramById("TELEMETRY_TEST_FLAG"); |
|
232 testFlag.add(1); |
|
233 let clone = Telemetry.histogramFrom("FlagClone", "TELEMETRY_TEST_FLAG"); |
|
234 compareHistograms(testFlag, clone); |
|
235 } |
|
236 |
|
237 function test_getSlowSQL() { |
|
238 var slow = Telemetry.slowSQL; |
|
239 do_check_true(("mainThread" in slow) && ("otherThreads" in slow)); |
|
240 } |
|
241 |
|
242 function test_addons() { |
|
243 var addon_id = "testing-addon"; |
|
244 var fake_addon_id = "fake-addon"; |
|
245 var name1 = "testing-histogram1"; |
|
246 var register = Telemetry.registerAddonHistogram; |
|
247 expect_success(function () |
|
248 register(addon_id, name1, 1, 5, 6, Telemetry.HISTOGRAM_LINEAR)); |
|
249 // Can't register the same histogram multiple times. |
|
250 expect_fail(function () |
|
251 register(addon_id, name1, 1, 5, 6, Telemetry.HISTOGRAM_LINEAR)); |
|
252 // Make sure we can't get at it with another name. |
|
253 expect_fail(function () Telemetry.getAddonHistogram(fake_addon_id, name1)); |
|
254 |
|
255 // Check for reflection capabilities. |
|
256 var h1 = Telemetry.getAddonHistogram(addon_id, name1); |
|
257 // Verify that although we've created storage for it, we don't reflect it into JS. |
|
258 var snapshots = Telemetry.addonHistogramSnapshots; |
|
259 do_check_false(name1 in snapshots[addon_id]); |
|
260 h1.add(1); |
|
261 h1.add(3); |
|
262 var s1 = h1.snapshot(); |
|
263 do_check_eq(s1.histogram_type, Telemetry.HISTOGRAM_LINEAR); |
|
264 do_check_eq(s1.min, 1); |
|
265 do_check_eq(s1.max, 5); |
|
266 do_check_eq(s1.counts[1], 1); |
|
267 do_check_eq(s1.counts[3], 1); |
|
268 |
|
269 var name2 = "testing-histogram2"; |
|
270 expect_success(function () |
|
271 register(addon_id, name2, 2, 4, 4, Telemetry.HISTOGRAM_LINEAR)); |
|
272 |
|
273 var h2 = Telemetry.getAddonHistogram(addon_id, name2); |
|
274 h2.add(2); |
|
275 h2.add(3); |
|
276 var s2 = h2.snapshot(); |
|
277 do_check_eq(s2.histogram_type, Telemetry.HISTOGRAM_LINEAR); |
|
278 do_check_eq(s2.min, 2); |
|
279 do_check_eq(s2.max, 4); |
|
280 do_check_eq(s2.counts[1], 1); |
|
281 do_check_eq(s2.counts[2], 1); |
|
282 |
|
283 // Check that we can register histograms for a different addon with |
|
284 // identical names. |
|
285 var extra_addon = "testing-extra-addon"; |
|
286 expect_success(function () |
|
287 register(extra_addon, name1, 0, 1, 2, Telemetry.HISTOGRAM_BOOLEAN)); |
|
288 |
|
289 // Check that we can register flag histograms. |
|
290 var flag_addon = "testing-flag-addon"; |
|
291 var flag_histogram = "flag-histogram"; |
|
292 expect_success(function() |
|
293 register(flag_addon, flag_histogram, 0, 1, 2, Telemetry.HISTOGRAM_FLAG)) |
|
294 expect_success(function() |
|
295 register(flag_addon, name2, 2, 4, 4, Telemetry.HISTOGRAM_LINEAR)); |
|
296 |
|
297 // Check that we reflect registered addons and histograms. |
|
298 snapshots = Telemetry.addonHistogramSnapshots; |
|
299 do_check_true(addon_id in snapshots) |
|
300 do_check_true(extra_addon in snapshots); |
|
301 do_check_true(flag_addon in snapshots); |
|
302 |
|
303 // Check that we have data for our created histograms. |
|
304 do_check_true(name1 in snapshots[addon_id]); |
|
305 do_check_true(name2 in snapshots[addon_id]); |
|
306 var s1_alt = snapshots[addon_id][name1]; |
|
307 var s2_alt = snapshots[addon_id][name2]; |
|
308 do_check_eq(s1_alt.min, s1.min); |
|
309 do_check_eq(s1_alt.max, s1.max); |
|
310 do_check_eq(s1_alt.histogram_type, s1.histogram_type); |
|
311 do_check_eq(s2_alt.min, s2.min); |
|
312 do_check_eq(s2_alt.max, s2.max); |
|
313 do_check_eq(s2_alt.histogram_type, s2.histogram_type); |
|
314 |
|
315 // Even though we've registered it, it shouldn't show up until data is added to it. |
|
316 do_check_false(name1 in snapshots[extra_addon]); |
|
317 |
|
318 // Flag histograms should show up automagically. |
|
319 do_check_true(flag_histogram in snapshots[flag_addon]); |
|
320 do_check_false(name2 in snapshots[flag_addon]); |
|
321 |
|
322 // Check that we can remove addon histograms. |
|
323 Telemetry.unregisterAddonHistograms(addon_id); |
|
324 snapshots = Telemetry.addonHistogramSnapshots; |
|
325 do_check_false(addon_id in snapshots); |
|
326 // Make sure other addons are unaffected. |
|
327 do_check_true(extra_addon in snapshots); |
|
328 } |
|
329 |
|
330 // Check that telemetry doesn't record in private mode |
|
331 function test_privateMode() { |
|
332 var h = Telemetry.newHistogram("test::private_mode_boolean", "never", 1,2,3, Telemetry.HISTOGRAM_BOOLEAN); |
|
333 var orig = h.snapshot(); |
|
334 Telemetry.canRecord = false; |
|
335 h.add(1); |
|
336 do_check_eq(uneval(orig), uneval(h.snapshot())); |
|
337 Telemetry.canRecord = true; |
|
338 h.add(1); |
|
339 do_check_neq(uneval(orig), uneval(h.snapshot())); |
|
340 } |
|
341 |
|
342 // Check that histograms that aren't flagged as needing extended stats |
|
343 // don't record extended stats. |
|
344 function test_extended_stats() { |
|
345 var h = Telemetry.getHistogramById("GRADIENT_DURATION"); |
|
346 var s = h.snapshot(); |
|
347 do_check_eq(s.sum, 0); |
|
348 do_check_eq(s.log_sum, 0); |
|
349 do_check_eq(s.log_sum_squares, 0); |
|
350 h.add(1); |
|
351 s = h.snapshot(); |
|
352 do_check_eq(s.sum, 1); |
|
353 do_check_eq(s.log_sum, 0); |
|
354 do_check_eq(s.log_sum_squares, 0); |
|
355 } |
|
356 |
|
357 function generateUUID() { |
|
358 let str = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID().toString(); |
|
359 // strip {} |
|
360 return str.substring(1, str.length - 1); |
|
361 } |
|
362 |
|
363 function run_test() |
|
364 { |
|
365 let kinds = [Telemetry.HISTOGRAM_EXPONENTIAL, Telemetry.HISTOGRAM_LINEAR] |
|
366 for each (let histogram_type in kinds) { |
|
367 let [min, max, bucket_count] = [1, INT_MAX - 1, 10] |
|
368 test_histogram(histogram_type, "test::"+histogram_type, min, max, bucket_count); |
|
369 |
|
370 const nh = Telemetry.newHistogram; |
|
371 expect_fail(function () nh("test::min", "never", 0, max, bucket_count, histogram_type)); |
|
372 expect_fail(function () nh("test::bucket_count", "never", min, max, 1, histogram_type)); |
|
373 } |
|
374 |
|
375 // Instantiate the storage for this histogram and make sure it doesn't |
|
376 // get reflected into JS, as it has no interesting data in it. |
|
377 let h = Telemetry.getHistogramById("NEWTAB_PAGE_PINNED_SITES_COUNT"); |
|
378 do_check_false("NEWTAB_PAGE_PINNED_SITES_COUNT" in Telemetry.histogramSnapshots); |
|
379 |
|
380 test_boolean_histogram(); |
|
381 test_getHistogramById(); |
|
382 test_histogramFrom(); |
|
383 test_getSlowSQL(); |
|
384 test_privateMode(); |
|
385 test_addons(); |
|
386 test_extended_stats(); |
|
387 test_expired_histogram(); |
|
388 } |