| /* | |
| * Copyright (C) 2009 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| import java.io.IOException; | |
| import java.io.FileReader; | |
| import java.io.BufferedReader; | |
| import java.io.PrintStream; | |
| import java.util.Set; | |
| import java.util.TreeSet; | |
| import java.util.HashSet; | |
| import java.util.Iterator; | |
| /** | |
| * Prints HTML containing removed and added files. | |
| */ | |
| public class PrintHtmlDiff { | |
| private static final String OLD_PRELOADED_CLASSES | |
| = "old-preloaded-classes"; | |
| public static void main(String[] args) throws IOException, | |
| ClassNotFoundException { | |
| Root root = Root.fromFile(args[0]); | |
| BufferedReader oldClasses = new BufferedReader( | |
| new FileReader(OLD_PRELOADED_CLASSES)); | |
| // Classes loaded implicitly by the zygote. | |
| Set<LoadedClass> zygote = new HashSet<LoadedClass>(); | |
| for (Proc proc : root.processes.values()) { | |
| if (proc.name.equals("zygote")) { | |
| for (Operation op : proc.operations) { | |
| zygote.add(op.loadedClass); | |
| } | |
| break; | |
| } | |
| } | |
| Set<LoadedClass> removed = new TreeSet<LoadedClass>(); | |
| Set<LoadedClass> added = new TreeSet<LoadedClass>(); | |
| for (LoadedClass loadedClass : root.loadedClasses.values()) { | |
| if (loadedClass.preloaded && !zygote.contains(loadedClass)) { | |
| added.add(loadedClass); | |
| } | |
| } | |
| String line; | |
| while ((line = oldClasses.readLine()) != null) { | |
| line = line.trim(); | |
| LoadedClass clazz = root.loadedClasses.get(line); | |
| if (clazz != null) { | |
| added.remove(clazz); | |
| if (!clazz.preloaded) removed.add(clazz); | |
| } | |
| } | |
| PrintStream out = System.out; | |
| out.println("<html><body>"); | |
| out.println("<style>"); | |
| out.println("a, th, td, h2 { font-family: arial }"); | |
| out.println("th, td { font-size: small }"); | |
| out.println("</style>"); | |
| out.println("<script src=\"sorttable.js\"></script>"); | |
| out.println("<p><a href=\"#removed\">Removed</a>"); | |
| out.println("<a name=\"added\"/><h2>Added</h2>"); | |
| printTable(out, root.baseline, added); | |
| out.println("<a name=\"removed\"/><h2>Removed</h2>"); | |
| printTable(out, root.baseline, removed); | |
| out.println("</body></html>"); | |
| } | |
| static void printTable(PrintStream out, MemoryUsage baseline, | |
| Iterable<LoadedClass> classes) { | |
| out.println("<table border=\"1\" cellpadding=\"5\"" | |
| + " class=\"sortable\">"); | |
| out.println("<thead><tr>"); | |
| out.println("<th>Name</th>"); | |
| out.println("<th>Load Time (us)</th>"); | |
| out.println("<th>Loaded By</th>"); | |
| out.println("<th>Heap (B)</th>"); | |
| out.println("<th>Pages</th>"); | |
| out.println("</tr></thead>"); | |
| for (LoadedClass clazz : classes) { | |
| out.println("<tr>"); | |
| out.println("<td>" + clazz.name + "</td>"); | |
| out.println("<td>" + clazz.medianTimeMicros() + "</td>"); | |
| 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>"); | |
| if (clazz.memoryUsage.isAvailable()) { | |
| MemoryUsage subtracted | |
| = clazz.memoryUsage.subtract(baseline); | |
| out.println("<td>" + (subtracted.javaHeapSize() | |
| + subtracted.nativeHeapSize) + "</td>"); | |
| out.println("<td>" + subtracted.totalPages() + "</td>"); | |
| } else { | |
| for (int i = 0; i < 2; i++) { | |
| out.println("<td>n/a</td>"); | |
| } | |
| } | |
| out.println("</tr>"); | |
| } | |
| out.println("</table>"); | |
| } | |
| } |