Merge change 24060 into eclair

* changes:
  Integrated the profiler into the framework. We run it all the time if the persist.sampling_profiler system property is set. Saves snapshots to the SD card.
This commit is contained in:
Android (Google) Code Review
2009-09-06 16:41:35 -07:00
5 changed files with 315 additions and 121 deletions

View File

@@ -68,6 +68,7 @@ import android.view.WindowManagerImpl;
import com.android.internal.os.BinderInternal; import com.android.internal.os.BinderInternal;
import com.android.internal.os.RuntimeInit; import com.android.internal.os.RuntimeInit;
import com.android.internal.os.SamplingProfilerIntegration;
import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils;
import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl; import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl;
@@ -87,6 +88,8 @@ import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import dalvik.system.SamplingProfiler;
final class IntentReceiverLeaked extends AndroidRuntimeException { final class IntentReceiverLeaked extends AndroidRuntimeException {
public IntentReceiverLeaked(String msg) { public IntentReceiverLeaked(String msg) {
super(msg); super(msg);
@@ -1727,6 +1730,10 @@ public final class ActivityThread {
} }
private final class H extends Handler { private final class H extends Handler {
private H() {
SamplingProfiler.getInstance().setEventThread(mLooper.getThread());
}
public static final int LAUNCH_ACTIVITY = 100; public static final int LAUNCH_ACTIVITY = 100;
public static final int PAUSE_ACTIVITY = 101; public static final int PAUSE_ACTIVITY = 101;
public static final int PAUSE_ACTIVITY_FINISHING= 102; public static final int PAUSE_ACTIVITY_FINISHING= 102;
@@ -1811,6 +1818,7 @@ public final class ActivityThread {
} break; } break;
case PAUSE_ACTIVITY: case PAUSE_ACTIVITY:
handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2); handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);
maybeSnapshot();
break; break;
case PAUSE_ACTIVITY_FINISHING: case PAUSE_ACTIVITY_FINISHING:
handlePauseActivity((IBinder)msg.obj, true, msg.arg1 != 0, msg.arg2); handlePauseActivity((IBinder)msg.obj, true, msg.arg1 != 0, msg.arg2);
@@ -1853,6 +1861,7 @@ public final class ActivityThread {
break; break;
case RECEIVER: case RECEIVER:
handleReceiver((ReceiverData)msg.obj); handleReceiver((ReceiverData)msg.obj);
maybeSnapshot();
break; break;
case CREATE_SERVICE: case CREATE_SERVICE:
handleCreateService((CreateServiceData)msg.obj); handleCreateService((CreateServiceData)msg.obj);
@@ -1868,6 +1877,7 @@ public final class ActivityThread {
break; break;
case STOP_SERVICE: case STOP_SERVICE:
handleStopService((IBinder)msg.obj); handleStopService((IBinder)msg.obj);
maybeSnapshot();
break; break;
case REQUEST_THUMBNAIL: case REQUEST_THUMBNAIL:
handleRequestThumbnail((IBinder)msg.obj); handleRequestThumbnail((IBinder)msg.obj);
@@ -1907,6 +1917,13 @@ public final class ActivityThread {
break; break;
} }
} }
void maybeSnapshot() {
if (mBoundApplication != null) {
SamplingProfilerIntegration.writeSnapshot(
mBoundApplication.processName);
}
}
} }
private final class Idler implements MessageQueue.IdleHandler { private final class Idler implements MessageQueue.IdleHandler {
@@ -4213,6 +4230,8 @@ public final class ActivityThread {
} }
public static final void main(String[] args) { public static final void main(String[] args) {
SamplingProfilerIntegration.start();
Process.setArgV0("<pre-initialized>"); Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper(); Looper.prepareMainLooper();
@@ -4228,8 +4247,11 @@ public final class ActivityThread {
thread.detach(); thread.detach();
String name; String name;
if (thread.mInitialApplication != null) name = thread.mInitialApplication.getPackageName(); if (thread.mInitialApplication != null) {
else name = "<unknown>"; name = thread.mInitialApplication.getPackageName();
} else {
name = "<unknown>";
}
Log.i(TAG, "Main thread of " + name + " is now exiting"); Log.i(TAG, "Main thread of " + name + " is now exiting");
} }
} }

View File

