• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 import java.io.File;
2 import java.io.IOException;
3 import java.io.PrintStream;
4 import java.io.DataInputStream;
5 import java.io.FileInputStream;
6 import java.util.Map;
7 import java.util.List;
8 import java.util.HashMap;
9 import java.util.ArrayList;
10 import java.util.Comparator;
11 import java.util.Set;
12 import java.util.TreeSet;
13 import java.util.Iterator;
14 
15 /**
16  * Prints HTML reports that can be attached to bugs.
17  */
18 public class PrintBugReports {
19 
20     private static final String DIR = "out/preload";
21     private static boolean PRINT_MEMORY_USAGE = false;
22 
23     private static final Comparator<LoadedClass> DEFAULT_ORDER
24             = new Comparator<LoadedClass>() {
25         public int compare(LoadedClass a, LoadedClass b) {
26             // Longest load time first.
27             int diff = b.medianTimeMicros() - a.medianTimeMicros();
28             if (diff != 0) {
29                 return diff;
30             }
31 
32             return a.name.compareTo(b.name);
33         }
34     };
35 
main(String[] args)36     public static void main(String[] args)
37             throws IOException, ClassNotFoundException {
38         Root root = Root.fromFile(args[0]);
39         String baseUrl = "";
40         if (args.length > 1) {
41             baseUrl = args[1];
42         }
43 
44         new File(DIR).mkdirs();
45 
46         Map<String, List<Proc>> procsByName = new HashMap<String, List<Proc>>();
47         for (Proc proc : root.processes.values()) {
48             if (proc.fromZygote()) {
49                 List<Proc> procs = procsByName.get(proc.name);
50                 if (procs == null) {
51                     procs = new ArrayList<Proc>();
52                     procsByName.put(proc.name, procs);
53                 }
54                 procs.add(proc);
55             }
56         }
57 
58         Set<LoadedClass> coreClasses = new TreeSet<LoadedClass>(DEFAULT_ORDER);
59         Set<LoadedClass> frameworkClasses = new TreeSet<LoadedClass>(DEFAULT_ORDER);
60 
61         for (List<Proc> procs : procsByName.values()) {
62             Proc first = procs.get(0);
63             Set<LoadedClass> classes = new TreeSet<LoadedClass>(DEFAULT_ORDER);
64             Set<LoadedClass> sharedClasses
65                     = new TreeSet<LoadedClass>(DEFAULT_ORDER);
66             for (Proc proc : procs) {
67                 for (Operation operation : proc.operations) {
68                     LoadedClass clazz = operation.loadedClass;
69                     if (clazz.isSharable() && clazz.systemClass) {
70                         if (clazz.name.startsWith("dalvik")
71                                 || clazz.name.startsWith("org")
72                                 || clazz.name.startsWith("java")) {
73                             coreClasses.add(clazz);
74                         } else {
75                             frameworkClasses.add(clazz);
76                         }
77                         sharedClasses.add(clazz);
78                     } else {
79                         classes.add(clazz);
80                     }
81                 }
82             }
83             printApplicationHtml(first.name, root.baseline, classes,
84                     sharedClasses);
85         }
86 
87         printHtml("core", root.baseline, coreClasses);
88         printHtml("framework", root.baseline, frameworkClasses);
89 
90         PrintStream out = new PrintStream(DIR + "/toc.html");
91         out.println("<html><body>");
92         out.println("<a href='" + baseUrl
93                 + "/core.html'>core</a><br/>");
94         out.println("<a href='" + baseUrl
95                 + "/framework.html'>framework</a><br/>");
96 
97         for (String s : new TreeSet<String>(procsByName.keySet())) {
98             out.println("<a href='" + baseUrl + "/"
99                     + s + ".html'>" + s + "</a><br/>");
100         }
101         out.println("</body></html>");
102         out.close();
103     }
104 
printApplicationHtml(String name, MemoryUsage baseline, Iterable<LoadedClass> classes, Iterable<LoadedClass> sharedClasses)105     static void printApplicationHtml(String name, MemoryUsage baseline,
106             Iterable<LoadedClass> classes, Iterable<LoadedClass> sharedClasses)
107             throws IOException {
108         PrintStream out = new PrintStream(DIR + "/" + name + ".html");
109 
110         printHeader(name, out);
111         out.println("<body>");
112         out.println("<h1><tt>" + name + "</tt></h1>");
113         out.println("<p><i>Click a column header to sort by that column.</i></p>");
114 
115         out.println("<p><a href=\"#shared\">Shared Classes</a></p>");
116 
117         out.println("<h3>Application-Specific Classes</h3>");
118 
119         out.println("<p>These classes were loaded only by " + name + ". If"
120                 + " the value of the <i>Preloaded</i> column is <i>yes</i> or "
121                 + " <i>no</i>, the class is in the boot classpath; if it's not"
122                 + " part of the published API, consider"
123                 + " moving it into the APK.</p>");
124 
125         printTable(out, baseline, classes, false);
126 
127         out.println("<p><a href=\"#\">Top</a></p>");
128 
129         out.println("<a name=\"shared\"/><h3>Shared Classes</h3>");
130 
131         out.println("<p>These classes are in the boot classpath. They are used"
132                 + " by " + name + " as well as others.");
133 
134         printTable(out, baseline, sharedClasses, true);
135 
136         out.println("</body></html>");
137         out.close();
138     }
139 
printHtml(String name, MemoryUsage baseline, Iterable<LoadedClass> classes)140     static void printHtml(String name, MemoryUsage baseline,
141             Iterable<LoadedClass> classes)
142             throws IOException {
143         PrintStream out = new PrintStream(DIR + "/" + name + ".html");
144 
145         printHeader(name, out);
146         out.println("<body>");
147         out.println("<h1><tt>" + name + "</tt></h1>");
148         out.println("<p><i>Click a column header to sort by that column.</i></p>");
149 
150         printTable(out, baseline, classes, true);
151 
152         out.println("</body></html>");
153         out.close();
154     }
155 
printHeader(String name, PrintStream out)156     private static void printHeader(String name, PrintStream out)
157             throws IOException {
158         out.println("<html><head>");
159         out.println("<title>" + name + "</title>");
160         out.println("<style>");
161         out.println("a, th, td, h1, h3, p { font-family: arial }");
162         out.println("th, td { font-size: small }");
163         out.println("</style>");
164         out.println("<script language=\"javascript\">");
165         out.write(SCRIPT);
166         out.println("</script>");
167         out.println("</head>");
168     }
169 
printTable(PrintStream out, MemoryUsage baseline, Iterable<LoadedClass> classes, boolean showProcNames)170     static void printTable(PrintStream out, MemoryUsage baseline,
171             Iterable<LoadedClass> classes, boolean showProcNames) {
172         out.println("<p><table border=\"1\" cellpadding=\"5\""
173                 + " class=\"sortable\" cellspacing=\"0\">");
174 
175         out.println("<thead bgcolor=\"#eeeeee\"><tr>");
176         out.println("<th>Name</th>");
177         out.println("<th>Preloaded</th>");
178         out.println("<th>Total Time (us)</th>");
179         out.println("<th>Load Time (us)</th>");
180         out.println("<th>Init Time (us)</th>");
181         if (PRINT_MEMORY_USAGE) {
182             out.println("<th>Total Heap (B)</th>");
183             out.println("<th>Dalvik Heap (B)</th>");
184             out.println("<th>Native Heap (B)</th>");
185             out.println("<th>Total Pages (kB)</th>");
186             out.println("<th>Dalvik Pages (kB)</th>");
187             out.println("<th>Native Pages (kB)</th>");
188             out.println("<th>Other Pages (kB)</th>");
189         }
190         if (showProcNames) {
191             out.println("<th>Loaded by</th>");
192         }
193         out.println("</tr></thead>");
194 
195         for (LoadedClass clazz : classes) {
196             out.println("<tr>");
197             out.println("<td>" + clazz.name + "</td>");
198 
199             out.println("<td>" + ((clazz.systemClass)
200                     ? ((clazz.preloaded) ? "yes" : "no") : "n/a") + "</td>");
201 
202             out.println("<td>" + clazz.medianTimeMicros() + "</td>");
203             out.println("<td>" + clazz.medianLoadTimeMicros() + "</td>");
204             out.println("<td>" + clazz.medianInitTimeMicros() + "</td>");
205 
206             if (PRINT_MEMORY_USAGE) {
207                 if (clazz.memoryUsage.isAvailable()) {
208                     MemoryUsage subtracted
209                             = clazz.memoryUsage.subtract(baseline);
210 
211                     long totalHeap = subtracted.javaHeapSize()
212                             + subtracted.nativeHeapSize;
213                     out.println("<td>" + totalHeap + "</td>");
214                     out.println("<td>" + subtracted.javaHeapSize() + "</td>");
215                     out.println("<td>" + subtracted.nativeHeapSize + "</td>");
216 
217                     out.println("<td>" + subtracted.totalPages() + "</td>");
218                     out.println("<td>" + subtracted.javaPagesInK() + "</td>");
219                     out.println("<td>" + subtracted.nativePagesInK() + "</td>");
220                     out.println("<td>" + subtracted.otherPagesInK() + "</td>");
221                 } else {
222                     for (int i = 0; i < 7; i++) {
223                         out.println("<td>&nbsp;</td>");
224                     }
225                 }
226             }
227 
228             if (showProcNames) {
229                 out.println("<td>");
230                 Set<String> procNames = new TreeSet<String>();
231                 for (Operation op : clazz.loads) {
232                     procNames.add(op.process.name);
233                 }
234                 for (Operation op : clazz.initializations) {
235                     procNames.add(op.process.name);
236                 }
237                 if (procNames.size() <= 3) {
238                     for (String name : procNames) {
239                         out.print(name + "<br/>");
240                     }
241                 } else {
242                     Iterator<String> i = procNames.iterator();
243                     out.print(i.next() + "<br/>");
244                     out.print(i.next() + "<br/>");
245                     out.print("...and " + (procNames.size() - 2)
246                             + " others.");
247                 }
248                 out.println("</td>");
249             }
250 
251             out.println("</tr>");
252         }
253 
254         out.println("</table></p>");
255     }
256 
257     static byte[] SCRIPT;
258     static {
259         try {
260             File script = new File(
261                     "frameworks/base/tools/preload/sorttable.js");
262             int length = (int) script.length();
263             SCRIPT = new byte[length];
264             DataInputStream in = new DataInputStream(
265                     new FileInputStream(script));
266             in.readFully(SCRIPT);
in.close()267             in.close();
268         } catch (IOException e) {
269             throw new RuntimeException(e);
270         }
271     }
272 }
273