From 0d99fb7955e6b57818f1554886b0d1531852ee55 Mon Sep 17 00:00:00 2001 From: "beard%netscape.com" Date: Sun, 10 Sep 2000 18:33:27 +0000 Subject: [PATCH] splitting out each individual type_size into separate report, to make it possible to visualize entire graph. --- gc/boehm/leaksoup/bloatsoup.java | 246 ++++++++++++++++++++++++------- 1 file changed, 192 insertions(+), 54 deletions(-) diff --git a/gc/boehm/leaksoup/bloatsoup.java b/gc/boehm/leaksoup/bloatsoup.java index c81df3b53ccb..9f843923cf00 100644 --- a/gc/boehm/leaksoup/bloatsoup.java +++ b/gc/boehm/leaksoup/bloatsoup.java @@ -77,32 +77,89 @@ public class bloatsoup { mTotalSize = 0; } + void setParents(Vector parents) { + mParents = new Entry[parents.size()]; + parents.copyInto(mParents); + } + public String toString() { - return ("" + mAddress + " [" + mRefCount + "] " + mType + " {" + mTotalSize + "}"); + String typeName = mType.mName; + int typeSize = mType.mSize; + String typeLink = "<" + typeName + "> (" + typeSize + ")"; + return ("" + mAddress + " [" + mRefCount + "] " + typeLink + " {" + mTotalSize + "}"); } } + + static class ByTypeBloat implements QuickSort.Comparator { + Histogram hist; + + ByTypeBloat(Histogram hist) { + this.hist = hist; + } + + public int compare(Object obj1, Object obj2) { + Entry e1 = (Entry) obj1, e2 = (Entry) obj2; + Type t1 = e1.mType, t2 = e2.mType; + return (hist.count(t2) * t2.mSize - hist.count(t1) * t1.mSize); + } + } + + /** + * Sorts the bins of a histogram by (count * typeSize) to show the + * most pressing leaks. + */ + static class HistComparator implements QuickSort.Comparator { + Histogram hist; + + HistComparator(Histogram hist) { + this.hist = hist; + } + + public int compare(Object obj1, Object obj2) { + Type t1 = (Type) obj1, t2 = (Type) obj2; + return (hist.count(t1) * t1.mSize - hist.count(t2) * t2.mSize); + } + } + + static void printHistogram(PrintWriter out, Histogram hist, String dir) throws IOException { + // sort the types by histogram count. + Object[] types = hist.objects(); + QuickSort sorter = new QuickSort(new leaksoup.HistComparator(hist)); + sorter.sort(types); + + out.println("
");
+		int index = types.length;
+		while (index > 0) {
+			Type type = (Type) types[--index];
+			int count = hist.count(type);
+            String name = type.mName;
+            int size = type.mSize;
+			out.print("<" + name + "> (" + size + ")");
+			out.println(" : " + count + " {" + (count * type.mSize) + "}");
+		}
+		out.println("
"); + } static String kStackCrawlScript = - "function finishedLoad() {\n" + - " document.loaded = true;\n" + - " document.layers['popup'].visibility='show';\n" + - " return true;\n" + - "}\n" + "var currentURL = null;\n" + - "function showCrawl(event, addr) {\n" + - " if (!document.loaded) return true;\n" + + "function showCrawl(event, crawlID) {\n" + + " if (!(event.modifiers & Event.SHIFT_MASK)) return true;\n" + " var l = document.layers['popup'];\n" + " var docURL = document.URL;\n" + - " var crawlURL = docURL.substring(0, docURL.lastIndexOf('/') + 1) + crawlDir + addr + '.html';\n" + + " var crawlURL = docURL.substring(0, docURL.lastIndexOf('/') + 1) + crawlID + '.html';\n" + " // alert(crawlURL);\n" + - " if (currentURL != crawlURL) {\n" + - " l.load(crawlURL, 800);\n" + - " currentURL = crawlURL\n" + + " if (l.visibility == 'hide' || currentURL != crawlURL) {\n" + + " if (currentURL != crawlURL) {\n" + + " l.load(crawlURL, 800);\n" + + " currentURL = crawlURL;\n" + + " }\n" + " l.top = event.target.y + 15;\n" + " l.left = event.target.x + 30;\n" + + " l.visibility='show';\n" + + " } else {\n" + + " l.visibility = 'hide';\n" + " }\n" + - " l.visibility='show';\n" + - " return true;\n" + + " return false;\n" + "}\n" + ""; @@ -122,7 +179,7 @@ public class bloatsoup { */ static void cook(String inputName) { String outputName = inputName + ".html"; - String crawlDir = inputName + ".crawls/"; + String contentsDir = inputName + ".contents/"; try { int objectCount = 0; @@ -132,7 +189,7 @@ public class bloatsoup { Hashtable types = new Hashtable(); Histogram hist = new Histogram(); CallTree calls = new CallTree(strings); - Vector entries = new Vector(); + Hashtable entriesTable = new Hashtable(); Vector vec = new Vector(); BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(inputName))); String line = reader.readLine(); @@ -142,7 +199,7 @@ public class bloatsoup { String name = strings.intern(line.substring(line.indexOf('<') + 1, line.indexOf('>'))); int size; try { - String str = line.substring(line.indexOf('(') + 1, line.indexOf(')')).trim(); + String str = line.substring(line.indexOf('(') + 1, line.indexOf(')')); size = Integer.parseInt(str); } catch (NumberFormatException nfe) { size = 0; @@ -181,55 +238,126 @@ public class bloatsoup { } while (line != null && line.charAt(0) == '<'); } - entries.addElement(new Entry(addr, type, refs, crawl)); + entriesTable.put(addr, new Entry(addr, type, refs, crawl)); } else { line = reader.readLine(); } } reader.close(); - // build the Entries graph. + // build the entries array & graph. + Entry[] entries = new Entry[objectCount]; - // Create the output .html report. + // now, we have a table full of leaked objects, lets derive reference counts, and build the graph. + { + Hashtable parentTable = new Hashtable(); + int entryIndex = 0; + Enumeration e = entriesTable.elements(); + while (e.hasMoreElements()) { + Entry entry = (Entry) e.nextElement(); + Object[] refs = entry.mReferences; + if (refs != null) { + int count = refs.length; + for (int i = 0; i < count; ++i) { + String addr = (String) refs[i]; + Entry ref = (Entry) entriesTable.get(addr); + if (ref != null) { + // increase the ref count. + ref.mRefCount++; + // change string to ref itself. + refs[i] = ref; + // add entry to ref's parents vector. + Vector parents = (Vector) parentTable.get(ref); + if (parents == null) { + parents = new Vector(); + parentTable.put(ref, parents); + } + parents.addElement(entry); + } + } + } + entries[entryIndex++] = entry; + } + + // be nice to the GC. + entriesTable.clear(); + entriesTable = null; + + // set the parents of each entry. + e = parentTable.keys(); + while (e.hasMoreElements()) { + Entry entry = (Entry) e.nextElement(); + Vector parents = (Vector) parentTable.get(entry); + if (parents != null) + entry.setParents(parents); + } + + // be nice to the GC. + parentTable.clear(); + parentTable = null; + } + + // Sort the entries by type bloat. + { + QuickSort sorter = new QuickSort(new ByTypeBloat(hist)); + sorter.sort(entries); + } + + // Create the bloat summary report. PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputName)))); - writer.println(""); Date now = new Date(); - writer.println("Bloat as of " + now + ""); + writer.println("Bloat Summary as of: " + now + ""); - // set up the stack crawl "layer". I know, this is deprecated, but still useful. - writer.println(""); - writer.println("\n"); - writer.println(""); - // print bloat summary. writer.println("

Bloat Summary

"); writer.println("total object count = " + objectCount + "
"); writer.println("total memory bloat = " + totalSize + " bytes.
"); + File contentsFile = new File(inputName + ".contents"); + if (!contentsFile.exists()) + contentsFile.mkdir(); + // print histogram sorted by count * size. writer.println("

Bloat Histogram

"); - leaksoup.printHistogram(writer, hist); - - File crawlFile = new File(inputName + ".crawls"); - if (!crawlFile.exists()) - crawlFile.mkdir(); - // String crawlPath = System.getProperty("user.dir") + "/" + crawlDir; + printHistogram(writer, hist, contentsDir); + writer.println(""); + writer.close(); + writer = null; // print the Entries graph. - writer.println("

Bloat Graph

"); - writer.println("
");
-			int count = entries.size();
-			for (int i = 0; i < count; ++i) {
-			    Entry entry = (Entry) entries.elementAt(i);
+			int length = entries.length;
+		    Type anchorType = null;
+			for (int i = 0; i < length; ++i) {
+			    Entry entry = entries[i];
+    			if (anchorType != entry.mType) {
+    			    if (writer != null) {
+        			    writer.println("
"); + writer.close(); + } + anchorType = entry.mType; + outputName = contentsDir + anchorType.mName + "_" + anchorType.mSize + ".html"; + writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputName)))); + // set up the stack crawl script. use a on Communicator 4.X, a separate + // window on other browsers. + writer.println("<" + anchorType.mName + ">"); + writer.println(""); + writer.println(""); + writer.println(""); + writer.println("

" + anchorType + " Bloat

"); + writer.println("
");
+    			}
                 writer.println("");
-                writer.println(entry);
+    			if (entry.mParents != null) {
+    				writer.print(entry);
+    				writer.println(" parents");
+    		    } else {
+                    writer.println(entry);
+                }
     			// print object's fields:
     			Object[] refs = entry.mReferences;
     			if (refs != null) {
-        			int length = refs.length;
-        			for (int j = 0; j < length; ++j)
+        			int count = refs.length;
+        			for (int j = 0; j < count; ++j)
         				leaksoup.printField(writer, refs[j]);
         		}
     			// print object's stack crawl, if it hasn't been printed already.
@@ -238,20 +366,30 @@ public class bloatsoup {
     			if (crawlID > 0) {
     			    // encode already printed by negating the crawl id.
     			    crawl.id = -crawlID;
-        			PrintWriter crawlWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(crawlDir + crawlID + ".html"))));
-        			crawlWriter.print(kStackCrawlPrefix);
-        			while (crawl != null) {
-        				String location = FileLocator.getFileLocation(crawl.data);
-        				crawlWriter.println(location);
-        				crawl = crawl.parent;
-        			}
-        			crawlWriter.print(kStackCrawlSuffix);
-        			crawlWriter.close();
+    			    File crawlFile = new File(contentsDir + crawlID + ".html");
+    			    if (! crawlFile.exists()) {
+            			PrintWriter crawlWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(crawlFile))));
+            			crawlWriter.print(kStackCrawlPrefix);
+            			while (crawl != null) {
+            				String location = FileLocator.getFileLocation(crawl.data);
+            				crawlWriter.println(location);
+            				crawl = crawl.parent;
+            			}
+            			crawlWriter.print(kStackCrawlSuffix);
+            			crawlWriter.close();
+            		}
         		}
+    			// print object's parents.
+    			if (entry.mParents != null) {
+    				writer.println("");
+    				writer.println("\nObject Parents:");
+    				Entry[] parents = entry.mParents;
+    				int count = parents.length;
+    				for (int j = 0; j < count; ++j)
+    					writer.println("\t" + parents[j]);
+    			}
 			}
 			writer.println("
"); - writer.println(""); - writer.close(); } catch (Exception e) { e.printStackTrace(System.err);