1 <!DOCTYPE html PUBLIC
"-//W3C//DTD HTML 4.01//EN"
2 "http://www.w3.org/TR/html4/strict.dtd">
5 ***** BEGIN LICENSE BLOCK *****
6 Version: MPL 1.1/GPL 2.0/LGPL 2.1
8 The contents of this file are subject to the Mozilla Public License Version
9 1.1 (the "License"); you may not use this file except in compliance with
10 the License. You may obtain a copy of the License at
11 http://www.mozilla.org/MPL/
13 Software distributed under the License is distributed on an "AS IS" basis,
14 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
15 for the specific language governing rights and limitations under the
18 The Original Code is leak-gauge.pl
20 The Initial Developer of the Original Code is the Mozilla Foundation.
21 Portions created by the Initial Developer are Copyright (C) 2005
22 the Initial Developer. All Rights Reserved.
25 L. David Baron <dbaron@dbaron.org>, Mozilla Corporation (original author)
27 Alternatively, the contents of this file may be used under the terms of
28 either the GNU General Public License Version 2 or later (the "GPL"), or
29 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 in which case the provisions of the GPL or the LGPL are applicable instead
31 of those above. If you wish to allow use of your version of this file only
32 under the terms of either the GPL or the LGPL, and not to allow others to
33 use your version of this file under the terms of the MPL, indicate your
34 decision by deleting the provisions above and replace them with the notice
35 and other provisions required by the GPL or the LGPL. If you do not delete
36 the provisions above, a recipient may use your version of this file under
37 the terms of any one of the MPL, the GPL or the LGPL.
39 ***** END LICENSE BLOCK *****
43 <title>Leak Gauge
</title>
45 <style type=
"text/css">
47 pre
.output
{ border: medium solid
; padding: 1em; margin: 1em; }
49 <script type=
"text/javascript">
51 function runfile(file
) {
52 // A hash of objects (keyed by the first word of the line in the log)
53 // that have two public methods, handle_line and dump (to be called using
54 // call, above), along with any private data they need.
59 handle_line: function(line
) {
60 var match
= line
.match(/^([0-9a-f]*) (\S*)(.*)/);
65 if (verb
== "created") {
66 var m
= rest
.match(/ outer
=([0-9a
-f
]*)$/);
68 throw "outer expected";
69 this.windows
[addr
] = { outer
: m
[1] };
71 } else if (verb
== "destroyed") {
72 delete this.windows
[addr
];
73 } else if (verb
== "SetNewDocument") {
74 var m
= rest
.match(/^ (.*)$/);
77 this.windows
[addr
][m
[1]] = true;
82 for (var addr
in this.windows
) {
83 var winobj
= this.windows
[addr
];
84 var outer
= winobj
.outer
;
86 result
+= "Leaked " + (outer
== "0" ? "outer" : "inner") +
87 " window " + addr
+ " " +
88 (outer
== "0" ? "" : "(outer " + outer
+ ") ") +
89 "at address " + addr
+ ".\n";
90 for (var uri
in winobj
) {
91 result
+= " ... with URI \"" + uri
+ "\".\n";
97 for (var w
in this.windows
)
99 result
+= 'Leaked ' + len
+ ' out of ' +
100 this.count
+ " DOM Windows\n";
106 handle_line: function(line
) {
107 var match
= line
.match(/^([0-9a-f]*) (\S*)(.*)/);
112 if (verb
== "created") {
113 this.docs
[addr
] = {};
115 } else if (verb
== "destroyed") {
116 delete this.docs
[addr
];
117 } else if (verb
== "ResetToURI" ||
118 verb
== "StartDocumentLoad") {
119 var m
= rest
.match(/^ (.*)$/);
121 throw "URI expected";
123 var doc_info
= this.docs
[addr
];
124 doc_info
[uri
] = true;
125 if ("nim" in doc_info
) {
126 doc_info
["nim"][uri
] = true;
132 for (var addr
in this.docs
) {
133 var doc
= this.docs
[addr
];
134 result
+= "Leaked document at address " + addr
+ ".\n";
135 for (var uri
in doc
) {
137 result
+= " ... with URI \"" + uri
+ "\".\n";
142 summary: function() {
144 for (var w
in this.docs
)
146 result
+= 'Leaked ' + len
+ ' out of ' +
147 this.count
+ " documents\n";
153 handle_line: function(line
) {
154 var match
= line
.match(/^([0-9a-f]*) (\S*)(.*)/);
159 if (verb
== "created") {
160 this.shells
[addr
] = {};
162 } else if (verb
== "destroyed") {
163 delete this.shells
[addr
];
164 } else if (verb
== "InternalLoad" ||
165 verb
== "SetCurrentURI") {
166 var m
= rest
.match(/^ (.*)$/);
168 throw "URI expected";
169 this.shells
[addr
][m
[1]] = true;
174 for (var addr
in this.shells
) {
175 var doc
= this.shells
[addr
];
176 result
+= "Leaked docshell at address " + addr
+ ".\n";
177 for (var uri
in doc
) {
178 result
+= " ... which loaded URI \"" + uri
+ "\".\n";
182 summary: function() {
184 for (var w
in this.shells
)
186 result
+= 'Leaked ' + len
+ ' out of ' +
187 this.count
+ " docshells\n";
193 handle_line: function(line
) {
194 var match
= line
.match(/^([0-9a-f]*) (\S*)(.*)/);
199 if (verb
== "created") {
200 this.nims
[addr
] = {};
202 } else if (verb
== "destroyed") {
203 delete this.nims
[addr
];
204 } else if (verb
== "Init") {
205 var m
= rest
.match(/^ document=(.*)$/);
207 throw "document pointer expected";
208 var nim_info
= this.nims
[addr
];
211 var doc_info
= handlers
["DOCUMENT"].docs
[doc
];
212 for (var uri
in doc_info
) {
213 nim_info
[uri
] = true;
215 doc_info
["nim"] = nim_info
;
221 for (var addr
in this.nims
) {
222 var nim
= this.nims
[addr
];
223 result
+= "Leaked content nodes associated with node info manager at address " + addr
+ ".\n";
224 for (var uri
in nim
) {
225 result
+= " ... with document URI \"" + uri
+ "\".\n";
229 summary: function() {
231 for (var w
in this.nims
)
233 result
+= 'Leaked content nodes in ' + len
+ ' out of ' +
234 this.count
+ " documents\n";
239 var result
= "Results of processing log " + file
.fileName
+ " :\n";
241 var contents
= file
.getAsText("iso-8859-1");
242 var lines
= contents
.split(/[\r\n]+/);
243 for (var j
in lines
) {
245 // strip off initial "-", thread id, and thread pointer; separate
246 // first word and rest
247 var matches
= line
.match(/^\-?[0-9]*\[[0-9a-f]*\]: (\S*) (.*)$/);
249 var handler
= matches
[1];
250 var data
= matches
[2];
251 if (typeof(handlers
[handler
]) != "undefined") {
252 handlers
[handler
].handle_line(data
);
257 for (var handler
in handlers
)
258 handlers
[handler
].dump();
261 result
+= "Summary:\n";
262 for (var handler
in handlers
)
263 handlers
[handler
].summary();
266 var out
= document
.createElement("pre");
267 out
.className
= "output";
268 out
.appendChild(document
.createTextNode(result
));
269 document
.body
.appendChild(out
);
273 var input
= document
.getElementById("fileinput");
274 var files
= input
.files
;
275 for (var i
= 0; i
< files
.length
; ++i
)
277 // So the user can process the same filename again (after
278 // overwriting the log), clear the value on the form input so we
279 // will always get an onchange event.
289 <pre>$Id: leak-gauge.html,v
1.8 2008/
02/
08 19:
55:
34 dbaron%dbaron.org Exp $
</pre>
291 <p>This script is designed to help testers isolate and simplify testcases
292 for many classes of leaks (those that involve large graphs of core
293 data structures) in Mozilla-based browsers. It is designed to print
294 information about what has leaked by processing a log taken while
295 running the browser. Such a log can be taken over a long session of
296 normal browsing and then the log can be processed to find sites that
297 leak. Once a site is known to leak, the logging can then be repeated
298 to figure out under what conditions the leak occurs.
</p>
300 <p>The way to create this log is to set the environment variables:
</p>
301 <pre> NSPR_LOG_MODULES=DOMLeak:
5,DocumentLeak:
5,nsDocShellLeak:
5,NodeInfoManagerLeak:
5
302 NSPR_LOG_FILE=nspr.log
<i>(or any other filename of your choice)
</i></pre>
303 <p>in your shell and then run the program.
</p>
305 <li>In a Windows command prompt, set environment variables with
306 <pre> set VAR=value
</pre></li>
307 <li> In an sh-based shell such as bash, set environment variables with
308 <pre> export VAR=value
</pre></li>
309 <li>In a csh-based shell such as tcsh, set environment variables with
310 <pre> setenv VAR value
</pre></li>
313 <p>Once you have this log from a complete run of the browser (you have
314 to exit; otherwise it will look like everything leaked), you can load
315 this page (be careful not to overwrite the log when starting the browser
316 to load this page) and enter the filename of the log:
</p>
318 <p><input type=
"file" id=
"fileinput" onchange=
"run()"></p>
320 <p>Then you'll see the output below, which will tell you which of
321 certain core objects leaked and the URLs associated with those