diff options
Diffstat (limited to 'toolkit/components/telemetry/tests/unit/test_ThreadHangStats.js')
-rw-r--r-- | toolkit/components/telemetry/tests/unit/test_ThreadHangStats.js | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/toolkit/components/telemetry/tests/unit/test_ThreadHangStats.js b/toolkit/components/telemetry/tests/unit/test_ThreadHangStats.js new file mode 100644 index 000000000..e8c9f868a --- /dev/null +++ b/toolkit/components/telemetry/tests/unit/test_ThreadHangStats.js @@ -0,0 +1,102 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +Cu.import("resource://gre/modules/Services.jsm"); + +function getMainThreadHangStats() { + let threads = Services.telemetry.threadHangStats; + return threads.find((thread) => (thread.name === "Gecko")); +} + +function run_test() { + let startHangs = getMainThreadHangStats(); + + // We disable hang reporting in several situations (e.g. debug builds, + // official releases). In those cases, we don't have hang stats available + // and should exit the test early. + if (!startHangs) { + ok("Hang reporting not enabled."); + return; + } + + if (Services.appinfo.OS === 'Linux' || Services.appinfo.OS === 'Android') { + // We use the rt_tgsigqueueinfo syscall on Linux which requires a + // certain kernel version. It's not an error if the system running + // the test is older than that. + let kernel = Services.sysinfo.get('kernel_version') || + Services.sysinfo.get('version'); + if (Services.vc.compare(kernel, '2.6.31') < 0) { + ok("Hang reporting not supported for old kernel."); + return; + } + } + + // Run three events in the event loop: + // the first event causes a transient hang; + // the second event causes a permanent hang; + // the third event checks results from previous events. + + do_execute_soon(() => { + // Cause a hang lasting 1 second (transient hang). + let startTime = Date.now(); + while ((Date.now() - startTime) < 1000); + }); + + do_execute_soon(() => { + // Cause a hang lasting 10 seconds (permanent hang). + let startTime = Date.now(); + while ((Date.now() - startTime) < 10000); + }); + + do_execute_soon(() => { + do_test_pending(); + + let check_results = () => { + let endHangs = getMainThreadHangStats(); + + // Because hangs are recorded asynchronously, if we don't see new hangs, + // we should wait for pending hangs to be recorded. On the other hand, + // if hang monitoring is broken, this test will time out. + if (endHangs.hangs.length === startHangs.hangs.length) { + do_timeout(100, check_results); + return; + } + + let check_histogram = (histogram) => { + equal(typeof histogram, "object"); + equal(histogram.histogram_type, 0); + equal(typeof histogram.min, "number"); + equal(typeof histogram.max, "number"); + equal(typeof histogram.sum, "number"); + ok(Array.isArray(histogram.ranges)); + ok(Array.isArray(histogram.counts)); + equal(histogram.counts.length, histogram.ranges.length); + }; + + // Make sure the hang stats structure is what we expect. + equal(typeof endHangs, "object"); + check_histogram(endHangs.activity); + + ok(Array.isArray(endHangs.hangs)); + notEqual(endHangs.hangs.length, 0); + + ok(Array.isArray(endHangs.hangs[0].stack)); + notEqual(endHangs.hangs[0].stack.length, 0); + equal(typeof endHangs.hangs[0].stack[0], "string"); + + // Make sure one of the hangs is a permanent + // hang containing a native stack. + ok(endHangs.hangs.some((hang) => ( + Array.isArray(hang.nativeStack) && + hang.nativeStack.length !== 0 && + typeof hang.nativeStack[0] === "string" + ))); + + check_histogram(endHangs.hangs[0].histogram); + + do_test_finished(); + }; + + check_results(); + }); +} |