Merge change 20713 into donut

* changes:
  Updated preloaded-classes file.
This commit is contained in:
Android (Google) Code Review
2009-08-11 12:48:36 -07:00
11 changed files with 1582 additions and 312 deletions

View File

@@ -291,6 +291,15 @@ public class ZygoteInit {
} else {
missingClasses += " " + line;
}
} catch (Throwable t) {
Log.e(TAG, "Error preloading " + line + ".", t);
if (t instanceof Error) {
throw (Error) t;
}
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
}
throw new RuntimeException(t);
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -26,7 +26,7 @@ class ClassRank implements Comparator<Operation> {
* Increase this number to add more weight to classes which were loaded
* earlier.
*/
static final int SEQUENCE_WEIGHT = 500; // 5 ms
static final int SEQUENCE_WEIGHT = 500; // 0.5ms
static final int BUCKET_SIZE = 5;

View File

@@ -15,10 +15,7 @@
*/
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.*;
/**
* A loaded class.
@@ -54,7 +51,7 @@ class LoadedClass implements Serializable, Comparable<LoadedClass> {
}
void measureMemoryUsage() {
this.memoryUsage = MemoryUsage.forClass(name);
// this.memoryUsage = MemoryUsage.forClass(name);
}
int mlt = -1;
@@ -102,31 +99,20 @@ class LoadedClass implements Serializable, Comparable<LoadedClass> {
}
}
/**
* Counts loads by apps.
*/
int appLoads() {
return operationsByApps(loads);
/** Returns names of apps that loaded this class. */
Set<String> applicationNames() {
Set<String> appNames = new HashSet<String>();
addProcessNames(loads, appNames);
addProcessNames(initializations, appNames);
return appNames;
}
/**
* Counts inits by apps.
*/
int appInits() {
return operationsByApps(initializations);
}
/**
* Counts number of app operations in the given list.
*/
private static int operationsByApps(List<Operation> operations) {
int byApps = 0;
for (Operation operation : operations) {
private void addProcessNames(List<Operation> ops, Set<String> appNames) {
for (Operation operation : ops) {
if (operation.process.isApplication()) {
byApps++;
appNames.add(operation.process.name);
}
}
return byApps;
}
public int compareTo(LoadedClass o) {
@@ -160,4 +146,8 @@ class LoadedClass implements Serializable, Comparable<LoadedClass> {
return false;
}
public boolean isPreloadable() {
return systemClass && Policy.isPreloadableClass(name);
}
}

View File

@@ -23,48 +23,33 @@ import java.util.Set;
*/
public class Policy {
/**
* No constructor - use static methods only
*/
private Policy() {}
/**
* This location (in the build system) of the preloaded-classes file.
*/
private static final String PRELOADED_CLASS_FILE = "frameworks/base/preloaded-classes";
private static final String PRELOADED_CLASS_FILE
= "frameworks/base/preloaded-classes";
/**
* The internal process name of the system process. Note, this also shows up as
* "system_process", e.g. in ddms.
*/
private static final String SYSTEM_SERVER_PROCESS_NAME = "system_server";
/**
* Names of non-application processes - these will not be checked for preloaded classes.
*
* TODO: Replace this hardcoded list with a walk up the parent chain looking for zygote.
*/
private static final Set<String> NOT_FROM_ZYGOTE = new HashSet<String>(Arrays.asList(
"zygote",
"dexopt",
"unknown",
SYSTEM_SERVER_PROCESS_NAME,
"com.android.development",
"app_process" // am & other shell commands
));
/**
* Long running services. These are restricted in their contribution to the preloader
* because their launch time is less critical.
* Long running services. These are restricted in their contribution to the
* preloader because their launch time is less critical.
*/
private static final Set<String> SERVICES = new HashSet<String>(Arrays.asList(
SYSTEM_SERVER_PROCESS_NAME,
"com.android.acore",
// Commented out to make sure DefaultTimeZones gets preloaded.
// "com.android.phone",
"system_server",
"com.google.process.content",
"android.process.media"
"android.process.media",
"com.google.process.gapps"
));
/**
* Classes which we shouldn't load from the Zygote.
*/
private static final Set<String> EXCLUDED_CLASSES = new HashSet<String>(Arrays.asList(
private static final Set<String> EXCLUDED_CLASSES
= new HashSet<String>(Arrays.asList(
// Binders
"android.app.AlarmManager",
"android.app.SearchManager",
@@ -75,14 +60,8 @@ public class Policy {
"android.os.AsyncTask",
"android.pim.ContactsAsyncHelper",
"java.lang.ProcessManager"
));
/**
* No constructor - use static methods only
*/
private Policy() {}
/**
* Returns the path/file name of the preloaded classes file that will be written
* by WritePreloadedClassFile.
@@ -91,13 +70,6 @@ public class Policy {
return PRELOADED_CLASS_FILE;
}
/**
* Reports if a given process name was created from zygote
*/
public static boolean isFromZygote(String processName) {
return !NOT_FROM_ZYGOTE.contains(processName);
}
/**
* Reports if the given process name is a "long running" process or service
*/

View File

@@ -18,6 +18,9 @@ import java.io.IOException;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.BufferedInputStream;
import java.util.Set;
import java.util.HashSet;
import java.util.TreeSet;
/**
* Prints raw information in CSV format.
@@ -37,13 +40,14 @@ public class PrintCsv {
+ ",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)");
+ ",Init Count");
// + ",Managed Heap (B)"
// + ",Native Heap (B)"
// + ",Managed Pages (kB)"
// + ",Native Pages (kB)"
// + ",Other Pages (kB)");
MemoryUsage baseline = root.baseline;
@@ -60,10 +64,23 @@ public class PrintCsv {
System.out.print(',');
System.out.print(loadedClass.medianInitTimeMicros());
System.out.print(',');
System.out.print('"');
Set<String> procNames = new TreeSet<String>();
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);
@@ -82,7 +99,7 @@ public class PrintCsv {
} else {
System.out.print(",n/a,n/a,n/a,n/a,n/a");
}
*/
System.out.println();
}
}

View File

@@ -14,8 +14,6 @@
* limitations under the License.
*/
import java.util.Set;
import java.util.HashSet;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
@@ -23,7 +21,6 @@ import java.util.LinkedList;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import java.util.TreeSet;
import java.io.Serializable;
/**
@@ -38,11 +35,6 @@ class Proc implements Serializable {
*/
static final int PERCENTAGE_TO_PRELOAD = 75;
/**
* Maximum number of classes to preload for a given process.
*/
static final int MAX_TO_PRELOAD = 100;
/** Parent process. */
final Proc parent;
@@ -97,11 +89,9 @@ class Proc implements Serializable {
/**
* Returns a list of classes which should be preloaded.
*
* @param takeAllClasses forces all classes to be taken (irrespective of ranking)
*/
List<LoadedClass> highestRankedClasses(boolean takeAllClasses) {
if (!isApplication()) {
List<LoadedClass> highestRankedClasses() {
if (!isApplication() || Policy.isService(this.name)) {
return Collections.emptyList();
}
@@ -114,25 +104,13 @@ class Proc implements Serializable {
int timeToSave = totalTimeMicros() * percentageToPreload() / 100;
int timeSaved = 0;
boolean service = Policy.isService(this.name);
int count = 0;
List<LoadedClass> highest = new ArrayList<LoadedClass>();
for (Operation operation : ranked) {
// These are actual ranking decisions, which can be overridden
if (!takeAllClasses) {
if (highest.size() >= MAX_TO_PRELOAD) {
System.out.println(name + " got "
+ (timeSaved * 100 / timeToSave) + "% through");
break;
}
if (timeSaved >= timeToSave) {
break;
}
if (timeSaved >= timeToSave || count++ > 100) {
break;
}
// The remaining rules apply even to wired-down processes
if (!Policy.isPreloadableClass(operation.loadedClass.name)) {
continue;
}
@@ -140,13 +118,8 @@ class Proc implements Serializable {
if (!operation.loadedClass.systemClass) {
continue;
}
// Only load java.* class for services.
if (!service || operation.loadedClass.name.startsWith("java.")) {
highest.add(operation.loadedClass);
}
// For services, still count the time even if it's not in java.*
highest.add(operation.loadedClass);
timeSaved += operation.medianExclusiveTimeMicros();
}
@@ -166,11 +139,13 @@ class Proc implements Serializable {
/**
* Returns true if this process is an app.
*
* TODO: Replace the hardcoded list with a walk up the parent chain looking for zygote.
*/
public boolean isApplication() {
return Policy.isFromZygote(name);
if (name.equals("com.android.development")) {
return false;
}
return parent != null && parent.name.equals("zygote");
}
/**

View File

@@ -20,8 +20,6 @@ import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
@@ -32,71 +30,85 @@ import java.util.TreeSet;
public class WritePreloadedClassFile {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// Process command-line arguments first
List<String> wiredProcesses = new ArrayList<String>();
String inputFileName = null;
int argOffset = 0;
try {
while ("--preload-all-process".equals(args[argOffset])) {
argOffset++;
wiredProcesses.add(args[argOffset++]);
}
inputFileName = args[argOffset++];
} catch (RuntimeException e) {
System.err.println("Usage: WritePreloadedClassFile " +
"[--preload-all-process process-name] " +
"[compiled log file]");
System.exit(0);
if (args.length != 1) {
System.err.println("Usage: WritePreloadedClassFile [compiled log]");
System.exit(-1);
}
String rootFile = args[0];
Root root = Root.fromFile(rootFile);
Root root = Root.fromFile(inputFileName);
// No classes are preloaded to start.
for (LoadedClass loadedClass : root.loadedClasses.values()) {
loadedClass.preloaded = false;
}
// Open preloaded-classes file for output.
Writer out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(Policy.getPreloadedClassFileName()),
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
out.write("# percent=" + Proc.PERCENTAGE_TO_PRELOAD
+ ", weight=" + ClassRank.SEQUENCE_WEIGHT
+ ", bucket_size=" + ClassRank.BUCKET_SIZE
+ "\n");
for (String wiredProcess : wiredProcesses) {
out.write("# forcing classes loaded by: " + wiredProcess + "\n");
}
Set<LoadedClass> highestRanked = new TreeSet<LoadedClass>();
for (Proc proc : root.processes.values()) {
// test to see if this is one of the wired-down ("take all classes") processes
boolean isWired = wiredProcesses.contains(proc.name);
List<LoadedClass> highestForProc = proc.highestRankedClasses(isWired);
Set<LoadedClass> toPreload = new TreeSet<LoadedClass>();
System.out.println(proc.name + ": " + highestForProc.size());
for (LoadedClass loadedClass : highestForProc) {
loadedClass.preloaded = true;
// Preload all classes that were loaded by at least 2 apps, if both
// apps run at the same time, they'll share memory.
for (LoadedClass loadedClass : root.loadedClasses.values()) {
if (!loadedClass.isPreloadable()) {
continue;
}
Set<String> appNames = loadedClass.applicationNames();
if (appNames.size() > 3) {
toPreload.add(loadedClass);
}
highestRanked.addAll(highestForProc);
}
for (LoadedClass loadedClass : highestRanked) {
// Try to make individual apps start faster by preloading slowest
// classes.
for (Proc proc : root.processes.values()) {
toPreload.addAll(proc.highestRankedClasses());
}
System.out.println(toPreload.size() + " classes will be preloaded.");
// Make classes that were already loaded by the zygote explicit.
// This adds minimal overhead but avoid confusion about classes not
// appearing in the list.
addAllClassesFor("zygote", root, toPreload);
for (LoadedClass loadedClass : toPreload) {
out.write(loadedClass.name);
out.write('\n');
}
out.close();
System.out.println(highestRanked.size()
+ " classes will be preloaded.");
// Update data to reflect LoadedClass.preloaded changes.
root.toFile(inputFileName);
for (LoadedClass loadedClass : toPreload) {
loadedClass.preloaded = true;
}
root.toFile(rootFile);
}
private static void addAllClassesFor(String packageName, Root root,
Set<LoadedClass> toPreload) {
for (Proc proc : root.processes.values()) {
if (proc.name.equals(packageName)) {
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()) {
toPreload.add(operation.loadedClass);
}
}
}
}
}
}

View File

@@ -1,15 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module relativePaths="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="false">
<output url="file:///tmp/preload/" />
<output url="file:///tmp/preload" />
<output-test url="file:///tmp/preload" />
<exclude-output />
<output-test url="file:///tmp/preload/" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntryProperties />
</component>
</module>

View File

@@ -114,6 +114,7 @@
<option name="ADDITIONAL_OPTIONS_STRING" value="" />
<option name="MAXIMUM_HEAP_SIZE" value="128" />
</component>
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
@@ -125,13 +126,13 @@
<component name="IdProvider" IDEtalkID="D171F99B9178C1675593DC9A76A5CC7E" />
<component name="InspectionProjectProfileManager">
<option name="PROJECT_PROFILE" value="Project Default" />
<option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
<scopes />
<option name="USE_PROJECT_PROFILE" value="true" />
<version value="1.0" />
<profiles>
<profile version="1.0" is_locked="false">
<option name="myName" value="Project Default" />
<option name="myLocal" value="false" />
<inspection_tool class="JavaDoc" level="WARNING" enabled="false">
<inspection_tool class="JavaDoc" enabled="false" level="WARNING" enabled_by_default="false">
<option name="TOP_LEVEL_CLASS_OPTIONS">
<value>
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
@@ -160,14 +161,19 @@
<option name="IGNORE_JAVADOC_PERIOD" value="true" />
<option name="myAdditionalJavadocTags" value="" />
</inspection_tool>
<inspection_tool class="OnDemandImport" level="WARNING" enabled="true" />
<inspection_tool class="SamePackageImport" level="WARNING" enabled="true" />
<inspection_tool class="JavaLangImport" level="WARNING" enabled="true" />
<inspection_tool class="RedundantImport" level="WARNING" enabled="true" />
<inspection_tool class="UnusedImport" level="WARNING" enabled="true" />
<inspection_tool class="JavaLangImport" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="OnDemandImport" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="RedundantImport" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SamePackageImport" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnusedImport" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</profiles>
<list size="0" />
<list size="4">
<item index="0" class="java.lang.String" itemvalue="WARNING" />
<item index="1" class="java.lang.String" itemvalue="SERVER PROBLEM" />
<item index="2" class="java.lang.String" itemvalue="INFO" />
<item index="3" class="java.lang.String" itemvalue="ERROR" />
</list>
</component>
<component name="JavacSettings">
<option name="DEBUGGING_INFO" value="true" />
@@ -332,13 +338,19 @@
<option name="USE_CLIENT_FILTER" value="true" />
<option name="CLIENT" value="" />
</component>
<component name="ProjectDetails">
<option name="projectName" value="preload" />
</component>
<component name="ProjectFileVersion" converted="true" />
<component name="ProjectKey">
<option name="state" value="project:///Volumes/Android/donut/frameworks/base/tools/preload/preload.ipr" />
</component>
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/preload.iml" filepath="$PROJECT_DIR$/preload.iml" />
</modules>
</component>
<component name="ProjectRootManager" version="2" assert-keyword="true" jdk-15="true" project-jdk-name="1.5" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_5" assert-keyword="true" jdk-15="true" project-jdk-name="1.5" project-jdk-type="JavaSDK">
<output url="file:///tmp/preload" />
</component>
<component name="RmicSettings">
@@ -374,6 +386,9 @@
<option name="myValidatorValidationEnabled" value="true" />
<option name="myReportErrorsAsWarnings" value="true" />
</component>
<component name="SvnBranchConfigurationManager">
<option name="mySupportsUserInfoFilter" value="true" />
</component>
<component name="SvnChangesBrowserSettings">
<option name="USE_AUTHOR_FIELD" value="true" />
<option name="AUTHOR" value="" />
@@ -381,15 +396,6 @@
<option name="USE_PROJECT_SETTINGS" value="true" />
<option name="USE_ALTERNATE_LOCATION" value="false" />
</component>
<component name="SvnConfiguration">
<option name="USER" value="" />
<option name="PASSWORD" value="" />
<option name="PROCESS_UNRESOLVED" value="false" />
<option name="LAST_MERGED_REVISION" />
<option name="UPDATE_RUN_STATUS" value="false" />
<option name="UPDATE_RECURSIVELY" value="true" />
<option name="MERGE_DRY_RUN" value="false" />
</component>
<component name="VCS.FileViewConfiguration">
<option name="SELECTED_STATUSES" value="DEFAULT" />
<option name="SELECTED_COLUMNS" value="DEFAULT" />