Bug 1855360 - Fix the skip-if syntax. a=bustage-fix
[gecko.git] / tools / leak-gauge / leak-gauge.html
blob7eb2de10c1ae051531ca8abf2f52c84e4b55c32b
1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
2 <!--
3 vim:sw=4:ts=4:et:
4 This Source Code Form is subject to the terms of the Mozilla Public
5 - License, v. 2.0. If a copy of the MPL was not distributed with this
6 - file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 -->
8 <html lang="en-US">
9 <head>
10 <meta charset="UTF-8" />
11 <title>Leak Gauge</title>
13 <style type="text/css">
14 pre {
15 margin: 0;
17 pre.output {
18 border: medium solid;
19 padding: 1em;
20 margin: 1em;
22 </style>
23 <script>
24 function runfile(file) {
25 var result = "Results of processing log " + file.fileName + " :\n";
27 var fileReader = new FileReader();
28 fileReader.onload = function (e) {
29 runContents(result, e.target.result);
31 fileReader.readAsText(file, "iso-8859-1");
34 function runContents(result, contents) {
35 // A hash of objects (keyed by the first word of the line in the log)
36 // that have two public methods, handle_line and dump (to be called using
37 // call, above), along with any private data they need.
38 var handlers = {
39 DOMWINDOW: {
40 count: 0,
41 windows: {},
42 handle_line(line) {
43 var match = line.match(/^([0-9a-f]*) (\S*)(.*)/);
44 if (match) {
45 var addr = match[1];
46 var verb = match[2];
47 var rest = match[3];
48 if (verb == "created") {
49 let m = rest.match(/ outer=([0-9a-f]*)$/);
50 if (!m) throw new Error("outer expected");
51 this.windows[addr] = { outer: m[1] };
52 ++this.count;
53 } else if (verb == "destroyed") {
54 delete this.windows[addr];
55 } else if (verb == "SetNewDocument") {
56 let m = rest.match(/^ (.*)$/);
57 if (!m) throw new Error("URI expected");
58 this.windows[addr][m[1]] = true;
62 dump() {
63 for (var addr in this.windows) {
64 var winobj = this.windows[addr];
65 var outer = winobj.outer;
66 delete winobj.outer;
67 result +=
68 "Leaked " +
69 (outer == "0" ? "outer" : "inner") +
70 " window " +
71 addr +
72 " " +
73 (outer == "0" ? "" : "(outer " + outer + ") ") +
74 "at address " +
75 addr +
76 ".\n";
77 for (var uri in winobj) {
78 result += ' ... with URI "' + uri + '".\n';
82 summary() {
83 result +=
84 "Leaked " +
85 Object.keys(this.windows).length +
86 " out of " +
87 this.count +
88 " DOM Windows\n";
91 DOCUMENT: {
92 count: 0,
93 docs: {},
94 handle_line(line) {
95 var match = line.match(/^([0-9a-f]*) (\S*)(.*)/);
96 if (match) {
97 var addr = match[1];
98 var verb = match[2];
99 var rest = match[3];
100 if (verb == "created") {
101 this.docs[addr] = {};
102 ++this.count;
103 } else if (verb == "destroyed") {
104 delete this.docs[addr];
105 } else if (
106 verb == "ResetToURI" ||
107 verb == "StartDocumentLoad"
109 var m = rest.match(/^ (.*)$/);
110 if (!m) throw new Error("URI expected");
111 var uri = m[1];
112 var doc_info = this.docs[addr];
113 doc_info[uri] = true;
114 if ("nim" in doc_info) {
115 doc_info.nim[uri] = true;
120 dump() {
121 for (var addr in this.docs) {
122 var doc = this.docs[addr];
123 result += "Leaked document at address " + addr + ".\n";
124 for (var uri in doc) {
125 if (uri != "nim") {
126 result += ' ... with URI "' + uri + '".\n';
131 summary() {
132 result +=
133 "Leaked " +
134 Object.keys(this.docs).length +
135 " out of " +
136 this.count +
137 " documents\n";
140 DOCSHELL: {
141 count: 0,
142 shells: {},
143 handle_line(line) {
144 var match = line.match(/^([0-9a-f]*) (\S*)(.*)/);
145 if (match) {
146 var addr = match[1];
147 var verb = match[2];
148 var rest = match[3];
149 if (verb == "created") {
150 this.shells[addr] = {};
151 ++this.count;
152 } else if (verb == "destroyed") {
153 delete this.shells[addr];
154 } else if (verb == "InternalLoad" || verb == "SetCurrentURI") {
155 var m = rest.match(/^ (.*)$/);
156 if (!m) throw new Error("URI expected");
157 this.shells[addr][m[1]] = true;
161 dump() {
162 for (var addr in this.shells) {
163 var doc = this.shells[addr];
164 result += "Leaked docshell at address " + addr + ".\n";
165 for (var uri in doc) {
166 result += ' ... which loaded URI "' + uri + '".\n';
170 summary() {
171 result +=
172 "Leaked " +
173 Object.keys(this.shells).length +
174 " out of " +
175 this.count +
176 " docshells\n";
179 NODEINFOMANAGER: {
180 count: 0,
181 nims: {},
182 handle_line(line) {
183 var match = line.match(/^([0-9a-f]*) (\S*)(.*)/);
184 if (match) {
185 var addr = match[1];
186 var verb = match[2];
187 var rest = match[3];
188 if (verb == "created") {
189 this.nims[addr] = {};
190 ++this.count;
191 } else if (verb == "destroyed") {
192 delete this.nims[addr];
193 } else if (verb == "Init") {
194 var m = rest.match(/^ document=(.*)$/);
195 if (!m) throw new Error("document pointer expected");
196 var nim_info = this.nims[addr];
197 var doc = m[1];
198 if (doc != "0") {
199 var doc_info = handlers.DOCUMENT.docs[doc];
200 for (var uri in doc_info) {
201 nim_info[uri] = true;
203 doc_info.nim = nim_info;
208 dump() {
209 for (var addr in this.nims) {
210 var nim = this.nims[addr];
211 result +=
212 "Leaked content nodes associated with node info manager at address " +
213 addr +
214 ".\n";
215 for (var uri in nim) {
216 result += ' ... with document URI "' + uri + '".\n';
220 summary() {
221 result +=
222 "Leaked content nodes in " +
223 Object.keys(this.nims).length +
224 " out of " +
225 this.count +
226 " documents\n";
231 var lines = contents.split(/[\r\n]+/);
232 for (var j in lines) {
233 var line = lines[j];
234 // strip off initial "-", thread id, and thread pointer; separate
235 // first word and rest
236 var matches = line.match(/^\-?[0-9]*\[[0-9a-f]*\]: (\S*) (.*)$/);
237 if (matches) {
238 let handler = matches[1];
239 var data = matches[2];
240 if (typeof handlers[handler] != "undefined") {
241 handlers[handler].handle_line(data);
246 for (let handler in handlers) handlers[handler].dump();
247 if (result.length) result += "\n";
248 result += "Summary:\n";
249 for (let handler in handlers) handlers[handler].summary();
250 result += "\n";
252 var out = document.createElement("pre");
253 out.className = "output";
254 out.appendChild(document.createTextNode(result));
255 document.body.appendChild(out);
258 function run() {
259 var input = document.getElementById("fileinput");
260 var files = input.files;
261 for (var i = 0; i < files.length; ++i) runfile(files[i]);
262 // So the user can process the same filename again (after
263 // overwriting the log), clear the value on the form input so we
264 // will always get an onchange event.
265 input.value = "";
267 </script>
268 </head>
269 <body>
270 <h1>Leak Gauge</h1>
272 <pre>
273 $Id: leak-gauge.html,v 1.8 2008/02/08 19:55:34 dbaron%dbaron.org Exp $</pre
277 This script is designed to help testers isolate and simplify testcases for
278 many classes of leaks (those that involve large graphs of core data
279 structures) in Mozilla-based browsers. It is designed to print information
280 about what has leaked by processing a log taken while running the browser.
281 Such a log can be taken over a long session of normal browsing and then
282 the log can be processed to find sites that leak. Once a site is known to
283 leak, the logging can then be repeated to figure out under what conditions
284 the leak occurs.
285 </p>
287 <p>The way to create this log is to set the environment variables:</p>
288 <pre> MOZ_LOG=DOMLeak:5,DocumentLeak:5,nsDocShellLeak:5,NodeInfoManagerLeak:5
289 MOZ_LOG_FILE=nspr.log <i>(or any other filename of your choice)</i></pre>
290 <p>in your shell and then run the program.</p>
291 <ul>
292 <li>
293 In a Windows command prompt, set environment variables with
294 <pre> set VAR=value</pre>
295 </li>
296 <li>
297 In an sh-based shell such as bash, set environment variables with
298 <pre> export VAR=value</pre>
299 </li>
300 <li>
301 In a csh-based shell such as tcsh, set environment variables with
302 <pre> setenv VAR value</pre>
303 </li>
304 </ul>
307 Once you have this log from a complete run of the browser (you have to
308 exit; otherwise it will look like everything leaked), you can load this
309 page (be careful not to overwrite the log when starting the browser to
310 load this page) and enter the filename of the log:
311 </p>
313 <p><input type="file" id="fileinput" onchange="run()" /></p>
316 Then you'll see the output below, which will tell you which of certain
317 core objects leaked and the URLs associated with those objects.
318 </p>
319 </body>
320 </html>