1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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();
});
}
|