19d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee/*
29d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee * Copyright (C) 2009 The Android Open Source Project
39d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee *
49d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee * Licensed under the Apache License, Version 2.0 (the "License");
59d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee * you may not use this file except in compliance with the License.
69d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee * You may obtain a copy of the License at
79d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee *
89d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee *      http://www.apache.org/licenses/LICENSE-2.0
99d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee *
109d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee * Unless required by applicable law or agreed to in writing, software
119d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee * distributed under the License is distributed on an "AS IS" BASIS,
129d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee * See the License for the specific language governing permissions and
149d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee * limitations under the License.
159d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee */
169d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
179d2d6e14b0932b6a74e01f393d5efed61458941bBob Leeimport java.io.IOException;
189d2d6e14b0932b6a74e01f393d5efed61458941bBob Leeimport java.io.FileReader;
199d2d6e14b0932b6a74e01f393d5efed61458941bBob Leeimport java.io.BufferedReader;
209d2d6e14b0932b6a74e01f393d5efed61458941bBob Leeimport java.io.PrintStream;
219d2d6e14b0932b6a74e01f393d5efed61458941bBob Leeimport java.util.Set;
229d2d6e14b0932b6a74e01f393d5efed61458941bBob Leeimport java.util.TreeSet;
239d2d6e14b0932b6a74e01f393d5efed61458941bBob Leeimport java.util.HashSet;
249d2d6e14b0932b6a74e01f393d5efed61458941bBob Leeimport java.util.Iterator;
259d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
269d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee/**
279d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee * Prints HTML containing removed and added files.
289d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee */
299d2d6e14b0932b6a74e01f393d5efed61458941bBob Leepublic class PrintHtmlDiff {
309d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
319d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee    private static final String OLD_PRELOADED_CLASSES
329d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            = "old-preloaded-classes";
339d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
349d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee    public static void main(String[] args) throws IOException,
359d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            ClassNotFoundException {
369d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        Root root = Root.fromFile(args[0]);
379d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
389d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        BufferedReader oldClasses = new BufferedReader(
399d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            new FileReader(OLD_PRELOADED_CLASSES));
409d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
419d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        // Classes loaded implicitly by the zygote.
429d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        Set<LoadedClass> zygote = new HashSet<LoadedClass>();
439d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        for (Proc proc : root.processes.values()) {
449d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            if (proc.name.equals("zygote")) {
459d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                for (Operation op : proc.operations) {
469d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                    zygote.add(op.loadedClass);
479d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                }
489d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                break;
499d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            }
509d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        }
519d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
529d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        Set<LoadedClass> removed = new TreeSet<LoadedClass>();
539d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        Set<LoadedClass> added = new TreeSet<LoadedClass>();
549d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
559d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        for (LoadedClass loadedClass : root.loadedClasses.values()) {
569d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            if (loadedClass.preloaded && !zygote.contains(loadedClass)) {
579d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                added.add(loadedClass);
589d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            }
599d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        }
609d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
619d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        String line;
629d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        while ((line = oldClasses.readLine()) != null) {
639d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            line = line.trim();
649d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            LoadedClass clazz = root.loadedClasses.get(line);
659d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            if (clazz != null) {
669d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                added.remove(clazz);
679d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                if (!clazz.preloaded) removed.add(clazz);
689d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            }
699d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        }
709d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
719d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        PrintStream out = System.out;
729d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
739d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("<html><body>");
749d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("<style>");
759d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("a, th, td, h2 { font-family: arial }");
769d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("th, td { font-size: small }");
779d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("</style>");
789d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("<script src=\"sorttable.js\"></script>");
799d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("<p><a href=\"#removed\">Removed</a>");
809d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("<a name=\"added\"/><h2>Added</h2>");
819d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        printTable(out, root.baseline, added);
829d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("<a name=\"removed\"/><h2>Removed</h2>");
839d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        printTable(out, root.baseline, removed);
849d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("</body></html>");
859d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee    }
869d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
879d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee    static void printTable(PrintStream out, MemoryUsage baseline,
889d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            Iterable<LoadedClass> classes) {
899d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("<table border=\"1\" cellpadding=\"5\""
909d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                + " class=\"sortable\">");
919d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
929d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("<thead><tr>");
939d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("<th>Name</th>");
949d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("<th>Load Time (us)</th>");
959d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("<th>Loaded By</th>");
969d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("<th>Heap (B)</th>");
979d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("<th>Pages</th>");
989d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("</tr></thead>");
999d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
1009d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        for (LoadedClass clazz : classes) {
1019d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            out.println("<tr>");
1029d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            out.println("<td>" + clazz.name + "</td>");
1039d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            out.println("<td>" + clazz.medianTimeMicros() + "</td>");
1049d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
1059d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            out.println("<td>");
1069d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            Set<String> procNames = new TreeSet<String>();
1079d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            for (Operation op : clazz.loads) procNames.add(op.process.name);
1089d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            for (Operation op : clazz.initializations) {
1099d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                procNames.add(op.process.name);
1109d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            }
1119d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            if (procNames.size() <= 3) {
1129d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                for (String name : procNames) {
1139d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                    out.print(name + "<br/>");
1149d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                }
1159d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            } else {
1169d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                Iterator<String> i = procNames.iterator();
1179d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                out.print(i.next() + "<br/>");
1189d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                out.print(i.next() + "<br/>");
1199d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                out.print("...and " + (procNames.size() - 2)
1209d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                        + " others.");
1219d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            }
1229d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            out.println("</td>");
1239d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
1249d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            if (clazz.memoryUsage.isAvailable()) {
1259d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                MemoryUsage subtracted
1269d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                        = clazz.memoryUsage.subtract(baseline);
1279d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
1289d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                out.println("<td>" + (subtracted.javaHeapSize()
1299d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                        + subtracted.nativeHeapSize) + "</td>");
1309d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                out.println("<td>" + subtracted.totalPages() + "</td>");
1319d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            } else {
1329d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                for (int i = 0; i < 2; i++) {
1339d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                    out.println("<td>n/a</td>");
1349d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee                }
1359d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            }
1369d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
1379d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee            out.println("</tr>");
1389d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        }
1399d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee
1409d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee        out.println("</table>");
1419d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee    }
1429d2d6e14b0932b6a74e01f393d5efed61458941bBob Lee}
143