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
17import java.io.IOException;
18import java.io.FileReader;
19import java.io.BufferedReader;
20import java.io.PrintStream;
21import java.util.Set;
22import java.util.TreeSet;
23import java.util.HashSet;
24import java.util.Iterator;
25
26/**
27 * Prints HTML containing removed and added files.
28 */
29public class PrintHtmlDiff {
30
31    private static final String OLD_PRELOADED_CLASSES
32            = "old-preloaded-classes";
33
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
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