Add leak logging for node info managers that can be added to leak-gauge.
b=414704 r+sr=sicking a=schrep
--- a/content/base/src/nsNodeInfoManager.cpp
+++ b/content/base/src/nsNodeInfoManager.cpp
@@ -48,16 +48,26 @@
#include "nsIPrincipal.h"
#include "nsIURI.h"
#include "nsContentUtils.h"
#include "nsReadableUtils.h"
#include "nsGkAtoms.h"
#include "nsComponentManagerUtils.h"
#include "nsLayoutStatics.h"
+#ifdef MOZ_LOGGING
+// so we can get logging even in release builds
+#define FORCE_PR_LOG 1
+#endif
+#include "prlog.h"
+
+#ifdef PR_LOGGING
+static PRLogModuleInfo* gNodeInfoManagerLeakPRLog;
+#endif
+
PLHashNumber
nsNodeInfoManager::GetNodeInfoInnerHashValue(const void *key)
{
NS_ASSERTION(key, "Null key passed to nsNodeInfo::GetHashValue!");
const nsINodeInfo::nsNodeInfoInner *node =
reinterpret_cast<const nsINodeInfo::nsNodeInfoInner *>(key);
@@ -86,30 +96,45 @@ nsNodeInfoManager::nsNodeInfoManager()
: mDocument(nsnull),
mPrincipal(nsnull),
mTextNodeInfo(nsnull),
mCommentNodeInfo(nsnull),
mDocumentNodeInfo(nsnull)
{
nsLayoutStatics::AddRef();
+#ifdef PR_LOGGING
+ if (!gNodeInfoManagerLeakPRLog)
+ gNodeInfoManagerLeakPRLog = PR_NewLogModule("NodeInfoManagerLeak");
+
+ if (gNodeInfoManagerLeakPRLog)
+ PR_LOG(gNodeInfoManagerLeakPRLog, PR_LOG_DEBUG,
+ ("NODEINFOMANAGER %p created", this));
+#endif
+
mNodeInfoHash = PL_NewHashTable(32, GetNodeInfoInnerHashValue,
NodeInfoInnerKeyCompare,
PL_CompareValues, nsnull, nsnull);
}
nsNodeInfoManager::~nsNodeInfoManager()
{
if (mNodeInfoHash)
PL_HashTableDestroy(mNodeInfoHash);
// Note: mPrincipal may be null here if we never got inited correctly
NS_IF_RELEASE(mPrincipal);
+#ifdef PR_LOGGING
+ if (gNodeInfoManagerLeakPRLog)
+ PR_LOG(gNodeInfoManagerLeakPRLog, PR_LOG_DEBUG,
+ ("NODEINFOMANAGER %p destroyed", this));
+#endif
+
nsLayoutStatics::Release();
}
nsrefcnt
nsNodeInfoManager::AddRef()
{
NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt");
@@ -145,16 +170,22 @@ nsNodeInfoManager::Init(nsIDocument *aDo
nsresult rv = CallCreateInstance("@mozilla.org/nullprincipal;1",
&mPrincipal);
NS_ENSURE_TRUE(mPrincipal, rv);
mDefaultPrincipal = mPrincipal;
mDocument = aDocument;
+#ifdef PR_LOGGING
+ if (gNodeInfoManagerLeakPRLog)
+ PR_LOG(gNodeInfoManagerLeakPRLog, PR_LOG_DEBUG,
+ ("NODEINFOMANAGER %p Init document=%p", this, aDocument));
+#endif
+
return NS_OK;
}
void
nsNodeInfoManager::DropDocumentReference()
{
mDocument = nsnull;
}
--- a/tools/footprint/leak-gauge.html
+++ b/tools/footprint/leak-gauge.html
@@ -116,26 +116,33 @@ function run() {
++this.count;
} else if (verb == "destroyed") {
delete this.docs[addr];
} else if (verb == "ResetToURI" ||
verb == "StartDocumentLoad") {
var m = rest.match(/^ (.*)$/);
if (!m)
throw "URI expected";
- this.docs[addr][m[1]] = true;
+ 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: function() {
for (var addr in this.docs) {
var doc = this.docs[addr];
result += "Leaked document at address " + addr + ".\n";
for (var uri in doc) {
- result += " ... with URI \"" + uri + "\".\n";
+ if (uri != "nim") {
+ result += " ... with URI \"" + uri + "\".\n";
+ }
}
}
},
summary: function() {
var len = 0;
for (var w in this.docs)
++len;
result += 'Leaked ' + len + ' out of ' +
@@ -176,16 +183,63 @@ function run() {
},
summary: function() {
var len = 0;
for (var w in this.shells)
++len;
result += 'Leaked ' + len + ' out of ' +
this.count + " docshells\n";
}
+ },
+ "NODEINFOMANAGER": {
+ count: 0,
+ nims: {},
+ handle_line: function(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 "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: function() {
+ 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: function() {
+ var len = 0;
+ for (var w in this.nims)
+ ++len;
+ result += 'Leaked content nodes in ' + len + ' out of ' +
+ this.count + " documents\n";
+ }
}
};
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
const cs = Components.classes;
const ifs = Components.interfaces;
@@ -232,29 +286,29 @@ function run() {
}
</script>
</head>
<body>
<h1>Leak Gauge</h1>
-<pre>$Id: leak-gauge.html,v 1.6 2006/01/14 00:27:41 dbaron%dbaron.org Exp $</pre>
+<pre>$Id: leak-gauge.html,v 1.7 2008/02/08 19:55:03 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> NSPR_LOG_MODULES=DOMLeak:5,DocumentLeak:5,nsDocShellLeak:5
+<pre> NSPR_LOG_MODULES=DOMLeak:5,DocumentLeak:5,nsDocShellLeak:5,NodeInfoManagerLeak:5
NSPR_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
--- a/tools/footprint/leak-gauge.pl
+++ b/tools/footprint/leak-gauge.pl
@@ -31,28 +31,28 @@
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
-# $Id: leak-gauge.pl,v 1.7 2006/01/14 00:27:41 dbaron%dbaron.org Exp $
+# $Id: leak-gauge.pl,v 1.8 2008/02/08 19:55:03 dbaron%dbaron.org Exp $
# 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.
#
# The way to create this log is to set the environment variables:
-# NSPR_LOG_MODULES=DOMLeak:5,DocumentLeak:5,nsDocShellLeak:5
+# NSPR_LOG_MODULES=DOMLeak:5,DocumentLeak:5,nsDocShellLeak:5,NodeInfoManagerLeak:5
# NSPR_LOG_FILE=nspr.log (or any other filename of your choice)
# in your shell and then run the program.
# * In a Windows command prompt, set environment variables with
# set VAR=value
# * In an sh-based shell such as bash, set environment variables with
# export VAR=value
# * In a csh-based shell such as tcsh, set environment variables with
# setenv VAR value
@@ -122,39 +122,45 @@ my $handlers = {
${$self}{count} . " DOM Windows\n";
}
},
"DOCUMENT" => {
count => 0,
docs => {},
handle_line => sub($$) {
my ($self, $line) = @_;
- my $docs = ${$self}{docs};
+ # This doesn't work; I don't have time to figure out why not.
+ # my $docs = ${$self}{docs};
+ my $docs = ${$handlers}{"DOCUMENT"}{docs};
if ($line =~ /^([0-9a-f]*) (\S*)/) {
my ($addr, $verb, $rest) = ($1, $2, $');
if ($verb eq "created") {
${$docs}{$addr} = {};
++${$self}{count};
} elsif ($verb eq "destroyed") {
delete ${$docs}{$addr};
} elsif ($verb eq "ResetToURI" ||
$verb eq "StartDocumentLoad") {
$rest =~ /^ (.*)$/ || die "URI expected";
my $uri = $1;
- ${${$docs}{$addr}}{$uri} = 1;
+ my $doc_info = ${$docs}{$addr};
+ ${$doc_info}{$uri} = 1;
+ if (exists(${$doc_info}{"nim"})) {
+ ${$doc_info}{"nim"}{$uri} = 1;
+ }
}
}
},
dump => sub ($) {
my ($self) = @_;
my $docs = ${$self}{docs};
foreach my $addr (keys(%{$docs})) {
print "Leaked document at address $addr.\n";
foreach my $uri (keys(%{${$docs}{$addr}})) {
- print " ... with URI \"$uri\".\n";
+ print " ... with URI \"$uri\".\n" unless $uri eq "nim";
}
}
},
summary => sub($) {
my ($self) = @_;
my $docs = ${$self}{docs};
print 'Leaked ' . keys(%{$docs}) . ' out of ' .
${$self}{count} . " documents\n";
@@ -192,16 +198,61 @@ my $handlers = {
}
},
summary => sub($) {
my ($self) = @_;
my $shells = ${$self}{shells};
print 'Leaked ' . keys(%{$shells}) . ' out of ' .
${$self}{count} . " docshells\n";
}
+ },
+ "NODEINFOMANAGER" => {
+ count => 0,
+ nims => {},
+ handle_line => sub($$) {
+ my ($self, $line) = @_;
+ my $nims = ${$self}{nims};
+ if ($line =~ /^([0-9a-f]*) (\S*)/) {
+ my ($addr, $verb, $rest) = ($1, $2, $');
+ if ($verb eq "created") {
+ ${$nims}{$addr} = {};
+ ++${$self}{count};
+ } elsif ($verb eq "destroyed") {
+ delete ${$nims}{$addr};
+ } elsif ($verb eq "Init") {
+ $rest =~ /^ document=(.*)$/ ||
+ die "document pointer expected";
+ my $doc = $1;
+ if ($doc ne "0") {
+ my $nim_info = ${$nims}{$addr};
+ my $doc_info = ${$handlers}{"DOCUMENT"}{docs}{$doc};
+ foreach my $uri (keys(%{$doc_info})) {
+ ${$nim_info}{$uri} = 1;
+ }
+ ${$doc_info}{"nim"} = $nim_info;
+ }
+ }
+ }
+ },
+ dump => sub ($) {
+ my ($self) = @_;
+ my $nims = ${$self}{nims};
+ foreach my $addr (keys(%{$nims})) {
+ print "Leaked content nodes associated with node info manager at address $addr.\n";
+ foreach my $uri (keys(%{${$nims}{$addr}})) {
+ print " ... with document URI \"$uri\".\n";
+ }
+ }
+ },
+ summary => sub($) {
+ my ($self) = @_;
+ my $nims = ${$self}{nims};
+ print 'Leaked content nodes within ' . keys(%{$nims}) . ' out of ' .
+ ${$self}{count} . " documents\n";
+ }
}
};
while (<>) {
# strip off initial "-", thread id, and thread pointer; separate
# first word and rest
if (/^\-?[0-9]*\[[0-9a-f]*\]: (\S*) ([^\n\r]*)[\n\r]*$/) {
my ($handler, $data) = ($1, $2);