tools/footprint/leak-gauge.html

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/tools/footprint/leak-gauge.html	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,301 @@
     1.4 +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
     1.5 +	"http://www.w3.org/TR/html4/strict.dtd">
     1.6 +<!--
     1.7 +  vim:sw=4:ts=4:et:
     1.8 + This Source Code Form is subject to the terms of the Mozilla Public
     1.9 +   - License, v. 2.0. If a copy of the MPL was not distributed with this
    1.10 +   - file, You can obtain one at http://mozilla.org/MPL/2.0/.
    1.11 +-->
    1.12 +<html lang="en-US">
    1.13 +<head>
    1.14 +<title>Leak Gauge</title>
    1.15 +
    1.16 +<style type="text/css">
    1.17 +pre { margin: 0; }
    1.18 +pre.output { border: medium solid; padding: 1em; margin: 1em; }
    1.19 +</style>
    1.20 +<script type="text/javascript">
    1.21 +
    1.22 +function runFile(file) {
    1.23 +  var result = "Results of processing log " + file.fileName + " :\n";
    1.24 +
    1.25 +  var fileReader = new FileReader();
    1.26 +  fileReader.onload = function(e)
    1.27 +  {
    1.28 +    runContents(result, e.target.result);
    1.29 +  }
    1.30 +  fileReader.readAsText(file, "iso-8859-1");
    1.31 +}
    1.32 +
    1.33 +function runContents(result, contents) {
    1.34 +    // A hash of objects (keyed by the first word of the line in the log)
    1.35 +    // that have two public methods, handle_line and dump (to be called using
    1.36 +    // call, above), along with any private data they need.
    1.37 +    var handlers = {
    1.38 +        "DOMWINDOW": {
    1.39 +            count: 0,
    1.40 +            windows: {},
    1.41 +            handle_line: function(line) {
    1.42 +                var match = line.match(/^([0-9a-f]*) (\S*)(.*)/);
    1.43 +                if (match) {
    1.44 +                    var addr = match[1];
    1.45 +                    var verb = match[2];
    1.46 +                    var rest = match[3];
    1.47 +                    if (verb == "created") {
    1.48 +                        var m = rest.match(/ outer=([0-9a-f]*)$/);
    1.49 +                        if (!m)
    1.50 +                            throw "outer expected";
    1.51 +                        this.windows[addr] = { outer: m[1] };
    1.52 +                        ++this.count;
    1.53 +                    } else if (verb == "destroyed") {
    1.54 +                        delete this.windows[addr];
    1.55 +                    } else if (verb == "SetNewDocument") {
    1.56 +                        var m = rest.match(/^ (.*)$/);
    1.57 +                        if (!m)
    1.58 +                            throw "URI expected";
    1.59 +                        this.windows[addr][m[1]] = true;
    1.60 +                    }
    1.61 +                }
    1.62 +            },
    1.63 +            dump: function() {
    1.64 +                for (var addr in this.windows) {
    1.65 +                    var winobj = this.windows[addr];
    1.66 +                    var outer = winobj.outer;
    1.67 +                    delete winobj.outer;
    1.68 +                    result += "Leaked " + (outer == "0" ? "outer" : "inner") +
    1.69 +                              " window " + addr + " " +
    1.70 +                              (outer == "0" ? "" : "(outer " + outer + ") ") +
    1.71 +                              "at address " + addr + ".\n";
    1.72 +                    for (var uri in winobj) {
    1.73 +                        result += " ... with URI \"" + uri + "\".\n";
    1.74 +                    }
    1.75 +                }
    1.76 +            },
    1.77 +            summary: function() {
    1.78 +                var len = 0;
    1.79 +                for (var w in this.windows)
    1.80 +                    ++len;
    1.81 +                result += 'Leaked ' + len + ' out of ' +
    1.82 +                          this.count + " DOM Windows\n";
    1.83 +            }
    1.84 +        },
    1.85 +        "DOCUMENT": {
    1.86 +            count: 0,
    1.87 +            docs: {},
    1.88 +            handle_line: function(line) {
    1.89 +                var match = line.match(/^([0-9a-f]*) (\S*)(.*)/);
    1.90 +                if (match) {
    1.91 +                    var addr = match[1];
    1.92 +                    var verb = match[2];
    1.93 +                    var rest = match[3];
    1.94 +                    if (verb == "created") {
    1.95 +                        this.docs[addr] = {};
    1.96 +                        ++this.count;
    1.97 +                    } else if (verb == "destroyed") {
    1.98 +                        delete this.docs[addr];
    1.99 +                    } else if (verb == "ResetToURI" ||
   1.100 +                               verb == "StartDocumentLoad") {
   1.101 +                        var m = rest.match(/^ (.*)$/);
   1.102 +                        if (!m)
   1.103 +                            throw "URI expected";
   1.104 +                        var uri = m[1];
   1.105 +                        var doc_info = this.docs[addr];
   1.106 +                        doc_info[uri] = true;
   1.107 +                        if ("nim" in doc_info) {
   1.108 +                            doc_info["nim"][uri] = true;
   1.109 +                        }
   1.110 +                    }
   1.111 +                }
   1.112 +            },
   1.113 +            dump: function() {
   1.114 +                for (var addr in this.docs) {
   1.115 +                    var doc = this.docs[addr];
   1.116 +                    result += "Leaked document at address " + addr + ".\n";
   1.117 +                    for (var uri in doc) {
   1.118 +                        if (uri != "nim") {
   1.119 +                            result += " ... with URI \"" + uri + "\".\n";
   1.120 +                        }
   1.121 +                    }
   1.122 +                }
   1.123 +            },
   1.124 +            summary: function() {
   1.125 +                var len = 0;
   1.126 +                for (var w in this.docs)
   1.127 +                    ++len;
   1.128 +                result += 'Leaked ' + len + ' out of ' +
   1.129 +                          this.count + " documents\n";
   1.130 +            }
   1.131 +        },
   1.132 +        "DOCSHELL": {
   1.133 +            count: 0,
   1.134 +            shells: {},
   1.135 +            handle_line: function(line) {
   1.136 +                var match = line.match(/^([0-9a-f]*) (\S*)(.*)/);
   1.137 +                if (match) {
   1.138 +                    var addr = match[1];
   1.139 +                    var verb = match[2];
   1.140 +                    var rest = match[3];
   1.141 +                    if (verb == "created") {
   1.142 +                        this.shells[addr] = {};
   1.143 +                        ++this.count;
   1.144 +                    } else if (verb == "destroyed") {
   1.145 +                        delete this.shells[addr];
   1.146 +                    } else if (verb == "InternalLoad" ||
   1.147 +                               verb == "SetCurrentURI") {
   1.148 +                        var m = rest.match(/^ (.*)$/);
   1.149 +                        if (!m)
   1.150 +                            throw "URI expected";
   1.151 +                        this.shells[addr][m[1]] = true;
   1.152 +                    }
   1.153 +                }
   1.154 +            },
   1.155 +            dump: function() {
   1.156 +                for (var addr in this.shells) {
   1.157 +                    var doc = this.shells[addr];
   1.158 +                    result += "Leaked docshell at address " + addr + ".\n";
   1.159 +                    for (var uri in doc) {
   1.160 +                        result += " ... which loaded URI \"" + uri + "\".\n";
   1.161 +                    }
   1.162 +                }
   1.163 +            },
   1.164 +            summary: function() {
   1.165 +                var len = 0;
   1.166 +                for (var w in this.shells)
   1.167 +                    ++len;
   1.168 +                result += 'Leaked ' + len + ' out of ' +
   1.169 +                          this.count + " docshells\n";
   1.170 +            }
   1.171 +        },
   1.172 +        "NODEINFOMANAGER": {
   1.173 +            count: 0,
   1.174 +            nims: {},
   1.175 +            handle_line: function(line) {
   1.176 +                var match = line.match(/^([0-9a-f]*) (\S*)(.*)/);
   1.177 +                if (match) {
   1.178 +                    var addr = match[1];
   1.179 +                    var verb = match[2];
   1.180 +                    var rest = match[3];
   1.181 +                    if (verb == "created") {
   1.182 +                        this.nims[addr] = {};
   1.183 +                        ++this.count;
   1.184 +                    } else if (verb == "destroyed") {
   1.185 +                        delete this.nims[addr];
   1.186 +                    } else if (verb == "Init") {
   1.187 +                        var m = rest.match(/^ document=(.*)$/);
   1.188 +                        if (!m)
   1.189 +                            throw "document pointer expected";
   1.190 +                        var nim_info = this.nims[addr];
   1.191 +                        var doc = m[1];
   1.192 +                        if (doc != "0") {
   1.193 +                            var doc_info = handlers["DOCUMENT"].docs[doc];
   1.194 +                            for (var uri in doc_info) {
   1.195 +                                nim_info[uri] = true;
   1.196 +                            }
   1.197 +                            doc_info["nim"] = nim_info;
   1.198 +                        }
   1.199 +                    }
   1.200 +                }
   1.201 +            },
   1.202 +            dump: function() {
   1.203 +                for (var addr in this.nims) {
   1.204 +                    var nim = this.nims[addr];
   1.205 +                    result += "Leaked content nodes associated with node info manager at address " + addr + ".\n";
   1.206 +                    for (var uri in nim) {
   1.207 +                        result += " ... with document URI \"" + uri + "\".\n";
   1.208 +                    }
   1.209 +                }
   1.210 +            },
   1.211 +            summary: function() {
   1.212 +                var len = 0;
   1.213 +                for (var w in this.nims)
   1.214 +                    ++len;
   1.215 +                result += 'Leaked content nodes in ' + len + ' out of ' +
   1.216 +                          this.count + " documents\n";
   1.217 +            }
   1.218 +        }
   1.219 +    };
   1.220 +
   1.221 +    var lines = contents.split(/[\r\n]+/);
   1.222 +    for (var j in lines) {
   1.223 +        var line = lines[j];
   1.224 +        // strip off initial "-", thread id, and thread pointer; separate
   1.225 +        // first word and rest
   1.226 +        var matches = line.match(/^\-?[0-9]*\[[0-9a-f]*\]: (\S*) (.*)$/);
   1.227 +        if (matches) {
   1.228 +            var handler = matches[1];
   1.229 +            var data = matches[2];
   1.230 +            if (typeof(handlers[handler]) != "undefined") {
   1.231 +                handlers[handler].handle_line(data);
   1.232 +            }
   1.233 +        }
   1.234 +    }
   1.235 +
   1.236 +    for (var handler in handlers)
   1.237 +        handlers[handler].dump();
   1.238 +    if (result.length)
   1.239 +        result += "\n";
   1.240 +    result += "Summary:\n";
   1.241 +    for (var handler in handlers)
   1.242 +        handlers[handler].summary();
   1.243 +    result += "\n";
   1.244 +
   1.245 +    var out = document.createElement("pre");
   1.246 +    out.className = "output";
   1.247 +    out.appendChild(document.createTextNode(result));
   1.248 +    document.body.appendChild(out);
   1.249 +}
   1.250 +
   1.251 +function run() {
   1.252 +    var input = document.getElementById("fileinput");
   1.253 +    var files = input.files;
   1.254 +    for (var i = 0; i < files.length; ++i)
   1.255 +        runfile(files[i]);
   1.256 +    // So the user can process the same filename again (after
   1.257 +    // overwriting the log), clear the value on the form input so we
   1.258 +    // will always get an onchange event.
   1.259 +    input.value = "";
   1.260 +}
   1.261 +
   1.262 +</script>
   1.263 +</head>
   1.264 +<body>
   1.265 +
   1.266 +<h1>Leak Gauge</h1>
   1.267 +
   1.268 +<pre>$Id: leak-gauge.html,v 1.8 2008/02/08 19:55:34 dbaron%dbaron.org Exp $</pre>
   1.269 +
   1.270 +<p>This script is designed to help testers isolate and simplify testcases
   1.271 +for many classes of leaks (those that involve large graphs of core
   1.272 +data structures) in Mozilla-based browsers.  It is designed to print
   1.273 +information about what has leaked by processing a log taken while
   1.274 +running the browser.  Such a log can be taken over a long session of
   1.275 +normal browsing and then the log can be processed to find sites that
   1.276 +leak.  Once a site is known to leak, the logging can then be repeated
   1.277 +to figure out under what conditions the leak occurs.</p>
   1.278 +
   1.279 +<p>The way to create this log is to set the environment variables:</p>
   1.280 +<pre>  NSPR_LOG_MODULES=DOMLeak:5,DocumentLeak:5,nsDocShellLeak:5,NodeInfoManagerLeak:5
   1.281 +  NSPR_LOG_FILE=nspr.log     <i>(or any other filename of your choice)</i></pre>
   1.282 +<p>in your shell and then run the program.</p>
   1.283 +<ul>
   1.284 +<li>In a Windows command prompt, set environment variables with
   1.285 +<pre>    set VAR=value</pre></li>
   1.286 +<li> In an sh-based shell such as bash, set environment variables with
   1.287 +<pre>    export VAR=value</pre></li>
   1.288 +<li>In a csh-based shell such as tcsh, set environment variables with
   1.289 +<pre>    setenv VAR value</pre></li>
   1.290 +</ul>
   1.291 +
   1.292 +<p>Once you have this log from a complete run of the browser (you have
   1.293 +to exit; otherwise it will look like everything leaked), you can load
   1.294 +this page (be careful not to overwrite the log when starting the browser
   1.295 +to load this page) and enter the filename of the log:</p>
   1.296 +
   1.297 +<p><input type="file" id="fileinput" onchange="run()"></p>
   1.298 +
   1.299 +<p>Then you'll see the output below, which will tell you which of
   1.300 +certain core objects leaked and the URLs associated with those
   1.301 +objects.</p>
   1.302 +
   1.303 +</body>
   1.304 +</html>

mercurial