summaryrefslogtreecommitdiffstats
path: root/tools/leak-gauge/leak-gauge.html
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tools/leak-gauge/leak-gauge.html320
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>