diff --git a/tools/preload/20090811.compiled b/tools/preload/20090811.compiled index dd61487c2f871..6dbeca094df5c 100644 Binary files a/tools/preload/20090811.compiled and b/tools/preload/20090811.compiled differ diff --git a/tools/preload/Android.mk b/tools/preload/Android.mk index e6fa103efd6d1..f325870727884 100644 --- a/tools/preload/Android.mk +++ b/tools/preload/Android.mk @@ -3,13 +3,13 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ - ClassRank.java \ Compile.java \ LoadedClass.java \ MemoryUsage.java \ Operation.java \ Policy.java \ PrintCsv.java \ + PrintHtmlDiff.java \ PrintPsTree.java \ Proc.java \ Record.java \ diff --git a/tools/preload/ClassRank.java b/tools/preload/ClassRank.java deleted file mode 100644 index c562d5c64a931..0000000000000 --- a/tools/preload/ClassRank.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2008 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.util.Comparator; - -/** - * Ranks classes for preloading based on how long their operations took - * and how early the operations happened. Higher ranked classes come first. - */ -class ClassRank implements Comparator { - - /** - * Increase this number to add more weight to classes which were loaded - * earlier. - */ - static final int SEQUENCE_WEIGHT = 500; // 0.5ms - - static final int BUCKET_SIZE = 5; - - public int compare(Operation a, Operation b) { - // Higher ranked operations should come first. - int result = rankOf(b) - rankOf(a); - if (result != 0) { - return result; - } - - // Make sure we don't drop one of two classes w/ the same rank. - // If a load and an initialization have the same rank, it's OK - // to treat the operations equally. - return a.loadedClass.name.compareTo(b.loadedClass.name); - } - - /** Ranks the given operation. */ - private static int rankOf(Operation o) { - return o.medianExclusiveTimeMicros() - + SEQUENCE_WEIGHT / (o.index / BUCKET_SIZE + 1); - } -} - - diff --git a/tools/preload/LoadedClass.java b/tools/preload/LoadedClass.java index 9ef17f5643f5e..86e5dfc0331a1 100644 --- a/tools/preload/LoadedClass.java +++ b/tools/preload/LoadedClass.java @@ -51,7 +51,7 @@ class LoadedClass implements Serializable, Comparable { } void measureMemoryUsage() { -// this.memoryUsage = MemoryUsage.forClass(name); + this.memoryUsage = MemoryUsage.forClass(name); } int mlt = -1; @@ -76,6 +76,10 @@ class LoadedClass implements Serializable, Comparable { return mit = calculateMedian(initializations); } + int medianTimeMicros() { + return medianInitTimeMicros() + medianLoadTimeMicros(); + } + /** Calculates the median duration for a list of operations. */ private static int calculateMedian(List operations) { int size = operations.size(); @@ -99,18 +103,18 @@ class LoadedClass implements Serializable, Comparable { } } - /** Returns names of apps that loaded this class. */ - Set applicationNames() { - Set appNames = new HashSet(); - addProcessNames(loads, appNames); - addProcessNames(initializations, appNames); - return appNames; + /** Returns names of processes that loaded this class. */ + Set processNames() { + Set names = new HashSet(); + addProcessNames(loads, names); + addProcessNames(initializations, names); + return names; } - private void addProcessNames(List ops, Set appNames) { + private void addProcessNames(List ops, Set names) { for (Operation operation : ops) { - if (operation.process.isApplication()) { - appNames.add(operation.process.name); + if (operation.process.fromZygote()) { + names.add(operation.process.name); } } } @@ -123,31 +127,4 @@ class LoadedClass implements Serializable, Comparable { public String toString() { return name; } - - /** - * Returns true if this class's initialization causes the given class to - * initialize. - */ - public boolean initializes(LoadedClass clazz, Set visited) { - // Avoid infinite recursion. - if (!visited.add(this)) { - return false; - } - - if (clazz == this) { - return true; - } - - for (Operation initialization : initializations) { - if (initialization.loadedClass.initializes(clazz, visited)) { - return true; - } - } - - return false; - } - - public boolean isPreloadable() { - return systemClass && Policy.isPreloadableClass(name); - } } diff --git a/tools/preload/MemoryUsage.java b/tools/preload/MemoryUsage.java index e5dfb2ac4c0b7..bc21b6f9277b8 100644 --- a/tools/preload/MemoryUsage.java +++ b/tools/preload/MemoryUsage.java @@ -34,8 +34,8 @@ class MemoryUsage implements Serializable { static final MemoryUsage NOT_AVAILABLE = new MemoryUsage(); static int errorCount = 0; - static final int MAXIMUM_ERRORS = 10; // give up after this many fails + // These values are in 1kB increments (not 4kB like you'd expect). final int nativeSharedPages; final int javaSharedPages; final int otherSharedPages; @@ -123,15 +123,24 @@ class MemoryUsage implements Serializable { return allocSize - freedSize; } + int totalHeap() { + return javaHeapSize() + (int) nativeHeapSize; + } + int javaPagesInK() { - return (javaSharedPages + javaPrivatePages) * 4; + return javaSharedPages + javaPrivatePages; } int nativePagesInK() { - return (nativeSharedPages + nativePrivatePages) * 4; + return nativeSharedPages + nativePrivatePages; } int otherPagesInK() { - return (otherSharedPages + otherPrivatePages) * 4; + return otherSharedPages + otherPrivatePages; + } + + int totalPages() { + return javaSharedPages + javaPrivatePages + nativeSharedPages + + nativePrivatePages + otherSharedPages + otherPrivatePages; } /** @@ -163,13 +172,6 @@ class MemoryUsage implements Serializable { * Measures memory usage for the given class. */ static MemoryUsage forClass(String className) { - - // This is a coarse approximation for determining that no device is connected, - // or that the communication protocol has changed, but we'll keep going and stop whining. - if (errorCount >= MAXIMUM_ERRORS) { - return NOT_AVAILABLE; - } - MeasureWithTimeout measurer = new MeasureWithTimeout(className); new Thread(measurer).start(); @@ -280,4 +282,17 @@ class MemoryUsage implements Serializable { e.printStackTrace(); } } + + /** Measures memory usage information and stores it in the model. */ + public static void main(String[] args) throws IOException, + ClassNotFoundException { + Root root = Root.fromFile(args[0]); + root.baseline = baseline(); + for (LoadedClass loadedClass : root.loadedClasses.values()) { + if (loadedClass.systemClass) { + loadedClass.measureMemoryUsage(); + } + } + root.toFile(args[0]); + } } diff --git a/tools/preload/Policy.java b/tools/preload/Policy.java index ade889e3e44b6..7a190ac273d45 100644 --- a/tools/preload/Policy.java +++ b/tools/preload/Policy.java @@ -19,10 +19,10 @@ import java.util.HashSet; import java.util.Set; /** - * This is not instantiated - we just provide data for other classes to use + * Policy that governs which classes are preloaded. */ public class Policy { - + /** * No constructor - use static methods only */ @@ -31,18 +31,24 @@ public class Policy { /** * This location (in the build system) of the preloaded-classes file. */ - private static final String PRELOADED_CLASS_FILE + static final String PRELOADED_CLASS_FILE = "frameworks/base/preloaded-classes"; /** * Long running services. These are restricted in their contribution to the * preloader because their launch time is less critical. */ + // TODO: Generate this automatically from package manager. private static final Set SERVICES = new HashSet(Arrays.asList( - "system_server", - "com.google.process.content", - "android.process.media", - "com.google.process.gapps" + "system_server", + "com.google.process.content", + "android.process.media", + "com.android.phone", + "com.google.android.apps.maps.FriendService", + "com.google.android.apps.maps.LocationFriendService", + "com.google.android.googleapps", + "com.google.process.gapps", + "android.tts" )); /** @@ -63,24 +69,15 @@ public class Policy { )); /** - * Returns the path/file name of the preloaded classes file that will be written - * by WritePreloadedClassFile. - */ - public static String getPreloadedClassFileName() { - return PRELOADED_CLASS_FILE; - } - - /** - * Reports if the given process name is a "long running" process or service + * Returns true if the given process name is a "long running" process or + * service. */ public static boolean isService(String processName) { return SERVICES.contains(processName); } - - /** - * Reports if the given class should never be preloaded - */ - public static boolean isPreloadableClass(String className) { - return !EXCLUDED_CLASSES.contains(className); + + /**Reports if the given class should be preloaded. */ + public static boolean isPreloadable(LoadedClass clazz) { + return clazz.systemClass && !EXCLUDED_CLASSES.contains(clazz.name); } } diff --git a/tools/preload/PrintCsv.java b/tools/preload/PrintCsv.java index 62f4271946462..1820830464711 100644 --- a/tools/preload/PrintCsv.java +++ b/tools/preload/PrintCsv.java @@ -18,9 +18,12 @@ import java.io.IOException; import java.io.FileInputStream; import java.io.ObjectInputStream; import java.io.BufferedInputStream; +import java.io.Writer; +import java.io.PrintStream; import java.util.Set; import java.util.HashSet; import java.util.TreeSet; +import java.util.Iterator; /** * Prints raw information in CSV format. @@ -36,71 +39,89 @@ public class PrintCsv { Root root = Root.fromFile(args[0]); - System.out.println("Name" - + ",Preloaded" - + ",Median Load Time (us)" - + ",Median Init Time (us)" - + ",Process Names" - + ",Load Count" - + ",Init Count"); -// + ",Managed Heap (B)" -// + ",Native Heap (B)" -// + ",Managed Pages (kB)" -// + ",Native Pages (kB)" -// + ",Other Pages (kB)"); + printHeaders(System.out); - MemoryUsage baseline = root.baseline; + MemoryUsage baseline = MemoryUsage.baseline(); for (LoadedClass loadedClass : root.loadedClasses.values()) { if (!loadedClass.systemClass) { continue; } - System.out.print(loadedClass.name); - System.out.print(','); - System.out.print(loadedClass.preloaded); - System.out.print(','); - System.out.print(loadedClass.medianLoadTimeMicros()); - System.out.print(','); - System.out.print(loadedClass.medianInitTimeMicros()); - System.out.print(','); - System.out.print('"'); - - Set procNames = new TreeSet(); - for (Operation op : loadedClass.loads) - procNames.add(op.process.name); - for (Operation op : loadedClass.initializations) - procNames.add(op.process.name); - for (String name : procNames) { - System.out.print(name + "\n"); - } - - System.out.print('"'); - System.out.print(','); - System.out.print(loadedClass.loads.size()); - System.out.print(','); - System.out.print(loadedClass.initializations.size()); -/* - if (loadedClass.memoryUsage.isAvailable()) { - MemoryUsage subtracted - = loadedClass.memoryUsage.subtract(baseline); - - System.out.print(','); - System.out.print(subtracted.javaHeapSize()); - System.out.print(','); - System.out.print(subtracted.nativeHeapSize); - System.out.print(','); - System.out.print(subtracted.javaPagesInK()); - System.out.print(','); - System.out.print(subtracted.nativePagesInK()); - System.out.print(','); - System.out.print(subtracted.otherPagesInK()); - - } else { - System.out.print(",n/a,n/a,n/a,n/a,n/a"); - } -*/ - System.out.println(); + printRow(System.out, baseline, loadedClass); } } + + static void printHeaders(PrintStream out) { + out.println("Name" + + ",Preloaded" + + ",Median Load Time (us)" + + ",Median Init Time (us)" + + ",Process Names" + + ",Load Count" + + ",Init Count" + + ",Managed Heap (B)" + + ",Native Heap (B)" + + ",Managed Pages (kB)" + + ",Native Pages (kB)" + + ",Other Pages (kB)"); + } + + static void printRow(PrintStream out, MemoryUsage baseline, + LoadedClass loadedClass) { + out.print(loadedClass.name); + out.print(','); + out.print(loadedClass.preloaded); + out.print(','); + out.print(loadedClass.medianLoadTimeMicros()); + out.print(','); + out.print(loadedClass.medianInitTimeMicros()); + out.print(','); + out.print('"'); + + Set procNames = new TreeSet(); + for (Operation op : loadedClass.loads) + procNames.add(op.process.name); + for (Operation op : loadedClass.initializations) + procNames.add(op.process.name); + + if (procNames.size() <= 3) { + for (String name : procNames) { + out.print(name + "\n"); + } + } else { + Iterator i = procNames.iterator(); + out.print(i.next() + "\n"); + out.print(i.next() + "\n"); + out.print("...and " + (procNames.size() - 2) + + " others."); + } + + out.print('"'); + out.print(','); + out.print(loadedClass.loads.size()); + out.print(','); + out.print(loadedClass.initializations.size()); + + if (loadedClass.memoryUsage.isAvailable()) { + MemoryUsage subtracted + = loadedClass.memoryUsage.subtract(baseline); + + out.print(','); + out.print(subtracted.javaHeapSize()); + out.print(','); + out.print(subtracted.nativeHeapSize); + out.print(','); + out.print(subtracted.javaPagesInK()); + out.print(','); + out.print(subtracted.nativePagesInK()); + out.print(','); + out.print(subtracted.otherPagesInK()); + + } else { + out.print(",n/a,n/a,n/a,n/a,n/a"); + } + + out.println(); + } } diff --git a/tools/preload/PrintHtmlDiff.java b/tools/preload/PrintHtmlDiff.java new file mode 100644 index 0000000000000..b101c85185c06 --- /dev/null +++ b/tools/preload/PrintHtmlDiff.java @@ -0,0 +1,142 @@ +/* + * 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 zygote = new HashSet(); + for (Proc proc : root.processes.values()) { + if (proc.name.equals("zygote")) { + for (Operation op : proc.operations) { + zygote.add(op.loadedClass); + } + break; + } + } + + Set removed = new TreeSet(); + Set added = new TreeSet(); + + 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(""); + out.println(""); + out.println(""); + out.println("

Removed"); + out.println("

Added

"); + printTable(out, root.baseline, added); + out.println("

Removed

"); + printTable(out, root.baseline, removed); + out.println(""); + } + + static void printTable(PrintStream out, MemoryUsage baseline, + Iterable classes) { + out.println(""); + + out.println(""); + out.println(""); + out.println(""); + out.println(""); + out.println(""); + out.println(""); + out.println(""); + + for (LoadedClass clazz : classes) { + out.println(""); + out.println(""); + out.println(""); + + out.println(""); + + if (clazz.memoryUsage.isAvailable()) { + MemoryUsage subtracted + = clazz.memoryUsage.subtract(baseline); + + out.println(""); + out.println(""); + } else { + for (int i = 0; i < 2; i++) { + out.println(""); + } + } + + out.println(""); + } + + out.println("
NameLoad Time (us)Loaded ByHeap (B)Pages
" + clazz.name + "" + clazz.medianTimeMicros() + ""); + Set procNames = new TreeSet(); + 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 + "
"); + } + } else { + Iterator i = procNames.iterator(); + out.print(i.next() + "
"); + out.print(i.next() + "
"); + out.print("...and " + (procNames.size() - 2) + + " others."); + } + out.println("
" + (subtracted.javaHeapSize() + + subtracted.nativeHeapSize) + "" + subtracted.totalPages() + "n/a
"); + } +} diff --git a/tools/preload/Proc.java b/tools/preload/Proc.java index 66e04dc360644..21050218ff8c5 100644 --- a/tools/preload/Proc.java +++ b/tools/preload/Proc.java @@ -14,13 +14,11 @@ * limitations under the License. */ -import java.util.Arrays; import java.util.List; import java.util.ArrayList; import java.util.LinkedList; import java.util.Map; import java.util.HashMap; -import java.util.Collections; import java.io.Serializable; /** @@ -30,11 +28,6 @@ class Proc implements Serializable { private static final long serialVersionUID = 0; - /** - * Default percentage of time to cut off of app class loading times. - */ - static final int PERCENTAGE_TO_PRELOAD = 75; - /** Parent process. */ final Proc parent; @@ -80,72 +73,11 @@ class Proc implements Serializable { } /** - * Returns the percentage of time we should cut by preloading for this - * app. + * Returns true if this process comes from the zygote. */ - int percentageToPreload() { - return PERCENTAGE_TO_PRELOAD; - } - - /** - * Returns a list of classes which should be preloaded. - */ - List highestRankedClasses() { - if (!isApplication() || Policy.isService(this.name)) { - return Collections.emptyList(); - } - - // Sort by rank. - Operation[] ranked = new Operation[operations.size()]; - ranked = operations.toArray(ranked); - Arrays.sort(ranked, new ClassRank()); - - // The percentage of time to save by preloading. - int timeToSave = totalTimeMicros() * percentageToPreload() / 100; - int timeSaved = 0; - - int count = 0; - List highest = new ArrayList(); - for (Operation operation : ranked) { - if (timeSaved >= timeToSave || count++ > 100) { - break; - } - - if (!Policy.isPreloadableClass(operation.loadedClass.name)) { - continue; - } - - if (!operation.loadedClass.systemClass) { - continue; - } - - highest.add(operation.loadedClass); - timeSaved += operation.medianExclusiveTimeMicros(); - } - - return highest; - } - - /** - * Total time spent class loading and initializing. - */ - int totalTimeMicros() { - int totalTime = 0; - for (Operation operation : operations) { - totalTime += operation.medianExclusiveTimeMicros(); - } - return totalTime; - } - - /** - * Returns true if this process is an app. - */ - public boolean isApplication() { - if (name.equals("com.android.development")) { - return false; - } - - return parent != null && parent.name.equals("zygote"); + public boolean fromZygote() { + return parent != null && parent.name.equals("zygote") + && !name.equals("com.android.development"); } /** diff --git a/tools/preload/Root.java b/tools/preload/Root.java index 949f9b7549b77..0bc29bfdd937e 100644 --- a/tools/preload/Root.java +++ b/tools/preload/Root.java @@ -46,7 +46,7 @@ public class Root implements Serializable { final Map loadedClasses = new HashMap(); - final MemoryUsage baseline = MemoryUsage.baseline(); + MemoryUsage baseline = MemoryUsage.baseline(); /** * Records class loads and initializations. diff --git a/tools/preload/WritePreloadedClassFile.java b/tools/preload/WritePreloadedClassFile.java index b209af0c25f60..96c539bb727ed 100644 --- a/tools/preload/WritePreloadedClassFile.java +++ b/tools/preload/WritePreloadedClassFile.java @@ -24,12 +24,18 @@ import java.util.Set; import java.util.TreeSet; /** - * Writes /frameworks/base/preloaded-classes. Also updates LoadedClass.preloaded - * fields and writes over compiled log file. + * Writes /frameworks/base/preloaded-classes. Also updates + * {@link LoadedClass#preloaded} fields and writes over compiled log file. */ public class WritePreloadedClassFile { - public static void main(String[] args) throws IOException, ClassNotFoundException { + /** + * Preload any class that take longer to load than MIN_LOAD_TIME_MICROS us. + */ + static final int MIN_LOAD_TIME_MICROS = 1250; + + public static void main(String[] args) throws IOException, + ClassNotFoundException { if (args.length != 1) { System.err.println("Usage: WritePreloadedClassFile [compiled log]"); System.exit(-1); @@ -44,48 +50,64 @@ public class WritePreloadedClassFile { // Open preloaded-classes file for output. Writer out = new BufferedWriter(new OutputStreamWriter( - new FileOutputStream(Policy.getPreloadedClassFileName()), + new FileOutputStream(Policy.PRELOADED_CLASS_FILE), Charset.forName("US-ASCII"))); - out.write("# Classes which are preloaded by com.android.internal.os.ZygoteInit.\n"); - out.write("# Automatically generated by /frameworks/base/tools/preload.\n"); - out.write("# percent=" + Proc.PERCENTAGE_TO_PRELOAD - + ", weight=" + ClassRank.SEQUENCE_WEIGHT - + ", bucket_size=" + ClassRank.BUCKET_SIZE - + "\n"); + out.write("# Classes which are preloaded by" + + " com.android.internal.os.ZygoteInit.\n"); + out.write("# Automatically generated by frameworks/base/tools/preload/" + + WritePreloadedClassFile.class.getSimpleName() + ".java.\n"); + out.write("# MIN_LOAD_TIME_MICROS=" + MIN_LOAD_TIME_MICROS + "\n"); + /* + * The set of classes to preload. We preload a class if: + * + * a) it's loaded in the bootclasspath (i.e., is a system class) + * b) it takes > MIN_LOAD_TIME_MICROS us to load, and + * c) it's loaded by more than one process, or it's loaded by an + * application (i.e., not a long running service) + */ Set toPreload = new TreeSet(); - // Preload all classes that were loaded by at least 2 apps, if both - // apps run at the same time, they'll share memory. + // Preload classes that were loaded by at least 2 processes. Hopefully, + // the memory associated with these classes will be shared. for (LoadedClass loadedClass : root.loadedClasses.values()) { - if (!loadedClass.isPreloadable()) { - continue; - } - - Set appNames = loadedClass.applicationNames(); - - if (appNames.size() > 3) { + Set names = loadedClass.processNames(); + if (shouldPreload(loadedClass) && names.size() > 1) { toPreload.add(loadedClass); } } - // Try to make individual apps start faster by preloading slowest - // classes. + int initialSize = toPreload.size(); + System.out.println(initialSize + + " classses were loaded by more than one app."); + + // Preload eligable classes from applications (not long-running + // services). for (Proc proc : root.processes.values()) { - toPreload.addAll(proc.highestRankedClasses()); + if (proc.fromZygote() && !Policy.isService(proc.name)) { + for (Operation operation : proc.operations) { + LoadedClass loadedClass = operation.loadedClass; + if (shouldPreload(loadedClass)) { + toPreload.add(loadedClass); + } + } + } } - System.out.println(toPreload.size() + " classes will be preloaded."); + System.out.println("Added " + (toPreload.size() - initialSize) + + " more to speed up applications."); - // Make classes that were already loaded by the zygote explicit. + System.out.println(toPreload.size() + + " total classes will be preloaded."); + + // Make classes that were implicitly loaded by the zygote explicit. // This adds minimal overhead but avoid confusion about classes not // appearing in the list. - addAllClassesFor("zygote", root, toPreload); + addAllClassesFrom("zygote", root, toPreload); for (LoadedClass loadedClass : toPreload) { - out.write(loadedClass.name); - out.write('\n'); + out.write(loadedClass.name + "\n"); } out.close(); @@ -97,18 +119,26 @@ public class WritePreloadedClassFile { root.toFile(rootFile); } - private static void addAllClassesFor(String packageName, Root root, - Set toPreload) { + private static void addAllClassesFrom(String processName, Root root, + Set toPreload) { for (Proc proc : root.processes.values()) { - if (proc.name.equals(packageName)) { + if (proc.name.equals(processName)) { for (Operation operation : proc.operations) { - // TODO: I'm not sure how the zygote loaded classes that - // aren't supposed to be preloadable... - if (operation.loadedClass.isPreloadable()) { + boolean preloadable + = Policy.isPreloadable(operation.loadedClass); + if (preloadable) { toPreload.add(operation.loadedClass); } } } } } + + /** + * Returns true if the class should be preloaded. + */ + private static boolean shouldPreload(LoadedClass clazz) { + return Policy.isPreloadable(clazz) + && clazz.medianTimeMicros() > MIN_LOAD_TIME_MICROS; + } } diff --git a/tools/preload/loadclass/LoadClass.java b/tools/preload/loadclass/LoadClass.java index 471cc842a8e08..a71b6a8b145e7 100644 --- a/tools/preload/loadclass/LoadClass.java +++ b/tools/preload/loadclass/LoadClass.java @@ -35,7 +35,11 @@ class LoadClass { if (args.length > 0) { try { + long start = System.currentTimeMillis(); Class.forName(args[0]); + long elapsed = System.currentTimeMillis() - start; + Log.i("LoadClass", "Loaded " + args[0] + " in " + elapsed + + "ms."); } catch (ClassNotFoundException e) { Log.w("LoadClass", e); return; diff --git a/tools/preload/preload.ipr b/tools/preload/preload.ipr index f78bf76567fb2..0c9621c6ed43c 100644 --- a/tools/preload/preload.ipr +++ b/tools/preload/preload.ipr @@ -25,7 +25,28 @@