diff options
Diffstat (limited to '')
-rw-r--r-- | tools/leak-gauge/leak-gauge.html | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/tools/leak-gauge/leak-gauge.html b/tools/leak-gauge/leak-gauge.html new file mode 100644 index 0000000000..7eb2de10c1 --- /dev/null +++ b/tools/leak-gauge/leak-gauge.html @@ -0,0 +1,320 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> +<!-- + vim:sw=4:ts=4:et: + This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. +--> +<html lang="en-US"> + <head> + <meta charset="UTF-8" /> + <title>Leak Gauge</title> + + <style type="text/css"> + pre { + margin: 0; + } + pre.output { + border: medium solid; + padding: 1em; + margin: 1em; + } + </style> + <script> + function runfile(file) { + var result = "Results of processing log " + file.fileName + " :\n"; + + var fileReader = new FileReader(); + fileReader.onload = function (e) { + runContents(result, e.target.result); + }; + fileReader.readAsText(file, "iso-8859-1"); + } + + function runContents(result, contents) { + // A hash of objects (keyed by the first word of the line in the log) + // that have two public methods, handle_line and dump (to be called using + // call, above), along with any private data they need. + var handlers = { + DOMWINDOW: { + count: 0, + windows: {}, + handle_line(line) { + var match = line.match(/^([0-9a-f]*) (\S*)(.*)/); + if (match) { + var addr = match[1]; + var verb = match[2]; + var rest = match[3]; + if (verb == "created") { + let m = rest.match(/ outer=([0-9a-f]*)$/); + if (!m) throw new Error("outer expected"); + this.windows[addr] = { outer: m[1] }; + ++this.count; + } else if (verb == "destroyed") { + delete this.windows[addr]; + } else if (verb == "SetNewDocument") { + let m = rest.match(/^ (.*)$/); + if (!m) throw new Error("URI expected"); + this.windows[addr][m[1]] = true; + } + } + }, + dump() { + for (var addr in this.windows) { + var winobj = this.windows[addr]; + var outer = winobj.outer; + delete winobj.outer; + result += + "Leaked " + + (outer == "0" ? "outer" : "inner") + + " window " + + addr + + " " + + (outer == "0" ? "" : "(outer " + outer + ") ") + + "at address " + + addr + + ".\n"; + for (var uri in winobj) { + result += ' ... with URI "' + uri + '".\n'; + } + } + }, + summary() { + result += + "Leaked " + + Object.keys(this.windows).length + + " out of " + + this.count + + " DOM Windows\n"; + }, + }, + DOCUMENT: { + count: 0, + docs: {}, + handle_line(line) { + var match = line.match(/^([0-9a-f]*) (\S*)(.*)/); + if (match) { + var addr = match[1]; + var verb = match[2]; + var rest = match[3]; + if (verb == "created") { + this.docs[addr] = {}; + ++this.count; + } else if (verb == "destroyed") { + delete this.docs[addr]; + } else if ( + verb == "ResetToURI" || + verb == "StartDocumentLoad" + ) { + var m = rest.match(/^ (.*)$/); + if (!m) throw new Error("URI expected"); + var uri = m[1]; + var doc_info = this.docs[addr]; + doc_info[uri] = true; + if ("nim" in doc_info) { + doc_info.nim[uri] = true; + } + } + } + }, + dump() { + for (var addr in this.docs) { + var doc = this.docs[addr]; + result += "Leaked document at address " + addr + ".\n"; + for (var uri in doc) { + if (uri != "nim") { + result += ' ... with URI "' + uri + '".\n'; + } + } + } + }, + summary() { + result += + "Leaked " + + Object.keys(this.docs).length + + " out of " + + this.count + + " documents\n"; + }, + }, + DOCSHELL: { + count: 0, + shells: {}, + handle_line(line) { + var match = line.match(/^([0-9a-f]*) (\S*)(.*)/); + if (match) { + var addr = match[1]; + var verb = match[2]; + var rest = match[3]; + if (verb == "created") { + this.shells[addr] = {}; + ++this.count; + } else if (verb == "destroyed") { + delete this.shells[addr]; + } else if (verb == "InternalLoad" || verb == "SetCurrentURI") { + var m = rest.match(/^ (.*)$/); + if (!m) throw new Error("URI expected"); + this.shells[addr][m[1]] = true; + } + } + }, + dump() { + for (var addr in this.shells) { + var doc = this.shells[addr]; + result += "Leaked docshell at address " + addr + ".\n"; + for (var uri in doc) { + result += ' ... which loaded URI "' + uri + '".\n'; + } + } + }, + summary() { + result += + "Leaked " + + Object.keys(this.shells).length + + " out of " + + this.count + + " docshells\n"; + }, + }, + NODEINFOMANAGER: { + count: 0, + nims: {}, + handle_line(line) { + var match = line.match(/^([0-9a-f]*) (\S*)(.*)/); + if (match) { + var addr = match[1]; + var verb = match[2]; + var rest = match[3]; + if (verb == "created") { + this.nims[addr] = {}; + ++this.count; + } else if (verb == "destroyed") { + delete this.nims[addr]; + } else if (verb == "Init") { + var m = rest.match(/^ document=(.*)$/); + if (!m) throw new Error("document pointer expected"); + var nim_info = this.nims[addr]; + var doc = m[1]; + if (doc != "0") { + var doc_info = handlers.DOCUMENT.docs[doc]; + for (var uri in doc_info) { + nim_info[uri] = true; + } + doc_info.nim = nim_info; + } + } + } + }, + dump() { + for (var addr in this.nims) { + var nim = this.nims[addr]; + result += + "Leaked content nodes associated with node info manager at address " + + addr + + ".\n"; + for (var uri in nim) { + result += ' ... with document URI "' + uri + '".\n'; + } + } + }, + summary() { + result += + "Leaked content nodes in " + + Object.keys(this.nims).length + + " out of " + + this.count + + " documents\n"; + }, + }, + }; + + var lines = contents.split(/[\r\n]+/); + for (var j in lines) { + var line = lines[j]; + // strip off initial "-", thread id, and thread pointer; separate + // first word and rest + var matches = line.match(/^\-?[0-9]*\[[0-9a-f]*\]: (\S*) (.*)$/); + if (matches) { + let handler = matches[1]; + var data = matches[2]; + if (typeof handlers[handler] != "undefined") { + handlers[handler].handle_line(data); + } + } + } + + for (let handler in handlers) handlers[handler].dump(); + if (result.length) result += "\n"; + result += "Summary:\n"; + for (let handler in handlers) handlers[handler].summary(); + result += "\n"; + + var out = document.createElement("pre"); + out.className = "output"; + out.appendChild(document.createTextNode(result)); + document.body.appendChild(out); + } + + function run() { + var input = document.getElementById("fileinput"); + var files = input.files; + for (var i = 0; i < files.length; ++i) runfile(files[i]); + // So the user can process the same filename again (after + // overwriting the log), clear the value on the form input so we + // will always get an onchange event. + input.value = ""; + } + </script> + </head> + <body> + <h1>Leak Gauge</h1> + + <pre> +$Id: leak-gauge.html,v 1.8 2008/02/08 19:55:34 dbaron%dbaron.org Exp $</pre + > + + <p> + This script is designed to help testers isolate and simplify testcases for + many classes of leaks (those that involve large graphs of core data + structures) in Mozilla-based browsers. It is designed to print information + about what has leaked by processing a log taken while running the browser. + Such a log can be taken over a long session of normal browsing and then + the log can be processed to find sites that leak. Once a site is known to + leak, the logging can then be repeated to figure out under what conditions + the leak occurs. + </p> + + <p>The way to create this log is to set the environment variables:</p> + <pre> MOZ_LOG=DOMLeak:5,DocumentLeak:5,nsDocShellLeak:5,NodeInfoManagerLeak:5 + MOZ_LOG_FILE=nspr.log <i>(or any other filename of your choice)</i></pre> + <p>in your shell and then run the program.</p> + <ul> + <li> + In a Windows command prompt, set environment variables with + <pre> set VAR=value</pre> + </li> + <li> + In an sh-based shell such as bash, set environment variables with + <pre> export VAR=value</pre> + </li> + <li> + In a csh-based shell such as tcsh, set environment variables with + <pre> setenv VAR value</pre> + </li> + </ul> + + <p> + Once you have this log from a complete run of the browser (you have to + exit; otherwise it will look like everything leaked), you can load this + page (be careful not to overwrite the log when starting the browser to + load this page) and enter the filename of the log: + </p> + + <p><input type="file" id="fileinput" onchange="run()" /></p> + + <p> + Then you'll see the output below, which will tell you which of certain + core objects leaked and the URLs associated with those objects. + </p> + </body> +</html> |