summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorBob Lee <crazybob@crazybob.org>2009-09-23 11:34:36 -0700
committerAndroid Git Automerger <android-git-automerger@android.com>2009-09-23 11:34:36 -0700
commita37b3616932e03122b536ff2b9f038c3ae65da4e (patch)
tree5896f7776611fda554b3e15de2a59f6fc0cc5ba5 /tools
parent2fd4943847d0209bef39171c1278ad6c86072dcc (diff)
parent3136d4b0108deaca5ab525881de47d2979911131 (diff)
downloadframeworks_base-a37b3616932e03122b536ff2b9f038c3ae65da4e.zip
frameworks_base-a37b3616932e03122b536ff2b9f038c3ae65da4e.tar.gz
frameworks_base-a37b3616932e03122b536ff2b9f038c3ae65da4e.tar.bz2
am 3136d4b0: Merge change 26635 into eclair
Merge commit '3136d4b0108deaca5ab525881de47d2979911131' into eclair-plus-aosp * commit '3136d4b0108deaca5ab525881de47d2979911131': 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.compiledbin11414749 -> 0 bytes
-rw-r--r--tools/preload/20090922.compiled (renamed from tools/preload/20090811.compiled)bin15943336 -> 13406836 bytes
-rw-r--r--tools/preload/Android.mk1
-rw-r--r--tools/preload/LoadedClass.java30
-rw-r--r--tools/preload/PrintBugReports.java272
-rw-r--r--tools/preload/Root.java5
-rw-r--r--tools/preload/WritePreloadedClassFile.java2
-rw-r--r--tools/preload/preload.ipr2
-rw-r--r--tools/preload/sorttable.js3
9 files changed, 309 insertions, 6 deletions
diff --git a/tools/preload/20080522.compiled b/tools/preload/20080522.compiled
deleted file mode 100644
index a2af422..0000000
--- a/tools/preload/20080522.compiled
+++ /dev/null
Binary files differ
diff --git a/tools/preload/20090811.compiled b/tools/preload/20090922.compiled
index 6dbeca0..fc66405 100644
--- a/tools/preload/20090811.compiled
+++ b/tools/preload/20090922.compiled
Binary files differ
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>&nbsp;</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) {