diff options
| author | Android (Google) Code Review <android-gerrit@google.com> | 2009-09-23 14:28:16 -0400 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2009-09-23 14:28:16 -0400 |
| commit | 3136d4b0108deaca5ab525881de47d2979911131 (patch) | |
| tree | b67a065e416e1db2cbfcdb61f035a8fbcaa99b78 /tools | |
| parent | 6d181166a2e5c819e274397f90e33d340061750f (diff) | |
| parent | fcc3ccb9769dd39ac93dbad56ee590e2f7d041c3 (diff) | |
| download | frameworks_base-3136d4b0108deaca5ab525881de47d2979911131.zip frameworks_base-3136d4b0108deaca5ab525881de47d2979911131.tar.gz frameworks_base-3136d4b0108deaca5ab525881de47d2979911131.tar.bz2 | |
Merge change 26635 into eclair
* changes:
Added tool to generate application-specific reports from class load profiling data. Generated new profiling data. Deleted old data. Generated new preloaded-classes file.
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/preload/20080522.compiled | bin | 11414749 -> 0 bytes | |||
| -rw-r--r-- | tools/preload/20090922.compiled (renamed from tools/preload/20090811.compiled) | bin | 15943336 -> 13406836 bytes | |||
| -rw-r--r-- | tools/preload/Android.mk | 1 | ||||
| -rw-r--r-- | tools/preload/LoadedClass.java | 30 | ||||
| -rw-r--r-- | tools/preload/PrintBugReports.java | 272 | ||||
| -rw-r--r-- | tools/preload/Root.java | 5 | ||||
| -rw-r--r-- | tools/preload/WritePreloadedClassFile.java | 2 | ||||
| -rw-r--r-- | tools/preload/preload.ipr | 2 | ||||
| -rw-r--r-- | tools/preload/sorttable.js | 3 |
9 files changed, 309 insertions, 6 deletions
diff --git a/tools/preload/20080522.compiled b/tools/preload/20080522.compiled Binary files differdeleted file mode 100644 index a2af422..0000000 --- a/tools/preload/20080522.compiled +++ /dev/null diff --git a/tools/preload/20090811.compiled b/tools/preload/20090922.compiled Binary files differindex 6dbeca0..fc66405 100644 --- a/tools/preload/20090811.compiled +++ b/tools/preload/20090922.compiled diff --git a/tools/preload/Android.mk b/tools/preload/Android.mk index f325870..65b7d1a 100644 --- a/tools/preload/Android.mk +++ b/tools/preload/Android.mk @@ -8,6 +8,7 @@ LOCAL_SRC_FILES := \ MemoryUsage.java \ Operation.java \ Policy.java \ + PrintBugReports.java \ PrintCsv.java \ PrintHtmlDiff.java \ PrintPsTree.java \ diff --git a/tools/preload/LoadedClass.java b/tools/preload/LoadedClass.java index 86e5dfc..02cff10 100644 --- a/tools/preload/LoadedClass.java +++ b/tools/preload/LoadedClass.java @@ -15,7 +15,11 @@ */ import java.io.Serializable; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; /** * A loaded class. @@ -50,6 +54,30 @@ class LoadedClass implements Serializable, Comparable<LoadedClass> { this.systemClass = systemClass; } + /** + * Returns true if this class was loaded by more than one proc. + */ + boolean isSharable() { + Set<String> procNames = new HashSet<String>(); + for (Operation load : loads) { + if (load.process.fromZygote()) { + procNames.add(load.process.name); + if (procNames.size() > 1) { + return true; + } + } + } + for (Operation init : initializations) { + if (init.process.fromZygote()) { + procNames.add(init.process.name); + if (procNames.size() > 1) { + return true; + } + } + } + return false; + } + void measureMemoryUsage() { this.memoryUsage = MemoryUsage.forClass(name); } diff --git a/tools/preload/PrintBugReports.java b/tools/preload/PrintBugReports.java new file mode 100644 index 0000000..a6d4187 --- /dev/null +++ b/tools/preload/PrintBugReports.java @@ -0,0 +1,272 @@ +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.io.DataInputStream; +import java.io.FileInputStream; +import java.util.Map; +import java.util.List; +import java.util.HashMap; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Set; +import java.util.TreeSet; +import java.util.Iterator; + +/** + * Prints HTML reports that can be attached to bugs. + */ +public class PrintBugReports { + + private static final String DIR = "out/preload"; + private static boolean PRINT_MEMORY_USAGE = false; + + private static final Comparator<LoadedClass> DEFAULT_ORDER + = new Comparator<LoadedClass>() { + public int compare(LoadedClass a, LoadedClass b) { + // Longest load time first. + int diff = b.medianTimeMicros() - a.medianTimeMicros(); + if (diff != 0) { + return diff; + } + + return a.name.compareTo(b.name); + } + }; + + public static void main(String[] args) + throws IOException, ClassNotFoundException { + Root root = Root.fromFile(args[0]); + String baseUrl = ""; + if (args.length > 1) { + baseUrl = args[1]; + } + + new File(DIR).mkdirs(); + + Map<String, List<Proc>> procsByName = new HashMap<String, List<Proc>>(); + for (Proc proc : root.processes.values()) { + if (proc.fromZygote()) { + List<Proc> procs = procsByName.get(proc.name); + if (procs == null) { + procs = new ArrayList<Proc>(); + procsByName.put(proc.name, procs); + } + procs.add(proc); + } + } + + Set<LoadedClass> coreClasses = new TreeSet<LoadedClass>(DEFAULT_ORDER); + Set<LoadedClass> frameworkClasses = new TreeSet<LoadedClass>(DEFAULT_ORDER); + + for (List<Proc> procs : procsByName.values()) { + Proc first = procs.get(0); + Set<LoadedClass> classes = new TreeSet<LoadedClass>(DEFAULT_ORDER); + Set<LoadedClass> sharedClasses + = new TreeSet<LoadedClass>(DEFAULT_ORDER); + for (Proc proc : procs) { + for (Operation operation : proc.operations) { + LoadedClass clazz = operation.loadedClass; + if (clazz.isSharable() && clazz.systemClass) { + if (clazz.name.startsWith("dalvik") + || clazz.name.startsWith("org") + || clazz.name.startsWith("java")) { + coreClasses.add(clazz); + } else { + frameworkClasses.add(clazz); + } + sharedClasses.add(clazz); + } else { + classes.add(clazz); + } + } + } + printApplicationHtml(first.name, root.baseline, classes, + sharedClasses); + } + + printHtml("core", root.baseline, coreClasses); + printHtml("framework", root.baseline, frameworkClasses); + + PrintStream out = new PrintStream(DIR + "/toc.html"); + out.println("<html><body>"); + out.println("<a href='" + baseUrl + + "/core.html'>core</a><br/>"); + out.println("<a href='" + baseUrl + + "/framework.html'>framework</a><br/>"); + + for (String s : new TreeSet<String>(procsByName.keySet())) { + out.println("<a href='" + baseUrl + "/" + + s + ".html'>" + s + "</a><br/>"); + } + out.println("</body></html>"); + out.close(); + } + + static void printApplicationHtml(String name, MemoryUsage baseline, + Iterable<LoadedClass> classes, Iterable<LoadedClass> sharedClasses) + throws IOException { + PrintStream out = new PrintStream(DIR + "/" + name + ".html"); + + printHeader(name, out); + out.println("<body>"); + out.println("<h1><tt>" + name + "</tt></h1>"); + out.println("<p><i>Click a column header to sort by that column.</i></p>"); + + out.println("<p><a href=\"#shared\">Shared Classes</a></p>"); + + out.println("<h3>Application-Specific Classes</h3>"); + + out.println("<p>These classes were loaded only by " + name + ". If" + + " the value of the <i>Preloaded</i> column is <i>yes</i> or " + + " <i>no</i>, the class is in the boot classpath; if it's not" + + " part of the published API, consider" + + " moving it into the APK.</p>"); + + printTable(out, baseline, classes, false); + + out.println("<p><a href=\"#\">Top</a></p>"); + + out.println("<a name=\"shared\"/><h3>Shared Classes</h3>"); + + out.println("<p>These classes are in the boot classpath. They are used" + + " by " + name + " as well as others."); + + printTable(out, baseline, sharedClasses, true); + + out.println("</body></html>"); + out.close(); + } + + static void printHtml(String name, MemoryUsage baseline, + Iterable<LoadedClass> classes) + throws IOException { + PrintStream out = new PrintStream(DIR + "/" + name + ".html"); + + printHeader(name, out); + out.println("<body>"); + out.println("<h1><tt>" + name + "</tt></h1>"); + out.println("<p><i>Click a column header to sort by that column.</i></p>"); + + printTable(out, baseline, classes, true); + + out.println("</body></html>"); + out.close(); + } + + private static void printHeader(String name, PrintStream out) + throws IOException { + out.println("<html><head>"); + out.println("<title>" + name + "</title>"); + out.println("<style>"); + out.println("a, th, td, h1, h3, p { font-family: arial }"); + out.println("th, td { font-size: small }"); + out.println("</style>"); + out.println("<script language=\"javascript\">"); + out.write(SCRIPT); + out.println("</script>"); + out.println("</head>"); + } + + static void printTable(PrintStream out, MemoryUsage baseline, + Iterable<LoadedClass> classes, boolean showProcNames) { + out.println("<p><table border=\"1\" cellpadding=\"5\"" + + " class=\"sortable\" cellspacing=\"0\">"); + + out.println("<thead bgcolor=\"#eeeeee\"><tr>"); + out.println("<th>Name</th>"); + out.println("<th>Preloaded</th>"); + out.println("<th>Total Time (us)</th>"); + out.println("<th>Load Time (us)</th>"); + out.println("<th>Init Time (us)</th>"); + if (PRINT_MEMORY_USAGE) { + out.println("<th>Total Heap (B)</th>"); + out.println("<th>Dalvik Heap (B)</th>"); + out.println("<th>Native Heap (B)</th>"); + out.println("<th>Total Pages (kB)</th>"); + out.println("<th>Dalvik Pages (kB)</th>"); + out.println("<th>Native Pages (kB)</th>"); + out.println("<th>Other Pages (kB)</th>"); + } + if (showProcNames) { + out.println("<th>Loaded by</th>"); + } + out.println("</tr></thead>"); + + for (LoadedClass clazz : classes) { + out.println("<tr>"); + out.println("<td>" + clazz.name + "</td>"); + + out.println("<td>" + ((clazz.systemClass) + ? ((clazz.preloaded) ? "yes" : "no") : "n/a") + "</td>"); + + out.println("<td>" + clazz.medianTimeMicros() + "</td>"); + out.println("<td>" + clazz.medianLoadTimeMicros() + "</td>"); + out.println("<td>" + clazz.medianInitTimeMicros() + "</td>"); + + if (PRINT_MEMORY_USAGE) { + if (clazz.memoryUsage.isAvailable()) { + MemoryUsage subtracted + = clazz.memoryUsage.subtract(baseline); + + long totalHeap = subtracted.javaHeapSize() + + subtracted.nativeHeapSize; + out.println("<td>" + totalHeap + "</td>"); + out.println("<td>" + subtracted.javaHeapSize() + "</td>"); + out.println("<td>" + subtracted.nativeHeapSize + "</td>"); + + out.println("<td>" + subtracted.totalPages() + "</td>"); + out.println("<td>" + subtracted.javaPagesInK() + "</td>"); + out.println("<td>" + subtracted.nativePagesInK() + "</td>"); + out.println("<td>" + subtracted.otherPagesInK() + "</td>"); + } else { + for (int i = 0; i < 7; i++) { + out.println("<td> </td>"); + } + } + } + + if (showProcNames) { + out.println("<td>"); + Set<String> procNames = new TreeSet<String>(); + for (Operation op : clazz.loads) { + procNames.add(op.process.name); + } + for (Operation op : clazz.initializations) { + procNames.add(op.process.name); + } + if (procNames.size() <= 3) { + for (String name : procNames) { + out.print(name + "<br/>"); + } + } else { + Iterator<String> i = procNames.iterator(); + out.print(i.next() + "<br/>"); + out.print(i.next() + "<br/>"); + out.print("...and " + (procNames.size() - 2) + + " others."); + } + out.println("</td>"); + } + + out.println("</tr>"); + } + + out.println("</table></p>"); + } + + static byte[] SCRIPT; + static { + try { + File script = new File( + "frameworks/base/tools/preload/sorttable.js"); + int length = (int) script.length(); + SCRIPT = new byte[length]; + DataInputStream in = new DataInputStream( + new FileInputStream(script)); + in.readFully(SCRIPT); + in.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/tools/preload/Root.java b/tools/preload/Root.java index 0bc29bf..3f12dea 100644 --- a/tools/preload/Root.java +++ b/tools/preload/Root.java @@ -46,7 +46,8 @@ public class Root implements Serializable { final Map<String, LoadedClass> loadedClasses = new HashMap<String, LoadedClass>(); - MemoryUsage baseline = MemoryUsage.baseline(); +// MemoryUsage baseline = MemoryUsage.baseline(); + MemoryUsage baseline = MemoryUsage.NOT_AVAILABLE; /** * Records class loads and initializations. @@ -73,7 +74,7 @@ public class Root implements Serializable { if (loadedClass.systemClass) { // Only measure memory for classes in the boot // classpath. - loadedClass.measureMemoryUsage(); +// loadedClass.measureMemoryUsage(); } loadedClasses.put(name, loadedClass); } diff --git a/tools/preload/WritePreloadedClassFile.java b/tools/preload/WritePreloadedClassFile.java index 96c539b..757d17d3 100644 --- a/tools/preload/WritePreloadedClassFile.java +++ b/tools/preload/WritePreloadedClassFile.java @@ -32,7 +32,7 @@ public class WritePreloadedClassFile { /** * Preload any class that take longer to load than MIN_LOAD_TIME_MICROS us. */ - static final int MIN_LOAD_TIME_MICROS = 1250; + static final int MIN_LOAD_TIME_MICROS = 1000; public static void main(String[] args) throws IOException, ClassNotFoundException { diff --git a/tools/preload/preload.ipr b/tools/preload/preload.ipr index 0c9621c..dddca3b 100644 --- a/tools/preload/preload.ipr +++ b/tools/preload/preload.ipr @@ -364,7 +364,7 @@ </component> <component name="ProjectFileVersion" converted="true" /> <component name="ProjectKey"> - <option name="state" value="project:///Volumes/Android/donut/frameworks/base/tools/preload/preload.ipr" /> + <option name="state" value="project:///Volumes/Android/eclair/frameworks/base/tools/preload/preload.ipr" /> </component> <component name="ProjectModuleManager"> <modules> diff --git a/tools/preload/sorttable.js b/tools/preload/sorttable.js index 25bccb2..f03859e 100644 --- a/tools/preload/sorttable.js +++ b/tools/preload/sorttable.js @@ -6,7 +6,7 @@ Instructions: Download this file - Add <script src="sorttable.js"></script> to your HTML + Add <script src="sorttable.js"> to your HTML Add class="sortable" to any table you'd like to make sortable Click on the headers to sort @@ -88,6 +88,7 @@ sorttable = { } // make it clickable to sort headrow[i].sorttable_columnindex = i; + headrow[i].style.cursor = "pointer"; headrow[i].sorttable_tbody = table.tBodies[0]; dean_addEvent(headrow[i],"click", function(e) { |
