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