The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2008 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.BufferedWriter; |
| 18 | import java.io.FileOutputStream; |
| 19 | import java.io.IOException; |
| 20 | import java.io.OutputStreamWriter; |
| 21 | import java.io.Writer; |
| 22 | import java.nio.charset.Charset; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 23 | import java.util.Set; |
| 24 | import java.util.TreeSet; |
| 25 | |
| 26 | /** |
Bob Lee | 9d2d6e1 | 2009-08-13 14:41:54 -0700 | [diff] [blame] | 27 | * Writes /frameworks/base/preloaded-classes. Also updates |
| 28 | * {@link LoadedClass#preloaded} fields and writes over compiled log file. |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 29 | */ |
| 30 | public class WritePreloadedClassFile { |
| 31 | |
Bob Lee | 9d2d6e1 | 2009-08-13 14:41:54 -0700 | [diff] [blame] | 32 | /** |
| 33 | * Preload any class that take longer to load than MIN_LOAD_TIME_MICROS us. |
| 34 | */ |
| 35 | static final int MIN_LOAD_TIME_MICROS = 1250; |
| 36 | |
Jesse Wilson | eaca10e | 2010-10-12 21:35:56 -0700 | [diff] [blame] | 37 | /** |
| 38 | * Preload any class that was loaded by at least MIN_PROCESSES processes. |
| 39 | */ |
| 40 | static final int MIN_PROCESSES = 10; |
| 41 | |
Bob Lee | 9d2d6e1 | 2009-08-13 14:41:54 -0700 | [diff] [blame] | 42 | public static void main(String[] args) throws IOException, |
| 43 | ClassNotFoundException { |
Bob Lee | 2e93f65 | 2009-08-11 01:16:03 -0700 | [diff] [blame] | 44 | if (args.length != 1) { |
| 45 | System.err.println("Usage: WritePreloadedClassFile [compiled log]"); |
| 46 | System.exit(-1); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 47 | } |
Bob Lee | 2e93f65 | 2009-08-11 01:16:03 -0700 | [diff] [blame] | 48 | String rootFile = args[0]; |
| 49 | Root root = Root.fromFile(rootFile); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 50 | |
Bob Lee | 2e93f65 | 2009-08-11 01:16:03 -0700 | [diff] [blame] | 51 | // No classes are preloaded to start. |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 52 | for (LoadedClass loadedClass : root.loadedClasses.values()) { |
| 53 | loadedClass.preloaded = false; |
| 54 | } |
| 55 | |
Bob Lee | 2e93f65 | 2009-08-11 01:16:03 -0700 | [diff] [blame] | 56 | // Open preloaded-classes file for output. |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 57 | Writer out = new BufferedWriter(new OutputStreamWriter( |
Bob Lee | 9d2d6e1 | 2009-08-13 14:41:54 -0700 | [diff] [blame] | 58 | new FileOutputStream(Policy.PRELOADED_CLASS_FILE), |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 59 | Charset.forName("US-ASCII"))); |
| 60 | |
Bob Lee | 9d2d6e1 | 2009-08-13 14:41:54 -0700 | [diff] [blame] | 61 | out.write("# Classes which are preloaded by" |
| 62 | + " com.android.internal.os.ZygoteInit.\n"); |
| 63 | out.write("# Automatically generated by frameworks/base/tools/preload/" |
| 64 | + WritePreloadedClassFile.class.getSimpleName() + ".java.\n"); |
| 65 | out.write("# MIN_LOAD_TIME_MICROS=" + MIN_LOAD_TIME_MICROS + "\n"); |
Jesse Wilson | eaca10e | 2010-10-12 21:35:56 -0700 | [diff] [blame] | 66 | out.write("# MIN_PROCESSES=" + MIN_PROCESSES + "\n"); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 67 | |
Bob Lee | 9d2d6e1 | 2009-08-13 14:41:54 -0700 | [diff] [blame] | 68 | /* |
| 69 | * The set of classes to preload. We preload a class if: |
| 70 | * |
| 71 | * a) it's loaded in the bootclasspath (i.e., is a system class) |
| 72 | * b) it takes > MIN_LOAD_TIME_MICROS us to load, and |
| 73 | * c) it's loaded by more than one process, or it's loaded by an |
| 74 | * application (i.e., not a long running service) |
| 75 | */ |
Bob Lee | 2e93f65 | 2009-08-11 01:16:03 -0700 | [diff] [blame] | 76 | Set<LoadedClass> toPreload = new TreeSet<LoadedClass>(); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 77 | |
Bob Lee | 9d2d6e1 | 2009-08-13 14:41:54 -0700 | [diff] [blame] | 78 | // Preload classes that were loaded by at least 2 processes. Hopefully, |
| 79 | // the memory associated with these classes will be shared. |
Bob Lee | 2e93f65 | 2009-08-11 01:16:03 -0700 | [diff] [blame] | 80 | for (LoadedClass loadedClass : root.loadedClasses.values()) { |
Bob Lee | 9d2d6e1 | 2009-08-13 14:41:54 -0700 | [diff] [blame] | 81 | Set<String> names = loadedClass.processNames(); |
Jesse Wilson | eaca10e | 2010-10-12 21:35:56 -0700 | [diff] [blame] | 82 | if (!Policy.isPreloadable(loadedClass)) { |
| 83 | continue; |
| 84 | } |
| 85 | |
| 86 | if (names.size() >= MIN_PROCESSES || |
| 87 | (loadedClass.medianTimeMicros() > MIN_LOAD_TIME_MICROS && names.size() > 1)) { |
Bob Lee | 2e93f65 | 2009-08-11 01:16:03 -0700 | [diff] [blame] | 88 | toPreload.add(loadedClass); |
| 89 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 90 | } |
| 91 | |
Bob Lee | 9d2d6e1 | 2009-08-13 14:41:54 -0700 | [diff] [blame] | 92 | int initialSize = toPreload.size(); |
| 93 | System.out.println(initialSize |
| 94 | + " classses were loaded by more than one app."); |
| 95 | |
| 96 | // Preload eligable classes from applications (not long-running |
| 97 | // services). |
Bob Lee | 2e93f65 | 2009-08-11 01:16:03 -0700 | [diff] [blame] | 98 | for (Proc proc : root.processes.values()) { |
Bob Lee | 9d2d6e1 | 2009-08-13 14:41:54 -0700 | [diff] [blame] | 99 | if (proc.fromZygote() && !Policy.isService(proc.name)) { |
| 100 | for (Operation operation : proc.operations) { |
| 101 | LoadedClass loadedClass = operation.loadedClass; |
| 102 | if (shouldPreload(loadedClass)) { |
| 103 | toPreload.add(loadedClass); |
| 104 | } |
| 105 | } |
| 106 | } |
Bob Lee | 2e93f65 | 2009-08-11 01:16:03 -0700 | [diff] [blame] | 107 | } |
| 108 | |
Bob Lee | 9d2d6e1 | 2009-08-13 14:41:54 -0700 | [diff] [blame] | 109 | System.out.println("Added " + (toPreload.size() - initialSize) |
| 110 | + " more to speed up applications."); |
Bob Lee | 2e93f65 | 2009-08-11 01:16:03 -0700 | [diff] [blame] | 111 | |
Bob Lee | 9d2d6e1 | 2009-08-13 14:41:54 -0700 | [diff] [blame] | 112 | System.out.println(toPreload.size() |
| 113 | + " total classes will be preloaded."); |
| 114 | |
| 115 | // Make classes that were implicitly loaded by the zygote explicit. |
Bob Lee | 2e93f65 | 2009-08-11 01:16:03 -0700 | [diff] [blame] | 116 | // This adds minimal overhead but avoid confusion about classes not |
| 117 | // appearing in the list. |
Bob Lee | 9d2d6e1 | 2009-08-13 14:41:54 -0700 | [diff] [blame] | 118 | addAllClassesFrom("zygote", root, toPreload); |
Bob Lee | 2e93f65 | 2009-08-11 01:16:03 -0700 | [diff] [blame] | 119 | |
| 120 | for (LoadedClass loadedClass : toPreload) { |
Bob Lee | 9d2d6e1 | 2009-08-13 14:41:54 -0700 | [diff] [blame] | 121 | out.write(loadedClass.name + "\n"); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 122 | } |
| 123 | |
| 124 | out.close(); |
| 125 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 126 | // Update data to reflect LoadedClass.preloaded changes. |
Bob Lee | 2e93f65 | 2009-08-11 01:16:03 -0700 | [diff] [blame] | 127 | for (LoadedClass loadedClass : toPreload) { |
| 128 | loadedClass.preloaded = true; |
| 129 | } |
| 130 | root.toFile(rootFile); |
| 131 | } |
| 132 | |
Bob Lee | 9d2d6e1 | 2009-08-13 14:41:54 -0700 | [diff] [blame] | 133 | private static void addAllClassesFrom(String processName, Root root, |
| 134 | Set<LoadedClass> toPreload) { |
Bob Lee | 2e93f65 | 2009-08-11 01:16:03 -0700 | [diff] [blame] | 135 | for (Proc proc : root.processes.values()) { |
Bob Lee | 9d2d6e1 | 2009-08-13 14:41:54 -0700 | [diff] [blame] | 136 | if (proc.name.equals(processName)) { |
Bob Lee | 2e93f65 | 2009-08-11 01:16:03 -0700 | [diff] [blame] | 137 | for (Operation operation : proc.operations) { |
Bob Lee | 9d2d6e1 | 2009-08-13 14:41:54 -0700 | [diff] [blame] | 138 | boolean preloadable |
| 139 | = Policy.isPreloadable(operation.loadedClass); |
| 140 | if (preloadable) { |
Bob Lee | 2e93f65 | 2009-08-11 01:16:03 -0700 | [diff] [blame] | 141 | toPreload.add(operation.loadedClass); |
| 142 | } |
| 143 | } |
| 144 | } |
| 145 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 146 | } |
Bob Lee | 9d2d6e1 | 2009-08-13 14:41:54 -0700 | [diff] [blame] | 147 | |
| 148 | /** |
| 149 | * Returns true if the class should be preloaded. |
| 150 | */ |
| 151 | private static boolean shouldPreload(LoadedClass clazz) { |
| 152 | return Policy.isPreloadable(clazz) |
| 153 | && clazz.medianTimeMicros() > MIN_LOAD_TIME_MICROS; |
| 154 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 155 | } |