@@ -0,0 +1,144 @@
package com.android.internal.os;
import dalvik.system.SamplingProfiler;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import android.util.Log;
import android.os.*;
import android.net.Uri;
/**
* Integrates the framework with Dalvik's sampling profiler.
*/
public class SamplingProfilerIntegration {
private static final String TAG = "SamplingProfilerIntegration";
private static final boolean enabled;
private static final Executor snapshotWriter;
static {
enabled = "1".equals(SystemProperties.get("persist.sampling_profiler"));
if (enabled) {
snapshotWriter = Executors.newSingleThreadExecutor();
Log.i(TAG, "Profiler is enabled.");
} else {
snapshotWriter = null;
Log.i(TAG, "Profiler is disabled.");
}
}
/**
* Is profiling enabled?
*/
public static boolean isEnabled() {
return enabled;
}
/**
* Starts the profiler if profiling is enabled.
*/
public static void start() {
if (!enabled) return;
SamplingProfiler.getInstance().start(10);
}
/** Whether or not we've created the snapshots dir. */
static boolean dirMade = false;
/** Whether or not a snapshot is being persisted. */
static volatile boolean pending;
/**
* Writes a snapshot to the SD card if profiling is enabled.
*/
public static void writeSnapshot(final String name) {
if (!enabled) return;
if (!pending) {
pending = true;
snapshotWriter.execute(new Runnable() {
public void run() {
String dir = "/sdcard/snapshots";
if (!dirMade) {
makeDirectory(dir);
dirMade = true;
}
try {
writeSnapshot(dir, name);
} finally {
pending = false;
}
}
});
}
}
/**
* Writes the zygote's snapshot to internal storage if profiling is enabled.
*/
public static void writeZygoteSnapshot() {
if (!enabled) return;
String dir = "/data/zygote/snapshots";
makeDirectory(dir);
writeSnapshot(dir, "zygote");
}
private static void writeSnapshot(String dir, String name) {
byte[] snapshot = SamplingProfiler.getInstance().snapshot();
if (snapshot == null) {
return;
}
/*
* We use the current time as a unique ID. We can't use a counter
* because processes restart. This could result in some overlap if
* we capture two snapshots in rapid succession.
*/
long start = System.currentTimeMillis();
String path = dir + "/" + name.replace(':', '.') + "-"
+ System.currentTimeMillis() + ".snapshot";
try {
// Try to open the file a few times. The SD card may not be mounted.
FileOutputStream out;
int count = 0;
while (true) {
try {
out = new FileOutputStream(path);
break;
} catch (FileNotFoundException e) {
if (++count > 3) {
Log.e(TAG, "Could not open " + path + ".");
return;
}
// Sleep for a bit and then try again.
try {
Thread.sleep(2500);
} catch (InterruptedException e1) { /* ignore */ }
}
}
try {
out.write(snapshot);
} finally {
out.close();
}
long elapsed = System.currentTimeMillis() - start;
Log.i(TAG, "Wrote snapshot for " + name
+ " in " + elapsed + "ms.");
} catch (IOException e) {
Log.e(TAG, "Error writing snapshot.", e);
}
}
private static void makeDirectory(String dir) {
new File(dir).mkdirs();
}
}

View File

@@ -19,7 +19,6 @@ package com.android.internal.os;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.res.Resources; import android.content.res.Resources;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.LocalServerSocket; import android.net.LocalServerSocket;
import android.os.Debug; import android.os.Debug;
@@ -31,6 +30,7 @@ import android.util.Log;
import dalvik.system.VMRuntime; import dalvik.system.VMRuntime;
import dalvik.system.Zygote; import dalvik.system.Zygote;
import dalvik.system.SamplingProfiler;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.FileDescriptor; import java.io.FileDescriptor;
@@ -573,6 +573,9 @@ public class ZygoteInit {
public static void main(String argv[]) { public static void main(String argv[]) {
try { try {
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();
registerZygoteSocket(); registerZygoteSocket();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis()); SystemClock.uptimeMillis());
@@ -582,6 +585,13 @@ public class ZygoteInit {
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis()); SystemClock.uptimeMillis());
if (SamplingProfilerIntegration.isEnabled()) {
SamplingProfiler sp = SamplingProfiler.getInstance();
sp.pause();
SamplingProfilerIntegration.writeZygoteSnapshot();
sp.shutDown();
}
// Do an initial gc to clean up after startup // Do an initial gc to clean up after startup
gc(); gc();

View File

@@ -18,6 +18,7 @@ package com.android.server;
import com.android.server.am.ActivityManagerService; import com.android.server.am.ActivityManagerService;
import com.android.server.status.StatusBarService; import com.android.server.status.StatusBarService;
import com.android.internal.os.SamplingProfilerIntegration;
import dalvik.system.VMRuntime; import dalvik.system.VMRuntime;
@@ -41,6 +42,9 @@ import android.util.EventLog;
import android.util.Log; import android.util.Log;
import android.accounts.AccountManagerService; import android.accounts.AccountManagerService;
import java.util.Timer;
import java.util.TimerTask;
class ServerThread extends Thread { class ServerThread extends Thread {
private static final String TAG = "SystemServer"; private static final String TAG = "SystemServer";
private final static boolean INCLUDE_DEMO = false; private final static boolean INCLUDE_DEMO = false;
@@ -452,6 +456,9 @@ public class SystemServer
public static final int FACTORY_TEST_LOW_LEVEL = 1; public static final int FACTORY_TEST_LOW_LEVEL = 1;
public static final int FACTORY_TEST_HIGH_LEVEL = 2; public static final int FACTORY_TEST_HIGH_LEVEL = 2;
static Timer timer;
static final long SNAPSHOT_INTERVAL = 60 * 60 * 1000; // 1hr
/** /**
* This method is called from Zygote to initialize the system. This will cause the native * This method is called from Zygote to initialize the system. This will cause the native
* services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back * services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back
@@ -460,6 +467,17 @@ public class SystemServer
native public static void init1(String[] args); native public static void init1(String[] args);
public static void main(String[] args) { public static void main(String[] args) {
if (SamplingProfilerIntegration.isEnabled()) {
SamplingProfilerIntegration.start();
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
SamplingProfilerIntegration.writeSnapshot("system_server");
}
}, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
}
// The system server has to run all of the time, so it needs to be // The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage. // as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f); VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);