1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 import java.io.IOException;
18 import java.io.FileReader;
19 import java.io.BufferedReader;
20 import java.io.PrintStream;
21 import java.util.Set;
22 import java.util.TreeSet;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 
26 /**
27  * Prints HTML containing removed and added files.
28  */
29 public class PrintHtmlDiff {
30 
31     private static final String OLD_PRELOADED_CLASSES
32             = "old-preloaded-classes";
33 
main(String[] args)34     public static void main(String[] args) throws IOException,
35             ClassNotFoundException {
36         Root root = Root.fromFile(args[0]);
37 
38         BufferedReader oldClasses = new BufferedReader(
39             new FileReader(OLD_PRELOADED_CLASSES));
40 
41         // Classes loaded implicitly by the zygote.
42         Set<LoadedClass> zygote = new HashSet<LoadedClass>();
43         for (Proc proc : root.processes.values()) {
44             if (proc.name.equals("zygote")) {
45                 for (Operation op : proc.operations) {
46                     zygote.add(op.loadedClass);
47                 }
48                 break;
49             }
50         }
51 
52         Set<LoadedClass> removed = new TreeSet<LoadedClass>();
53         Set<LoadedClass> added = new TreeSet<LoadedClass>();
54 
55         for (LoadedClass loadedClass : root.loadedClasses.values()) {
56             if (loadedClass.preloaded && !zygote.contains(loadedClass)) {
57                 added.add(loadedClass);
58             }
59         }
60 
61         String line;
62         while ((line = oldClasses.readLine()) != null) {
63             line = line.trim();
64             LoadedClass clazz = root.loadedClasses.get(line);
65             if (clazz != null) {
66                 added.remove(clazz);
67                 if (!clazz.preloaded) removed.add(clazz);
68             }
69         }
70 
71         PrintStream out = System.out;
72 
73         out.println("<html><body>");
74         out.println("<style>");
75         out.println("a, th, td, h2 { font-family: arial }");
76         out.println("th, td { font-size: small }");
77         out.println("</style>");
78         out.println("<script src=\"sorttable.js\"></script>");
79         out.println("<p><a href=\"#removed\">Removed</a>");
80         out.println("<a name=\"added\"/><h2>Added</h2>");
81         printTable(out, root.baseline, added);
82         out.println("<a name=\"removed\"/><h2>Removed</h2>");
83         printTable(out, root.baseline, removed);
84         out.println("</body></html>");
85     }
86 
printTable(PrintStream out, MemoryUsage baseline, Iterable<LoadedClass> classes)87     static void printTable(PrintStream out, MemoryUsage baseline,
88             Iterable<LoadedClass> classes) {
89         out.println("<table border=\"1\" cellpadding=\"5\""
90                 + " class=\"sortable\">");
91 
92         out.println("<thead><tr>");
93         out.println("<th>Name</th>");
94         out.println("<th>Load Time (us)</th>");
95         out.println("<th>Loaded By</th>");
96         out.println("<th>Heap (B)</th>");
97         out.println("<th>Pages</th>");
98         out.println("</tr></thead>");
99 
100         for (LoadedClass clazz : classes) {
101             out.println("<tr>");
102             out.println("<td>" + clazz.name + "</td>");
103             out.println("<td>" + clazz.medianTimeMicros() + "</td>");
104 
105             out.println("<td>");
106             Set<String> procNames = new TreeSet<String>();
107             for (Operation op : clazz.loads) procNames.add(op.process.name);
108             for (Operation op : clazz.initializations) {
109                 procNames.add(op.process.name);
110             }
111             if (procNames.size() <= 3) {
112                 for (String name : procNames) {
113                     out.print(name + "<br/>");
114                 }
115             } else {
116                 Iterator<String> i = procNames.iterator();
117                 out.print(i.next() + "<br/>");
118                 out.print(i.next() + "<br/>");
119                 out.print("...and " + (procNames.size() - 2)
120                         + " others.");
121             }
122             out.println("</td>");
123 
124             if (clazz.memoryUsage.isAvailable()) {
125                 MemoryUsage subtracted
126                         = clazz.memoryUsage.subtract(baseline);
127 
128                 out.println("<td>" + (subtracted.javaHeapSize()
129                         + subtracted.nativeHeapSize) + "</td>");
130                 out.println("<td>" + subtracted.totalPages() + "</td>");
131             } else {
132                 for (int i = 0; i < 2; i++) {
133                     out.println("<td>n/a</td>");
134                 }
135             }
136 
137             out.println("</tr>");
138         }
139 
140         out.println("</table>");
141     }
142 }
143